7#include "abstract_container_widget.hpp"
8#include "overlay_view_widget.hpp"
9#include "scroll_view_widget.hpp"
10#include "row_column_layout_widget.hpp"
11#include "menu_item_widget.hpp"
12#include "../stencils/label_stencil.hpp"
13#include "../GUI/draw_context.hpp"
14#include "../text/font_book.hpp"
15#include "../text/elusive_icon.hpp"
16#include "../observable.hpp"
36 template<
typename Value = value_type,
typename OptionList = option_list_type,
typename UnknownLabel = label>
40 Value &&value = value_type{},
42 UnknownLabel &&unknown_label =
label{
l10n(
"<unknown>")})
noexcept :
44 value(std::forward<Value>(value)),
45 option_list(std::forward<OptionList>(option_list)),
46 unknown_label(std::forward<UnknownLabel>(unknown_label))
52 void init() noexcept
override
54 _overlay_widget = super::make_widget<overlay_view_widget>();
60 _value_callback = this->value.subscribe([
this](
auto...) {
61 _request_reconstrain =
true;
63 _option_list_callback = this->option_list.subscribe([
this](
auto...) {
65 _request_reconstrain =
true;
67 _unknown_label_callback = this->unknown_label.subscribe([
this](
auto...) {
68 _request_reconstrain =
true;
79 ttlet index = get_value_as_index();
82 stencil::make_unique(alignment::middle_left, *unknown_label, theme::global->placeholderLabelStyle);
83 _text_stencil_color = theme::global->placeholderLabelStyle.color;
86 stencil::make_unique(alignment::middle_left, (*option_list)[index].second, theme::global->labelStyle);
87 _text_stencil_color = theme::global->labelStyle.color;
91 ttlet unknown_label_size =
92 stencil::make_unique(alignment::middle_left, *unknown_label, theme::global->placeholderLabelStyle)
95 ttlet overlay_width = _overlay_widget->preferred_size().minimum().width();
96 ttlet option_width =
std::max(overlay_width, unknown_label_size.width() + theme::global->margin * 2.0f);
97 ttlet option_height =
std::max(unknown_label_size.height(), _max_option_label_height) + theme::global->margin * 2.0f;
98 ttlet chevron_width = theme::global->smallSize;
100 _preferred_size = interval_vec2::make_minimum(
f32x4{chevron_width + option_width, option_height});
113 need_layout |= std::exchange(_request_relayout,
false);
123 ttlet overlay_width =
124 clamp(
rectangle().width() - theme::global->smallSize, _overlay_widget->preferred_size().width());
125 ttlet overlay_height = _overlay_widget->preferred_size().maximum().height();
126 ttlet overlay_x = _window_rectangle.x() + theme::global->smallSize;
127 ttlet overlay_y =
std::round(_window_rectangle.middle() - overlay_height * 0.5f);
128 ttlet overlay_rectangle =
aarect{overlay_x, overlay_y, overlay_width, overlay_height};
130 _overlay_widget->set_layout_parameters(overlay_rectangle, overlay_rectangle);
135 _left_box_rectangle =
aarect{0.0f, 0.0f, theme::global->smallSize,
rectangle().height()};
136 _chevrons_glyph = to_font_glyph_ids(elusive_icon::ChevronUp);
138 _chevrons_rectangle =
139 align(_left_box_rectangle, scale(chevrons_glyph_bbox, theme::global->small_icon_size), alignment::middle_center);
140 _chevrons_rectangle =
141 align(_left_box_rectangle, scale(chevrons_glyph_bbox, theme::global->small_icon_size), alignment::middle_center);
144 _option_rectangle =
aarect{
145 _left_box_rectangle.right() + theme::global->margin,
147 rectangle().width() - _left_box_rectangle.width() - theme::global->margin * 2.0f,
150 _text_stencil->set_layout_parameters(_option_rectangle,
base_line());
160 draw_outline(context);
161 draw_left_box(context);
162 draw_chevrons(context);
173 ttlet lock = std::scoped_lock(gui_system_mutex);
176 if (event.cause.leftButton) {
179 if (event.type == mouse_event::Type::ButtonUp && _window_rectangle.contains(event.position)) {
189 ttlet lock = std::scoped_lock(gui_system_mutex);
190 _request_relayout =
true;
194 using enum tt::command;
219 ttlet lock = std::scoped_lock(gui_system_mutex);
220 ttlet position = _from_window_transform * window_position;
229 r =
std::max(r,
hit_box{weak_from_this(), _draw_layer, *
enabled ? hit_box::Type::Button : hit_box::Type::Default});
238 return is_normal(group) && *
enabled;
243 keyboard_focus_group group,
244 keyboard_focus_direction direction)
const noexcept
246 ttlet lock = std::scoped_lock(gui_system_mutex);
257 template<
typename T,
typename... Args>
265 typename decltype(unknown_label)::callback_ptr_type _unknown_label_callback;
266 typename decltype(value)::callback_ptr_type _value_callback;
267 typename decltype(option_list)::callback_ptr_type _option_list_callback;
270 color _text_stencil_color;
272 float _max_option_label_height;
274 aarect _option_rectangle;
275 aarect _left_box_rectangle;
277 font_glyph_ids _chevrons_glyph;
278 aarect _chevrons_rectangle;
280 bool _selecting =
false;
288 [[nodiscard]] ssize_t get_value_as_index() const noexcept
291 for (ttlet & [ tag, unknown_label_text ] : *option_list) {
303 ttlet i = get_value_as_index();
304 if (i >= 0 && i < std::ssize(_menu_item_widgets)) {
305 return _menu_item_widgets[i];
311 void start_selecting() noexcept
314 if (
auto selected_menu_item = get_selected_menu_item()) {
319 void stop_selecting() noexcept
328 void repopulate_options() noexcept
330 ttlet
lock = std::scoped_lock(gui_system_mutex);
331 auto option_list_ = *option_list;
334 auto show_icon =
false;
335 for (ttlet & [ tag, label ] : option_list_) {
336 show_icon |= label.has_icon();
339 _column_widget->clear();
340 _menu_item_widgets.
clear();
341 _menu_item_callbacks.
clear();
342 for (ttlet & [ tag, text ] : option_list_) {
343 auto menu_item = _column_widget->make_widget<menu_item_widget<value_type>>(tag, this->value);
344 menu_item->set_show_check_mark(
true);
345 menu_item->set_show_icon(show_icon);
346 menu_item->label = text;
348 _menu_item_callbacks.
push_back(menu_item->subscribe([
this, tag] {
350 this->_selecting = false;
356 _max_option_label_height = 0.0f;
357 for (ttlet & [ tag, text ] : *option_list) {
358 _max_option_label_height =
std::max(
359 _max_option_label_height,
360 stencil::make_unique(alignment::middle_left, text, theme::global->labelStyle)->preferred_extent().height());
364 void draw_outline(draw_context context)
noexcept
368 context.corner_shapes = f32x4::broadcast(theme::global->roundingRadius);
369 context.draw_box_with_border_inside(
rectangle());
372 void draw_left_box(draw_context context)
noexcept
376 context.transform = translate3{0.0, 0.0, 0.1f} * context.transform;
378 context.line_color = theme::global->accentColor;
380 context.fill_color = context.line_color;
381 context.corner_shapes = f32x4{theme::global->roundingRadius, 0.0f, theme::global->roundingRadius, 0.0f};
382 context.draw_box_with_border_inside(_left_box_rectangle);
385 void draw_chevrons(draw_context context)
noexcept
389 context.transform = translate3{0.0, 0.0, 0.2f} * context.transform;
390 context.line_color = *
enabled ? theme::global->foregroundColor : context.fill_color;
391 context.draw_glyph(_chevrons_glyph, _chevrons_rectangle);
394 void draw_value(draw_context context)
noexcept
398 context.transform = translate3{0.0, 0.0, 0.1f} * context.transform;
399 context.line_color = *
enabled ? _text_stencil_color : context.line_color;
400 _text_stencil->draw(context,
true);
Definition alignment.hpp:104
Draw context for drawing using the TTauri shaders.
Definition draw_context.hpp:33
Definition gui_window.hpp:39
void update_keyboard_target(std::shared_ptr< tt::widget > widget, keyboard_focus_group group=keyboard_focus_group::normal) noexcept
Change the keyboard focus to the given widget.
void request_redraw(aarect rectangle=aarect::infinity()) noexcept
Request a rectangle on the window to be redrawn.
Definition gui_window.hpp:115
Definition hit_box.hpp:15
Definition mouse_event.hpp:13
static aarect getBoundingBox(font_glyph_ids const &glyphs) noexcept
Get the bounding box, including draw border of a glyph.
A localizable string.
Definition l10n.hpp:12
A localized text + icon label.
Definition label.hpp:76
Definition observable.hpp:20
int recurse_lock_count() const noexcept
This function should be used in tt_axiom() to check if the lock is held by current thread.
Definition unfair_recursive_mutex.hpp:60
Definition abstract_container_widget.hpp:11
void update_layout(hires_utc_clock::time_point display_time_point, bool need_layout) noexcept
Update the internal layout of the widget.
Definition abstract_container_widget.hpp:111
void draw(draw_context context, hires_utc_clock::time_point display_time_point) noexcept
Draw the widget.
Definition abstract_container_widget.hpp:125
std::shared_ptr< widget > find_next_widget(std::shared_ptr< widget > const ¤t_keyboard_widget, keyboard_focus_group group, keyboard_focus_direction direction) const noexcept
Find the next widget that handles keyboard focus.
Definition abstract_container_widget.hpp:185
hit_box hitbox_test(f32x4 window_position) const noexcept
Find the widget that is under the mouse cursor.
Definition abstract_container_widget.hpp:152
bool update_constraints(hires_utc_clock::time_point display_time_point, bool need_reconstrain) noexcept
Update the constraints of the widget.
Definition abstract_container_widget.hpp:96
Definition row_column_layout_widget.hpp:16
Definition scroll_view_widget.hpp:14
Definition selection_widget.hpp:26
std::shared_ptr< widget > find_next_widget(std::shared_ptr< widget > const ¤t_widget, keyboard_focus_group group, keyboard_focus_direction direction) const noexcept
Find the next widget that handles keyboard focus.
Definition selection_widget.hpp:241
bool accepts_keyboard_focus(keyboard_focus_group group) const noexcept override
Check if the widget will accept keyboard focus.
Definition selection_widget.hpp:235
void draw(draw_context context, hires_utc_clock::time_point display_time_point) noexcept override
Draw the widget.
Definition selection_widget.hpp:155
bool update_constraints(hires_utc_clock::time_point display_time_point, bool need_reconstrain) noexcept override
Update the constraints of the widget.
Definition selection_widget.hpp:72
bool handle_event(command command) noexcept override
Handle command.
Definition selection_widget.hpp:187
hit_box hitbox_test(f32x4 window_position) const noexcept override
Find the widget that is under the mouse cursor.
Definition selection_widget.hpp:217
bool handle_event(mouse_event const &event) noexcept override
Definition selection_widget.hpp:171
void update_layout(hires_utc_clock::time_point display_time_point, bool need_layout) noexcept override
Update the internal layout of the widget.
Definition selection_widget.hpp:109
void init() noexcept override
Should be called right after allocating and constructing a widget.
Definition selection_widget.hpp:52
observable< bool > enabled
The widget is enabled.
Definition widget.hpp:105
virtual std::shared_ptr< widget > find_next_widget(std::shared_ptr< widget > const ¤t_keyboard_widget, keyboard_focus_group group, keyboard_focus_direction direction) const noexcept
Find the next widget that handles keyboard focus.
virtual bool handle_event(command command) noexcept
Handle command.
gui_window & window
Convenient reference to the Window.
Definition widget.hpp:100
float base_line() const noexcept
Get the base-line in local coordinates.
Definition widget.hpp:350
abstract_container_widget const & parent() const noexcept
Get a reference to the parent.
virtual aarect window_clipping_rectangle() const noexcept
Get the clipping-rectangle in window coordinates.
Definition widget.hpp:320
aarect window_rectangle() const noexcept
Get the rectangle in window coordinates.
Definition widget.hpp:310
aarect rectangle() const noexcept
Get the rectangle in local coordinates.
Definition widget.hpp:340