polybar/src/modules/menu.cpp

158 lines
5.3 KiB
C++
Raw Permalink Normal View History

2016-11-02 19:22:45 +00:00
#include "modules/menu.hpp"
#include "drawtypes/label.hpp"
#include "events/signal.hpp"
#include "modules/meta/base.inl"
#include "utils/actions.hpp"
2016-11-02 19:22:45 +00:00
#include "utils/scope.hpp"
2016-11-20 22:04:31 +00:00
2016-11-19 05:22:44 +00:00
POLYBAR_NS
2016-11-02 19:22:45 +00:00
namespace modules {
2016-11-20 22:04:31 +00:00
template class module<menu_module>;
menu_module::menu_module(const bar_settings& bar, string name_, const config& config)
: static_module<menu_module>(bar, move(name_), config) {
m_expand_right = m_conf.get(name(), "expand-right", m_expand_right);
m_router->register_action_with_data(EVENT_OPEN, [this](const std::string& data) { action_open(data); });
m_router->register_action(EVENT_CLOSE, [this]() { action_close(); });
m_router->register_action_with_data(EVENT_EXEC, [this](const std::string& data) { action_exec(data); });
string default_format;
if (m_expand_right) {
default_format += TAG_LABEL_TOGGLE;
default_format += TAG_MENU;
} else {
default_format += TAG_MENU;
default_format += TAG_LABEL_TOGGLE;
}
2016-11-02 19:22:45 +00:00
m_formatter->add(DEFAULT_FORMAT, default_format, {TAG_LABEL_TOGGLE, TAG_MENU});
if (m_formatter->has(TAG_LABEL_TOGGLE)) {
m_labelopen = load_label(m_conf, name(), "label-open");
m_labelclose = load_optional_label(m_conf, name(), "label-close", "x");
}
m_labelseparator = load_optional_label(m_conf, name(), "label-separator", "");
2016-11-25 12:55:15 +00:00
if (!m_formatter->has(TAG_MENU)) {
2016-11-02 19:22:45 +00:00
return;
2016-11-25 12:55:15 +00:00
}
2016-11-02 19:22:45 +00:00
while (true) {
string level_param{"menu-" + to_string(m_levels.size())};
if (m_conf.get(name(), level_param + "-0", ""s).empty()) {
2016-11-02 19:22:45 +00:00
break;
2016-11-25 12:55:15 +00:00
}
2016-11-02 19:22:45 +00:00
m_log.trace("%s: Creating menu level %i", name(), m_levels.size());
m_levels.emplace_back(std::make_unique<menu_tree>());
2016-11-02 19:22:45 +00:00
while (true) {
string item_param{level_param + "-" + to_string(m_levels.back()->items.size())};
if (m_conf.get(name(), item_param, ""s).empty()) {
2016-11-02 19:22:45 +00:00
break;
2016-11-25 12:55:15 +00:00
}
2016-11-02 19:22:45 +00:00
m_log.trace("%s: Creating menu level item %i", name(), m_levels.back()->items.size());
auto item = std::make_unique<menu_tree_item>();
2016-11-02 19:22:45 +00:00
item->label = load_label(m_conf, name(), item_param);
item->exec = m_conf.get(name(), item_param + "-exec", actions_util::get_action_string(*this, EVENT_CLOSE, ""));
2016-11-25 12:55:15 +00:00
m_levels.back()->items.emplace_back(move(item));
2016-11-02 19:22:45 +00:00
}
}
}
2016-11-25 12:55:15 +00:00
bool menu_module::build(builder* builder, const string& tag) const {
2016-11-02 19:22:45 +00:00
if (tag == TAG_LABEL_TOGGLE && m_level == -1) {
builder->action(mousebtn::LEFT, *this, string(EVENT_OPEN), "0", m_labelopen);
2016-11-02 19:22:45 +00:00
} else if (tag == TAG_LABEL_TOGGLE && m_level > -1) {
builder->action(mousebtn::LEFT, *this, EVENT_CLOSE, "", m_labelclose);
2016-11-02 19:22:45 +00:00
} else if (tag == TAG_MENU && m_level > -1) {
auto spacing = m_formatter->get(get_format())->spacing;
// Insert separator after menu-toggle and before menu-items for expand-right=true
if (m_expand_right && *m_labelseparator) {
builder->node(m_labelseparator);
Add units support (POINT, PIXEL, SPACE) (#2578) * add units support (POINT, PIXEL, SPACE) for polybar - add a size_with_unit struct - add a geometry_format_values struct - move dpi initialisation from renderer.cpp to bar.cpp - add a string to size_with_unit converter - add point support (with pt) - add pixel support (with px) * Fix unit test compilation * clang-format * Better names The old names didn't really capture the purpose of the structs and function. space_type -> spacing_type space_size -> spacing_val size_type -> extent_type geometry -> extent_val geometry_format_values -> percentage_with_offset * Remove parse_size_with_unit No longer needed. The convert<spacing_val> function in config.cpp already does all the work for us and always setting the type to pixel was wrong. In addition, line-size should not be of type spacing_val but extent_val. * Cleanup I tried to address most of my comments on the old PR * Fix renderer width calculation We can't just blindly add the x difference to the width because for example the width should increase if x < width and the increase keeps x < width. Similarly, we can't just add the offset to the width. * Rename geom_format_to_pixels to percentage_with_offset_to_pixel * Cleanup * Apply suggested changes from Patrick on GitHub Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/bar.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/config.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/builder.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/builder.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * config: Use stod for parsing percentage * Use stof instead of strtof * units: Fix test edge cases * Remove unnecessary clang-format toggle * Use percentage_with_offset for margin-{top,bottom} * Support negative extent values * Rename unit to units and create a cpp file * Move percentage_with_offset_to_pixel unit test to units * Add unit tests for units_utils * Clarify when and how negative spacing/extent is allowed Negative spacing is never allowed and produces a config error. Extents allow negative values in theory, but only a few use-cases accept it. Only the extent value used for the `%{O}` tag and the offset value in percentage_with_offset can be negative. Everything else is capped below at 0. The final pixel value of percentage_with_offset also caps below at 0. * Fix parsing errors not being caught in config * Print a proper error message for uncaught exceptions * Cleanup module::get_output All changes preserve the existing semantics * Stop using remove_trailing_space in module::get_output Instead, we first check if the current tag is built, and only if it is, the spacing is prepended. * Remove unused imports * Restore old behavior If there are two tags and the second one isn't built (module::build returns false), the space in between them is removed. For example in the mpd module: format-online = <toggle> <label-song> foo If mpd is not running, the mpd module will return false when trying to build the `<label-song>` tag. If we don't remove the space between `<toggle>` and `<label-song>`, we end up with two spaces between `<toggle>` and `foo`. This change is to match the old behavior where at least one trailing space character was removed from the builder. * Add changelog entry * Remove unused setting * Use percentage with offset for tray-offset Co-authored-by: Jérôme BOULMIER <jerome.boulmier@outlook.fr> Co-authored-by: Joe Groocock <github@frebib.net>
2022-02-20 20:08:57 +00:00
builder->spacing(spacing);
}
auto&& items = m_levels[m_level]->items;
for (size_t i = 0; i < items.size(); i++) {
auto&& item = items[i];
builder->action(
mousebtn::LEFT, *this, string(EVENT_EXEC), to_string(m_level) + "-" + to_string(i), item->label);
if (item != m_levels[m_level]->items.back()) {
Add units support (POINT, PIXEL, SPACE) (#2578) * add units support (POINT, PIXEL, SPACE) for polybar - add a size_with_unit struct - add a geometry_format_values struct - move dpi initialisation from renderer.cpp to bar.cpp - add a string to size_with_unit converter - add point support (with pt) - add pixel support (with px) * Fix unit test compilation * clang-format * Better names The old names didn't really capture the purpose of the structs and function. space_type -> spacing_type space_size -> spacing_val size_type -> extent_type geometry -> extent_val geometry_format_values -> percentage_with_offset * Remove parse_size_with_unit No longer needed. The convert<spacing_val> function in config.cpp already does all the work for us and always setting the type to pixel was wrong. In addition, line-size should not be of type spacing_val but extent_val. * Cleanup I tried to address most of my comments on the old PR * Fix renderer width calculation We can't just blindly add the x difference to the width because for example the width should increase if x < width and the increase keeps x < width. Similarly, we can't just add the offset to the width. * Rename geom_format_to_pixels to percentage_with_offset_to_pixel * Cleanup * Apply suggested changes from Patrick on GitHub Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/bar.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/config.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/builder.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/builder.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * config: Use stod for parsing percentage * Use stof instead of strtof * units: Fix test edge cases * Remove unnecessary clang-format toggle * Use percentage_with_offset for margin-{top,bottom} * Support negative extent values * Rename unit to units and create a cpp file * Move percentage_with_offset_to_pixel unit test to units * Add unit tests for units_utils * Clarify when and how negative spacing/extent is allowed Negative spacing is never allowed and produces a config error. Extents allow negative values in theory, but only a few use-cases accept it. Only the extent value used for the `%{O}` tag and the offset value in percentage_with_offset can be negative. Everything else is capped below at 0. The final pixel value of percentage_with_offset also caps below at 0. * Fix parsing errors not being caught in config * Print a proper error message for uncaught exceptions * Cleanup module::get_output All changes preserve the existing semantics * Stop using remove_trailing_space in module::get_output Instead, we first check if the current tag is built, and only if it is, the spacing is prepended. * Remove unused imports * Restore old behavior If there are two tags and the second one isn't built (module::build returns false), the space in between them is removed. For example in the mpd module: format-online = <toggle> <label-song> foo If mpd is not running, the mpd module will return false when trying to build the `<label-song>` tag. If we don't remove the space between `<toggle>` and `<label-song>`, we end up with two spaces between `<toggle>` and `foo`. This change is to match the old behavior where at least one trailing space character was removed from the builder. * Add changelog entry * Remove unused setting * Use percentage with offset for tray-offset Co-authored-by: Jérôme BOULMIER <jerome.boulmier@outlook.fr> Co-authored-by: Joe Groocock <github@frebib.net>
2022-02-20 20:08:57 +00:00
builder->spacing(spacing);
if (*m_labelseparator) {
builder->node(m_labelseparator);
Add units support (POINT, PIXEL, SPACE) (#2578) * add units support (POINT, PIXEL, SPACE) for polybar - add a size_with_unit struct - add a geometry_format_values struct - move dpi initialisation from renderer.cpp to bar.cpp - add a string to size_with_unit converter - add point support (with pt) - add pixel support (with px) * Fix unit test compilation * clang-format * Better names The old names didn't really capture the purpose of the structs and function. space_type -> spacing_type space_size -> spacing_val size_type -> extent_type geometry -> extent_val geometry_format_values -> percentage_with_offset * Remove parse_size_with_unit No longer needed. The convert<spacing_val> function in config.cpp already does all the work for us and always setting the type to pixel was wrong. In addition, line-size should not be of type spacing_val but extent_val. * Cleanup I tried to address most of my comments on the old PR * Fix renderer width calculation We can't just blindly add the x difference to the width because for example the width should increase if x < width and the increase keeps x < width. Similarly, we can't just add the offset to the width. * Rename geom_format_to_pixels to percentage_with_offset_to_pixel * Cleanup * Apply suggested changes from Patrick on GitHub Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/bar.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/config.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/builder.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/builder.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * config: Use stod for parsing percentage * Use stof instead of strtof * units: Fix test edge cases * Remove unnecessary clang-format toggle * Use percentage_with_offset for margin-{top,bottom} * Support negative extent values * Rename unit to units and create a cpp file * Move percentage_with_offset_to_pixel unit test to units * Add unit tests for units_utils * Clarify when and how negative spacing/extent is allowed Negative spacing is never allowed and produces a config error. Extents allow negative values in theory, but only a few use-cases accept it. Only the extent value used for the `%{O}` tag and the offset value in percentage_with_offset can be negative. Everything else is capped below at 0. The final pixel value of percentage_with_offset also caps below at 0. * Fix parsing errors not being caught in config * Print a proper error message for uncaught exceptions * Cleanup module::get_output All changes preserve the existing semantics * Stop using remove_trailing_space in module::get_output Instead, we first check if the current tag is built, and only if it is, the spacing is prepended. * Remove unused imports * Restore old behavior If there are two tags and the second one isn't built (module::build returns false), the space in between them is removed. For example in the mpd module: format-online = <toggle> <label-song> foo If mpd is not running, the mpd module will return false when trying to build the `<label-song>` tag. If we don't remove the space between `<toggle>` and `<label-song>`, we end up with two spaces between `<toggle>` and `foo`. This change is to match the old behavior where at least one trailing space character was removed from the builder. * Add changelog entry * Remove unused setting * Use percentage with offset for tray-offset Co-authored-by: Jérôme BOULMIER <jerome.boulmier@outlook.fr> Co-authored-by: Joe Groocock <github@frebib.net>
2022-02-20 20:08:57 +00:00
builder->spacing(spacing);
}
// Insert separator after last menu-item and before menu-toggle for expand-right=false
} else if (!m_expand_right && *m_labelseparator) {
Add units support (POINT, PIXEL, SPACE) (#2578) * add units support (POINT, PIXEL, SPACE) for polybar - add a size_with_unit struct - add a geometry_format_values struct - move dpi initialisation from renderer.cpp to bar.cpp - add a string to size_with_unit converter - add point support (with pt) - add pixel support (with px) * Fix unit test compilation * clang-format * Better names The old names didn't really capture the purpose of the structs and function. space_type -> spacing_type space_size -> spacing_val size_type -> extent_type geometry -> extent_val geometry_format_values -> percentage_with_offset * Remove parse_size_with_unit No longer needed. The convert<spacing_val> function in config.cpp already does all the work for us and always setting the type to pixel was wrong. In addition, line-size should not be of type spacing_val but extent_val. * Cleanup I tried to address most of my comments on the old PR * Fix renderer width calculation We can't just blindly add the x difference to the width because for example the width should increase if x < width and the increase keeps x < width. Similarly, we can't just add the offset to the width. * Rename geom_format_to_pixels to percentage_with_offset_to_pixel * Cleanup * Apply suggested changes from Patrick on GitHub Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/bar.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/config.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/builder.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * Update src/components/builder.cpp Co-authored-by: Patrick Ziegler <p.ziegler96@gmail.com> * config: Use stod for parsing percentage * Use stof instead of strtof * units: Fix test edge cases * Remove unnecessary clang-format toggle * Use percentage_with_offset for margin-{top,bottom} * Support negative extent values * Rename unit to units and create a cpp file * Move percentage_with_offset_to_pixel unit test to units * Add unit tests for units_utils * Clarify when and how negative spacing/extent is allowed Negative spacing is never allowed and produces a config error. Extents allow negative values in theory, but only a few use-cases accept it. Only the extent value used for the `%{O}` tag and the offset value in percentage_with_offset can be negative. Everything else is capped below at 0. The final pixel value of percentage_with_offset also caps below at 0. * Fix parsing errors not being caught in config * Print a proper error message for uncaught exceptions * Cleanup module::get_output All changes preserve the existing semantics * Stop using remove_trailing_space in module::get_output Instead, we first check if the current tag is built, and only if it is, the spacing is prepended. * Remove unused imports * Restore old behavior If there are two tags and the second one isn't built (module::build returns false), the space in between them is removed. For example in the mpd module: format-online = <toggle> <label-song> foo If mpd is not running, the mpd module will return false when trying to build the `<label-song>` tag. If we don't remove the space between `<toggle>` and `<label-song>`, we end up with two spaces between `<toggle>` and `foo`. This change is to match the old behavior where at least one trailing space character was removed from the builder. * Add changelog entry * Remove unused setting * Use percentage with offset for tray-offset Co-authored-by: Jérôme BOULMIER <jerome.boulmier@outlook.fr> Co-authored-by: Joe Groocock <github@frebib.net>
2022-02-20 20:08:57 +00:00
builder->spacing(spacing);
builder->node(m_labelseparator);
}
2016-11-02 19:22:45 +00:00
}
} else {
return false;
}
return true;
}
void menu_module::action_open(const string& data) {
string level = data.empty() ? "0" : data;
int level_num = m_level = std::strtol(level.c_str(), nullptr, 10);
m_log.info("%s: Opening menu level '%i'", name(), static_cast<int>(level_num));
if (static_cast<size_t>(level_num) >= m_levels.size()) {
m_log.warn("%s: Cannot open unexisting menu level '%s'", name(), level);
m_level = -1;
} else {
m_level = level_num;
}
broadcast();
}
void menu_module::action_close() {
m_log.info("%s: Closing menu tree", name());
if (m_level != -1) {
m_level = -1;
broadcast();
}
}
void menu_module::action_exec(const string& element) {
auto sep = element.find("-");
if (sep == element.npos) {
m_log.err("%s: Malformed data for exec action (data: '%s')", name(), element);
}
2016-11-02 19:22:45 +00:00
auto level = std::strtoul(element.substr(0, sep).c_str(), nullptr, 10);
auto item = std::strtoul(element.substr(sep + 1).c_str(), nullptr, 10);
2016-11-02 19:22:45 +00:00
if (level >= m_levels.size() || item >= m_levels[level]->items.size()) {
m_log.err("%s: menu-exec-%d-%d doesn't exist (data: '%s')", name(), level, item, element);
}
2016-11-02 19:22:45 +00:00
string exec = m_levels[level]->items[item]->exec;
// Send exec action to be executed
m_sig.emit(signals::ipc::action{std::move(exec)});
/*
* Only close the menu if the executed action is visible in the menu
* This stops the menu from closing, if the exec action comes from an
* external source
*/
if (m_level == (int)level) {
2016-11-02 19:22:45 +00:00
m_level = -1;
broadcast();
2016-11-02 19:22:45 +00:00
}
}
} // namespace modules
2016-11-02 19:22:45 +00:00
2016-11-19 05:22:44 +00:00
POLYBAR_NS_END