31 constexpr static auto prefix = Name /
"window";
33 observer<label> title;
37 _toolbar = std::make_unique<toolbar_widget<prefix>>(
this);
39 if (operating_system::current == operating_system::windows) {
40#if HI_OPERATING_SYSTEM == HI_OS_WINDOWS
42 this->_system_menu->icon = this->title.get<
"icon">();
45 }
else if (operating_system::current == operating_system::macos) {
51 _content = std::make_unique<grid_widget<prefix>>(
this);
54 void set_window(gui_window& window)
noexcept
82 [[nodiscard]] generator<widget const&> children(
bool include_invisible)
const noexcept override
93 _content_constraints = _content->update_constraints();
94 _toolbar_constraints = _toolbar->update_constraints();
98 _toolbar_constraints.margins.left() + _toolbar_constraints.minimum.
width() + _toolbar_constraints.margins.right(),
99 _content_constraints.margins.left() + _content_constraints.minimum.
width() + _content_constraints.margins.right());
101 _toolbar_constraints.margins.left() + _toolbar_constraints.preferred.
width() + _toolbar_constraints.margins.right(),
102 _content_constraints.margins.left() + _content_constraints.preferred.
width() + _content_constraints.margins.right());
104 _toolbar_constraints.margins.left() + _toolbar_constraints.maximum.
width() + _toolbar_constraints.margins.right(),
105 _content_constraints.margins.left() + _content_constraints.maximum.
width() + _content_constraints.margins.right());
109 _toolbar_constraints.margins.top() +
110 _toolbar_constraints.preferred.
height() +
111 std::max(_toolbar_constraints.margins.bottom(), _content_constraints.margins.top()) +
112 _content_constraints.minimum.
height() +
113 _content_constraints.margins.bottom();
114 r.preferred.height() =
115 _toolbar_constraints.margins.top() +
116 _toolbar_constraints.preferred.
height() +
117 std::max(_toolbar_constraints.margins.bottom(), _content_constraints.margins.top()) +
118 _content_constraints.preferred.
height() +
119 _content_constraints.margins.bottom();
121 _toolbar_constraints.margins.top() +
122 _toolbar_constraints.preferred.
height() +
123 std::max(_toolbar_constraints.margins.bottom(), _content_constraints.margins.top()) +
124 _content_constraints.maximum.
height() +
125 _content_constraints.margins.bottom();
130 inplace_max(r.minimum.width(), os_settings::minimum_window_width());
131 inplace_max(r.minimum.height(), os_settings::minimum_window_height());
133 inplace_clamp(r.maximum.width(), r.minimum.width(), os_settings::maximum_window_width());
134 inplace_clamp(r.maximum.height(), r.minimum.height(), os_settings::maximum_window_height());
136 inplace_clamp(r.preferred.width(), r.minimum.width(), r.maximum.width());
137 inplace_clamp(r.preferred.height(), r.minimum.height(), r.maximum.height());
139 _can_resize_width = r.minimum.width() != r.maximum.width();
140 _can_resize_height = r.minimum.height() != r.maximum.height();
145 void set_layout(widget_layout
const& context)
noexcept override
148 hilet toolbar_height = _toolbar_constraints.preferred.
height();
149 hilet between_margin =
std::max(_toolbar_constraints.margins.bottom(), _content_constraints.margins.top());
151 hilet toolbar_rectangle = aarectangle{
153 _toolbar_constraints.margins.left(), context.height() - toolbar_height - _toolbar_constraints.margins.top()},
155 context.width() - _toolbar_constraints.margins.right(),
156 context.height() - _toolbar_constraints.margins.top()}};
157 _toolbar_shape = box_shape{_toolbar_constraints, toolbar_rectangle, theme<prefix>.cap_height(
this)};
159 hilet content_rectangle = aarectangle{
160 point2{_content_constraints.margins.left(), _content_constraints.margins.bottom()},
161 point2{context.width() - _content_constraints.margins.right(), toolbar_rectangle.bottom() - between_margin}};
162 _content_shape = box_shape{_content_constraints, content_rectangle, theme<prefix>.cap_height(
this)};
164 _toolbar->set_layout(context.transform(_toolbar_shape));
165 _content->set_layout(context.transform(_content_shape));
168 void draw(widget_draw_context& context)
noexcept override
173 layout.shape.rectangle,
174 theme<prefix>.background_color(
this),
175 theme<prefix>.border_color(
this),
176 theme<prefix>.border_width(
this),
178 theme<prefix>.border_radius(
this)
181 _toolbar->draw(context);
182 _content->draw(context);
186 [[nodiscard]] hitbox hitbox_test(point2 position)
const noexcept override
188 constexpr float BORDER_WIDTH = 10.0f;
192 auto r = _toolbar->hitbox_test_from_parent(position);
193 r = _content->hitbox_test_from_parent(position, r);
195 hilet is_on_l_edge = position.x() <= BORDER_WIDTH;
196 hilet is_on_r_edge = position.x() >= (layout.width() - BORDER_WIDTH);
197 hilet is_on_b_edge = position.y() <= BORDER_WIDTH;
198 hilet is_on_t_edge = position.y() >= (layout.height() - BORDER_WIDTH);
201 if (is_on_l_edge and is_on_b_edge) {
202 if (_can_resize_width and _can_resize_height) {
203 return {
id, layout.elevation, hitbox_type::bottom_left_resize_corner};
204 }
else if (_can_resize_width) {
205 return {
id, layout.elevation, hitbox_type::left_resize_border};
206 }
else if (_can_resize_height) {
207 return {
id, layout.elevation, hitbox_type::bottom_resize_border};
209 }
else if (is_on_r_edge and is_on_b_edge) {
210 if (_can_resize_width and _can_resize_height) {
211 return {
id, layout.elevation, hitbox_type::bottom_right_resize_corner};
212 }
else if (_can_resize_width) {
213 return {
id, layout.elevation, hitbox_type::right_resize_border};
214 }
else if (_can_resize_height) {
215 return {
id, layout.elevation, hitbox_type::bottom_resize_border};
217 }
else if (is_on_l_edge and is_on_t_edge) {
218 if (_can_resize_width and _can_resize_height) {
219 return {
id, layout.elevation, hitbox_type::top_left_resize_corner};
220 }
else if (_can_resize_width) {
221 return {
id, layout.elevation, hitbox_type::left_resize_border};
222 }
else if (_can_resize_height) {
223 return {
id, layout.elevation, hitbox_type::top_resize_border};
225 }
else if (is_on_r_edge and is_on_t_edge) {
226 if (_can_resize_width and _can_resize_height) {
227 return {
id, layout.elevation, hitbox_type::top_right_resize_corner};
228 }
else if (_can_resize_width) {
229 return {
id, layout.elevation, hitbox_type::right_resize_border};
230 }
else if (_can_resize_height) {
231 return {
id, layout.elevation, hitbox_type::top_resize_border};
236 if (r.type != hitbox_type::scroll_bar) {
237 if (is_on_l_edge and _can_resize_width) {
238 return {
id, layout.elevation, hitbox_type::left_resize_border};
239 }
else if (is_on_r_edge and _can_resize_width) {
240 return {
id, layout.elevation, hitbox_type::right_resize_border};
241 }
else if (is_on_b_edge and _can_resize_height) {
242 return {
id, layout.elevation, hitbox_type::bottom_resize_border};
243 }
else if (is_on_t_edge and _can_resize_height) {
244 return {
id, layout.elevation, hitbox_type::top_resize_border};
251 bool handle_event(gui_event
const& event)
noexcept override
255 switch (event.type()) {
256 case gui_toolbar_open:
258 gui_event::window_set_keyboard_target(
id, keyboard_focus_group::toolbar, keyboard_focus_direction::forward));
264 bool process_event(gui_event
const& event)
const noexcept override
266 if (_window ==
nullptr) {
273 if (not _events_before_window.
empty()) {
274 for (
hilet& e : _events_before_window) {
275 _window->process_event(e);
277 _events_before_window.
clear();
280 return _window->process_event(event);
287 gui_window *_window =
nullptr;
292 box_constraints _content_constraints;
293 box_shape _content_shape;
296 box_constraints _toolbar_constraints;
297 box_shape _toolbar_shape;
299 mutable bool _can_resize_width;
300 mutable bool _can_resize_height;
302#if HI_OPERATING_SYSTEM == HI_OS_WINDOWS
303 system_menu_widget<prefix> *_system_menu =
nullptr;