diff --git a/include/components/bar.hpp b/include/components/bar.hpp index 8afbe6ea..886992e0 100644 --- a/include/components/bar.hpp +++ b/include/components/bar.hpp @@ -10,7 +10,7 @@ #include "events/signal_fwd.hpp" #include "events/signal_receiver.hpp" #include "settings.hpp" -#include "tags/context.hpp" +#include "tags/action_context.hpp" #include "utils/math.hpp" #include "x11/types.hpp" #include "x11/window.hpp" diff --git a/include/components/renderer_interface.hpp b/include/components/renderer_interface.hpp index dd43bb3f..84189851 100644 --- a/include/components/renderer_interface.hpp +++ b/include/components/renderer_interface.hpp @@ -2,6 +2,7 @@ #include #include "common.hpp" +#include "tags/action_context.hpp" #include "tags/context.hpp" POLYBAR_NS diff --git a/include/tags/action_context.hpp b/include/tags/action_context.hpp new file mode 100644 index 00000000..e672dcb4 --- /dev/null +++ b/include/tags/action_context.hpp @@ -0,0 +1,114 @@ +#pragma once + +#include + +#include "common.hpp" +#include "components/types.hpp" + +POLYBAR_NS + +namespace tags { + /** + * An identifier for an action block. + * + * A value of NO_ACTION denotes an undefined identifier and is guaranteed to + * be smaller (<) than any valid identifier. + * + * If two action blocks overlap, the action with the higher identifier will + * be above. + * + * Except for NO_ACTION, negative values are not allowed + */ + using action_t = int; + + static constexpr action_t NO_ACTION = -1; + + /** + * Defines a clickable (or scrollable) action block. + * + * An action block is an area on the bar that executes some command when clicked. + */ + struct action_block { + action_block(const string&& cmd, mousebtn button, alignment align, bool is_open) + : cmd(std::move(cmd)), button(button), align(align), is_open(is_open){}; + + string cmd; + /** + * Start position of the action block (inclusive), relative to the alignment. + */ + double start_x{0}; + + /** + * End position of the action block (exclusive), relative to the alignment. + */ + double end_x{0}; + mousebtn button; + alignment align; + /** + * Tracks whether this block is still open or whether it already has a + * corresponding closing tag. + * + * After rendering, all action blocks should be closed. + */ + bool is_open; + + unsigned int width() const { + return static_cast(end_x - start_x + 0.5); + } + + /** + * Tests whether a given point is inside this block. + * + * This additionally needs the position of the start of the alignment + * because the given point is relative to the bar window. + */ + bool test(double align_start, int point) const { + return static_cast(start_x + align_start) <= point && static_cast(end_x + align_start) > point; + } + }; + + class action_context { + public: + void reset(); + + action_t action_open(mousebtn btn, const string&& cmd, alignment align, double x); + std::pair action_close(mousebtn btn, alignment align, double x); + + void set_alignmnent_start(const alignment a, const double x); + + std::map get_actions(int x) const; + action_t has_action(mousebtn btn, int x) const; + + string get_action(action_t id) const; + bool has_double_click() const; + + size_t num_actions() const; + size_t num_unclosed() const; + + const std::vector& get_blocks() const; + + protected: + void set_start(action_t id, double x); + void set_end(action_t id, double x); + + /** + * Stores all currently known action blocks. + * + * The action_t type is an index into this vector. + */ + std::vector m_action_blocks; + + /** + * Stores the x-coordinate for the start of all the alignment blocks. + * + * This is needed because the action block coordinates are relative to the + * alignment blocks and thus need the alignment block coordinates for + * intersection tests. + */ + std::map m_align_start{ + {alignment::NONE, 0}, {alignment::LEFT, 0}, {alignment::CENTER, 0}, {alignment::RIGHT, 0}}; + }; + +} // namespace tags + +POLYBAR_NS_END diff --git a/include/tags/context.hpp b/include/tags/context.hpp index 21d6a628..798e5c9e 100644 --- a/include/tags/context.hpp +++ b/include/tags/context.hpp @@ -1,7 +1,5 @@ #pragma once -#include - #include "common.hpp" #include "components/types.hpp" #include "tags/types.hpp" @@ -82,108 +80,6 @@ namespace tags { private: const bar_settings& m_settings; }; - - /** - * An identifier for an action block. - * - * A value of NO_ACTION denotes an undefined identifier and is guaranteed to - * be smaller (<) than any valid identifier. - * - * If two action blocks overlap, the action with the higher identifier will - * be above. - * - * Except for NO_ACTION, negative values are not allowed - */ - using action_t = int; - - static constexpr action_t NO_ACTION = -1; - - /** - * Defines a clickable (or scrollable) action block. - * - * An action block is an area on the bar that executes some command when clicked. - */ - struct action_block { - action_block(const string&& cmd, mousebtn button, alignment align, bool is_open) - : cmd(std::move(cmd)), button(button), align(align), is_open(is_open){}; - - string cmd; - /** - * Start position of the action block (inclusive), relative to the alignment. - */ - double start_x{0}; - - /** - * End position of the action block (exclusive), relative to the alignment. - */ - double end_x{0}; - mousebtn button; - alignment align; - /** - * Tracks whether this block is still open or whether it already has a - * corresponding closing tag. - * - * After rendering, all action blocks should be closed. - */ - bool is_open; - - unsigned int width() const { - return static_cast(end_x - start_x + 0.5); - } - - /** - * Tests whether a given point is inside this block. - * - * This additionally needs the position of the start of the alignment - * because the given point is relative to the bar window. - */ - bool test(double align_start, int point) const { - return static_cast(start_x + align_start) <= point && static_cast(end_x + align_start) > point; - } - }; - - class action_context { - public: - void reset(); - - action_t action_open(mousebtn btn, const string&& cmd, alignment align, double x); - std::pair action_close(mousebtn btn, alignment align, double x); - - void set_alignmnent_start(const alignment a, const double x); - - std::map get_actions(int x) const; - action_t has_action(mousebtn btn, int x) const; - - string get_action(action_t id) const; - bool has_double_click() const; - - size_t num_actions() const; - size_t num_unclosed() const; - - const std::vector& get_blocks() const; - - protected: - void set_start(action_t id, double x); - void set_end(action_t id, double x); - - /** - * Stores all currently known action blocks. - * - * The action_t type is an index into this vector. - */ - std::vector m_action_blocks; - - /** - * Stores the x-coordinate for the start of all the alignment blocks. - * - * This is needed because the action block coordinates are relative to the - * alignment blocks and thus need the alignment block coordinates for - * intersection tests. - */ - std::map m_align_start{ - {alignment::NONE, 0}, {alignment::LEFT, 0}, {alignment::CENTER, 0}, {alignment::RIGHT, 0}}; - }; - } // namespace tags POLYBAR_NS_END diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 22d57efd..4c0294e3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -96,6 +96,7 @@ if(BUILD_LIBPOLY) ${src_dir}/modules/xwindow.cpp ${src_dir}/modules/xworkspaces.cpp + ${src_dir}/tags/action_context.cpp ${src_dir}/tags/context.cpp ${src_dir}/tags/dispatch.cpp ${src_dir}/tags/parser.cpp diff --git a/src/tags/action_context.cpp b/src/tags/action_context.cpp new file mode 100644 index 00000000..eea56eb5 --- /dev/null +++ b/src/tags/action_context.cpp @@ -0,0 +1,110 @@ +#include "tags/action_context.hpp" + +#include + +POLYBAR_NS + +namespace tags { + + void action_context::reset() { + m_action_blocks.clear(); + } + + action_t action_context::action_open(mousebtn btn, const string&& cmd, alignment align, double x) { + action_t id = m_action_blocks.size(); + m_action_blocks.emplace_back(std::move(cmd), btn, align, true); + set_start(id, x); + return id; + } + + std::pair action_context::action_close(mousebtn btn, alignment align, double x) { + for (auto it = m_action_blocks.rbegin(); it != m_action_blocks.rend(); it++) { + if (it->is_open && it->align == align && (btn == mousebtn::NONE || it->button == btn)) { + it->is_open = false; + + // Converts a reverse iterator into an index + action_t id = std::distance(m_action_blocks.begin(), it.base()) - 1; + set_end(id, x); + return {id, it->button}; + } + } + + return {NO_ACTION, mousebtn::NONE}; + } + + void action_context::set_start(action_t id, double x) { + m_action_blocks[id].start_x = x; + } + + void action_context::set_end(action_t id, double x) { + m_action_blocks[id].end_x = x; + } + + void action_context::set_alignmnent_start(const alignment a, const double x) { + m_align_start[a] = x; + } + + std::map action_context::get_actions(int x) const { + std::map buttons; + + for (int i = static_cast(mousebtn::NONE); i < static_cast(mousebtn::BTN_COUNT); i++) { + buttons[static_cast(i)] = tags::NO_ACTION; + } + + for (action_t id = 0; (unsigned)id < m_action_blocks.size(); id++) { + auto action = m_action_blocks[id]; + mousebtn btn = action.button; + + // Higher IDs are higher in the action stack. + if (id > buttons[btn] && action.test(m_align_start.at(action.align), x)) { + buttons[action.button] = id; + } + } + + return buttons; + } + + action_t action_context::has_action(mousebtn btn, int x) const { + // TODO optimize + return get_actions(x)[btn]; + } + + string action_context::get_action(action_t id) const { + assert(id >= 0 && (unsigned)id < num_actions()); + + return m_action_blocks[id].cmd; + } + + bool action_context::has_double_click() const { + for (auto&& a : m_action_blocks) { + if (a.button == mousebtn::DOUBLE_LEFT || a.button == mousebtn::DOUBLE_MIDDLE || + a.button == mousebtn::DOUBLE_RIGHT) { + return true; + } + } + + return false; + } + + size_t action_context::num_actions() const { + return m_action_blocks.size(); + } + + size_t action_context::num_unclosed() const { + size_t num = 0; + + for (const auto& a : m_action_blocks) { + if (a.is_open) { + num++; + } + } + + return num; + } + + const std::vector& action_context::get_blocks() const { + return m_action_blocks; + } +} // namespace tags + +POLYBAR_NS_END diff --git a/src/tags/context.cpp b/src/tags/context.cpp index c3046a86..93de3abf 100644 --- a/src/tags/context.cpp +++ b/src/tags/context.cpp @@ -1,7 +1,5 @@ #include "tags/context.hpp" -#include - POLYBAR_NS namespace tags { @@ -113,107 +111,6 @@ namespace tags { alignment context::get_alignment() const { return m_align; } - - void action_context::reset() { - m_action_blocks.clear(); - } - - action_t action_context::action_open(mousebtn btn, const string&& cmd, alignment align, double x) { - action_t id = m_action_blocks.size(); - m_action_blocks.emplace_back(std::move(cmd), btn, align, true); - set_start(id, x); - return id; - } - - std::pair action_context::action_close(mousebtn btn, alignment align, double x) { - for (auto it = m_action_blocks.rbegin(); it != m_action_blocks.rend(); it++) { - if (it->is_open && it->align == align && (btn == mousebtn::NONE || it->button == btn)) { - it->is_open = false; - - // Converts a reverse iterator into an index - action_t id = std::distance(m_action_blocks.begin(), it.base()) - 1; - set_end(id, x); - return {id, it->button}; - } - } - - return {NO_ACTION, mousebtn::NONE}; - } - - void action_context::set_start(action_t id, double x) { - m_action_blocks[id].start_x = x; - } - - void action_context::set_end(action_t id, double x) { - m_action_blocks[id].end_x = x; - } - - void action_context::set_alignmnent_start(const alignment a, const double x) { - m_align_start[a] = x; - } - - std::map action_context::get_actions(int x) const { - std::map buttons; - - for (int i = static_cast(mousebtn::NONE); i < static_cast(mousebtn::BTN_COUNT); i++) { - buttons[static_cast(i)] = tags::NO_ACTION; - } - - for (action_t id = 0; (unsigned)id < m_action_blocks.size(); id++) { - auto action = m_action_blocks[id]; - mousebtn btn = action.button; - - // Higher IDs are higher in the action stack. - if (id > buttons[btn] && action.test(m_align_start.at(action.align), x)) { - buttons[action.button] = id; - } - } - - return buttons; - } - - action_t action_context::has_action(mousebtn btn, int x) const { - // TODO optimize - return get_actions(x)[btn]; - } - - string action_context::get_action(action_t id) const { - assert(id >= 0 && (unsigned)id < num_actions()); - - return m_action_blocks[id].cmd; - } - - bool action_context::has_double_click() const { - for (auto&& a : m_action_blocks) { - if (a.button == mousebtn::DOUBLE_LEFT || a.button == mousebtn::DOUBLE_MIDDLE || - a.button == mousebtn::DOUBLE_RIGHT) { - return true; - } - } - - return false; - } - - size_t action_context::num_actions() const { - return m_action_blocks.size(); - } - - size_t action_context::num_unclosed() const { - size_t num = 0; - - for (const auto& a : m_action_blocks) { - if (a.is_open) { - num++; - } - } - - return num; - } - - const std::vector& action_context::get_blocks() const { - return m_action_blocks; - } - } // namespace tags POLYBAR_NS_END diff --git a/tests/unit_tests/tags/action_context.cpp b/tests/unit_tests/tags/action_context.cpp index 7d1bec34..eca576d0 100644 --- a/tests/unit_tests/tags/action_context.cpp +++ b/tests/unit_tests/tags/action_context.cpp @@ -1,6 +1,7 @@ +#include "tags/action_context.hpp" + #include "common/test.hpp" #include "components/logger.hpp" -#include "tags/context.hpp" using namespace polybar; using namespace std;