Skip to content

Commit

Permalink
Merge pull request #2574 from Syndelis/feat/group-drawers
Browse files Browse the repository at this point in the history
  • Loading branch information
Alexays authored Oct 15, 2023
2 parents 7645ae1 + ff9b6c9 commit 93daf08
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 12 deletions.
3 changes: 2 additions & 1 deletion include/bar.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <vector>

#include "AModule.hpp"
#include "group.hpp"
#include "xdg-output-unstable-v1-client-protocol.h"

namespace waybar {
Expand Down Expand Up @@ -101,7 +102,7 @@ class Bar {
private:
void onMap(GdkEventAny *);
auto setupWidgets() -> void;
void getModules(const Factory &, const std::string &, Gtk::Box *);
void getModules(const Factory &, const std::string &, waybar::Group *);
void setupAltFormatKeyForModule(const std::string &module_name);
void setupAltFormatKeyForModuleList(const char *module_list_name);
void setMode(const bar_mode &);
Expand Down
19 changes: 16 additions & 3 deletions include/group.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,31 @@
#include <json/json.h>

#include "AModule.hpp"
#include "bar.hpp"
#include "factory.hpp"
#include "gtkmm/revealer.h"

namespace waybar {

class Group : public AModule {
public:
Group(const std::string&, const std::string&, const Json::Value&, bool);
~Group() = default;
virtual ~Group() = default;
auto update() -> void override;
operator Gtk::Widget&() override;

virtual Gtk::Box& getBox();
void addWidget(Gtk::Widget& widget);

bool handleMouseHover(GdkEventCrossing* const& e);

protected:
Gtk::Box box;
Gtk::Box revealer_box;
Gtk::Revealer revealer;
bool is_first_widget = true;
bool is_drawer = false;
std::string add_class_to_drawer_children;

void addHoverHandlerTo(Gtk::Widget& widget);
};

} // namespace waybar
39 changes: 38 additions & 1 deletion man/waybar.5.scd.in
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ Valid options for the "rotate" property are: 0, 90, 180 and 270.

## Grouping modules

Module groups allow stacking modules in the direction orthogonal to the bar direction. When the bar is positioned on the top or bottom of the screen, modules in a group are stacked vertically. Likewise, when positioned on the left or right, modules in a group are stacked horizontally.
Module groups allow stacking modules in any direction. By default, when the bar is positioned on the top or bottom of the screen, modules in a group are stacked vertically. Likewise, when positioned on the left or right, modules in a group are stacked horizontally. This can be changed with the "orientation" property.

A module group is defined by specifying a module named "group/some-group-name". The group must also be configured with a list of contained modules. Example:

Expand All @@ -263,6 +263,43 @@ A module group is defined by specifying a module named "group/some-group-name".

Valid options for the (optional) "orientation" property are: "horizontal", "vertical", "inherit", and "orthogonal" (default).

## Group Drawers

A group may hide all but one element, showing them only on mouse hover. In order to configure this, you can use the `drawer` property, whose value is an object with the following properties:

*transition-duration*: ++
typeof: integer ++
default: 500 ++
Defines the duration of the transition animation in milliseconds.

*children-class*: ++
typeof: string ++
default: "hidden" ++
Defines the CSS class to be applied to the hidden elements.

*transition-left-to-right*: ++
typeof: bool ++
default: true ++
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.

```
"group/power": {
"orientation": "inherit",
"drawer": {
"transition-duration": 500,
"children-class": "not-power",
"transition-left-to-right": false,
},
"modules": [
"custom/power", // First element is the "group leader" and won't ever be hidden
"custom/quit",
"custom/lock",
"custom/reboot",
]
},
```

# SUPPORTED MODULES

- *waybar-backlight(5)*
Expand Down
11 changes: 6 additions & 5 deletions src/bar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -740,7 +740,7 @@ void waybar::Bar::handleSignal(int signal) {
}

void waybar::Bar::getModules(const Factory& factory, const std::string& pos,
Gtk::Box* group = nullptr) {
waybar::Group* group = nullptr) {
auto module_list = group ? config[pos]["modules"] : config[pos];
if (module_list.isArray()) {
for (const auto& name : module_list) {
Expand All @@ -753,10 +753,11 @@ void waybar::Bar::getModules(const Factory& factory, const std::string& pos,
auto id_name = ref.substr(6, hash_pos - 6);
auto class_name = hash_pos != std::string::npos ? ref.substr(hash_pos + 1) : "";

auto parent = group ? group : &this->box_;
auto vertical = parent->get_orientation() == Gtk::ORIENTATION_VERTICAL;
auto vertical = (group ? group->getBox().get_orientation() : box_.get_orientation()) ==
Gtk::ORIENTATION_VERTICAL;

auto group_module = new waybar::Group(id_name, class_name, config[ref], vertical);
getModules(factory, ref, &group_module->box);
getModules(factory, ref, group_module);
module = group_module;
} else {
module = factory.makeModule(ref);
Expand All @@ -765,7 +766,7 @@ void waybar::Bar::getModules(const Factory& factory, const std::string& pos,
std::shared_ptr<AModule> module_sp(module);
modules_all_.emplace_back(module_sp);
if (group) {
group->pack_start(*module, false, false);
group->addWidget(*module);
} else {
if (pos == "modules-left") {
modules_left_.emplace_back(module_sp);
Expand Down
89 changes: 87 additions & 2 deletions src/group.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,32 @@

#include <util/command.hpp>

#include "gdkmm/device.h"
#include "gtkmm/widget.h"

namespace waybar {

const Gtk::RevealerTransitionType getPreferredTransitionType(bool is_vertical, bool left_to_right) {
if (is_vertical) {
if (left_to_right) {
return Gtk::RevealerTransitionType::REVEALER_TRANSITION_TYPE_SLIDE_DOWN;
} else {
return Gtk::RevealerTransitionType::REVEALER_TRANSITION_TYPE_SLIDE_UP;
}
} else {
if (left_to_right) {
return Gtk::RevealerTransitionType::REVEALER_TRANSITION_TYPE_SLIDE_RIGHT;
} else {
return Gtk::RevealerTransitionType::REVEALER_TRANSITION_TYPE_SLIDE_LEFT;
}
}
}

Group::Group(const std::string& name, const std::string& id, const Json::Value& config,
bool vertical)
: AModule(config, name, id, false, false),
box{vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0} {
: AModule(config, name, id, true, true),
box{vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0},
revealer_box{vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0} {
box.set_name(name_);
if (!id.empty()) {
box.get_style_context()->add_class(id);
Expand All @@ -29,12 +49,77 @@ Group::Group(const std::string& name, const std::string& id, const Json::Value&
} else {
throw std::runtime_error("Invalid orientation value: " + orientation);
}

if (config_["drawer"].isObject()) {
is_drawer = true;

const auto& drawer_config = config_["drawer"];
const int transition_duration =
(drawer_config["transition-duration"].isInt() ? drawer_config["transition-duration"].asInt()
: 500);
add_class_to_drawer_children =
(drawer_config["children-class"].isString() ? drawer_config["children-class"].asString()
: "drawer-child");
const bool left_to_right = (drawer_config["transition-left-to-right"].isBool()
? drawer_config["transition-left-to-right"].asBool()
: true);

auto transition_type = getPreferredTransitionType(vertical, left_to_right);

revealer.set_transition_type(transition_type);
revealer.set_transition_duration(transition_duration);
revealer.set_reveal_child(false);

revealer.get_style_context()->add_class("drawer");

revealer.add(revealer_box);
box.pack_start(revealer);

addHoverHandlerTo(revealer);
}
}

bool Group::handleMouseHover(GdkEventCrossing* const& e) {
switch (e->type) {
case GDK_ENTER_NOTIFY:
revealer.set_reveal_child(true);
break;
case GDK_LEAVE_NOTIFY:
revealer.set_reveal_child(false);
break;
default:
break;
}

return true;
}

void Group::addHoverHandlerTo(Gtk::Widget& widget) {
widget.add_events(Gdk::EventMask::ENTER_NOTIFY_MASK | Gdk::EventMask::LEAVE_NOTIFY_MASK);
widget.signal_enter_notify_event().connect(sigc::mem_fun(*this, &Group::handleMouseHover));
widget.signal_leave_notify_event().connect(sigc::mem_fun(*this, &Group::handleMouseHover));
}

auto Group::update() -> void {
// noop
}

Gtk::Box& Group::getBox() { return is_drawer ? (is_first_widget ? box : revealer_box) : box; }

void Group::addWidget(Gtk::Widget& widget) {
getBox().pack_start(widget, false, false);

if (is_drawer) {
// Necessary because of GTK's hitbox detection
addHoverHandlerTo(widget);
if (!is_first_widget) {
widget.get_style_context()->add_class(add_class_to_drawer_children);
}
}

is_first_widget = false;
}

Group::operator Gtk::Widget&() { return box; }

} // namespace waybar

0 comments on commit 93daf08

Please sign in to comment.