lgui_core/core/input/event/
dispatcher.rs1use super::*;
2
3pub struct UiEventDispatcher {
4 state: UiInteractionState,
5 pressed_hit: Option<HitResult>,
6 active_focus_scope: Option<UiId>,
7 focus_history: HashMap<UiId, Option<UiId>>,
8}
9
10impl UiEventDispatcher {
11 pub fn new() -> Self {
12 Self {
13 state: UiInteractionState::default(),
14 pressed_hit: None,
15 active_focus_scope: None,
16 focus_history: HashMap::new(),
17 }
18 }
19
20 pub fn state(&self) -> UiInteractionState {
21 self.state.clone()
22 }
23
24 pub fn clear_interaction_state(&mut self) -> bool {
25 if self.state == UiInteractionState::default() {
26 return false;
27 }
28 self.state = UiInteractionState::default();
29 self.active_focus_scope = None;
30 self.focus_history.clear();
31 true
32 }
33
34 pub fn dispatch(&mut self, tree: &HostTree, event: InputEvent) -> Vec<UiEvent> {
35 match event {
36 InputEvent::PointerMove(pointer) => self.pointer_move(tree, pointer),
37 InputEvent::PointerDown { pointer, .. } => self.pointer_down(tree, pointer),
38 InputEvent::PointerUp { pointer, .. } => self.pointer_up(tree, pointer),
39 InputEvent::PointerEnter(pointer) => self.pointer_move(tree, pointer),
40 InputEvent::Wheel { point, delta } => self.wheel(tree, point, delta),
41 InputEvent::TextInput(text) => self.text_input(text),
42 InputEvent::Ime(ImeEvent::Enabled) => self.ime_start(),
43 InputEvent::Ime(ImeEvent::Preedit { text, cursor }) => self.ime_update(text, cursor),
44 InputEvent::Ime(ImeEvent::Commit(text)) => self.text_input(text),
45 InputEvent::Ime(ImeEvent::Disabled) => self.ime_end(),
46 InputEvent::Keyboard(event) => self.keyboard(event),
47 InputEvent::PointerLeave(_) => self.pointer_leave(),
48 InputEvent::Touch { pointer, phase } => match phase {
49 TouchPhase::Started => self.pointer_down(tree, pointer),
50 TouchPhase::Moved => self.pointer_move(tree, pointer),
51 TouchPhase::Ended => self.pointer_up(tree, pointer),
52 TouchPhase::Cancelled => self.pointer_leave(),
53 },
54 InputEvent::Platform(_) => Vec::new(),
55 InputEvent::Semantic(input) => self.semantic(tree, input),
56 }
57 }
58
59 fn semantic(&mut self, tree: &HostTree, input: SemanticInput) -> Vec<UiEvent> {
60 match input {
61 SemanticInput::Click(id) => tree
62 .hit_for_id(&id)
63 .map(UiEvent::Clicked)
64 .into_iter()
65 .collect(),
66 SemanticInput::Focus(id) => tree
67 .focusable_hit(&id)
68 .map(|hit| self.set_focus(Some(hit)))
69 .unwrap_or_default(),
70 SemanticInput::Blur(id) => {
71 if self.state.focused.as_ref() == Some(&id) {
72 self.set_focus(None)
73 } else {
74 Vec::new()
75 }
76 }
77 SemanticInput::SetValue { target, value } => {
78 vec![UiEvent::SemanticValue { target, value }]
79 }
80 SemanticInput::Action { target, action } => {
81 vec![UiEvent::SemanticAction { target, action }]
82 }
83 }
84 }
85
86 fn pointer_move(&mut self, tree: &HostTree, pointer: PointerData) -> Vec<UiEvent> {
87 let hit = tree.hit_test(pointer.point).filter(|hit| hit.policy.hover);
88 let current = hit.as_ref().map(|hit| hit.id.clone());
89 let drag = self
90 .pressed_hit
91 .clone()
92 .map(|hit| UiEvent::PointerDragged { hit, pointer });
93 if self.state.hovered == current {
94 let mut events = hit
95 .map(|hit| UiEvent::PointerMoved { hit, pointer })
96 .into_iter()
97 .collect::<Vec<_>>();
98 events.extend(drag);
99 return events;
100 }
101 let previous = self.state.hovered.clone();
102 self.state.hovered = current.clone();
103 let mut events = vec![UiEvent::HoverChanged {
104 previous,
105 current: hit,
106 }];
107 if let Some(event) = drag {
108 events.push(event);
109 }
110 if let Some(hit) = current.as_ref().and_then(|id| tree.hit_for_id(id)) {
111 events.push(UiEvent::PointerMoved { hit, pointer });
112 }
113 events
114 }
115
116 fn pointer_down(&mut self, tree: &HostTree, pointer: PointerData) -> Vec<UiEvent> {
117 let hit = tree.hit_test(pointer.point).filter(|hit| hit.policy.press);
118 let current = hit.as_ref().map(|hit| hit.id.clone());
119 let mut events = Vec::new();
120 if self.state.pressed != current {
121 let previous = self.state.pressed.clone();
122 self.state.pressed = current.clone();
123 self.pressed_hit = hit.clone();
124 events.push(UiEvent::PressedChanged {
125 previous,
126 current: hit.clone(),
127 });
128 } else {
129 self.pressed_hit = hit.clone();
130 }
131 if let Some(hit) = hit {
132 if hit.policy.focus {
133 let previous_focus = self.state.focused.clone();
134 self.state.focused = Some(hit.id.clone());
135 if previous_focus != self.state.focused {
136 events.push(UiEvent::FocusChanged {
137 previous: previous_focus,
138 current: Some(hit.clone()),
139 });
140 }
141 }
142 events.push(UiEvent::PointerPressed { hit, pointer });
143 } else if let Some(previous) = self.state.focused.take() {
144 events.push(UiEvent::FocusChanged {
145 previous: Some(previous),
146 current: None,
147 });
148 }
149 events
150 }
151
152 fn pointer_up(&mut self, tree: &HostTree, pointer: PointerData) -> Vec<UiEvent> {
153 let hit = tree.hit_test(pointer.point).filter(|hit| hit.policy.press);
154 let mut events = Vec::new();
155 let previous = self.state.pressed.clone();
156 let pressed_hit = self.pressed_hit.take();
157 self.state.pressed = None;
158 if previous.is_some() {
159 events.push(UiEvent::PressedChanged {
160 previous: previous.clone(),
161 current: None,
162 });
163 }
164 if let Some(hit) = pressed_hit {
165 events.push(UiEvent::PointerReleased { hit, pointer });
166 }
167 if let Some(hit) = hit {
168 if previous == Some(hit.id.clone()) {
169 if hit.policy.focus {
170 let previous_focus = self.state.focused.clone();
171 self.state.focused = Some(hit.id.clone());
172 if previous_focus != self.state.focused {
173 events.push(UiEvent::FocusChanged {
174 previous: previous_focus,
175 current: Some(hit.clone()),
176 });
177 }
178 }
179 events.push(UiEvent::Clicked(hit));
180 }
181 }
182 events
183 }
184
185 fn wheel(&mut self, tree: &HostTree, point: Point, delta: WheelDelta) -> Vec<UiEvent> {
186 tree.wheel_hit_test(point)
187 .map(|hit| vec![UiEvent::Wheel { hit, delta }])
188 .unwrap_or_default()
189 }
190
191 fn text_input(&mut self, text: String) -> Vec<UiEvent> {
192 self.state
193 .focused
194 .clone()
195 .map(|target| vec![UiEvent::TextInput { target, text }])
196 .unwrap_or_default()
197 }
198
199 fn ime_start(&self) -> Vec<UiEvent> {
200 self.state
201 .focused
202 .clone()
203 .map(|target| vec![UiEvent::ImeStarted { target }])
204 .unwrap_or_default()
205 }
206
207 fn ime_update(&self, text: String, cursor: Option<Range<usize>>) -> Vec<UiEvent> {
208 self.state
209 .focused
210 .clone()
211 .map(|target| {
212 vec![UiEvent::ImeUpdated {
213 target,
214 text,
215 cursor,
216 }]
217 })
218 .unwrap_or_default()
219 }
220
221 fn ime_end(&self) -> Vec<UiEvent> {
222 self.state
223 .focused
224 .clone()
225 .map(|target| vec![UiEvent::ImeEnded { target }])
226 .unwrap_or_default()
227 }
228
229 fn keyboard(&self, event: KeyboardEvent) -> Vec<UiEvent> {
230 self.state
231 .focused
232 .clone()
233 .map(|target| vec![UiEvent::Keyboard { target, event }])
234 .unwrap_or_default()
235 }
236
237 pub(crate) fn focus_adjacent(&mut self, tree: &HostTree, reverse: bool) -> Vec<UiEvent> {
238 let focusable = tree
239 .active_focus_scope_id()
240 .map(|scope_id| tree.focusable_hits_in_scope(&scope_id))
241 .unwrap_or_else(|| tree.focusable_hits());
242 if focusable.is_empty() {
243 return Vec::new();
244 }
245 let current_index = self
246 .state
247 .focused
248 .as_ref()
249 .and_then(|focused| focusable.iter().position(|hit| &hit.id == focused));
250 let next_index = match (current_index, reverse) {
251 (Some(index), false) => (index + 1) % focusable.len(),
252 (Some(0), true) => focusable.len() - 1,
253 (Some(index), true) => index - 1,
254 (None, false) => 0,
255 (None, true) => focusable.len() - 1,
256 };
257 let next = focusable[next_index].clone();
258 self.set_focus(Some(next))
259 }
260
261 pub fn sync_focus_for_tree(&mut self, tree: &HostTree) -> Vec<UiEvent> {
262 let focus_scope_ids = tree.focus_scope_ids();
263 let next_scope = tree.active_focus_scope_id();
264
265 if self.active_focus_scope != next_scope {
266 let previous_scope = self.active_focus_scope.take();
267 let restored = previous_scope
268 .as_ref()
269 .filter(|scope_id| !focus_scope_ids.iter().any(|id| id == *scope_id))
270 .and_then(|scope_id| self.focus_history.remove(scope_id))
271 .flatten();
272 self.focus_history
273 .retain(|scope_id, _| focus_scope_ids.iter().any(|id| id == scope_id));
274
275 if let Some(scope_id) = next_scope.clone() {
276 self.focus_history
277 .entry(scope_id.clone())
278 .or_insert_with(|| self.state.focused.clone());
279 self.active_focus_scope = Some(scope_id.clone());
280 let target = restored
281 .as_ref()
282 .and_then(|id| tree.focusable_hit_in_scope(id, &scope_id))
283 .or_else(|| tree.auto_focus_hit_in_scope(&scope_id))
284 .or_else(|| tree.focusable_hits_in_scope(&scope_id).into_iter().next());
285 return self.set_focus(target);
286 }
287
288 let target = restored
289 .as_ref()
290 .and_then(|id| tree.focusable_hit(id))
291 .or_else(|| tree.auto_focus_hit());
292 return self.set_focus(target);
293 }
294
295 self.focus_history
296 .retain(|scope_id, _| focus_scope_ids.iter().any(|id| id == scope_id));
297
298 if let Some(scope_id) = next_scope {
299 if self
300 .state
301 .focused
302 .as_ref()
303 .is_some_and(|id| tree.focusable_hit_in_scope(id, &scope_id).is_some())
304 {
305 return Vec::new();
306 }
307 let target = tree
308 .auto_focus_hit_in_scope(&scope_id)
309 .or_else(|| tree.focusable_hits_in_scope(&scope_id).into_iter().next());
310 return self.set_focus(target);
311 }
312
313 if let Some(focused) = self.state.focused.as_ref() {
314 if tree.focusable_hit(focused).is_some() {
315 return Vec::new();
316 }
317 return self.set_focus(tree.auto_focus_hit());
318 }
319 if let Some(hit) = tree.auto_focus_hit() {
320 return self.set_focus(Some(hit));
321 }
322 Vec::new()
323 }
324
325 pub fn sync_interaction_for_tree(&mut self, tree: &HostTree) -> Vec<UiEvent> {
326 let mut events = Vec::new();
327 if self
328 .state
329 .hovered
330 .as_ref()
331 .is_some_and(|id| tree.node(id).map_or(true, |node| !node.event_policy.hover))
332 {
333 let previous = self.state.hovered.clone();
334 self.state.hovered = None;
335 events.push(UiEvent::HoverChanged {
336 previous,
337 current: None,
338 });
339 }
340 if self
341 .state
342 .pressed
343 .as_ref()
344 .is_some_and(|id| tree.node(id).map_or(true, |node| !node.event_policy.press))
345 {
346 let previous = self.state.pressed.clone();
347 self.state.pressed = None;
348 self.pressed_hit = None;
349 events.push(UiEvent::PressedChanged {
350 previous,
351 current: None,
352 });
353 }
354 events
355 }
356
357 pub fn focus_node(&mut self, tree: &HostTree, id: &UiId) -> Vec<UiEvent> {
358 self.set_focus(tree.focusable_hit(id))
359 }
360
361 fn set_focus(&mut self, current: Option<HitResult>) -> Vec<UiEvent> {
362 let previous = self.state.focused.clone();
363 self.state.focused = current.as_ref().map(|hit| hit.id.clone());
364 if previous == self.state.focused {
365 return Vec::new();
366 }
367 vec![UiEvent::FocusChanged { previous, current }]
368 }
369
370 fn pointer_leave(&mut self) -> Vec<UiEvent> {
371 let previous = self.state.hovered.clone();
372 self.state.hovered = None;
373 self.state.pressed = None;
374 self.pressed_hit = None;
375 vec![UiEvent::PointerLeft { previous }]
376 }
377}
378
379impl Default for UiEventDispatcher {
380 fn default() -> Self {
381 Self::new()
382 }
383}