MayaFlux 1.0.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
Picker.cpp
Go to the documentation of this file.
1#include "Picker.hpp"
2
5
11
13
14namespace {
15
16 constexpr uint32_t k_max_visible_rows = 10;
17 constexpr uint32_t k_width_px = 520;
18 constexpr uint32_t k_min_row_px = 48;
19 constexpr uint32_t k_row_padding_px = 16;
20
21 struct PickerState {
23 std::weak_ptr<Core::Window> window;
24 bool done {};
25
26 void finish(std::optional<size_t> index)
27 {
28 if (done) {
29 return;
30 }
31 done = true;
32
33 if (index) {
34 if (auto w = window.lock()) {
35 w->request_close();
36 }
37 }
38 if (callback) {
40 }
41 }
42 };
43
44} // namespace
45
46void pick(
47 std::string title,
48 std::vector<std::string> labels,
50{
51 if (labels.empty()) {
53 "Forma::pick: empty list");
54 if (callback) {
55 callback(std::nullopt);
56 }
57 return;
58 }
59
60 uint32_t row_px = k_min_row_px;
61 if (auto atlas = Text::TypeFaceFoundry::instance().get_default_glyph_atlas()) {
62 row_px = std::max(row_px, static_cast<uint32_t>(atlas->pixel_size()) + k_row_padding_px);
63 }
64
65 const auto rows = static_cast<uint32_t>(labels.size());
66 const uint32_t visible = std::min(rows, k_max_visible_rows);
67 const bool scrolling = rows > visible;
68 const uint32_t window_h = row_px * visible + (scrolling ? row_px / 2 : 0);
69
70 auto& atelier = internal::atelier();
71
73 .title = std::move(title),
74 .width = k_width_px,
75 .height = window_h,
76 .resizable = false,
77 });
78
79 auto state = std::make_shared<PickerState>();
80 state->callback = std::move(callback);
81 state->window = window;
82
83 Surface surface = atelier.create_surface(SurfaceConfig {
84 .window = window,
85 .name = window->get_create_info().title,
86 .on_close = [state] { state->finish(std::nullopt); },
87 });
88
89 const auto text_batch = atelier.create_buffer(
90 surface.render_config({ .additional_textures = { { "text", nullptr } } }));
91
92 std::optional<Scrollable> panel;
93 std::function<void(uint32_t, glm::vec2, double, double)> wheel;
94 if (scrolling) {
96 panel = make_scrollable(std::move(panel_buf), surface, surface.full(), glm::vec3(internal::row_idle_color()));
97 wheel = panel->wheel_handler(surface);
98 }
99
100 const auto row_dims = std::make_shared<glm::uvec2>(k_width_px, row_px);
101
102 const float row_h = 2.F * static_cast<float>(row_px) / static_cast<float>(window_h);
103 const float gap = 2.F / static_cast<float>(window_h);
104
105 for (uint32_t i = 0; i < rows; ++i) {
106 const float top = 1.F - row_h * static_cast<float>(i);
107 const Kinesis::AABB2D bounds {
108 .min = { -1.F, top - row_h + gap },
109 .max = { 1.F, top - gap },
110 };
111
112 auto made = internal::add_text_row(surface, labels.at(i), bounds, *row_dims, text_batch);
113 const uint32_t id = made.first;
114 const auto& row = made.second;
115
116 internal::hover_text_row(surface, id, row, labels.at(i), row_dims);
117 surface.ctx().on_press(id, IO::MouseButtons::Left, [state, i](uint32_t, glm::vec2) {
118 state->finish(i);
119 });
120
121 if (panel) {
122 surface.ctx().on_scroll(id, wheel);
123 panel->track(
124 surface.layer(), id, bounds,
125 [row](Kinesis::AABB2D shifted) { row->retarget(shifted); },
126 row->buffer);
127 }
128 }
129}
130
131} // namespace MayaFlux::Portal::Forma
#define MF_WARN(comp, ctx,...)
uint32_t rows
bool done
Definition Picker.cpp:24
PickCallback callback
Definition Picker.cpp:22
std::weak_ptr< Core::Window > window
Definition Picker.cpp:23
uint32_t index
Definition VKDevice.cpp:122
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
Portal::Graphics::RenderConfig render_config(Portal::Graphics::RenderConfig base={}) const
base targeting this Surface's window.
Definition Surface.hpp:227
Named owner of a (Window, Layer, Context) triple: the Forma canvas.
Definition Surface.hpp:121
Surface create_surface(SurfaceConfig config)
Build a Surface from a SurfaceConfig, creating Layer and Context when config.layer/config....
Definition Atelier.cpp:160
std::shared_ptr< Core::Window > create_window(const Core::WindowCreateInfo &info)
Create a window through the stored WindowManager and show it.
Definition Atelier.cpp:104
std::shared_ptr< Buffers::FormaBuffer > create_buffer(Graphics::RenderConfig render)
The single buffer construction path.
Definition Atelier.cpp:117
@ API
API calls from external code.
@ Portal
High-level user-facing API layer.
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::function< void(std::optional< size_t >)> PickCallback
Receives the chosen index, or nullopt when the window was closed without a choice.
Definition Picker.hpp:8
Scrollable make_scrollable(FormaTarget buf, Surface &surface, Kinesis::AABB2D viewport, glm::vec3 background_color, float wheel_speed)
Construct a scrollable viewport.
void pick(std::string title, std::vector< std::string > labels, PickCallback callback)
Open a window of clickable rows, one per label, and report the choice.
Definition Picker.cpp:46
std::string title
Window title/identifier.
Configuration for creating a single window instance.
Axis-aligned bounding rectangle in a 2D coordinate space.
Definition Bounds.hpp:63
std::shared_ptr< Core::Window > window
Target window. Must outlive the Surface.
Definition Surface.hpp:28
The single argument every Surface-creating function in this module takes, at every level of abstracti...
Definition Surface.hpp:26