28class window_widget final :
public widget {
32 observer<label> title;
34 window_widget(
forward_of<observer<label>>
auto&& title) noexcept : super(
nullptr), title(hi_forward(title))
36 _toolbar = std::make_unique<toolbar_widget>(
this);
38#if HI_OPERATING_SYSTEM == HI_OS_WINDOWS
40 this->_system_menu->icon = this->title.get<
"icon">();
43#elif HI_OPERATING_SYSTEM == HI_OS_MACOS
47#error "Not implemented"
50 _content = std::make_unique<grid_widget>(
this);
59 hi_axiom(loop::main().on_thread());
69 hi_axiom(loop::main().on_thread());
70 hi_assert_not_null(_content);
81 hi_axiom(loop::main().on_thread());
82 hi_assert_not_null(_toolbar);
87 [[nodiscard]] generator<widget_intf&> children(
bool include_invisible)
noexcept override
94 hi_assert_not_null(_content);
95 hi_assert_not_null(_toolbar);
98 _content_constraints = _content->update_constraints();
99 _toolbar_constraints = _toolbar->update_constraints();
101 auto r = box_constraints{};
103 _toolbar_constraints.margins.left() + _toolbar_constraints.minimum.width() + _toolbar_constraints.margins.right(),
104 _content_constraints.margins.left() + _content_constraints.minimum.width() + _content_constraints.margins.right());
106 _toolbar_constraints.margins.left() + _toolbar_constraints.preferred.width() + _toolbar_constraints.margins.right(),
107 _content_constraints.margins.left() + _content_constraints.preferred.width() + _content_constraints.margins.right());
109 _toolbar_constraints.margins.left() + _toolbar_constraints.maximum.width() + _toolbar_constraints.margins.right(),
110 _content_constraints.margins.left() + _content_constraints.maximum.width() + _content_constraints.margins.right());
114 _toolbar_constraints.margins.top() +
115 _toolbar_constraints.preferred.height() +
116 std::max(_toolbar_constraints.margins.bottom(), _content_constraints.margins.top()) +
117 _content_constraints.minimum.height() +
118 _content_constraints.margins.bottom();
119 r.preferred.height() =
120 _toolbar_constraints.margins.top() +
121 _toolbar_constraints.preferred.height() +
122 std::max(_toolbar_constraints.margins.bottom(), _content_constraints.margins.top()) +
123 _content_constraints.preferred.height() +
124 _content_constraints.margins.bottom();
126 _toolbar_constraints.margins.top() +
127 _toolbar_constraints.preferred.height() +
128 std::max(_toolbar_constraints.margins.bottom(), _content_constraints.margins.top()) +
129 _content_constraints.maximum.height() +
130 _content_constraints.margins.bottom();
135 inplace_max(r.minimum.width(), os_settings::minimum_window_width());
136 inplace_max(r.minimum.height(), os_settings::minimum_window_height());
138 inplace_clamp(r.maximum.width(), r.minimum.width(), os_settings::maximum_window_width());
139 inplace_clamp(r.maximum.height(), r.minimum.height(), os_settings::maximum_window_height());
141 inplace_clamp(r.preferred.width(), r.minimum.width(), r.maximum.width());
142 inplace_clamp(r.preferred.height(), r.minimum.height(), r.maximum.height());
144 _can_resize_width = r.minimum.width() != r.maximum.width();
145 _can_resize_height = r.minimum.height() != r.maximum.height();
149 void set_layout(widget_layout
const& context)
noexcept override
152 hilet toolbar_height = _toolbar_constraints.preferred.height();
153 hilet between_margin =
std::max(_toolbar_constraints.margins.bottom(), _content_constraints.margins.top());
155 hilet toolbar_rectangle = aarectangle{
157 _toolbar_constraints.margins.left(), context.height() - toolbar_height - _toolbar_constraints.margins.top()},
159 context.width() - _toolbar_constraints.margins.right(),
160 context.height() - _toolbar_constraints.margins.top()}};
161 _toolbar_shape = box_shape{_toolbar_constraints, toolbar_rectangle, theme().baseline_adjustment()};
163 hilet content_rectangle = aarectangle{
164 point2{_content_constraints.margins.left(), _content_constraints.margins.bottom()},
165 point2{context.width() - _content_constraints.margins.right(), toolbar_rectangle.bottom() - between_margin}};
166 _content_shape = box_shape{_content_constraints, content_rectangle, theme().baseline_adjustment()};
168 _toolbar->set_layout(context.transform(_toolbar_shape));
169 _content->set_layout(context.transform(_content_shape));
171 void draw(draw_context
const& context)
noexcept override
176 _toolbar->draw(context);
177 _content->draw(context);
180 [[nodiscard]] hitbox hitbox_test(point2 position)
const noexcept override
182 constexpr float BORDER_WIDTH = 10.0f;
184 hi_axiom(loop::main().on_thread());
186 auto r = _toolbar->hitbox_test_from_parent(position);
187 r = _content->hitbox_test_from_parent(position, r);
189 hilet is_on_l_edge = position.x() <= BORDER_WIDTH;
190 hilet is_on_r_edge = position.x() >= (
layout().width() - BORDER_WIDTH);
191 hilet is_on_b_edge = position.y() <= BORDER_WIDTH;
192 hilet is_on_t_edge = position.y() >= (
layout().height() - BORDER_WIDTH);
195 if (is_on_l_edge and is_on_b_edge) {
196 if (_can_resize_width and _can_resize_height) {
197 return {
id, _layout.elevation, hitbox_type::bottom_left_resize_corner};
198 }
else if (_can_resize_width) {
199 return {
id, _layout.elevation, hitbox_type::left_resize_border};
200 }
else if (_can_resize_height) {
201 return {
id, _layout.elevation, hitbox_type::bottom_resize_border};
203 }
else if (is_on_r_edge and is_on_b_edge) {
204 if (_can_resize_width and _can_resize_height) {
205 return {
id, _layout.elevation, hitbox_type::bottom_right_resize_corner};
206 }
else if (_can_resize_width) {
207 return {
id, _layout.elevation, hitbox_type::right_resize_border};
208 }
else if (_can_resize_height) {
209 return {
id, _layout.elevation, hitbox_type::bottom_resize_border};
211 }
else if (is_on_l_edge and is_on_t_edge) {
212 if (_can_resize_width and _can_resize_height) {
213 return {
id, _layout.elevation, hitbox_type::top_left_resize_corner};
214 }
else if (_can_resize_width) {
215 return {
id, _layout.elevation, hitbox_type::left_resize_border};
216 }
else if (_can_resize_height) {
217 return {
id, _layout.elevation, hitbox_type::top_resize_border};
219 }
else if (is_on_r_edge and is_on_t_edge) {
220 if (_can_resize_width and _can_resize_height) {
221 return {
id, _layout.elevation, hitbox_type::top_right_resize_corner};
222 }
else if (_can_resize_width) {
223 return {
id, _layout.elevation, hitbox_type::right_resize_border};
224 }
else if (_can_resize_height) {
225 return {
id, _layout.elevation, hitbox_type::top_resize_border};
230 if (r.type != hitbox_type::scroll_bar) {
231 if (is_on_l_edge and _can_resize_width) {
232 return {
id, _layout.elevation, hitbox_type::left_resize_border};
233 }
else if (is_on_r_edge and _can_resize_width) {
234 return {
id, _layout.elevation, hitbox_type::right_resize_border};
235 }
else if (is_on_b_edge and _can_resize_height) {
236 return {
id, _layout.elevation, hitbox_type::bottom_resize_border};
237 }
else if (is_on_t_edge and _can_resize_height) {
238 return {
id, _layout.elevation, hitbox_type::top_resize_border};
244 bool handle_event(gui_event
const& event)
noexcept override
248 switch (event.type()) {
249 case gui_toolbar_open:
251 gui_event::window_set_keyboard_target(
id, keyboard_focus_group::toolbar, keyboard_focus_direction::forward));
256 bool process_event(gui_event
const& event)
const noexcept override
259 return _window->process_event(event);
265 void set_window(gui_window *window)
noexcept override
269 _window->set_title(*title);
272 [[nodiscard]] gui_window *
window() const noexcept
override
278 gui_window *_window =
nullptr;
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;