MayaFlux 0.4.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches
Layer.cpp
Go to the documentation of this file.
1#include "Layer.hpp"
2
4
5// =============================================================================
6// Element registration
7// =============================================================================
8
10{
11 element.id = m_next_id++;
12 m_elements.push_back(std::move(element));
13 return Slot(*this, m_elements.back().id);
14}
15
16bool Layer::remove(uint32_t id)
17{
18 auto it = std::ranges::find_if(m_elements,
19 [id](const Element& e) { return e.id == id; });
20 if (it == m_elements.end())
21 return false;
22 m_elements.erase(it);
23 return true;
24}
25
27{
28 m_elements.clear();
29 m_relations.clear();
30}
31
32// =============================================================================
33// Element mutation
34// =============================================================================
35
36bool Layer::set_bounds(uint32_t id, Kinesis::AABB2D bounds)
37{
38 if (auto* el = get(id)) {
39 el->bounds_hint = bounds;
40 return true;
41 }
42 return false;
43}
44
45bool Layer::set_contains(uint32_t id, std::function<bool(glm::vec2)> fn)
46{
47 if (auto* el = get(id)) {
48 el->contains = std::move(fn);
49 return true;
50 }
51 return false;
52}
53
54bool Layer::set_interactive(uint32_t id, bool interactive)
55{
56 if (auto* el = get(id)) {
57 el->interactive = interactive;
58 return true;
59 }
60 return false;
61}
62
63bool Layer::set_visible(uint32_t id, bool visible)
64{
65 auto* root = get(id);
66 if (!root)
67 return false;
68
69 root->visible = visible;
70 if (root->buffer)
71 root->buffer->mark_for_processing(visible);
72
73 if (auto it = m_relations.find(id); it != m_relations.end()) {
74 for (uint32_t rel_id : it->second)
75 set_visible(rel_id, visible);
76 }
77 return true;
78}
79
80bool Layer::bring_to_front(uint32_t id)
81{
82 if (auto rit = m_relations.find(id); rit != m_relations.end()) {
83 for (uint32_t rel_id : rit->second) {
84 auto it = std::ranges::find_if(m_elements,
85 [rel_id](const Element& e) { return e.id == rel_id; });
86 if (it != m_elements.end())
87 std::rotate(it, it + 1, m_elements.end());
88 }
89 }
90 auto it = std::ranges::find_if(m_elements,
91 [id](const Element& e) { return e.id == id; });
92 if (it == m_elements.end())
93 return false;
94 std::rotate(it, it + 1, m_elements.end());
95 return true;
96}
97
98bool Layer::send_to_back(uint32_t id)
99{
100 if (auto rit = m_relations.find(id); rit != m_relations.end()) {
101 for (uint32_t rel_id : rit->second)
102 send_to_back(rel_id);
103 }
104
105 auto it = std::ranges::find_if(m_elements,
106 [id](const Element& e) { return e.id == id; });
107 if (it == m_elements.end())
108 return false;
109 std::rotate(m_elements.begin(), it, it + 1);
110 return true;
111}
112
113// =============================================================================
114// Spatial queries
115// =============================================================================
116
117std::optional<uint32_t> Layer::hit_test(glm::vec2 ndc) const
118{
119 for (const auto& m_element : std::views::reverse(m_elements)) {
120 if (test_element(m_element, ndc))
121 return m_element.id;
122 }
123 return std::nullopt;
124}
125
126std::vector<uint32_t> Layer::hit_test_all(glm::vec2 ndc) const
127{
128 std::vector<uint32_t> result;
129 for (const auto& m_element : std::views::reverse(m_elements)) {
130 if (test_element(m_element, ndc))
131 result.push_back(m_element.id);
132 }
133 return result;
134}
135
136std::optional<uint32_t> Layer::hit_test(
137 double px, double py, uint32_t win_w, uint32_t win_h) const
138{
139 return hit_test(to_ndc(px, py, win_w, win_h));
140}
141
142std::vector<uint32_t> Layer::hit_test_all(
143 double px, double py, uint32_t win_w, uint32_t win_h) const
144{
145 return hit_test_all(to_ndc(px, py, win_w, win_h));
146}
147
148// =========================================================================
149// Relations
150// =========================================================================
151
152bool Layer::relate(uint32_t primary_id, uint32_t related_id)
153{
154 auto* p = get(primary_id);
155 auto* r = get(related_id);
156 if (!p || !r || primary_id == related_id)
157 return false;
158
159 auto& rel = m_relations[primary_id];
160 if (std::ranges::find(rel, related_id) == rel.end())
161 rel.push_back(related_id);
162
163 r->visible = p->visible;
164 if (r->buffer)
165 r->buffer->mark_for_processing(p->visible);
166
167 return true;
168}
169
170bool Layer::unrelate(uint32_t primary_id, uint32_t related_id)
171{
172 auto it = m_relations.find(primary_id);
173 if (it == m_relations.end())
174 return false;
175 auto& rel = it->second;
176 auto rit = std::ranges::find(rel, related_id);
177 if (rit == rel.end())
178 return false;
179 rel.erase(rit);
180 if (rel.empty())
181 m_relations.erase(it);
182 return true;
183}
184
185std::vector<uint32_t> Layer::related_ids(uint32_t primary_id) const
186{
187 auto it = m_relations.find(primary_id);
188 return it != m_relations.end() ? it->second : std::vector<uint32_t> {};
189}
190
191// =============================================================================
192// Introspection
193// =============================================================================
194
195const Element* Layer::get(uint32_t id) const
196{
197 auto it = std::ranges::find_if(m_elements,
198 [id](const Element& e) { return e.id == id; });
199 return it != m_elements.end() ? &*it : nullptr;
200}
201
202Element* Layer::get(uint32_t id)
203{
204 auto it = std::ranges::find_if(m_elements,
205 [id](const Element& e) { return e.id == id; });
206 return it != m_elements.end() ? &*it : nullptr;
207}
208
209// =============================================================================
210// Internal
211// =============================================================================
212
213glm::vec2 Layer::to_ndc(double px, double py, uint32_t w, uint32_t h) noexcept
214{
215 auto ndc3 = Kinesis::to_ndc(px, py, w, h);
216 return { ndc3.x, ndc3.y };
217}
218
219bool Layer::test_element(const Element& el, glm::vec2 ndc) noexcept
220{
221 if (!el.interactive || !el.visible)
222 return false;
223 if (el.bounds_hint && !el.bounds_hint->contains(ndc))
224 return false;
225 if (el.contains)
226 return el.contains(ndc);
227 return el.bounds_hint.has_value();
228}
229
230} // namespace MayaFlux::Portal::Forma
uint32_t h
Definition InkPress.cpp:28
Handle returned by Layer::add, carrying the assigned element id.
Definition Layer.hpp:49
bool set_interactive(uint32_t id, bool interactive)
Definition Layer.cpp:54
bool set_visible(uint32_t id, bool visible)
Definition Layer.cpp:63
bool bring_to_front(uint32_t id)
Move element to the top of the hit-test order (drawn last).
Definition Layer.cpp:80
void clear()
Remove all elements.
Definition Layer.cpp:26
bool relate(uint32_t primary_id, uint32_t related_id)
Record that related_id belongs with primary_id.
Definition Layer.cpp:152
const Element * get(uint32_t id) const
Definition Layer.cpp:195
std::vector< uint32_t > related_ids(uint32_t primary_id) const
Return the ids related to primary_id, or empty if none.
Definition Layer.cpp:185
bool set_bounds(uint32_t id, Kinesis::AABB2D bounds)
Replace the bounds_hint on an existing element.
Definition Layer.cpp:36
bool remove(uint32_t id)
Remove an element by id.
Definition Layer.cpp:16
std::vector< Element > m_elements
Definition Layer.hpp:280
std::vector< uint32_t > hit_test_all(glm::vec2 ndc) const
Return all interactive, visible elements containing ndc, ordered back-to-front.
Definition Layer.cpp:126
static glm::vec2 to_ndc(double px, double py, uint32_t win_w, uint32_t win_h) noexcept
Definition Layer.cpp:213
bool unrelate(uint32_t primary_id, uint32_t related_id)
Remove a specific relation between two elements.
Definition Layer.cpp:170
bool send_to_back(uint32_t id)
Move element to the bottom of the hit-test order (drawn first).
Definition Layer.cpp:98
Slot add(Element element)
Add an element to the layer.
Definition Layer.cpp:9
bool set_contains(uint32_t id, std::function< bool(glm::vec2)> fn)
Replace the contains callable on an existing element.
Definition Layer.cpp:45
std::unordered_map< uint32_t, std::vector< uint32_t > > m_relations
Definition Layer.hpp:283
std::optional< uint32_t > hit_test(glm::vec2 ndc) const
Return the topmost interactive, visible element containing ndc.
Definition Layer.cpp:117
static bool test_element(const Element &el, glm::vec2 ndc) noexcept
Definition Layer.cpp:219
glm::vec3 to_ndc(double window_x, double window_y, uint32_t width, uint32_t height)
Convert window pixel coordinates to NDC.
bool contains(glm::vec2 p) const noexcept
Definition Bounds.hpp:25
Axis-aligned bounding rectangle in a 2D coordinate space.
Definition Bounds.hpp:21
uint32_t id
Stable id assigned by Layer::add. Never zero.
Definition Element.hpp:60
A bounded, renderable region on a window surface.
Definition Element.hpp:58