diff --git a/include/group.hpp b/include/group.hpp index c5faf7c3..afd705b0 100644 --- a/include/group.hpp +++ b/include/group.hpp @@ -10,7 +10,7 @@ namespace waybar { class Group : public AModule { - sigc::connection reveal_timeout_; + sigc::connection reveal_timeout_; public: Group(const std::string&, const std::string&, const Json::Value&, bool); @@ -28,6 +28,7 @@ class Group : public AModule { bool is_first_widget = true; bool is_drawer = false; bool click_to_reveal = false; + bool empty_if_drawer_empty = false; int reveal_delay = 0; std::string add_class_to_drawer_children; bool handleMouseEnter(GdkEventCrossing* const& ev) override; diff --git a/man/waybar.5.scd.in b/man/waybar.5.scd.in index 25a1da97..4209c053 100644 --- a/man/waybar.5.scd.in +++ b/man/waybar.5.scd.in @@ -375,6 +375,11 @@ A group may hide all but one element, showing them only on mouse hover. In order Defines the direction of the transition animation. If true, the hidden elements will slide from left to right. If false, they will slide from right to left. When the bar is vertical, it reads as top-to-bottom. +*empty-if-drawer-empty*: ++ + typeof: bool ++ + default: false ++ + Defines whether the group should be assigned the "empty" CSS class when all modules inside the drawer are hidden or missing. If false, the group will not receive the "empty" class as long as the leader module remains visible. This allows users to dynamically style or hide the entire group using CSS when its drawer contents are unavailable. + *reveal-by-default*: ++ typeof: bool ++ default: false ++ @@ -398,6 +403,19 @@ Group drawers are also given the `.expanded` CSS class when they are expanded. ] }, ``` +To hide the power group if it is empty, apply to #power and all its children: +``` +#power.empty, +#power.empty * { + min-width: 0px; + min-height: 0px; + padding: 0px; + margin: 0px; + border: none; + font-size: 0px; + opacity: 0; +} +``` # SUPPORTED MODULES diff --git a/src/group.cpp b/src/group.cpp index 3c72a522..729a3080 100644 --- a/src/group.cpp +++ b/src/group.cpp @@ -30,6 +30,7 @@ Group::Group(const std::string& name, const std::string& id, const Json::Value& box{vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0}, revealer_box{vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0} { box.set_name(name_); + box.get_style_context()->add_class("empty"); if (!id.empty()) { box.get_style_context()->add_class(id); } @@ -72,6 +73,9 @@ Group::Group(const std::string& name, const std::string& id, const Json::Value& const bool start_expanded = (drawer_config["start-expanded"].isBool() ? drawer_config["start-expanded"].asBool() : false); + empty_if_drawer_empty = (drawer_config["empty-if-drawer-empty"].isBool() + ? drawer_config["empty-if-drawer-empty"].asBool() + : false); auto transition_type = getPreferredTransitionType(vertical); @@ -154,7 +158,44 @@ bool Group::handleToggle(GdkEventButton* const& e) { } auto Group::update() -> void { - // noop + bool has_visible_child = false; + bool has_visible_drawer_child = false; + + if (is_drawer) { + for (auto* rev_child : revealer_box.get_children()) { + if (rev_child->get_visible()) { + has_visible_drawer_child = true; + break; + } + } + } + + if (is_drawer && empty_if_drawer_empty) { + has_visible_child = has_visible_drawer_child; + } else { + for (auto* child : box.get_children()) { + if (child == &revealer) { + if (has_visible_drawer_child) { + has_visible_child = true; + break; + } + } else if (child->get_visible()) { + has_visible_child = true; + break; + } + } + } + + auto style = box.get_style_context(); + if (has_visible_child) { + if (style->has_class("empty")) { + style->remove_class("empty"); + } + } else { + if (!style->has_class("empty")) { + style->add_class("empty"); + } + } } bool Group::handleScroll(GdkEventScroll* e) { @@ -172,6 +213,8 @@ void Group::addWidget(Gtk::Widget& widget) { } is_first_widget = false; + widget.property_visible().signal_changed().connect(sigc::mem_fun(*this, &Group::update)); + update(); } Group::operator Gtk::Widget&() { return event_box_; }