diff --git a/include/components/renderer.hpp b/include/components/renderer.hpp index 77e20837..a6c8f0ec 100644 --- a/include/components/renderer.hpp +++ b/include/components/renderer.hpp @@ -32,13 +32,9 @@ struct alignment_block { double y; }; -class renderer - : public renderer_interface, - public signal_receiver { +class renderer : public renderer_interface, + public signal_receiver { public: using make_type = unique_ptr; static make_type make(const bar_settings& bar); @@ -58,12 +54,12 @@ class renderer void reserve_space(edge side, unsigned int w); #endif void fill_background(); - void fill_overline(double x, double w); - void fill_underline(double x, double w); + void fill_overline(rgba color, double x, double w); + void fill_underline(rgba color, double x, double w); void fill_borders(); - void draw_text(const string& contents); void render_offset(const tags::context& ctxt, int pixels) override; + void render_text(const tags::context& ctxt, const string&&) override; protected: double block_x(alignment a) const; @@ -75,20 +71,9 @@ class renderer void highlight_clickable_areas(); bool on(const signals::ui::request_snapshot& evt) override; - bool on(const signals::parser::change_background& evt) override; - bool on(const signals::parser::change_foreground& evt) override; - bool on(const signals::parser::change_underline& evt) override; - bool on(const signals::parser::change_overline& evt) override; - bool on(const signals::parser::change_font& evt) override; bool on(const signals::parser::change_alignment& evt) override; - bool on(const signals::parser::reverse_colors&) override; - bool on(const signals::parser::attribute_set& evt) override; - bool on(const signals::parser::attribute_unset& evt) override; - bool on(const signals::parser::attribute_toggle& evt) override; bool on(const signals::parser::action_begin& evt) override; bool on(const signals::parser::action_end& evt) override; - bool on(const signals::parser::text& evt) override; - bool on(const signals::parser::control& evt) override; protected: struct reserve_area { @@ -129,12 +114,6 @@ class renderer bool m_pseudo_transparency{false}; alignment m_align; - std::bitset<3> m_attr; - int m_font{0}; - rgba m_bg{}; - rgba m_fg{}; - rgba m_ol{}; - rgba m_ul{}; vector m_actions; bool m_fixedcenter; diff --git a/include/components/renderer_interface.hpp b/include/components/renderer_interface.hpp index 8adf94d7..d94042f9 100644 --- a/include/components/renderer_interface.hpp +++ b/include/components/renderer_interface.hpp @@ -6,6 +6,7 @@ POLYBAR_NS class renderer_interface { public: virtual void render_offset(const tags::context& ctxt, int pixels) = 0; + virtual void render_text(const tags::context& ctxt, const string&& str) = 0; }; POLYBAR_NS_END diff --git a/include/events/signal.hpp b/include/events/signal.hpp index 7cc09691..ac776937 100644 --- a/include/events/signal.hpp +++ b/include/events/signal.hpp @@ -132,48 +132,15 @@ namespace signals { } // namespace ui_tray namespace parser { - struct change_background : public detail::value_signal { - using base_type::base_type; - }; - struct change_foreground : public detail::value_signal { - using base_type::base_type; - }; - struct change_underline : public detail::value_signal { - using base_type::base_type; - }; - struct change_overline : public detail::value_signal { - using base_type::base_type; - }; - struct change_font : public detail::value_signal { - using base_type::base_type; - }; struct change_alignment : public detail::value_signal { using base_type::base_type; }; - struct reverse_colors : public detail::base_signal { - using base_type::base_type; - }; - struct attribute_set : public detail::value_signal { - using base_type::base_type; - }; - struct attribute_unset : public detail::value_signal { - using base_type::base_type; - }; - struct attribute_toggle : public detail::value_signal { - using base_type::base_type; - }; struct action_begin : public detail::value_signal { using base_type::base_type; }; struct action_end : public detail::value_signal { using base_type::base_type; }; - struct text : public detail::value_signal { - using base_type::base_type; - }; - struct control : public detail::value_signal { - using base_type::base_type; - }; } // namespace parser } // namespace signals diff --git a/include/events/signal_fwd.hpp b/include/events/signal_fwd.hpp index 790625a4..44cb49db 100644 --- a/include/events/signal_fwd.hpp +++ b/include/events/signal_fwd.hpp @@ -45,20 +45,9 @@ namespace signals { struct mapped_clients; } namespace parser { - struct change_background; - struct change_foreground; - struct change_underline; - struct change_overline; - struct change_font; struct change_alignment; - struct reverse_colors; - struct attribute_set; - struct attribute_unset; - struct attribute_toggle; struct action_begin; struct action_end; - struct text; - struct control; } // namespace parser } // namespace signals diff --git a/include/tags/context.hpp b/include/tags/context.hpp index 174ffe88..2f864f14 100644 --- a/include/tags/context.hpp +++ b/include/tags/context.hpp @@ -1,11 +1,87 @@ #pragma once #include "common.hpp" +#include "components/types.hpp" +#include "tags/types.hpp" +#include "utils/color.hpp" POLYBAR_NS namespace tags { - class context {}; + /** + * Stores all the formatting data which comes from formatting tags needed to + * render a formatting string. + */ + class context { + public: + context() = delete; + context(const bar_settings& settings); + + /** + * Resets to the initial state. + * + * The initial state depends on the colors set on the bar itself. + */ + void reset(); + + void apply_bg(color_value c); + void apply_fg(color_value c); + void apply_ol(color_value c); + void apply_ul(color_value c); + void apply_font(int font); + void apply_reverse(); + void apply_alignment(alignment align); + void apply_attr(attr_activation act, attribute attr); + void apply_reset(); + + rgba get_bg() const; + rgba get_fg() const; + rgba get_ol() const; + rgba get_ul() const; + int get_font() const; + bool has_overline() const; + bool has_underline() const; + alignment get_alignment() const; + + protected: + rgba get_color(color_value c, rgba fallback) const; + + /** + * Background color + */ + rgba m_bg; + /** + * Foreground color + */ + rgba m_fg; + /** + * Overline color + */ + rgba m_ol; + /** + * Underline color + */ + rgba m_ul; + /** + * Font index (1-based) + */ + int m_font; + /** + * Is overline enabled? + */ + bool m_attr_overline; + /** + * Is underline enabled? + */ + bool m_attr_underline; + /** + * Alignment block + */ + alignment m_align; + + private: + const bar_settings& m_settings; + }; } // namespace tags POLYBAR_NS_END diff --git a/include/tags/dispatch.hpp b/include/tags/dispatch.hpp index 7a022abb..d96818a8 100644 --- a/include/tags/dispatch.hpp +++ b/include/tags/dispatch.hpp @@ -29,8 +29,9 @@ namespace tags { void parse(const bar_settings& bar, renderer_interface&, string data); protected: - void text(string&& data); + void handle_text(renderer_interface& renderer, context& ctxt, string&& data); void handle_action(mousebtn btn, bool closing, const string&& cmd); + void handle_control(context& ctxt, controltag ctrl); private: signal_emitter& m_sig; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dcd58307..22d57efd 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/context.cpp ${src_dir}/tags/dispatch.cpp ${src_dir}/tags/parser.cpp diff --git a/src/components/renderer.cpp b/src/components/renderer.cpp index c6b84540..bbc270d1 100644 --- a/src/components/renderer.cpp +++ b/src/components/renderer.cpp @@ -209,15 +209,8 @@ void renderer::begin(xcb_rectangle_t rect) { // Reset state m_rect = rect; m_actions.clear(); - m_attr.reset(); m_align = alignment::NONE; - // Reset colors - m_bg = m_bar.background; - m_fg = m_bar.foreground; - m_ul = m_bar.underline.color; - m_ol = m_bar.overline.color; - // Clear canvas m_context->save(); m_context->clear(); @@ -593,12 +586,12 @@ void renderer::fill_background() { /** * Fill overline color */ -void renderer::fill_overline(double x, double w) { - if (m_bar.overline.size && m_attr.test(static_cast(tags::attribute::OVERLINE))) { +void renderer::fill_overline(rgba color, double x, double w) { + if (m_bar.overline.size) { m_log.trace_x("renderer: overline(x=%f, w=%f)", x, w); m_context->save(); *m_context << m_comp_ol; - *m_context << m_ol; + *m_context << color; *m_context << cairo::rect{x, static_cast(m_rect.y), w, static_cast(m_bar.overline.size)}; m_context->fill(); m_context->restore(); @@ -608,12 +601,12 @@ void renderer::fill_overline(double x, double w) { /** * Fill underline color */ -void renderer::fill_underline(double x, double w) { - if (m_bar.underline.size && m_attr.test(static_cast(tags::attribute::UNDERLINE))) { +void renderer::fill_underline(rgba color, double x, double w) { + if (m_bar.underline.size) { m_log.trace_x("renderer: underline(x=%f, w=%f)", x, w); m_context->save(); *m_context << m_comp_ul; - *m_context << m_ul; + *m_context << color; *m_context << cairo::rect{x, static_cast(m_rect.y + m_rect.height - m_bar.underline.size), w, static_cast(m_bar.underline.size)}; m_context->fill(); @@ -670,7 +663,7 @@ void renderer::fill_borders() { /** * Draw text contents */ -void renderer::draw_text(const string& contents) { +void renderer::render_text(const tags::context& ctxt, const string&& contents) { m_log.trace_x("renderer: text(%s)", contents.c_str()); cairo::abspos origin{}; @@ -680,17 +673,19 @@ void renderer::draw_text(const string& contents) { cairo::textblock block{}; block.align = m_align; block.contents = contents; - block.font = m_font; + block.font = ctxt.get_font(); block.x_advance = &m_blocks[m_align].x; block.y_advance = &m_blocks[m_align].y; block.bg_rect = cairo::rect{0.0, 0.0, 0.0, 0.0}; + rgba bg = ctxt.get_bg(); + // Only draw text background if the color differs from // the background color of the bar itself // Note: this means that if the user explicitly set text // background color equal to background-0 it will be ignored - if (m_bg != m_bar.background) { - block.bg = m_bg; + if (bg != m_bar.background) { + block.bg = bg; block.bg_operator = m_comp_bg; block.bg_rect.x = m_rect.x; block.bg_rect.y = m_rect.y; @@ -700,14 +695,19 @@ void renderer::draw_text(const string& contents) { m_context->save(); *m_context << origin; *m_context << m_comp_fg; - *m_context << m_fg; + *m_context << ctxt.get_fg(); *m_context << block; m_context->restore(); double dx = m_rect.x + m_blocks[m_align].x - origin.x; if (dx > 0.0) { - fill_underline(origin.x, dx); - fill_overline(origin.x, dx); + if (ctxt.has_underline()) { + fill_underline(ctxt.get_ul(), origin.x, dx); + } + + if (ctxt.has_overline()) { + fill_overline(ctxt.get_ol(), origin.x, dx); + } } } @@ -746,51 +746,6 @@ bool renderer::on(const signals::ui::request_snapshot& evt) { return true; } -bool renderer::on(const signals::parser::change_background& evt) { - const rgba color{evt.cast()}; - if (color != m_bg) { - m_log.trace_x("renderer: change_background(#%08x)", color); - m_bg = color; - } - return true; -} - -bool renderer::on(const signals::parser::change_foreground& evt) { - const rgba color{evt.cast()}; - if (color != m_fg) { - m_log.trace_x("renderer: change_foreground(#%08x)", color); - m_fg = color; - } - return true; -} - -bool renderer::on(const signals::parser::change_underline& evt) { - const rgba color{evt.cast()}; - if (color != m_ul) { - m_log.trace_x("renderer: change_underline(#%08x)", color); - m_ul = color; - } - return true; -} - -bool renderer::on(const signals::parser::change_overline& evt) { - const rgba color{evt.cast()}; - if (color != m_ol) { - m_log.trace_x("renderer: change_overline(#%08x)", color); - m_ol = color; - } - return true; -} - -bool renderer::on(const signals::parser::change_font& evt) { - const int font{evt.cast()}; - if (font != m_font) { - m_log.trace_x("renderer: change_font(%i)", font); - m_font = font; - } - return true; -} - bool renderer::on(const signals::parser::change_alignment& evt) { auto align = static_cast(evt.cast()); if (align != m_align) { @@ -812,30 +767,6 @@ bool renderer::on(const signals::parser::change_alignment& evt) { return true; } -bool renderer::on(const signals::parser::reverse_colors&) { - m_log.trace_x("renderer: reverse_colors"); - std::swap(m_fg, m_bg); - return true; -} - -bool renderer::on(const signals::parser::attribute_set& evt) { - m_log.trace_x("renderer: attribute_set(%i)", static_cast(evt.cast())); - m_attr.set(static_cast(evt.cast()), true); - return true; -} - -bool renderer::on(const signals::parser::attribute_unset& evt) { - m_log.trace_x("renderer: attribute_unset(%i)", static_cast(evt.cast())); - m_attr.set(static_cast(evt.cast()), false); - return true; -} - -bool renderer::on(const signals::parser::attribute_toggle& evt) { - m_log.trace_x("renderer: attribute_toggle(%i)", static_cast(evt.cast())); - m_attr.flip(static_cast(evt.cast())); - return true; -} - bool renderer::on(const signals::parser::action_begin& evt) { auto a = evt.cast(); m_log.trace_x("renderer: action_begin(btn=%i, command=%s)", static_cast(a.button), a.command); @@ -866,30 +797,4 @@ bool renderer::on(const signals::parser::action_end& evt) { return true; } -bool renderer::on(const signals::parser::text& evt) { - auto text = evt.cast(); - draw_text(text); - return true; -} - -bool renderer::on(const signals::parser::control& evt) { - auto ctrl = evt.cast(); - - switch (ctrl) { - case tags::controltag::R: - m_bg = m_bar.background; - m_fg = m_bar.foreground; - m_ul = m_bar.underline.color; - m_ol = m_bar.overline.color; - m_font = 0; - m_attr.reset(); - break; - - case tags::controltag::NONE: - break; - } - - return true; -} - POLYBAR_NS_END diff --git a/src/tags/context.cpp b/src/tags/context.cpp new file mode 100644 index 00000000..cd633538 --- /dev/null +++ b/src/tags/context.cpp @@ -0,0 +1,116 @@ +#include "tags/context.hpp" + +POLYBAR_NS + +namespace tags { + context::context(const bar_settings& settings) : m_settings(settings) { + reset(); + } + + void context::reset() { + apply_reset(); + m_align = alignment::NONE; + } + + void context::apply_bg(color_value c) { + m_bg = get_color(c, m_settings.background); + } + + void context::apply_fg(color_value c) { + m_fg = get_color(c, m_settings.foreground); + } + + void context::apply_ol(color_value c) { + m_ol = get_color(c, m_settings.overline.color); + } + + void context::apply_ul(color_value c) { + m_ul = get_color(c, m_settings.underline.color); + } + + void context::apply_font(int font) { + m_font = std::max(font, 0); + } + + void context::apply_reverse() { + std::swap(m_bg, m_fg); + } + + void context::apply_alignment(alignment align) { + m_align = align; + } + + void context::apply_attr(attr_activation act, attribute attr) { + if (attr == attribute::NONE) { + return; + } + + bool& current = attr == attribute::OVERLINE ? m_attr_overline : m_attr_underline; + + switch (act) { + case attr_activation::ON: + current = true; + break; + case attr_activation::OFF: + current = false; + break; + case attr_activation::TOGGLE: + current = !current; + break; + default: + break; + } + } + + void context::apply_reset() { + m_bg = m_settings.background; + m_fg = m_settings.foreground; + m_ul = m_settings.underline.color; + m_ol = m_settings.overline.color; + m_font = 0; + m_attr_overline = false; + m_attr_underline = false; + } + + rgba context::get_bg() const { + return m_bg; + } + + rgba context::get_fg() const { + return m_fg; + } + + rgba context::get_ol() const { + return m_ol; + } + + rgba context::get_ul() const { + return m_ul; + } + + int context::get_font() const { + return m_font; + } + + bool context::has_overline() const { + return m_attr_overline; + } + + bool context::has_underline() const { + return m_attr_underline; + } + + alignment context::get_alignment() const { + return m_align; + } + + rgba context::get_color(color_value c, rgba fallback) const { + if (c.type == color_type::RESET) { + return fallback; + } else { + return c.val; + } + } +} // namespace tags + +POLYBAR_NS_END diff --git a/src/tags/dispatch.cpp b/src/tags/dispatch.cpp index 514fa492..3b1b3ee3 100644 --- a/src/tags/dispatch.cpp +++ b/src/tags/dispatch.cpp @@ -14,14 +14,6 @@ POLYBAR_NS using namespace signals::parser; namespace tags { - static rgba get_color(tags::color_value c, rgba fallback) { - if (c.type == tags::color_type::RESET) { - return fallback; - } else { - return c.val; - } - } - /** * Create instance */ @@ -41,6 +33,8 @@ namespace tags { tags::parser p; p.set(std::move(data)); + context ctxt(bar); + while (p.has_next_element()) { tags::element el; try { @@ -58,36 +52,39 @@ namespace tags { handle_action(el.tag_data.action.btn, el.tag_data.action.closing, std::move(el.data)); break; case tags::syntaxtag::B: - m_sig.emit(change_background{get_color(el.tag_data.color, bar.background)}); + ctxt.apply_bg(el.tag_data.color); break; case tags::syntaxtag::F: - m_sig.emit(change_foreground{get_color(el.tag_data.color, bar.foreground)}); + ctxt.apply_fg(el.tag_data.color); break; case tags::syntaxtag::T: - m_sig.emit(change_font{el.tag_data.font}); + ctxt.apply_font(el.tag_data.font); break; case tags::syntaxtag::O: - renderer.render_offset(tags::context{}, el.tag_data.offset); + renderer.render_offset(ctxt, el.tag_data.offset); break; case tags::syntaxtag::R: - m_sig.emit(reverse_colors{}); + ctxt.apply_reverse(); break; case tags::syntaxtag::o: - m_sig.emit(change_overline{get_color(el.tag_data.color, bar.overline.color)}); + ctxt.apply_ol(el.tag_data.color); break; case tags::syntaxtag::u: - m_sig.emit(change_underline{get_color(el.tag_data.color, bar.underline.color)}); + ctxt.apply_ul(el.tag_data.color); break; case tags::syntaxtag::P: - m_sig.emit(control{el.tag_data.ctrl}); + handle_control(ctxt, el.tag_data.ctrl); break; case tags::syntaxtag::l: + ctxt.apply_alignment(alignment::LEFT); m_sig.emit(change_alignment{alignment::LEFT}); break; case tags::syntaxtag::r: + ctxt.apply_alignment(alignment::RIGHT); m_sig.emit(change_alignment{alignment::RIGHT}); break; case tags::syntaxtag::c: + ctxt.apply_alignment(alignment::CENTER); m_sig.emit(change_alignment{alignment::CENTER}); break; default: @@ -96,25 +93,11 @@ namespace tags { } break; case tags::tag_type::ATTR: - tags::attribute act = el.tag_data.attr; - switch (el.tag_data.subtype.activation) { - case tags::attr_activation::ON: - m_sig.emit(attribute_set{act}); - break; - case tags::attr_activation::OFF: - m_sig.emit(attribute_unset{act}); - break; - case tags::attr_activation::TOGGLE: - m_sig.emit(attribute_toggle{act}); - break; - default: - throw runtime_error("Unrecognized attribute activation: " + - to_string(static_cast(el.tag_data.subtype.activation))); - } + ctxt.apply_attr(el.tag_data.subtype.activation, el.tag_data.attr); break; } } else { - text(std::move(el.data)); + handle_text(renderer, ctxt, std::move(el.data)); } } @@ -126,7 +109,7 @@ namespace tags { /** * Process text contents */ - void dispatch::text(string&& data) { + void dispatch::handle_text(renderer_interface& renderer, context& ctxt, string&& data) { #ifdef DEBUG_WHITESPACE string::size_type p; while ((p = data.find(' ')) != string::npos) { @@ -134,7 +117,7 @@ namespace tags { } #endif - m_sig.emit(signals::parser::text{std::move(data)}); + renderer.render_text(ctxt, std::move(data)); } void dispatch::handle_action(mousebtn btn, bool closing, const string&& cmd) { @@ -166,6 +149,17 @@ namespace tags { m_sig.emit(action_begin{action{btn, std::move(cmd)}}); } } + + void dispatch::handle_control(context& ctxt, controltag ctrl) { + switch (ctrl) { + case controltag::R: + ctxt.reset(); + break; + default: + throw runtime_error("Unrecognized polybar control tag: " + to_string(static_cast(ctrl))); + } + } + } // namespace tags POLYBAR_NS_END