38 template<forward_of<observer<label>> Title>
41 _toolbar = std::make_unique<toolbar_widget>();
42 _toolbar->set_parent(
this);
44#if HI_OPERATING_SYSTEM == HI_OS_WINDOWS
46 this->_system_menu->icon = this->title.
sub<
"icon">();
49#elif HI_OPERATING_SYSTEM == HI_OS_MACOS
53#error "Not implemented"
56 _content = std::make_unique<grid_widget>();
57 _content->set_parent(
this);
66 hi_axiom(loop::main().on_thread());
67 return theme().fill_color(_layout.layer);
76 hi_axiom(loop::main().on_thread());
77 hi_assert_not_null(_content);
88 hi_axiom(loop::main().on_thread());
89 hi_assert_not_null(_toolbar);
94 [[nodiscard]] generator<widget_intf&> children(
bool include_invisible)
noexcept override
105 hi_assert_not_null(_content);
106 hi_assert_not_null(_toolbar);
109 _content_constraints = _content->update_constraints();
110 _toolbar_constraints = _toolbar->update_constraints();
112 auto r = box_constraints{};
114 _toolbar_constraints.margins.left() + _toolbar_constraints.minimum.width() + _toolbar_constraints.margins.right(),
115 _content_constraints.margins.left() + _content_constraints.minimum.width() + _content_constraints.margins.right());
117 _toolbar_constraints.margins.left() + _toolbar_constraints.preferred.width() + _toolbar_constraints.margins.right(),
118 _content_constraints.margins.left() + _content_constraints.preferred.width() + _content_constraints.margins.right());
120 _toolbar_constraints.margins.left() + _toolbar_constraints.maximum.width() + _toolbar_constraints.margins.right(),
121 _content_constraints.margins.left() + _content_constraints.maximum.width() + _content_constraints.margins.right());
125 _toolbar_constraints.margins.top() +
126 _toolbar_constraints.preferred.height() +
127 std::max(_toolbar_constraints.margins.bottom(), _content_constraints.margins.top()) +
128 _content_constraints.minimum.height() +
129 _content_constraints.margins.bottom();
130 r.preferred.height() =
131 _toolbar_constraints.margins.top() +
132 _toolbar_constraints.preferred.height() +
133 std::max(_toolbar_constraints.margins.bottom(), _content_constraints.margins.top()) +
134 _content_constraints.preferred.height() +
135 _content_constraints.margins.bottom();
137 _toolbar_constraints.margins.top() +
138 _toolbar_constraints.preferred.height() +
139 std::max(_toolbar_constraints.margins.bottom(), _content_constraints.margins.top()) +
140 _content_constraints.maximum.height() +
141 _content_constraints.margins.bottom();
146 inplace_max(r.minimum.width(), os_settings::minimum_window_width());
147 inplace_max(r.minimum.height(), os_settings::minimum_window_height());
149 inplace_clamp(r.maximum.width(), r.minimum.width(), os_settings::maximum_window_width());
150 inplace_clamp(r.maximum.height(), r.minimum.height(), os_settings::maximum_window_height());
152 inplace_clamp(r.preferred.width(), r.minimum.width(), r.maximum.width());
153 inplace_clamp(r.preferred.height(), r.minimum.height(), r.maximum.height());
155 _can_resize_width = r.minimum.width() != r.maximum.width();
156 _can_resize_height = r.minimum.height() != r.maximum.height();
161 void set_layout(widget_layout
const& context)
noexcept override
164 auto const toolbar_height = _toolbar_constraints.preferred.height();
165 auto const between_margin =
std::max(_toolbar_constraints.margins.bottom(), _content_constraints.margins.top());
167 auto const toolbar_rectangle = aarectangle{
169 _toolbar_constraints.margins.left(), context.height() - toolbar_height - _toolbar_constraints.margins.top()},
171 context.width() - _toolbar_constraints.margins.right(),
172 context.height() - _toolbar_constraints.margins.top()}};
173 _toolbar_shape = box_shape{_toolbar_constraints, toolbar_rectangle, theme().baseline_adjustment()};
175 auto const content_rectangle = aarectangle{
176 point2{_content_constraints.margins.left(), _content_constraints.margins.bottom()},
177 point2{context.width() - _content_constraints.margins.right(), toolbar_rectangle.bottom() - between_margin}};
178 _content_shape = box_shape{_content_constraints, content_rectangle, theme().baseline_adjustment()};
180 _toolbar->set_layout(context.transform(_toolbar_shape));
181 _content->set_layout(context.transform(_content_shape));
183 void draw(draw_context
const& context)
noexcept override
188 _toolbar->draw(context);
189 _content->draw(context);
192 [[nodiscard]] hitbox hitbox_test(point2 position)
const noexcept override
194 constexpr float BORDER_WIDTH = 10.0f;
196 hi_axiom(loop::main().on_thread());
198 auto r = _toolbar->hitbox_test_from_parent(position);
199 r = _content->hitbox_test_from_parent(position, r);
201 auto const is_on_l_edge = position.x() <= BORDER_WIDTH;
202 auto const is_on_r_edge = position.x() >= (
layout().width() - BORDER_WIDTH);
203 auto const is_on_b_edge = position.y() <= BORDER_WIDTH;
204 auto const is_on_t_edge = position.y() >= (
layout().height() - BORDER_WIDTH);
207 if (is_on_l_edge and is_on_b_edge) {
208 if (_can_resize_width and _can_resize_height) {
209 return {
id, _layout.elevation, hitbox_type::bottom_left_resize_corner};
210 }
else if (_can_resize_width) {
211 return {
id, _layout.elevation, hitbox_type::left_resize_border};
212 }
else if (_can_resize_height) {
213 return {
id, _layout.elevation, hitbox_type::bottom_resize_border};
215 }
else if (is_on_r_edge and is_on_b_edge) {
216 if (_can_resize_width and _can_resize_height) {
217 return {
id, _layout.elevation, hitbox_type::bottom_right_resize_corner};
218 }
else if (_can_resize_width) {
219 return {
id, _layout.elevation, hitbox_type::right_resize_border};
220 }
else if (_can_resize_height) {
221 return {
id, _layout.elevation, hitbox_type::bottom_resize_border};
223 }
else if (is_on_l_edge and is_on_t_edge) {
224 if (_can_resize_width and _can_resize_height) {
225 return {
id, _layout.elevation, hitbox_type::top_left_resize_corner};
226 }
else if (_can_resize_width) {
227 return {
id, _layout.elevation, hitbox_type::left_resize_border};
228 }
else if (_can_resize_height) {
229 return {
id, _layout.elevation, hitbox_type::top_resize_border};
231 }
else if (is_on_r_edge and is_on_t_edge) {
232 if (_can_resize_width and _can_resize_height) {
233 return {
id, _layout.elevation, hitbox_type::top_right_resize_corner};
234 }
else if (_can_resize_width) {
235 return {
id, _layout.elevation, hitbox_type::right_resize_border};
236 }
else if (_can_resize_height) {
237 return {
id, _layout.elevation, hitbox_type::top_resize_border};
242 if (r.type != hitbox_type::scroll_bar) {
243 if (is_on_l_edge and _can_resize_width) {
244 return {
id, _layout.elevation, hitbox_type::left_resize_border};
245 }
else if (is_on_r_edge and _can_resize_width) {
246 return {
id, _layout.elevation, hitbox_type::right_resize_border};
247 }
else if (is_on_b_edge and _can_resize_height) {
248 return {
id, _layout.elevation, hitbox_type::bottom_resize_border};
249 }
else if (is_on_t_edge and _can_resize_height) {
250 return {
id, _layout.elevation, hitbox_type::top_resize_border};
256 bool handle_event(gui_event
const& event)
noexcept override
260 switch (event.type()) {
261 case gui_toolbar_open:
263 gui_event::window_set_keyboard_target(
id, keyboard_focus_group::toolbar, keyboard_focus_direction::forward));
269 bool process_event(gui_event
const& event)
const noexcept override
272 return window->process_event(event);
280 std::unique_ptr<grid_widget> _content;
281 box_constraints _content_constraints;
282 box_shape _content_shape;
284 std::unique_ptr<toolbar_widget> _toolbar;
285 box_constraints _toolbar_constraints;
286 box_shape _toolbar_shape;
288 mutable bool _can_resize_width;
289 mutable bool _can_resize_height;
291#if HI_OPERATING_SYSTEM == HI_OS_WINDOWS
292 system_menu_widget* _system_menu =
nullptr;