lgui_core/core/view/tree/
events.rs1use super::*;
2
3impl HostTree {
4 pub fn action_handler(&self, target: &UiId, id: &ActionId) -> Option<UiActionHandler> {
5 self.node(target)?
6 .action_handlers
7 .iter()
8 .find(|binding| &binding.id == id)
9 .map(|binding| binding.handler.clone())
10 }
11
12 pub fn hit_test(&self, point: Point) -> Option<HitResult> {
13 let node = self.frontmost_node_at(point, |node| {
14 node.interaction != InteractionRole::None
15 || node.click_handler.is_some()
16 || node.click_capture_handler.is_some()
17 || node.input_event_handlers.iter().any(|binding| {
18 matches!(
19 binding.kind,
20 UiEventKind::Click
21 | UiEventKind::PointerDown
22 | UiEventKind::PointerMove
23 | UiEventKind::PointerUp
24 )
25 })
26 })?;
27 Some(self.hit_for_node(node, node.click_action.clone()))
28 }
29
30 pub fn wheel_hit_test(&self, point: Point) -> Option<HitResult> {
31 let node = self.frontmost_node_at(point, |node| {
32 node.wheel_action.is_some()
33 || node
34 .input_event_handlers
35 .iter()
36 .any(|binding| binding.kind == UiEventKind::Wheel)
37 })?;
38 let mut hit = self.hit_for_node(node, node.wheel_action.clone());
39 hit.click_handler = None;
40 hit.capture_handlers.clear();
41 hit.bubble_handlers.clear();
42 Some(hit)
43 }
44
45 pub fn focusable_hits(&self) -> Vec<HitResult> {
46 self.nodes
47 .iter()
48 .filter(|node| node.event_policy.focus)
49 .map(|node| self.hit_for_node(node, None))
50 .collect()
51 }
52
53 pub fn focusable_hits_in_scope(&self, scope_id: &UiId) -> Vec<HitResult> {
54 self.nodes
55 .iter()
56 .filter(|node| {
57 node.event_policy.focus
58 && (&node.id == scope_id || self.node_is_descendant_of(&node.id, scope_id))
59 })
60 .map(|node| self.hit_for_node(node, None))
61 .collect()
62 }
63
64 pub fn focusable_hit(&self, id: &UiId) -> Option<HitResult> {
65 self.nodes
66 .iter()
67 .find(|node| &node.id == id && node.event_policy.focus)
68 .map(|node| self.hit_for_node(node, None))
69 }
70
71 pub fn hit_for_id(&self, id: &UiId) -> Option<HitResult> {
72 self.node(id).map(|node| self.hit_for_node(node, None))
73 }
74
75 pub fn handler_events(&self, event: &UiEvent) -> Vec<UiHandlerEvent> {
76 match event {
77 UiEvent::Clicked(hit) => self
78 .handler_event(&hit.id, UiEventPayload::Click)
79 .into_iter()
80 .collect(),
81 UiEvent::Wheel { hit, delta } => self
82 .handler_event(&hit.id, UiEventPayload::Wheel { delta: *delta })
83 .into_iter()
84 .collect(),
85 UiEvent::TextInput { target, text } => self
86 .handler_event(target, UiEventPayload::Input { text: text.clone() })
87 .into_iter()
88 .collect(),
89 UiEvent::ImeStarted { target } => self
90 .handler_event(target, UiEventPayload::CompositionStart)
91 .into_iter()
92 .collect(),
93 UiEvent::ImeUpdated {
94 target,
95 text,
96 cursor,
97 } => self
98 .handler_event(
99 target,
100 UiEventPayload::CompositionUpdate {
101 text: text.clone(),
102 cursor: cursor.clone(),
103 },
104 )
105 .into_iter()
106 .collect(),
107 UiEvent::ImeEnded { target } => self
108 .handler_event(target, UiEventPayload::CompositionEnd)
109 .into_iter()
110 .collect(),
111 UiEvent::Keyboard { target, event } => self
112 .handler_event(
113 target,
114 UiEventPayload::Keyboard {
115 event: event.clone(),
116 },
117 )
118 .into_iter()
119 .collect(),
120 UiEvent::PointerPressed { hit, pointer } => self
121 .handler_event(&hit.id, UiEventPayload::PointerDown { pointer: *pointer })
122 .into_iter()
123 .collect(),
124 UiEvent::PointerMoved { hit, pointer } | UiEvent::PointerDragged { hit, pointer } => {
125 self.handler_event(&hit.id, UiEventPayload::PointerMove { pointer: *pointer })
126 .into_iter()
127 .collect()
128 }
129 UiEvent::PointerReleased { hit, pointer } => self
130 .handler_event(&hit.id, UiEventPayload::PointerUp { pointer: *pointer })
131 .into_iter()
132 .collect(),
133 UiEvent::FocusChanged { previous, current } => {
134 let mut events = previous
135 .as_ref()
136 .and_then(|id| self.handler_event(id, UiEventPayload::Blur))
137 .into_iter()
138 .collect::<Vec<_>>();
139 events.extend(
140 current
141 .as_ref()
142 .and_then(|hit| self.handler_event(&hit.id, UiEventPayload::Focus)),
143 );
144 events
145 }
146 UiEvent::HoverChanged { .. }
147 | UiEvent::PressedChanged { .. }
148 | UiEvent::PointerLeft { .. }
149 | UiEvent::SemanticValue { .. }
150 | UiEvent::SemanticAction { .. } => Vec::new(),
151 }
152 }
153
154 pub fn handler_event(&self, target: &UiId, payload: UiEventPayload) -> Option<UiHandlerEvent> {
155 let node = self.node(target)?;
156 let kind = payload.kind();
157 let mut lineage = vec![node];
158 let mut parent = node.parent.as_ref();
159 while let Some(parent_id) = parent {
160 let Some(parent_node) = self.node(parent_id) else {
161 break;
162 };
163 lineage.push(parent_node);
164 parent = parent_node.parent.as_ref();
165 }
166 let capture_handlers = lineage
167 .iter()
168 .rev()
169 .flat_map(|node| &node.input_event_handlers)
170 .filter(|binding| binding.capture && binding.kind == kind)
171 .map(|binding| binding.handler.clone())
172 .collect::<Vec<_>>();
173 let bubble_handlers = lineage
174 .iter()
175 .flat_map(|node| &node.input_event_handlers)
176 .filter(|binding| !binding.capture && binding.kind == kind)
177 .map(|binding| binding.handler.clone())
178 .collect::<Vec<_>>();
179 (!capture_handlers.is_empty() || !bubble_handlers.is_empty()).then(|| UiHandlerEvent {
180 target: target.clone(),
181 payload,
182 capture_handlers,
183 bubble_handlers,
184 })
185 }
186
187 pub fn auto_focus_hit(&self) -> Option<HitResult> {
188 self.nodes
189 .iter()
190 .find(|node| node.auto_focus && node.event_policy.focus)
191 .map(|node| self.hit_for_node(node, None))
192 }
193
194 pub fn focus_scope_ids(&self) -> Vec<UiId> {
195 self.nodes
196 .iter()
197 .filter(|node| node.focus_scope)
198 .map(|node| node.id.clone())
199 .collect()
200 }
201
202 pub fn active_focus_scope_id(&self) -> Option<UiId> {
203 self.nodes
204 .iter()
205 .rev()
206 .find(|node| node.focus_scope && node.render_phase == RenderPhase::Popup)
207 .or_else(|| self.nodes.iter().rev().find(|node| node.focus_scope))
208 .map(|node| node.id.clone())
209 }
210
211 pub fn focusable_hit_in_scope(&self, id: &UiId, scope_id: &UiId) -> Option<HitResult> {
212 self.node(id)
213 .filter(|node| {
214 node.event_policy.focus
215 && (&node.id == scope_id || self.node_is_descendant_of(&node.id, scope_id))
216 })
217 .map(|node| self.hit_for_node(node, None))
218 }
219
220 pub fn auto_focus_hit_in_scope(&self, scope_id: &UiId) -> Option<HitResult> {
221 self.nodes
222 .iter()
223 .find(|node| {
224 node.auto_focus
225 && node.event_policy.focus
226 && self.node_is_descendant_of(&node.id, scope_id)
227 })
228 .map(|node| self.hit_for_node(node, None))
229 }
230
231 fn node_is_descendant_of(&self, id: &UiId, ancestor_id: &UiId) -> bool {
232 let mut parent = self.node(id).and_then(|node| node.parent.as_ref());
233 while let Some(parent_id) = parent {
234 if parent_id == ancestor_id {
235 return true;
236 }
237 parent = self.node(parent_id).and_then(|node| node.parent.as_ref());
238 }
239 false
240 }
241
242 fn frontmost_node_at(
243 &self,
244 point: Point,
245 accepts: impl Fn(&UiNode) -> bool,
246 ) -> Option<&UiNode> {
247 let contains = |node: &UiNode| {
248 let offset = self.ancestor_content_offset(node);
249 accepts(node)
250 && node.hit_rect.translate(offset.0, offset.1).contains(point)
251 && self.node_visible_at_point(node, point)
252 };
253 self.nodes
254 .iter()
255 .rev()
256 .find(|node| node.render_phase == RenderPhase::Popup && contains(node))
257 .or_else(|| {
258 self.nodes
259 .iter()
260 .rev()
261 .find(|node| node.render_phase != RenderPhase::Popup && contains(node))
262 })
263 .map(Arc::as_ref)
264 }
265
266 fn node_visible_at_point(&self, node: &UiNode, point: Point) -> bool {
267 if node.render_phase == RenderPhase::Popup {
268 return true;
269 }
270 let mut parent = node.parent.as_ref();
271 while let Some(parent_id) = parent {
272 let Some(parent_node) = self.node(parent_id) else {
273 return true;
274 };
275 let offset = self.ancestor_content_offset(parent_node);
276 if parent_node
277 .clip_rect
278 .is_some_and(|clip| !clip.translate(offset.0, offset.1).contains(point))
279 {
280 return false;
281 }
282 parent = parent_node.parent.as_ref();
283 }
284 true
285 }
286
287 pub(crate) fn ancestor_content_offset(&self, node: &UiNode) -> (f32, f32) {
288 let mut x = 0.0;
289 let mut y = 0.0;
290 let mut parent = node.parent.as_ref();
291 while let Some(parent_id) = parent {
292 let Some(parent_node) = self.node(parent_id) else {
293 break;
294 };
295 x += parent_node.content_offset.0;
296 y += parent_node.content_offset.1;
297 parent = parent_node.parent.as_ref();
298 }
299 (x, y)
300 }
301
302 fn hit_for_node(&self, node: &UiNode, action: Option<UiAction>) -> HitResult {
303 let offset = self.ancestor_content_offset(node);
304 let mut lineage = vec![node];
305 let mut parent = node.parent.as_ref();
306 while let Some(parent_id) = parent {
307 let Some(parent_node) = self.node(parent_id) else {
308 break;
309 };
310 lineage.push(parent_node);
311 parent = parent_node.parent.as_ref();
312 }
313 let capture_handlers = lineage
314 .iter()
315 .rev()
316 .filter_map(|node| node.click_capture_handler.clone())
317 .collect();
318 let bubble_handlers = lineage
319 .iter()
320 .filter_map(|node| node.click_handler.clone())
321 .collect();
322 HitResult {
323 id: node.id.clone(),
324 rect: node.hit_rect.translate(offset.0, offset.1),
325 interaction: node.interaction,
326 policy: node.event_policy,
327 action,
328 action_target: node.action_target.clone(),
329 capture_handlers,
330 bubble_handlers,
331 click_handler: node.click_handler.clone(),
332 }
333 }
334}