MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
Dropdown.cpp
Go to the documentation of this file.
1#include "Dropdown.hpp"
2
3#include "Entry.hpp"
4#include "Scrollable.hpp"
5
10
12
13namespace {
14
15 std::string header_label(std::string_view label, bool open)
16 {
17 return std::string(open ? "^ " : "v ") + std::string(label);
18 }
19
20}
21
23 Surface& surface,
24 LayoutCursor& cursor,
25 float x_min, float x_max, float row_h)
26{
27 if (m_labels.empty()) {
29 "Dropdown::place: no options");
30 return *this;
31 }
32
33 auto& ctx = surface.ctx();
34 const auto layer_ptr = surface.layer_ptr();
35
36 const Kinesis::AABB2D advanced = cursor.advance(row_h);
37 const Kinesis::AABB2D header_rect {
38 .min = { x_min, advanced.min.y },
39 .max = { x_max, advanced.max.y },
40 };
41
42 const auto labels = std::make_shared<std::vector<std::string>>(m_labels);
43 const size_t initial = std::min(m_initial, labels->size() - 1);
44 const auto dims = std::make_shared<glm::uvec2>(
45 row_pixel_dims(surface.window(), x_min, x_max, row_h));
46
47 auto header = internal::add_text_row(surface, header_label(labels->at(initial), false), header_rect, *dims);
48 const uint32_t hid = header.first;
49 const auto& header_row = header.second;
50
51 auto selected_state = std::make_shared<MappedState<size_t>>();
52 selected_state->write(initial);
53 auto open_state = std::make_shared<MappedState<bool>>();
54 open_state->write(false);
55
56 auto refresh_header = [header_row, labels, selected_state, open_state, dims]() {
57 header_row->set_text(
58 internal::row_caption(header_label(labels->at(selected_state->value), open_state->value)),
60 };
61
62 auto set_open = [layer_ptr, hid, open_state, refresh_header](bool next) {
63 open_state->write(next);
64 for (const uint32_t rel_id : layer_ptr->related_ids(hid))
65 layer_ptr->set_visible(rel_id, next);
66 if (next)
67 layer_ptr->bring_to_front(hid);
68 refresh_header();
69 };
70
71 auto choose = [selected_state, set_open, callback = m_on_select](size_t index) {
72 selected_state->write(index);
73 set_open(false);
74 if (callback)
76 };
77
78 const auto count = static_cast<uint32_t>(labels->size());
79 const uint32_t visible = std::min(count, m_max_visible);
80 const float list_top = header_rect.min.y;
81
82 const auto text_batch = internal::atelier().create_buffer(
83 surface.render_config({ .additional_textures = { { "text", nullptr } } }));
84
85 std::optional<Scrollable> panel;
86 std::function<void(uint32_t, glm::vec2, double, double)> wheel;
87 if (count > visible) {
89 panel = make_scrollable(
90 std::move(panel_buf), surface,
91 { .min = { x_min, list_top - row_h * static_cast<float>(visible) }, .max = { x_max, list_top } },
92 glm::vec3(internal::row_idle_color()));
93 wheel = panel->wheel_handler(surface);
94 layer_ptr->relate(hid, panel->viewport_id);
95 }
96
97 const auto rows = std::make_shared<std::vector<std::shared_ptr<Element>>>();
98
99 for (uint32_t i = 0; i < count; ++i) {
100 const float top = list_top - row_h * static_cast<float>(i);
101 const Kinesis::AABB2D row_rect { .min = { x_min, top - row_h }, .max = { x_max, top } };
102
103 auto made = internal::add_text_row(surface, labels->at(i), row_rect, *dims, text_batch);
104 const uint32_t id = made.first;
105 const auto& row = made.second;
106 rows->push_back(row);
107
108 internal::hover_text_row(surface, id, row, labels->at(i), dims);
109 ctx.on_press(id, IO::MouseButtons::Left, [choose, i](uint32_t, glm::vec2) { choose(i); });
110
111 if (panel) {
112 ctx.on_scroll(id, wheel);
113 panel->track(
114 *layer_ptr, id, row_rect,
115 [row](Kinesis::AABB2D shifted) { row->retarget(shifted); },
116 row->buffer);
117 } else {
118 layer_ptr->relate(hid, id);
119 }
120 }
121
122 ctx.on_press(hid, IO::MouseButtons::Left,
123 [open_state, set_open](uint32_t, glm::vec2) { set_open(!open_state->value); });
124
125 ctx.on_resize(hid,
126 [window = surface.window(), x_min, x_max, row_h, dims, labels, rows, refresh_header](uint32_t, uint32_t) {
127 *dims = row_pixel_dims(window, x_min, x_max, row_h);
128 refresh_header();
129 const auto idle = internal::row_press_params(*dims, internal::row_idle_color());
130 for (size_t i = 0; i < rows->size(); ++i)
131 rows->at(i)->set_text(internal::row_caption(labels->at(i)), idle);
132 });
133
134 set_open(false);
135
137 ElementRef { layer_ptr, hid }, selected_state, header_row->buffer.buffer());
138
139 header_id = hid;
140 selected = std::move(selected_state);
141 open = std::move(open_state);
142 header_bounds = header_rect;
143 cursor_out = cursor;
144 return *this;
145}
146
147Dropdown& Dropdown::place(
148 Surface& surface,
149 LayoutCursor& cursor,
150 float row_h)
151{
152 return place(surface, cursor, cursor.x_min(), cursor.x_max(), row_h);
153}
154
155} // namespace MayaFlux::Portal::Forma
#define MF_WARN(comp, ctx,...)
uint32_t label
Definition Contours.cpp:16
uint32_t rows
PickCallback callback
Definition Picker.cpp:22
std::weak_ptr< Core::Window > window
Definition Picker.cpp:23
uint32_t index
Definition VKDevice.cpp:122
size_t count
void register_element(const ElementRef &ref, std::shared_ptr< MappedState< T > > state, std::shared_ptr< Buffers::FormaBuffer > buffer, std::function< float(T)> project={})
Register a MappedState<T> so that MappedState overloads and outbound bindings can resolve to the corr...
Definition Bridge.hpp:378
static FormaTarget slice_of(const std::shared_ptr< Buffers::FormaBuffer > &buffer, std::optional< Graphics::PrimitiveTopology > topology=std::nullopt)
A new empty slice of buffer, drawn after the others.
Definition Target.cpp:19
Kinesis::AABB2D advance(float height)
Advance the cursor downward by height and return the NDC AABB occupied by the primitive just placed,...
Reactive Y-position accumulator for vertical primitive stacking.
const std::shared_ptr< Layer > & layer_ptr() const noexcept
Shared handles for callers that need to keep components alive independently of the Surface (backgroun...
Definition Surface.hpp:188
Portal::Graphics::RenderConfig render_config(Portal::Graphics::RenderConfig base={}) const
base targeting this Surface's window.
Definition Surface.hpp:227
const std::shared_ptr< Core::Window > & window() const noexcept
Access the rendering target window.
Definition Surface.hpp:178
Context & ctx() noexcept
Access the event router.
Definition Surface.hpp:170
Named owner of a (Window, Layer, Context) triple: the Forma canvas.
Definition Surface.hpp:121
std::shared_ptr< Buffers::FormaBuffer > create_buffer(Graphics::RenderConfig render)
The single buffer construction path.
Definition Atelier.cpp:117
Bridge & bridge()
Bridge instance constructed during initialize.
Definition Atelier.cpp:80
@ API
API calls from external code.
@ Portal
High-level user-facing API layer.
void open(std::span< const float > mask, std::span< float > tmp, std::span< float > dst, uint32_t w, uint32_t h, uint32_t radius)
Morphological opening writing into dst.
Text::PressParams row_press_params(glm::uvec2 dims, glm::vec4 background)
White text over background, laid out at dims pixels.
Definition TextRow.cpp:18
std::pair< uint32_t, std::shared_ptr< Element > > add_text_row(Surface &surface, std::string_view label, Kinesis::AABB2D bounds, glm::uvec2 dims, const std::shared_ptr< Buffers::FormaBuffer > &batch)
Register a clickable text row on surface.
Definition TextRow.cpp:28
Atelier & atelier()
Accessor for the process-wide Atelier.
Definition Atelier.hpp:304
void hover_text_row(Surface &surface, uint32_t id, const std::shared_ptr< Element > &row, std::string_view label, const std::shared_ptr< glm::uvec2 > &dims)
Highlight a row's background while the cursor is over it.
Definition TextRow.cpp:49
std::string row_caption(std::string_view label)
Caption drawn for a row labelled label.
Definition TextRow.cpp:13
std::pair< std::weak_ptr< Layer >, uint32_t > ElementRef
Layer-scoped element identity.
Definition Bridge.hpp:34
Scrollable make_scrollable(FormaTarget buf, Surface &surface, Kinesis::AABB2D viewport, glm::vec3 background_color, float wheel_speed)
Construct a scrollable viewport.
glm::uvec2 row_pixel_dims(const std::shared_ptr< Core::Window > &window, float x_min, float x_max, float row_h)
Convert an NDC row rect into integer pixel dimensions.
Definition Entry.cpp:12
Axis-aligned bounding rectangle in a 2D coordinate space.
Definition Bounds.hpp:63
MAYAFLUX_API Dropdown & place(Surface &surface, LayoutCursor &cursor, float x_min, float x_max, float row_h)
Register the header and its option rows and wire their input.
Definition Dropdown.cpp:22
std::function< void(size_t)> m_on_select
Called with the index each time a row is chosen.
Definition Dropdown.hpp:60
std::vector< std::string > m_labels
Option captions, in display order.
Definition Dropdown.hpp:51
uint32_t m_max_visible
Rows shown at once before the list scrolls. Default: 8.
Definition Dropdown.hpp:57
Dropdown & initial(size_t index)
Definition Dropdown.hpp:68
size_t m_initial
Index chosen before any interaction. Default: 0.
Definition Dropdown.hpp:54
A header showing the current choice that opens into a list of options.
Definition Dropdown.hpp:31
MAYAFLUX_API std::function< void(uint32_t, glm::vec2, double, double)> wheel_handler(Surface &surface) const
A self-contained wheel-scroll handler bound to this Scrollable's own state.