26 constexpr static auto prefix = Name /
"aperture";
28 observer<int> content_width;
29 observer<int> content_height;
30 observer<int> aperture_width;
31 observer<int> aperture_height;
32 observer<int> offset_x;
33 observer<int> offset_y;
43 _content_width_cbt = content_width.subscribe([&](
auto...) {
44 ++global_counter<
"scroll_aperture_widget:content_width:relayout">;
47 _content_height_cbt = content_height.subscribe([&](
auto...) {
48 ++global_counter<
"scroll_aperture_widget:content_height:relayout">;
51 _aperture_width_cbt = aperture_width.subscribe([&](
auto...) {
52 ++global_counter<
"scroll_aperture_widget:aperture_width:relayout">;
55 _aperture_height_cbt = aperture_height.subscribe([&](
auto...) {
56 ++global_counter<
"scroll_aperture_widget:aperture_height:relayout">;
59 _offset_x_cbt = offset_x.subscribe([&](
auto...) {
60 ++global_counter<
"scroll_aperture_widget:offset_x:relayout">;
63 _offset_y_cbt = offset_y.subscribe([&](
auto...) {
64 ++global_counter<
"scroll_aperture_widget:offset_y:relayout">;
67 _minimum_cbt =
minimum.subscribe([&](
auto...) {
68 ++global_counter<
"scroll_aperture_widget:minimum:reconstrain">;
73 template<
typename Widget,
typename... Args>
74 Widget& make_widget(Args&&...args)
noexcept
79 auto tmp = std::make_unique<Widget>(
this, std::forward<Args>(args)...);
85 [[nodiscard]]
bool x_axis_scrolls()
const noexcept
87 return *content_width > *aperture_width;
90 [[nodiscard]]
bool y_axis_scrolls()
const noexcept
92 return *content_height > *aperture_height;
96 [[nodiscard]] generator<widget const&> children(
bool include_invisible)
const noexcept override
103 _content_constraints = _content->update_constraints();
106 auto aperture_constraints = _content_constraints;
107 aperture_constraints.minimum =
extent2i{0, 0};
109 return aperture_constraints.internalize_margins().constrain(*
minimum, *
maximum);
112 void set_layout(
widget_layout const& context)
noexcept override
115 aperture_width = context.width() - _content_constraints.margins.left() - _content_constraints.margins.right();
116 aperture_height = context.height() - _content_constraints.margins.bottom() - _content_constraints.margins.top();
120 content_width = *aperture_width < _content_constraints.preferred.
width() ? _content_constraints.preferred.
width() :
122 content_height = *aperture_height < _content_constraints.preferred.
height() ?
123 _content_constraints.preferred.
height() :
128 hilet offset_x_max =
std::max(*content_width - *aperture_width, 0);
129 hilet offset_y_max =
std::max(*content_height - *aperture_height, 0);
130 offset_x = std::clamp(*offset_x, 0, offset_x_max);
131 offset_y = std::clamp(*offset_y, 0, offset_y_max);
136 _content_constraints,
138 -*offset_x + _content_constraints.margins.left(),
139 -*offset_y + _content_constraints.margins.bottom(),
142 theme<prefix>.cap_height(
this)};
146 _content->set_layout(context.
transform(_content_shape, 1.0f, context.rectangle()));
152 _content->draw(context);
156 [[nodiscard]] hitbox hitbox_test(point2i position)
const noexcept override
161 auto r = _content->hitbox_test_from_parent(position);
173 bool handle_event(
gui_event const& event)
noexcept override
177 if (event == gui_event_type::mouse_wheel) {
180 hilet max_offset_x =
std::max(0, *content_width - *aperture_width);
181 hilet max_offset_y =
std::max(0, *content_height - *aperture_height);
183 offset_x = std::clamp(new_offset_x, 0, max_offset_x);
184 offset_y = std::clamp(new_offset_y, 0, max_offset_y);
185 ++global_counter<
"scroll_aperture_widget:mouse_wheel:relayout">;
201 theme<prefix>.margin_left(
this),
202 theme<prefix>.margin_right(
this),
203 theme<prefix>.margin_top(
this),
204 theme<prefix>.margin_bottom(
this));
205 if (safe_rectangle.width() > margin * 2 and safe_rectangle.height() > margin * 2) {
209 safe_rectangle = safe_rectangle - margin;
211 if (to_show.right() > safe_rectangle.right()) {
212 delta_x = to_show.right() - safe_rectangle.right();
213 }
else if (to_show.left() < safe_rectangle.left()) {
214 delta_x = to_show.left() - safe_rectangle.left();
217 if (to_show.top() > safe_rectangle.top()) {
218 delta_y = to_show.top() - safe_rectangle.top();
219 }
else if (to_show.bottom() < safe_rectangle.bottom()) {
220 delta_y = to_show.bottom() - safe_rectangle.bottom();
242 decltype(content_width)::callback_token _content_width_cbt;
243 decltype(content_height)::callback_token _content_height_cbt;
244 decltype(aperture_width)::callback_token _aperture_width_cbt;
245 decltype(aperture_height)::callback_token _aperture_height_cbt;
246 decltype(offset_x)::callback_token _offset_x_cbt;
247 decltype(offset_y)::callback_token _offset_y_cbt;
248 decltype(
minimum)::callback_token _minimum_cbt;