Merge pull request #2574 from Syndelis/feat/group-drawers

This commit is contained in:
Alexis Rouillard 2023-10-15 21:26:04 +02:00 committed by GitHub
commit 93daf089b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 149 additions and 12 deletions

View File

@ -12,6 +12,7 @@
#include <vector>
#include "AModule.hpp"
#include "group.hpp"
#include "xdg-output-unstable-v1-client-protocol.h"
namespace waybar {
@ -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 &);

View File

@ -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

View File

@ -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:
@ -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)*

View File

@ -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) {
@ -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);
@ -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);

View File

@ -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);
@ -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