24 hi_axiom(is_gui_thread());
31 _content_width_cbt = content_width.subscribe([&](
auto...){ request_relayout(); });
32 _content_height_cbt = content_height.subscribe([&](
auto...){ request_relayout(); });
33 _aperture_width_cbt = aperture_width.subscribe([&](
auto...){ request_relayout(); });
34 _aperture_height_cbt = aperture_height.subscribe([&](
auto...){ request_relayout(); });
35 _offset_x_cbt = offset_x.subscribe([&](
auto...){ request_relayout(); });
36 _offset_y_cbt = offset_y.subscribe([&](
auto...){ request_relayout(); });
40 template<
typename Widget,
typename... Args>
41 Widget &make_widget(Args &&...args)
noexcept
43 hi_axiom(is_gui_thread());
44 hi_axiom(not _content);
46 auto tmp = std::make_unique<Widget>(window,
this, std::forward<Args>(args)...);
52 [[nodiscard]]
bool x_axis_scrolls()
const noexcept
54 return *content_width > *aperture_width;
57 [[nodiscard]]
bool y_axis_scrolls()
const noexcept
59 return *content_height > *aperture_height;
65 co_yield _content.get();
73 hilet content_constraints = _content->set_constraints();
76 content_constraints.margins.left() + content_constraints.minimum.
width() + content_constraints.margins.right(),
77 content_constraints.margins.top() + content_constraints.minimum.height() + content_constraints.margins.bottom()};
79 content_constraints.margins.left() + content_constraints.preferred.
width() + content_constraints.margins.right(),
80 content_constraints.margins.top() + content_constraints.preferred.height() + content_constraints.margins.bottom()};
82 content_constraints.margins.left() + content_constraints.maximum.
width() + content_constraints.margins.right(),
83 content_constraints.margins.top() + content_constraints.maximum.height() + content_constraints.margins.bottom()};
85 return _constraints = {minimum_size, preferred_size, maximum_size,
margins{}};
88 void set_layout(
widget_layout const &layout)
noexcept override
90 hilet content_constraints = _content->constraints();
93 if (compare_store(_layout, layout)) {
94 hilet preferred_size = content_constraints.preferred;
96 aperture_width = layout.width() -
margins.left() -
margins.right();
97 aperture_height = layout.height() -
margins.bottom() -
margins.top();
101 content_width = *aperture_width < preferred_size.width() ? preferred_size.width() : *aperture_width;
102 content_height = *aperture_height < preferred_size.height() ? preferred_size.height() : *aperture_height;
106 hilet offset_x_max =
std::max(*content_width - *aperture_width, 0.0f);
107 hilet offset_y_max =
std::max(*content_height - *aperture_height, 0.0f);
108 offset_x = std::clamp(
std::round(*offset_x), 0.0f, offset_x_max);
109 offset_y = std::clamp(
std::round(*offset_y), 0.0f, offset_y_max);
113 _content_rectangle = {
114 -*offset_x +
margins.left(), -*offset_y +
margins.bottom(), *content_width, *content_height};
118 _content->set_layout(layout.
transform(_content_rectangle, 1.0f, layout.rectangle()));
124 _content->draw(context);
128 [[nodiscard]]
hitbox hitbox_test(
point3 position)
const noexcept override
130 hi_axiom(is_gui_thread());
132 if (*visible and *enabled) {
133 auto r = _content->hitbox_test_from_parent(position);
135 if (layout().contains(position)) {
145 bool handle_event(
mouse_event const &event)
noexcept override
147 hi_axiom(is_gui_thread());
148 auto handled = super::handle_event(event);
150 if (event.type == mouse_event::Type::Wheel) {
154 hilet max_offset_x =
std::max(0.0f, *content_width - *aperture_width);
155 hilet max_offset_y =
std::max(0.0f, *content_height - *aperture_height);
157 offset_x = std::clamp(new_offset_x, 0.0f, max_offset_x);
158 offset_y = std::clamp(new_offset_y, 0.0f, max_offset_y);
165 void scroll_to_show(hi::aarectangle to_show)
noexcept override
167 auto safe_rectangle = intersect(_layout.rectangle(), _layout.clipping_rectangle);
168 float delta_x = 0.0f;
169 float delta_y = 0.0f;
171 if (safe_rectangle.width() >
theme().margin and safe_rectangle.height() >
theme().margin) {
177 if (to_show.right() > safe_rectangle.right()) {
178 delta_x = to_show.right() - safe_rectangle.right();
179 }
else if (to_show.left() < safe_rectangle.left()) {
180 delta_x = to_show.left() - safe_rectangle.left();
183 if (to_show.top() > safe_rectangle.top()) {
184 delta_y = to_show.top() - safe_rectangle.top();
185 }
else if (to_show.bottom() < safe_rectangle.bottom()) {
186 delta_y = to_show.bottom() - safe_rectangle.bottom();
203 decltype(content_width)::token_type _content_width_cbt;
204 decltype(content_height)::token_type _content_height_cbt;
205 decltype(aperture_width)::token_type _aperture_width_cbt;
206 decltype(aperture_height)::token_type _aperture_height_cbt;
207 decltype(offset_x)::token_type _offset_x_cbt;
208 decltype(offset_y)::token_type _offset_y_cbt;