From 305279c0f7f2480572aea9914fce32a1b7fb5ecc Mon Sep 17 00:00:00 2001 From: hippoz <10706925-hippoz@users.noreply.gitlab.com> Date: Sat, 11 Jun 2022 15:52:23 +0300 Subject: [PATCH] add improved style system for widgets --- meson.build | 1 + src/Button.cpp | 26 +++---------------- src/Button.hpp | 1 - src/Forward.hpp | 2 +- src/GenericStyle.hpp | 49 ++++++++++++++++++++++++++++++++++++ src/Label.cpp | 9 +++---- src/Label.hpp | 1 - src/Painter.cpp | 2 +- src/Painter.hpp | 2 +- src/PropMacros.hpp | 9 ------- src/Styles.cpp | 41 ++++++++++++++++++++++++++++++ src/Styles.hpp | 11 ++++++++ src/TopLevelStyles.cpp | 12 --------- src/TopLevelStyles.hpp | 57 ------------------------------------------ src/Widget.cpp | 34 +++++++++++++++++-------- src/Widget.hpp | 23 ++++++----------- src/Window.hpp | 3 --- 17 files changed, 144 insertions(+), 139 deletions(-) create mode 100644 src/GenericStyle.hpp delete mode 100644 src/PropMacros.hpp create mode 100644 src/Styles.cpp create mode 100644 src/Styles.hpp delete mode 100644 src/TopLevelStyles.cpp delete mode 100644 src/TopLevelStyles.hpp diff --git a/meson.build b/meson.build index a796c6e..38dc1a1 100644 --- a/meson.build +++ b/meson.build @@ -7,6 +7,7 @@ xlib_dep = dependency('x11') executable( 'ravenapp', './src/Box.cpp', + './src/Styles.cpp', './src/Painter.cpp', './src/Window.cpp', './src/Widget.cpp', diff --git a/src/Button.cpp b/src/Button.cpp index 8faf7cb..3acde4c 100644 --- a/src/Button.cpp +++ b/src/Button.cpp @@ -3,6 +3,7 @@ #include "Box.hpp" #include "Window.hpp" #include "Painter.hpp" +#include "Styles.hpp" #include "pango/pango-layout.h" #include @@ -17,40 +18,21 @@ void Button::set_text(std::string text) { } void Button::on_init() { - set_background_border_radius(styles()->button_border_radius()); - set_background_fill_color(styles()->button_normal_color()); - set_do_background_fill(true); + set_style(&default_button_style); fit_text(m_text); - set_did_init(true); } -void Button::update_color() { - if (is_active()) { - set_background_fill_color(styles()->button_active_color()); - } else if (is_focused()) { - set_background_fill_color(styles()->button_focused_color()); - } else { - set_background_fill_color(styles()->button_normal_color()); - } -} - void Button::on_paint() { auto painter = window()->painter(); - auto text_color = styles()->button_text_color(); - painter.source_rgb(text_color); - painter.set_pango_font_description(styles()->controls_font_description()); + painter.source_rgb(style()->foreground()); + painter.set_pango_font_description(style()->font_description()); painter.text(current_geometry(), m_text, PaintTextAlign::Center, PANGO_ELLIPSIZE_END, true); painter.fill(); } -void Button::on_focus_update(FocusUpdateEvent &event) { - update_color(); -} - void Button::on_activation_update(ActivationUpdateEvent &event) { - update_color(); if (event.activation_status() == false) { on_click(); } diff --git a/src/Button.hpp b/src/Button.hpp index 13634be..c543970 100644 --- a/src/Button.hpp +++ b/src/Button.hpp @@ -22,7 +22,6 @@ public: protected: void on_paint(); void on_init(); - void on_focus_update(FocusUpdateEvent &event); void on_activation_update(ActivationUpdateEvent &event); private: void update_color(); diff --git a/src/Forward.hpp b/src/Forward.hpp index 7b20264..fda750e 100644 --- a/src/Forward.hpp +++ b/src/Forward.hpp @@ -1,10 +1,10 @@ namespace Raven { + class GenericStyle; class Box; class Button; class Events; class Painter; class Point; - class TopLevelStyles; class Layout; class Widget; class Window; diff --git a/src/GenericStyle.hpp b/src/GenericStyle.hpp new file mode 100644 index 0000000..eee9c31 --- /dev/null +++ b/src/GenericStyle.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include "pango/pango-font.h" +#include "RGB.hpp" + +#define __RAVEN_STYLE_PROP(name, type, ...) \ + private: \ + type m_##name {__VA_ARGS__}; \ + public: \ + void set_##name(type new_prop_value) { m_##name = new_prop_value; style_prop_updated(); } \ + type name() { return m_##name; } \ + private: + +namespace Raven { + +class GenericStyle { +__RAVEN_STYLE_PROP(font_description, PangoFontDescription*, nullptr) +__RAVEN_STYLE_PROP(foreground, RGB, 0.00000, 0.00000, 0.00000) +__RAVEN_STYLE_PROP(background_norm, RGB, 1.00000, 1.00000, 1.00000) +__RAVEN_STYLE_PROP(background_focused, RGB, 1.00000, 1.00000, 1.00000) +__RAVEN_STYLE_PROP(background_active, RGB, 1.00000, 1.00000, 1.00000) +__RAVEN_STYLE_PROP(border_radius, double, 0.0) +__RAVEN_STYLE_PROP(fill_background, bool, true) +__RAVEN_STYLE_PROP(update_background, bool, false) + +private: + void style_prop_updated() { } +public: + GenericStyle( + PangoFontDescription* font_description, + RGB foreground, + RGB background_norm, + RGB background_focused, + RGB background_active, + double border_radius, + bool fill_background, + bool update_background + ) + : m_font_description(font_description) + , m_foreground(foreground) + , m_background_norm(background_norm) + , m_background_focused(background_focused) + , m_background_active(background_active) + , m_border_radius(border_radius) + , m_fill_background(fill_background) + , m_update_background(update_background) {} +}; + +} \ No newline at end of file diff --git a/src/Label.cpp b/src/Label.cpp index b3b24a7..0f59781 100644 --- a/src/Label.cpp +++ b/src/Label.cpp @@ -1,6 +1,7 @@ #include "Label.hpp" #include "Window.hpp" #include "pango/pango-layout.h" +#include "Styles.hpp" #include namespace Raven { @@ -13,18 +14,16 @@ void Label::set_text(std::string text) { } } void Label::on_init() { + set_style(&default_label_style); fit_text(m_text); - set_did_init(true); - set_do_background_fill(false); } void Label::on_paint() { auto painter = window()->painter(); - auto text_color = styles()->label_text_color(); - painter.source_rgb(text_color); - painter.set_pango_font_description(styles()->controls_font_description()); + painter.source_rgb(style()->foreground()); + painter.set_pango_font_description(style()->font_description()); painter.text(current_geometry(), m_text, PaintTextAlign::Left, PANGO_ELLIPSIZE_NONE, true); painter.fill(); } diff --git a/src/Label.hpp b/src/Label.hpp index 7697956..430742f 100644 --- a/src/Label.hpp +++ b/src/Label.hpp @@ -1,7 +1,6 @@ #pragma once #include "Widget.hpp" -#include "PropMacros.hpp" namespace Raven { diff --git a/src/Painter.cpp b/src/Painter.cpp index 2caf394..d21879b 100644 --- a/src/Painter.cpp +++ b/src/Painter.cpp @@ -83,7 +83,7 @@ Point Painter::text(Box &geometry, std::string &text, PaintTextAlign align, Pang return {pango_units_to_double(pango_width), pango_units_to_double(pango_height)}; } -void Painter::source_rgb(RGB &source_rgb) { +void Painter::source_rgb(RGB source_rgb) { m_cairo->set_source_rgb(source_rgb.r(), source_rgb.g(), source_rgb.b()); } diff --git a/src/Painter.hpp b/src/Painter.hpp index c1e2ae3..880dbcf 100644 --- a/src/Painter.hpp +++ b/src/Painter.hpp @@ -33,7 +33,7 @@ public: bool can_paint() { if (m_cairo) return true; else return false; } - void source_rgb(RGB &source_rgb); + void source_rgb(RGB source_rgb); void fill(); void begin_paint_group(); diff --git a/src/PropMacros.hpp b/src/PropMacros.hpp deleted file mode 100644 index ed98e92..0000000 --- a/src/PropMacros.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#define DEF_WIDGET_STYLE_PROP(name, type, ...) \ - private: \ - type m_##name {__VA_ARGS__}; \ - public: \ - void set_##name(type new_prop_value) { m_##name = new_prop_value; repaint(); } \ - type name() { return m_##name; } \ - private: diff --git a/src/Styles.cpp b/src/Styles.cpp new file mode 100644 index 0000000..596472a --- /dev/null +++ b/src/Styles.cpp @@ -0,0 +1,41 @@ +#include "Styles.hpp" + +#include "pango/pango-font.h" +#include "src/RGB.hpp" + +namespace Raven { + +GenericStyle default_widget_style { + pango_font_description_from_string("sans-serif"), + RGB(0.00000, 0.00000, 0.00000), + RGB(1.00000, 1.00000, 1.00000), + RGB(1.00000, 1.00000, 1.00000), + RGB(1.00000, 1.00000, 1.00000), + 0.0, + true, + false +}; + +GenericStyle default_button_style { + pango_font_description_from_string("sans-serif"), + RGB(0.00000, 0.00000, 0.00000), + RGB(0.73333, 0.40392, 0.89412), + RGB(0.63922, 0.27843, 0.81961), + RGB(0.54118, 0.18039, 0.72157), + 6.0, + true, + true +}; + +GenericStyle default_label_style { + pango_font_description_from_string("sans-serif"), + RGB(0.00000, 0.00000, 0.00000), + RGB(0.00000, 0.00000, 0.00000), + RGB(0.00000, 0.00000, 0.00000), + RGB(0.00000, 0.00000, 0.00000), + 0.0, + false, + false +}; + +} diff --git a/src/Styles.hpp b/src/Styles.hpp new file mode 100644 index 0000000..dfe60ed --- /dev/null +++ b/src/Styles.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include "src/GenericStyle.hpp" + +namespace Raven { + +extern GenericStyle default_widget_style; +extern GenericStyle default_button_style; +extern GenericStyle default_label_style; + +} diff --git a/src/TopLevelStyles.cpp b/src/TopLevelStyles.cpp deleted file mode 100644 index ae8fff7..0000000 --- a/src/TopLevelStyles.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "TopLevelStyles.hpp" -#include "Window.hpp" - -namespace Raven { - -void TopLevelStyles::wants_repaint() { - // when one of the styles here changes, we will dispatch - // a full repaint to the entire window :^) - m_window->dispatch_full_repaint(); -} - -} diff --git a/src/TopLevelStyles.hpp b/src/TopLevelStyles.hpp deleted file mode 100644 index 386f371..0000000 --- a/src/TopLevelStyles.hpp +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once - -#include "Forward.hpp" -#include "pango/pango-font.h" -#include "PropMacros.hpp" -#include "RGB.hpp" - -namespace Raven { - -class TopLevelStyles { -DEF_WIDGET_STYLE_PROP(controls_font_description, PangoFontDescription*, nullptr) - -/* FIXME: */ -/* right now, these colors are gruvbox */ -/* however the `accent_color_darkest` is a darkened version of `accent_color_darker` */ -DEF_WIDGET_STYLE_PROP(text_color, RGB, 0.0, 0.0, 0.0) -DEF_WIDGET_STYLE_PROP(accent_color, RGB, 0.6941, 0.3843, 0.5254) -DEF_WIDGET_STYLE_PROP(accent_color_darker, RGB, 0.5607, 0.2470, 0.4431) -DEF_WIDGET_STYLE_PROP(accent_color_darkest, RGB, 0.48069, 0.1669, 0.3631) -DEF_WIDGET_STYLE_PROP(background_color, RGB, 0.9764, 0.9607, 0.8431) - -DEF_WIDGET_STYLE_PROP(button_text_color, RGB, m_text_color) -DEF_WIDGET_STYLE_PROP(button_normal_color, RGB, m_accent_color) -DEF_WIDGET_STYLE_PROP(button_focused_color, RGB, m_accent_color_darker) -DEF_WIDGET_STYLE_PROP(button_active_color, RGB, m_accent_color_darkest) -DEF_WIDGET_STYLE_PROP(button_border_radius, double, 6.0) - -DEF_WIDGET_STYLE_PROP(label_text_color, RGB, m_text_color) - -private: - Window *m_window; -public: - TopLevelStyles(Window *window) - : m_window(window) - { - PangoFontDescription *font_description = pango_font_description_new(); - - pango_font_description_set_family(font_description, "sans-serif"); - pango_font_description_set_weight(font_description, PANGO_WEIGHT_NORMAL); - pango_font_description_set_absolute_size(font_description, 16 * PANGO_SCALE); - - m_controls_font_description = font_description; - } - - ~TopLevelStyles() { - if (m_controls_font_description) { - pango_font_description_free(m_controls_font_description); - } - } - - Window *window() { return m_window; } - void set_window(Window *window) { m_window = window; } - - void repaint(); -}; - -} diff --git a/src/Widget.cpp b/src/Widget.cpp index 84cbb91..9942f92 100644 --- a/src/Widget.cpp +++ b/src/Widget.cpp @@ -21,7 +21,7 @@ void Widget::fit_text(std::string &text) { if (!window()) return; - window()->painter().set_pango_font_description(styles()->controls_font_description()); + window()->painter().set_pango_font_description(m_style->font_description()); auto size = window()->painter().compute_text_size(current_geometry(), text); if (!resize(size)) { reflow(); @@ -65,7 +65,6 @@ void Widget::set_window(Window *window) { throw std::logic_error{"null window value for set_window"}; m_window = window; - m_styles = m_window->top_level_styles(); on_init(); } @@ -122,14 +121,24 @@ void Widget::handle_repaint_rect(RepaintRectEvent &event) { cr->save(); // clip this widget. this ensures that the background fill or children won't overflow the bounds of it - painter.rounded_rectangle(m_current_geometry, m_background_border_radius); + painter.rounded_rectangle(m_current_geometry, m_style->border_radius()); cr->clip(); // paint the background fill // note that we're using the bounds of the paint event as the rectangle, this ensures that we dont draw over other widgets which won't be repainted. - if (m_do_background_fill) { - painter.source_rgb(m_background_fill_color); - painter.rounded_rectangle(event.box(), m_background_border_radius); + if (m_style->fill_background()) { + if (m_style->update_background()) { + if (m_is_focused) { + painter.source_rgb(m_style->background_focused()); + } else if (m_is_active) { + painter.source_rgb(m_style->background_active()); + } else { + painter.source_rgb(m_style->background_norm()); + } + } else { + painter.source_rgb(m_style->background_norm()); + } + painter.rounded_rectangle(event.box(), m_style->border_radius()); cr->fill(); } @@ -176,6 +185,10 @@ void Widget::handle_mouse_move_event(MouseMoveEvent &event) { auto focus_update_event = FocusUpdateEvent(update_focus_to); on_focus_update(focus_update_event); + + if (m_style->update_background()) { + repaint(); + } } if (!m_consumes_hits) { @@ -208,6 +221,10 @@ void Widget::handle_mouse_button_event(MouseButtonEvent &event) { auto activation_update_event = ActivationUpdateEvent(update_activation_to); on_activation_update(activation_update_event); + + if (m_style->update_background()) { + repaint(); + } } if (!m_consumes_hits) { @@ -260,9 +277,4 @@ void Widget::dispatch_event(Event &event) { } } -void Widget::on_init() { - set_background_fill_color(styles()->background_color()); - set_did_init(true); -} - } diff --git a/src/Widget.hpp b/src/Widget.hpp index 969cacb..2fd8fc8 100644 --- a/src/Widget.hpp +++ b/src/Widget.hpp @@ -9,8 +9,8 @@ #include "Events.hpp" #include "Forward.hpp" #include "RGB.hpp" -#include "TopLevelStyles.hpp" -#include "PropMacros.hpp" +#include "src/GenericStyle.hpp" +#include "src/Styles.hpp" namespace Raven { @@ -27,10 +27,6 @@ enum class ControlWidgetType { }; class Widget { -DEF_WIDGET_STYLE_PROP(do_background_fill, bool, true) -DEF_WIDGET_STYLE_PROP(background_fill_color, RGB, 0, 0, 0) -DEF_WIDGET_STYLE_PROP(background_border_radius, double, 0.0) - public: Widget() {} @@ -73,14 +69,11 @@ public: Window *window() { return m_window; } void set_window(Window *window); - std::shared_ptr styles() { return m_styles; } - void set_styles(std::shared_ptr styles) { m_styles = styles; wants_relayout(); } + GenericStyle *style() { return m_style; } + void set_style(GenericStyle *style) { m_style = style; reflow(); } - void set_did_init(bool did_init) { m_did_init = did_init; } bool did_init() { return m_did_init; } - bool is_focused() { return m_is_focused; } - bool is_active() { return m_is_active; } bool consumes_hits() { return m_consumes_hits; } @@ -96,8 +89,6 @@ public: std::shared_ptr layout() { return m_layout; } void dispatch_event(Event &event); - void wants_repaint(); - void wants_relayout(); template std::shared_ptr set_layout(Args&&... args) { @@ -115,13 +106,15 @@ public: protected: WidgetType m_type { WidgetType::Widget }; - virtual void on_init(); + virtual void on_init() { set_did_init(true); } virtual void on_mouse_button(MouseButtonEvent &event) {} virtual void on_mouse_move(MouseMoveEvent &event) {} virtual void on_focus_update(FocusUpdateEvent &event) {} virtual void on_activation_update(ActivationUpdateEvent &event) {} virtual void on_paint() {} + void set_did_init(bool did_init) { m_did_init = did_init; } + void repaint(); void reflow(); private: @@ -135,7 +128,7 @@ private: std::vector> m_children; Widget *m_parent { nullptr }; Window *m_window { nullptr }; - std::shared_ptr m_styles { nullptr }; + GenericStyle *m_style { &default_widget_style }; std::shared_ptr m_layout { nullptr }; bool m_did_init { false }; bool m_is_focused { false }; diff --git a/src/Window.hpp b/src/Window.hpp index 08aa7dd..d8be93c 100644 --- a/src/Window.hpp +++ b/src/Window.hpp @@ -34,8 +34,6 @@ public: std::shared_ptr main_widget() { return m_main_widget; } void set_main_widget(std::shared_ptr main_widget); - std::shared_ptr top_level_styles() { return m_top_level_styles; } - void repaint(); void repaint(Box geometry); void repaint(Widget *target); @@ -57,7 +55,6 @@ private: std::shared_ptr m_main_widget { nullptr }; Box m_current_geometry { 0, 0, 800, 600 }; Painter m_painter {}; - std::shared_ptr m_top_level_styles = std::make_shared(this); Cairo::RefPtr m_xlib_surface { nullptr }; bool m_is_batching { true }; bool m_did_relayout_during_batch { true };