40 using button_widget_type = ButtonWidget;
41 using button_attributes_type = button_widget_type::attributes_type;
42 using delegate_type = button_widget_type::delegate_type;
69 set_attributes<0>(std::forward<Attributes>(attributes)...);
73 void set_attributes() noexcept
78 void set_attributes(First&& first, Rest&&...rest)
noexcept
81 if constexpr (I == 0) {
82 label = std::forward<First>(first);
83 }
else if constexpr (I == 1) {
84 shortcut = std::forward<First>(first);
86 hi_static_no_default();
88 set_attributes<I + 1>(std::forward<Rest>(rest)...);
90 }
else if constexpr (forward_of<First, observer<hi::alignment>>) {
92 set_attributes<I>(std::forward<Rest>(rest)...);
94 }
else if constexpr (forward_of<First, observer<hi::semantic_text_style>>) {
96 set_attributes<I>(std::forward<Rest>(rest)...);
99 hi_static_no_default();
104 attributes_type attributes;
106 template<
typename... Args>
107 [[nodiscard]]
consteval static size_t num_default_delegate_arguments() noexcept
109 return button_widget_type::template num_default_delegate_arguments<Args...>();
112 template<
size_t N,
typename... Args>
113 [[nodiscard]]
static auto make_default_delegate(Args&&...args)
115 return button_widget_type::template make_default_delegate<N, Args...>(std::forward<Args>(args)...);
118 hi_call_right_arguments(
static, make_attributes, attributes_type);
122 widget_intf
const*
parent,
123 attributes_type attributes,
127 _button_widget = std::make_unique<button_widget_type>(
128 this, button_attributes_type{this->attributes.alignment, keyboard_focus_group::menu},
std::move(delegate));
130 std::make_unique<label_widget>(
this, this->attributes.label, this->attributes.alignment, this->attributes.text_style);
131 _shortcut_widget = std::make_unique<label_widget>(
132 this, this->attributes.shortcut, this->attributes.alignment, this->attributes.text_style);
135 _button_widget->state =
state;
137 _button_widget_cbt = _button_widget->subscribe([&] {
142 _button_widget_cbt();
151 template<
typename... Args>
153 requires(num_default_delegate_arguments<Args...>() != 0)
157 make_attributes<num_default_delegate_arguments<Args...>()>(std::forward<Args>(args)...),
158 make_default_delegate<num_default_delegate_arguments<Args...>()>(std::forward<Args>(args)...))
168 _grid.
add_cell(0, 0, grid_cell_type::button);
169 _grid.
add_cell(1, 0, grid_cell_type::label,
true);
170 _grid.
add_cell(2, 0, grid_cell_type::shortcut);
172 for (
auto& cell : _grid) {
173 if (cell.value == grid_cell_type::button) {
174 auto constraints = _button_widget->update_constraints();
175 inplace_max(constraints.minimum.width(), theme().size() * 2.0f);
176 inplace_max(constraints.preferred.width(), theme().size() * 2.0f);
177 inplace_max(constraints.maximum.width(), theme().size() * 2.0f);
178 cell.set_constraints(constraints);
180 }
else if (cell.value == grid_cell_type::label) {
181 cell.set_constraints(_label_widget->update_constraints());
183 }
else if (cell.value == grid_cell_type::shortcut) {
184 auto constraints = _shortcut_widget->update_constraints();
185 inplace_max(constraints.minimum.width(), theme().size() * 3.0f);
186 inplace_max(constraints.preferred.width(), theme().size() * 3.0f);
187 inplace_max(constraints.maximum.width(), theme().size() * 3.0f);
188 cell.set_constraints(constraints);
195 auto constraints = _grid.constraints(os_settings::left_to_right());
196 constraints.minimum += extent2{theme().template margin<float>() * 2.0f, theme().template margin<float>() * 2.0f};
197 constraints.preferred += extent2{theme().template margin<float>() * 2.0f, theme().template margin<float>() * 2.0f};
198 constraints.maximum += extent2{theme().template margin<float>() * 2.0f, theme().template margin<float>() * 2.0f};
199 constraints.margins = {};
203 void set_layout(widget_layout
const& context)
noexcept override
206 auto shape = context.shape;
207 shape.rectangle -= theme().template margin<float>();
208 _grid.
set_layout(shape, theme().baseline_adjustment());
211 for (
auto const& cell : _grid) {
212 if (cell.value == grid_cell_type::button) {
215 }
else if (cell.value == grid_cell_type::label) {
216 _label_widget->set_layout(context.transform(cell.shape));
218 }
else if (cell.value == grid_cell_type::shortcut) {
219 _shortcut_widget->set_layout(context.transform(cell.shape));
227 void draw(draw_context
const& context)
noexcept override
230 auto outline_color = focus() ? focus_color() : background_color();
234 for (
auto const& cell : _grid) {
235 if (cell.value == grid_cell_type::button) {
236 _button_widget->draw(context);
238 }
else if (cell.value == grid_cell_type::label) {
239 _label_widget->draw(context);
241 }
else if (cell.value == grid_cell_type::shortcut) {
242 _shortcut_widget->draw(context);
251 [[nodiscard]] generator<widget_intf&> children(
bool include_invisible)
noexcept override
253 co_yield *_button_widget;
254 co_yield *_label_widget;
255 co_yield *_shortcut_widget;
258 [[nodiscard]] hitbox hitbox_test(point2 position)
const noexcept override
260 hi_axiom(loop::main().on_thread());
264 return {_button_widget->id, _layout.elevation, hitbox_type::button};
271 enum class grid_cell_type { button, label, shortcut };
273 grid_layout<grid_cell_type> _grid;
280 callback<void()> _button_widget_cbt;