HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
scroll_widget.hpp
Go to the documentation of this file.
1// Copyright Take Vos 2021-2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
9#pragma once
10
11#include "widget.hpp"
12#include "scroll_bar_widget.hpp"
14#include "../geometry/module.hpp"
15#include "../layout/module.hpp"
16#include "../macros.hpp"
17
18namespace hi { inline namespace v1 {
19
46template<axis Axis = axis::both>
47class scroll_widget final : public widget {
48public:
49 using super = widget;
50 using horizontal_scroll_bar_type = scroll_bar_widget<axis::horizontal>;
51 using vertical_scroll_bar_type = scroll_bar_widget<axis::vertical>;
52
53 constexpr static hi::axis axis = Axis;
54
56
62 {
63 hi_axiom(loop::main().on_thread());
64 hi_assert_not_null(parent);
65
66 // The scroll-widget will not draw itself, only its selected content.
67 semantic_layer = parent->semantic_layer;
68
69 auto aperture = std::make_unique<scroll_aperture_widget>(this);
70 auto horizontal_scroll_bar = std::make_unique<horizontal_scroll_bar_type>(
71 this, aperture->content_width, aperture->aperture_width, aperture->offset_x);
72 auto vertical_scroll_bar = std::make_unique<vertical_scroll_bar_type>(
73 this, aperture->content_height, aperture->aperture_height, aperture->offset_y);
74
75 if (to_bool(axis & axis::horizontal)) {
76 minimum.copy()->width() = 0;
77 } else {
79 }
80
81 if (to_bool(axis & axis::vertical)) {
82 minimum.copy()->height() = 0;
83 } else {
85 }
86
87 _aperture = aperture.get();
88 _horizontal_scroll_bar = horizontal_scroll_bar.get();
89 _vertical_scroll_bar = vertical_scroll_bar.get();
90
91 _grid.add_cell(0, 0, std::move(aperture));
92 _grid.add_cell(1, 0, std::move(vertical_scroll_bar));
93 _grid.add_cell(0, 1, std::move(horizontal_scroll_bar));
94 }
95
105 template<typename Widget, typename... Args>
106 Widget& make_widget(Args&&...args) noexcept
107 {
108 return _aperture->make_widget<Widget>(std::forward<Args>(args)...);
109 }
110
112 [[nodiscard]] generator<widget_intf &> children(bool include_invisible) noexcept override
113 {
114 co_yield *_aperture;
115 co_yield *_vertical_scroll_bar;
116 co_yield *_horizontal_scroll_bar;
117 }
118
119 [[nodiscard]] box_constraints update_constraints() noexcept override
120 {
121 _layout = {};
122
123 for (auto& cell : _grid) {
124 cell.set_constraints(cell.value->update_constraints());
125 }
126 auto grid_constraints = _grid.constraints(os_settings::left_to_right());
127 return grid_constraints.constrain(*minimum, *maximum);
128 }
129
130 void set_layout(widget_layout const& context) noexcept override
131 {
132 if (compare_store(_layout, context)) {
133 _grid.set_layout(context.shape, theme().baseline_adjustment());
134 }
135
136 for (hilet& cell : _grid) {
137 auto shape = cell.shape;
138
139 if (cell.value.get() == _aperture) {
140 // This is the content. Move the content slightly when the scroll-bars aren't visible.
141 // The grid cells are always ordered in row-major.
142 // This the vertical scroll bar is _grid[1] and the horizontal scroll bar is _grid[2].
143 if (not _vertical_scroll_bar->visible()) {
144 shape.rectangle = aarectangle{0, shape.y(), _layout.width(), shape.height()};
145 }
146 if (not _horizontal_scroll_bar->visible()) {
147 shape.rectangle = aarectangle{shape.x(), 0, shape.width(), _layout.height()};
148 }
149 }
150
151 cell.value->set_layout(context.transform(shape, 0.0f));
152 }
153 }
154
155 void draw(draw_context const& context) noexcept override
156 {
158 for (hilet& cell : _grid) {
159 cell.value->draw(context);
160 }
161 }
162 }
163
164 [[nodiscard]] hitbox hitbox_test(point2 position) const noexcept override
165 {
166 hi_axiom(loop::main().on_thread());
167
168 if (*mode >= widget_mode::partial) {
169 auto r = _aperture->hitbox_test_from_parent(position);
170 r = _horizontal_scroll_bar->hitbox_test_from_parent(position, r);
171 r = _vertical_scroll_bar->hitbox_test_from_parent(position, r);
172
173 if (layout().contains(position)) {
174 r = std::max(r, hitbox{id, _layout.elevation});
175 }
176 return r;
177
178 } else {
179 return {};
180 }
181 }
182 // @endprivatesection
183private:
185
186 scroll_aperture_widget *_aperture;
187 horizontal_scroll_bar_type *_horizontal_scroll_bar;
188 vertical_scroll_bar_type *_vertical_scroll_bar;
189};
190
199
208
209}} // namespace hi::v1
Defines widget.
Defines scroll_bar_widget.
Defines scroll_aperture_widget.
axis
An enumeration of the 3 axis for 3D geometry.
Definition axis.hpp:19
@ partial
A widget is partially enabled.
@ collapse
The widget is collapsed.
@ invisible
The widget is invisible.
DOXYGEN BUG.
Definition algorithm.hpp:16
geometry/margins.hpp
Definition lookahead_iterator.hpp:5
bool compare_store(T &lhs, U &&rhs) noexcept
Compare then store if there was a change.
Definition misc.hpp:56
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:377
widget_id id
The numeric identifier of a widget.
Definition widget_intf.hpp:23
widget_intf * parent
Pointer to the parent widget.
Definition widget_intf.hpp:28
2D constraints.
Definition box_constraints.hpp:25
Scroll bar widget This widget is used in a pair of a vertical and horizontal scrollbar as a child of ...
Definition scroll_bar_widget.hpp:37
The scroll widget allows a content widget to be shown in less space than is required.
Definition scroll_widget.hpp:47
Widget & make_widget(Args &&...args) noexcept
Add a content widget directly to this scroll widget.
Definition scroll_widget.hpp:106
scroll_widget(widget *parent) noexcept
Constructs an empty scroll widget.
Definition scroll_widget.hpp:61
An interactive graphical object as part of the user-interface.
Definition widget.hpp:37
widget_layout const & layout() const noexcept override
Get the current layout for this widget.
Definition widget.hpp:169
int semantic_layer
The draw layer of the widget.
Definition widget.hpp:66
observer< extent2 > minimum
The minimum size this widget is allowed to be.
Definition widget.hpp:79
widget(widget *parent) noexcept
Definition widget.hpp:87
virtual hitbox hitbox_test_from_parent(point2 position) const noexcept
Call hitbox_test from a parent widget.
Definition widget.hpp:132
observer< widget_mode > mode
The widget mode.
Definition widget.hpp:42
observer< extent2 > maximum
The maximum size this widget is allowed to be.
Definition widget.hpp:83
T max(T... args)
T move(T... args)