Merge pull request #2574 from Syndelis/feat/group-drawers
This commit is contained in:
commit
93daf089b5
|
@ -12,6 +12,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "AModule.hpp"
|
#include "AModule.hpp"
|
||||||
|
#include "group.hpp"
|
||||||
#include "xdg-output-unstable-v1-client-protocol.h"
|
#include "xdg-output-unstable-v1-client-protocol.h"
|
||||||
|
|
||||||
namespace waybar {
|
namespace waybar {
|
||||||
|
@ -101,7 +102,7 @@ class Bar {
|
||||||
private:
|
private:
|
||||||
void onMap(GdkEventAny *);
|
void onMap(GdkEventAny *);
|
||||||
auto setupWidgets() -> void;
|
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 setupAltFormatKeyForModule(const std::string &module_name);
|
||||||
void setupAltFormatKeyForModuleList(const char *module_list_name);
|
void setupAltFormatKeyForModuleList(const char *module_list_name);
|
||||||
void setMode(const bar_mode &);
|
void setMode(const bar_mode &);
|
||||||
|
|
|
@ -5,18 +5,31 @@
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
|
|
||||||
#include "AModule.hpp"
|
#include "AModule.hpp"
|
||||||
#include "bar.hpp"
|
#include "gtkmm/revealer.h"
|
||||||
#include "factory.hpp"
|
|
||||||
|
|
||||||
namespace waybar {
|
namespace waybar {
|
||||||
|
|
||||||
class Group : public AModule {
|
class Group : public AModule {
|
||||||
public:
|
public:
|
||||||
Group(const std::string&, const std::string&, const Json::Value&, bool);
|
Group(const std::string&, const std::string&, const Json::Value&, bool);
|
||||||
~Group() = default;
|
virtual ~Group() = default;
|
||||||
auto update() -> void override;
|
auto update() -> void override;
|
||||||
operator Gtk::Widget&() 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 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
|
} // namespace waybar
|
||||||
|
|
|
@ -240,7 +240,7 @@ Valid options for the "rotate" property are: 0, 90, 180 and 270.
|
||||||
|
|
||||||
## Grouping modules
|
## 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:
|
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).
|
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
|
# SUPPORTED MODULES
|
||||||
|
|
||||||
- *waybar-backlight(5)*
|
- *waybar-backlight(5)*
|
||||||
|
|
11
src/bar.cpp
11
src/bar.cpp
|
@ -740,7 +740,7 @@ void waybar::Bar::handleSignal(int signal) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void waybar::Bar::getModules(const Factory& factory, const std::string& pos,
|
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];
|
auto module_list = group ? config[pos]["modules"] : config[pos];
|
||||||
if (module_list.isArray()) {
|
if (module_list.isArray()) {
|
||||||
for (const auto& name : module_list) {
|
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 id_name = ref.substr(6, hash_pos - 6);
|
||||||
auto class_name = hash_pos != std::string::npos ? ref.substr(hash_pos + 1) : "";
|
auto class_name = hash_pos != std::string::npos ? ref.substr(hash_pos + 1) : "";
|
||||||
|
|
||||||
auto parent = group ? group : &this->box_;
|
auto vertical = (group ? group->getBox().get_orientation() : box_.get_orientation()) ==
|
||||||
auto vertical = parent->get_orientation() == Gtk::ORIENTATION_VERTICAL;
|
Gtk::ORIENTATION_VERTICAL;
|
||||||
|
|
||||||
auto group_module = new waybar::Group(id_name, class_name, config[ref], 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;
|
module = group_module;
|
||||||
} else {
|
} else {
|
||||||
module = factory.makeModule(ref);
|
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);
|
std::shared_ptr<AModule> module_sp(module);
|
||||||
modules_all_.emplace_back(module_sp);
|
modules_all_.emplace_back(module_sp);
|
||||||
if (group) {
|
if (group) {
|
||||||
group->pack_start(*module, false, false);
|
group->addWidget(*module);
|
||||||
} else {
|
} else {
|
||||||
if (pos == "modules-left") {
|
if (pos == "modules-left") {
|
||||||
modules_left_.emplace_back(module_sp);
|
modules_left_.emplace_back(module_sp);
|
||||||
|
|
|
@ -4,12 +4,32 @@
|
||||||
|
|
||||||
#include <util/command.hpp>
|
#include <util/command.hpp>
|
||||||
|
|
||||||
|
#include "gdkmm/device.h"
|
||||||
|
#include "gtkmm/widget.h"
|
||||||
|
|
||||||
namespace waybar {
|
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,
|
Group::Group(const std::string& name, const std::string& id, const Json::Value& config,
|
||||||
bool vertical)
|
bool vertical)
|
||||||
: AModule(config, name, id, false, false),
|
: AModule(config, name, id, true, true),
|
||||||
box{vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0} {
|
box{vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0},
|
||||||
|
revealer_box{vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0} {
|
||||||
box.set_name(name_);
|
box.set_name(name_);
|
||||||
if (!id.empty()) {
|
if (!id.empty()) {
|
||||||
box.get_style_context()->add_class(id);
|
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 {
|
} else {
|
||||||
throw std::runtime_error("Invalid orientation value: " + orientation);
|
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 {
|
auto Group::update() -> void {
|
||||||
// noop
|
// 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; }
|
Group::operator Gtk::Widget&() { return box; }
|
||||||
|
|
||||||
} // namespace waybar
|
} // namespace waybar
|
||||||
|
|
Loading…
Reference in New Issue