diff --git a/examples/caption_example.cpp b/examples/caption_example.cpp index 4f9ef6a..1842afb 100644 --- a/examples/caption_example.cpp +++ b/examples/caption_example.cpp @@ -6,8 +6,8 @@ auto main() -> int { run_example([]() { return bwidgets::create_caption(); }, [](auto w, auto f, auto, auto) { - w->alignment = - bwidgets::Caption::Alignment::CENTER; + w->alignment( + bwidgets::Caption::Alignment::CENTER); w->text("¡jello!"); w->font(f); }, diff --git a/examples/example_widget.hpp b/examples/example_widget.hpp index 6777a58..487d4cd 100644 --- a/examples/example_widget.hpp +++ b/examples/example_widget.hpp @@ -14,9 +14,11 @@ using bwidgets::WidgetImpl; class Example final : public WidgetImpl { + SDL_Rect _widget_area {}; + void _handle_geometry_change(const SDL_Rect& vp) noexcept override { - _widget_area = {2, 2, vp.w - 4, vp.h - 4}; + _widget_area = {0, 0, vp.w, vp.h}; } void _handle_rendering() override @@ -32,14 +34,15 @@ class Example final : public WidgetImpl const int border = 10; for (auto i = 0; i < border; i += 3) { uint8_t alpha = 255 * i / border; // NOLINT(readability-magic-numbers) - _renderer + renderer() ->draw_color({ {base_color().r, base_color().g, base_color().b, alpha} }) ->draw_rect(rect_margin(_widget_area, {i, i})); } - _renderer->draw_color(base_color) + renderer() + ->draw_color(base_color) ->draw_rect(nullptr) ->fill_rect(rect_margin(_widget_area, {border * 2, border * 2})); } diff --git a/examples/run.hpp b/examples/run.hpp index 9141b28..bb09757 100644 --- a/examples/run.hpp +++ b/examples/run.hpp @@ -26,7 +26,7 @@ void run_example( const bwidgets::Size size_init {854, 480}; auto font = std::make_shared(bwidgets::Font::find("Monospace"), - 16); // NOLINT(readability-magic-numbers) + 18); // NOLINT(readability-magic-numbers) auto win = std::unique_ptr( bwidgets::ptr_or_throw(SDL_CreateWindow( diff --git a/inc/basic_widgets/w/aligned_layout.hpp b/inc/basic_widgets/w/aligned_layout.hpp index 5aa3bc3..7d7aa60 100644 --- a/inc/basic_widgets/w/aligned_layout.hpp +++ b/inc/basic_widgets/w/aligned_layout.hpp @@ -5,18 +5,9 @@ namespace bwidgets { - enum struct LayoutAlignment - { - HORIZONTAL, - VERTICAL - }; - // Align vertically or horizontally widgets. class AlignedLayout : public virtual Layout - { - public: - using Layout::Layout; - }; + {}; } #endif diff --git a/inc/basic_widgets/w/aligned_layout_impl.hpp b/inc/basic_widgets/w/aligned_layout_impl.hpp index a302002..b4fd8a5 100644 --- a/inc/basic_widgets/w/aligned_layout_impl.hpp +++ b/inc/basic_widgets/w/aligned_layout_impl.hpp @@ -8,6 +8,12 @@ namespace bwidgets { + enum struct LayoutAlignment + { + HORIZONTAL, + VERTICAL + }; + template class AlignedLayoutImpl final : public virtual AlignedLayout, public virtual LayoutImpl, @@ -16,6 +22,18 @@ namespace bwidgets public: using LayoutImpl::LayoutImpl; + void add_widget(std::unique_ptr widget_ptr) override + { + if (renderer()) widget_ptr->renderer(renderer()); + _widgets.emplace_back(std::move(widget_ptr)); + _handle_geometry_change(viewport()); + } + + void for_widgets(const std::function& f) + { + for (const auto& w : _widgets) f(w.get()); + } + // Return smallest usable size. [[nodiscard]] auto size() const noexcept -> Size override { @@ -28,8 +46,8 @@ namespace bwidgets } return {(int)_widgets.size() * min_size.w - + ((int)_widgets.size() + 1) * margins.w, - min_size.h + 2 * margins.h}; + + ((int)_widgets.size() + 1) * theme()->size_layout_margin().w, + min_size.h + 2 * theme()->size_layout_margin().h}; } // Vertical @@ -39,22 +57,28 @@ namespace bwidgets min_size.h += w->size().h; } - return {min_size.w + 2 * margins.w, - min_size.h + ((int)_widgets.size() + 1) * margins.h}; + return {min_size.w + 2 * theme()->size_layout_margin().w, + min_size.h + + ((int)_widgets.size() + 1) * theme()->size_layout_margin().h}; } private: - void _update_layout(const SDL_Rect& vp) override + std::vector> _widgets; + + void _handle_geometry_change(const SDL_Rect& vp) override { if constexpr (alignment == LayoutAlignment::HORIZONTAL) { const int widget_width = - (vp.w - ((int)_widgets.size() + 1) * margins.w) / (int)_widgets.size(); + (vp.w - ((int)_widgets.size() + 1) * theme()->size_layout_margin().w) + / (int)_widgets.size(); for (std::vector::size_type i = 0; i < _widgets.size(); i++) { const auto& w {_widgets[i]}; - w->viewport({vp.x + margins.w + (int)i * (widget_width + margins.w), - vp.y + center_line(vp.h, w->size().h), widget_width, - w->size().h}); + w->viewport( + {vp.x + theme()->size_layout_margin().w + + (int)i * (widget_width + theme()->size_layout_margin().w), + vp.y + center_line(vp.h, w->size().h), widget_width, + w->size().h}); } } else { // Vertical @@ -63,7 +87,7 @@ namespace bwidgets const auto& w {_widgets[i]}; w->viewport({ vp.x, - vp.y + ((int)i + 1) * margins.h + offset, + vp.y + ((int)i + 1) * theme()->size_layout_margin().h + offset, vp.w, w->size().h, }); diff --git a/inc/basic_widgets/w/base/input_impl.hpp b/inc/basic_widgets/w/base/input_impl.hpp index ccce2b6..6b12505 100644 --- a/inc/basic_widgets/w/base/input_impl.hpp +++ b/inc/basic_widgets/w/base/input_impl.hpp @@ -117,6 +117,7 @@ namespace bwidgets protected: std::unique_ptr _input_caption; + SDL_Rect _text_area {}; InputImpl(Widget* parent = nullptr) : WidgetImpl {parent}, _input_caption {create_caption(this)} @@ -180,7 +181,7 @@ namespace bwidgets else if (!focus()) _input_caption->font_color_bg(theme()->color_input_bg()); }); - enable_mouse_handler(_widget_area, _viewport); + enable_mouse_handler(_text_area, viewport()); _input_caption->font_color_bg(theme()->color_input_bg()); } @@ -188,7 +189,7 @@ namespace bwidgets void _handle_font_change(const std::shared_ptr& f) override { _input_caption->font(f); - _handle_geometry_change(_viewport); + _handle_geometry_change(viewport()); } void _handle_font_color_change(const Color fg, const Color bg) override @@ -201,11 +202,11 @@ namespace bwidgets { const auto input_h = _input_caption->size().h + 2 * theme()->size_widget_border(); - _widget_area = {0, center_line(vp.h, input_h), vp.w, input_h}; + _text_area = {0, center_line(vp.h, input_h), vp.w, input_h}; _input_caption->viewport( - rect_offset({rect_margin(_widget_area, {theme()->size_widget_border(), - theme()->size_widget_border()})}, + rect_offset({rect_margin(_text_area, {theme()->size_widget_border(), + theme()->size_widget_border()})}, vp)); } @@ -219,7 +220,7 @@ namespace bwidgets const auto& color_end = focus() ? theme()->color_input_bg_active() : theme()->color_input_bg(); - fill_rect_gradient(*_renderer, _widget_area, theme()->color_widget_border(), + fill_rect_gradient(*renderer(), _text_area, theme()->color_widget_border(), color_end, theme()->size_widget_border()); _input_caption->render(); } diff --git a/inc/basic_widgets/w/base/layout.hpp b/inc/basic_widgets/w/base/layout.hpp index 0840234..01efd6d 100644 --- a/inc/basic_widgets/w/base/layout.hpp +++ b/inc/basic_widgets/w/base/layout.hpp @@ -12,11 +12,6 @@ namespace bwidgets using Widget::Widget; public: - static inline const Size default_margins {8, 8}; - - // Margins between layout widgets. - Size margins = default_margins; - // Add widget to the layout virtual void add_widget(std::unique_ptr) = 0; // Apply a function to every layout widget. diff --git a/inc/basic_widgets/w/base/layout_impl.hpp b/inc/basic_widgets/w/base/layout_impl.hpp index e88a020..99ee5dd 100644 --- a/inc/basic_widgets/w/base/layout_impl.hpp +++ b/inc/basic_widgets/w/base/layout_impl.hpp @@ -19,19 +19,15 @@ namespace bwidgets public: using WidgetImpl::WidgetImpl; - void add_widget(std::unique_ptr) override; - void for_widgets(const std::function&) override; + // TODO: remove widget void handle_event(const SDL_Event&) override; protected: std::vector> _widgets; - void _handle_geometry_change(const SDL_Rect&) override; void _handle_renderer_change(const std::shared_ptr&) override; void _handle_rendering() override; - - // Compute and set widget geometry. - virtual void _update_layout(const SDL_Rect&) = 0; + void _handle_theme_change(const std::shared_ptr&) override; }; } diff --git a/inc/basic_widgets/w/base/theme.hpp b/inc/basic_widgets/w/base/theme.hpp index 01adac7..4e21847 100644 --- a/inc/basic_widgets/w/base/theme.hpp +++ b/inc/basic_widgets/w/base/theme.hpp @@ -20,8 +20,9 @@ namespace bwidgets [[nodiscard]] virtual auto color_widget_bg_hl() const -> const Color& = 0; [[nodiscard]] virtual auto color_widget_border() const -> const Color& = 0; [[nodiscard]] virtual auto color_widget_border_pushed() const - -> const Color& = 0; - [[nodiscard]] virtual auto size_widget_border() const -> int = 0; + -> const Color& = 0; + [[nodiscard]] virtual auto size_layout_margin() const -> const Size& = 0; + [[nodiscard]] virtual auto size_widget_border() const -> int = 0; }; } diff --git a/inc/basic_widgets/w/base/widget.hpp b/inc/basic_widgets/w/base/widget.hpp index c353116..d4794f6 100644 --- a/inc/basic_widgets/w/base/widget.hpp +++ b/inc/basic_widgets/w/base/widget.hpp @@ -17,17 +17,15 @@ namespace bwidgets class Widget : public virtual EventHandler { public: - // Parent widget for bidirectional message passing between widgets. - // Currently not used by this lib. - Widget* parent; - - explicit Widget(Widget* p = nullptr) : parent {p} {} - + explicit Widget(Widget* p = nullptr) {}; + [[nodiscard]] virtual auto parent() -> Widget* = 0; + virtual void parent(Widget*) = 0; // Render widget on current renderer target. virtual void render() = 0; + [[nodiscard]] virtual auto renderer() -> const std::shared_ptr& = 0; // Set widget renderer. virtual void renderer(std::shared_ptr) = 0; - // Get prefered or minimal widget size. + // Get prefered or minimal widget size. TODO: change that. [[nodiscard]] virtual auto size() const noexcept -> Size = 0; [[nodiscard]] virtual auto theme() const -> const std::shared_ptr& = 0; virtual void theme(std::shared_ptr) = 0; diff --git a/inc/basic_widgets/w/base/widget_impl.hpp b/inc/basic_widgets/w/base/widget_impl.hpp index c463e08..91f1d19 100644 --- a/inc/basic_widgets/w/base/widget_impl.hpp +++ b/inc/basic_widgets/w/base/widget_impl.hpp @@ -12,7 +12,10 @@ namespace bwidgets public: WidgetImpl(Widget* p = nullptr); + [[nodiscard]] auto parent() -> Widget* override; + void parent(Widget*) override; void render() override; + [[nodiscard]] auto renderer() -> const std::shared_ptr& override; void renderer(std::shared_ptr) override; [[nodiscard]] auto theme() const -> const std::shared_ptr& override; void theme(std::shared_ptr) override; @@ -20,11 +23,6 @@ namespace bwidgets [[nodiscard]] auto viewport() const -> const SDL_Rect& override; protected: - std::shared_ptr _renderer; - SDL_Rect _viewport {0, 0, 0, 0}; - // Area actually used by the widget. - SDL_Rect _widget_area {0, 0, 0, 0}; - // Called on viewport change. virtual void _handle_geometry_change(const SDL_Rect&) = 0; // Called on renderer change. @@ -34,7 +32,10 @@ namespace bwidgets virtual void _handle_theme_change(const std::shared_ptr&) {} // = 0; private: - std::shared_ptr _theme; + Widget* _parent; + std::shared_ptr _renderer; + std::shared_ptr _theme; + SDL_Rect _viewport {0, 0, 0, 0}; }; } diff --git a/inc/basic_widgets/w/button_impl.hpp b/inc/basic_widgets/w/button_impl.hpp index 5b64361..60f82a0 100644 --- a/inc/basic_widgets/w/button_impl.hpp +++ b/inc/basic_widgets/w/button_impl.hpp @@ -25,9 +25,7 @@ namespace bwidgets protected: std::unique_ptr _caption; SDL_Rect _caption_area {}; - Color _color_bg; - Color _color_bg_hl; - Color _color_border; + SDL_Rect _mouse_area; void _handle_font_change(const std::shared_ptr&) override; void _handle_font_color_change(Color, Color) override; diff --git a/inc/basic_widgets/w/caption.hpp b/inc/basic_widgets/w/caption.hpp index 416916e..d7a74a3 100644 --- a/inc/basic_widgets/w/caption.hpp +++ b/inc/basic_widgets/w/caption.hpp @@ -20,14 +20,10 @@ namespace bwidgets LEFT, RIGHT }; - inline static const Size default_margins = {3, 3}; // Text horizontal alignment on the caption viewport. - Alignment alignment {Alignment::LEFT}; - Size margins {default_margins}; - - using Widget::Widget; - + [[nodiscard]] virtual auto alignment() const -> Alignment = 0; + virtual void alignment(Alignment) = 0; // Set caption text rendering mode. virtual void render_mode(Font::RenderMode) = 0; // Get caption text. diff --git a/inc/basic_widgets/w/caption_impl.hpp b/inc/basic_widgets/w/caption_impl.hpp index b5b5b4d..6e8be01 100644 --- a/inc/basic_widgets/w/caption_impl.hpp +++ b/inc/basic_widgets/w/caption_impl.hpp @@ -14,14 +14,18 @@ namespace bwidgets public: CaptionImpl(Widget* p = nullptr) noexcept; + [[nodiscard]] auto alignment() const -> Alignment override; + void alignment(Alignment) override; void render_mode(Font::RenderMode) override; [[nodiscard]] auto size() const noexcept -> Size override; [[nodiscard]] auto text() const noexcept -> std::string_view override; void text(std::string) override; protected: + Alignment _alignment; Font::RenderMode _render_mode {Font::RenderMode::SHADED}; std::string _text; + SDL_Rect _text_area; std::shared_ptr _text_texture {nullptr}; void _handle_font_change(const std::shared_ptr&) override; diff --git a/inc/basic_widgets/w/default_theme.hpp b/inc/basic_widgets/w/default_theme.hpp index 3062e61..1dbc05f 100644 --- a/inc/basic_widgets/w/default_theme.hpp +++ b/inc/basic_widgets/w/default_theme.hpp @@ -19,6 +19,7 @@ namespace bwidgets [[nodiscard]] auto color_widget_bg_hl() const -> const Color& override; [[nodiscard]] auto color_widget_border() const -> const Color& override; [[nodiscard]] auto color_widget_border_pushed() const -> const Color& override; + [[nodiscard]] auto size_layout_margin() const -> const Size& override; [[nodiscard]] auto size_widget_border() const -> int override; private: @@ -31,6 +32,7 @@ namespace bwidgets static const Color _color_widget_bg_hl; static const Color _color_widget_border; static const Color _color_widget_border_pushed; + static const Size _size_layout_margin; static const int _size_widget_border; }; diff --git a/inc/basic_widgets/w/numeric_input_impl.hpp b/inc/basic_widgets/w/numeric_input_impl.hpp index 4f2524a..afc9a25 100644 --- a/inc/basic_widgets/w/numeric_input_impl.hpp +++ b/inc/basic_widgets/w/numeric_input_impl.hpp @@ -18,7 +18,7 @@ namespace bwidgets _increment_button(create_button(this)), _decrement_button(create_button(this)) { - Self::_input_caption->alignment = Caption::Alignment::RIGHT; + Self::_input_caption->alignment(Caption::Alignment::RIGHT); Self::input_min_width = 10; // NOLINT(readability-magic-numbers) Self::input_width_unit = '0'; @@ -160,19 +160,19 @@ namespace bwidgets const int spacing = center_line(button_area_width, widest_button); const int field_width = vp.w - 2 * button_area_width; - Self::_widget_area.x = Self::_widget_area.x + button_area_width; - Self::_widget_area.w = field_width; + Self::_text_area.x = Self::_text_area.x + button_area_width; + Self::_text_area.w = field_width; Self::_input_caption->viewport(rect_offset( - rect_margin(Self::_widget_area, {Self::theme()->size_widget_border(), - Self::theme()->size_widget_border()}), + rect_margin(Self::_text_area, {Self::theme()->size_widget_border(), + Self::theme()->size_widget_border()}), vp)); - _decrement_button_area = {spacing, Self::_widget_area.y, + _decrement_button_area = {spacing, Self::_text_area.y, _decrement_button->size().w, _decrement_button->size().h}; _increment_button_area = {vp.w - spacing - _increment_button->size().w, - Self::_widget_area.y, _increment_button->size().w, + Self::_text_area.y, _increment_button->size().w, _increment_button->size().h}; _increment_button->viewport(rect_offset(_increment_button_area, vp)); diff --git a/inc/basic_widgets/w/scrollbar_impl.hpp b/inc/basic_widgets/w/scrollbar_impl.hpp index 999994c..b6a4736 100644 --- a/inc/basic_widgets/w/scrollbar_impl.hpp +++ b/inc/basic_widgets/w/scrollbar_impl.hpp @@ -30,9 +30,11 @@ namespace bwidgets void value(int) override; protected: + SDL_Rect _bar_area; std::unique_ptr