HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
toolbar_widget.hpp
Go to the documentation of this file.
1// Copyright Take Vos 2020-2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
9#pragma once
10
11#include "widget.hpp"
12#include "../layout/module.hpp"
13#include "../geometry/module.hpp"
14#include "../macros.hpp"
15#include <memory>
16#include <ranges>
17
18namespace hi { inline namespace v1 {
19
35class toolbar_widget final : public widget {
36public:
37 using super = widget;
38
44 {
45 hi_axiom(loop::main().on_thread());
46
47 // The toolbar is a top level widget, which draws its background as the next level.
49
50 _children.push_back(std::make_unique<spacer_widget>(this));
51 }
52
70 {
71 auto widget = std::make_unique<Widget>(this, std::forward<Args>(args)...);
72 return static_cast<Widget&>(add_widget(Alignment, std::move(widget)));
73 }
74
76 [[nodiscard]] generator<widget_intf &> children(bool include_invisible) noexcept override
77 {
78 for (hilet& child : _children) {
79 co_yield *child.value;
80 }
81 }
82
83 [[nodiscard]] box_constraints update_constraints() noexcept override
84 {
85 _layout = {};
86
87 for (auto& child : _children) {
88 child.set_constraints(child.value->update_constraints());
89 }
90
91 auto r = _children.constraints(os_settings::left_to_right());
92 _child_height_adjustment = -r.margins.top();
93
94 r.minimum.height() += r.margins.top();
95 r.preferred.height() += r.margins.top();
96 r.maximum.height() += r.margins.top();
97 r.padding.top() += r.margins.top();
98 r.margins.top() = 0;
99
100 return r;
101 }
102 void set_layout(widget_layout const& context) noexcept override
103 {
104 // Clip directly around the toolbar, so that tab buttons looks proper.
105 if (compare_store(_layout, context)) {
106 auto shape = context.shape;
107 shape.rectangle = aarectangle{shape.x(), shape.y(), shape.width(), shape.height() + _child_height_adjustment};
108 _children.set_layout(shape, theme().baseline_adjustment());
109 }
110
111 hilet overhang = context.redraw_overhang;
112
113 for (hilet& child : _children) {
115 aarectangle{child.shape.x() - overhang, 0, child.shape.width() + overhang * 2, context.height() + overhang * 2};
116
117 child.value->set_layout(context.transform(child.shape, 1.0f, child_clipping_rectangle));
118 }
119 }
120 void draw(draw_context const& context) noexcept override
121 {
123 if (overlaps(context, layout())) {
124 context.draw_box(layout(), layout().rectangle(), theme().color(semantic_color::fill, semantic_layer + 1));
125
126 if (tab_button_has_focus()) {
127 // Draw the line at a higher elevation, so that the tab buttons can draw above or below the focus
128 // line depending if that specific button is in focus or not.
129 hilet focus_rectangle = aarectangle{0.0f, 0.0f, layout().rectangle().width(), theme().border_width()};
130 context.draw_box(layout(), translate3{0.0f, 0.0f, 1.5f} * focus_rectangle, focus_color());
131 }
132 }
133
134 for (hilet& child : _children) {
135 hi_assert_not_null(child.value);
136 child.value->draw(context);
137 }
138 }
139 }
140 hitbox hitbox_test(point2 position) const noexcept override
141 {
142 hi_axiom(loop::main().on_thread());
143
144 // By default the toolbar is used for dragging the window.
145 if (*mode >= widget_mode::partial) {
146 auto r = layout().contains(position) ? hitbox{id, _layout.elevation, hitbox_type::move_area} : hitbox{};
147
148 for (hilet& child : _children) {
149 hi_assert_not_null(child.value);
150 r = child.value->hitbox_test_from_parent(position, r);
151 }
152
153 return r;
154 } else {
155 return {};
156 }
157 }
158 [[nodiscard]] color focus_color() const noexcept override
159 {
160 if (*mode >= widget_mode::partial) {
161 return theme().color(semantic_color::accent);
162 } else {
163 return theme().color(semantic_color::border, semantic_layer - 1);
164 }
165 }
167private:
168 mutable row_layout<std::unique_ptr<widget>> _children;
169 mutable float _child_height_adjustment = 0.0f;
170 size_t _spacer_index = 0;
171
172 void update_layout_for_child(widget& child, ssize_t index, widget_layout const& context) const noexcept;
173
176 widget& add_widget(horizontal_alignment alignment, std::unique_ptr<widget> widget) noexcept
177 {
178 auto& ref = *widget;
179 switch (alignment) {
181 case left:
182 _children.insert(_children.cbegin() + _spacer_index, std::move(widget));
183 ++_spacer_index;
184 break;
185 case right:
186 _children.insert(_children.cbegin() + _spacer_index + 1, std::move(widget));
187 break;
188 default:
189 hi_no_default();
190 }
191
192 return ref;
193 }
194
199 bool tab_button_has_focus() const noexcept
200 {
201 for (hilet& cell : _children) {
202 if (auto const *const c = dynamic_cast<toolbar_tab_button_widget *>(cell.value.get())) {
203 if (*c->focus and c->state() == hi::button_state::on) {
204 return true;
205 }
206 }
207 }
208
209 return false;
210 }
211};
212
213}} // namespace hi::v1
Defines widget.
horizontal_alignment
Horizontal alignment.
Definition alignment.hpp:103
@ right
Align the text to the right side.
@ left
Align the text to the left side.
@ rectangle
The gui_event has rectangle data.
@ partial
A widget is partially enabled.
@ invisible
The widget is invisible.
DOXYGEN BUG.
Definition algorithm.hpp:16
geometry/margins.hpp
Definition lookahead_iterator.hpp:5
std::ptrdiff_t ssize_t
Signed size/index into an array.
Definition misc.hpp:33
bool compare_store(T &lhs, U &&rhs) noexcept
Compare then store if there was a change.
Definition misc.hpp:56
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:377
widget_id id
The numeric identifier of a widget.
Definition widget_intf.hpp:23
widget_intf * parent
Pointer to the parent widget.
Definition widget_intf.hpp:28
constexpr bool contains(point3 mouse_position) const noexcept
Check if the mouse position is inside the widget.
Definition widget_layout.hpp:149
A toolbar widget is located at the top of a window and lays out its children horizontally.
Definition toolbar_widget.hpp:35
Widget & make_widget(Args &&...args)
Add a widget directly to this toolbar-widget.
Definition toolbar_widget.hpp:69
toolbar_widget(widget *parent) noexcept
Constructs an empty row/column widget.
Definition toolbar_widget.hpp:43
An interactive graphical object as part of the user-interface.
Definition widget.hpp:37
widget_layout const & layout() const noexcept override
Get the current layout for this widget.
Definition widget.hpp:169
int semantic_layer
The draw layer of the widget.
Definition widget.hpp:66
widget(widget *parent) noexcept
Definition widget.hpp:87
observer< widget_mode > mode
The widget mode.
Definition widget.hpp:42
T move(T... args)
T ref(T... args)