Skip to main content

bliss_dom/events/
driver.rs

1use crate::Document;
2use bliss_traits::events::{
3    BlissPointerEvent, BlissPointerId, DomEvent, DomEventData, EventPhase, EventSink, EventState,
4    UiEvent,
5};
6use std::collections::VecDeque;
7
8pub trait EventHandler {
9    fn handle_event(
10        &mut self,
11        chain: &[usize],
12        event: &mut DomEvent,
13        doc: &mut dyn Document,
14        event_state: &mut EventState,
15    );
16}
17
18pub struct NoopEventHandler;
19impl EventHandler for NoopEventHandler {
20    fn handle_event(
21        &mut self,
22        _chain: &[usize],
23        _event: &mut DomEvent,
24        _doc: &mut dyn Document,
25        _event_state: &mut EventState,
26    ) {
27        // Do nothing
28    }
29}
30
31pub struct EventDriver<'doc, Handler: EventHandler> {
32    doc: &'doc mut dyn Document,
33    handler: Handler,
34    queue: VecDeque<DomEvent>,
35    event_sink: Option<&'doc dyn EventSink>,
36}
37
38impl<'doc, Handler: EventHandler> EventDriver<'doc, Handler> {
39    pub fn new(doc: &'doc mut dyn Document, handler: Handler) -> Self {
40        EventDriver {
41            doc,
42            handler,
43            queue: VecDeque::with_capacity(4),
44            event_sink: None,
45        }
46    }
47
48    pub fn with_event_sink(
49        doc: &'doc mut dyn Document,
50        handler: Handler,
51        event_sink: &'doc dyn EventSink,
52    ) -> Self {
53        EventDriver {
54            doc,
55            handler,
56            queue: VecDeque::with_capacity(4),
57            event_sink: Some(event_sink),
58        }
59    }
60
61    pub fn handle_pointer_move(&mut self, event: &BlissPointerEvent) -> Option<usize> {
62        let mut doc = self.doc.inner_mut();
63
64        let prev_hover_node_id = doc.hover_node_id;
65        let changed = doc.set_hover_to(event.page_x(), event.page_y());
66        let hover_node_id = doc.hover_node_id;
67
68        drop(doc);
69
70        if !changed {
71            return prev_hover_node_id;
72        }
73
74        let doc = self.doc.inner();
75        let mut old_chain = prev_hover_node_id
76            .map(|id| doc.node_chain(id))
77            .unwrap_or_default();
78        let mut new_chain = hover_node_id
79            .map(|id| doc.node_chain(id))
80            .unwrap_or_default();
81        old_chain.reverse();
82        new_chain.reverse();
83
84        // Find the difference in the node chain of the last hovered objected and the newest
85        let old_len = old_chain.len();
86        let new_len = new_chain.len();
87
88        let first_difference_index = old_chain
89            .iter()
90            .zip(&new_chain)
91            .position(|(old, new)| old != new)
92            .unwrap_or_else(|| old_len.min(new_len));
93
94        drop(doc);
95
96        let is_mouse = event.is_mouse();
97
98        if let Some(target) = prev_hover_node_id {
99            self.handle_dom_event(DomEvent::new(
100                target,
101                DomEventData::PointerOut(event.clone()),
102            ));
103            if is_mouse {
104                self.handle_dom_event(DomEvent::new(target, DomEventData::MouseOut(event.clone())));
105            }
106
107            // Send an mouseleave event to all old elements on the chain
108            for node_id in old_chain
109                .get(first_difference_index..)
110                .unwrap_or(&[])
111                .iter()
112            {
113                self.handle_dom_event(DomEvent::new(
114                    *node_id,
115                    DomEventData::PointerLeave(event.clone()),
116                ));
117                if is_mouse {
118                    self.handle_dom_event(DomEvent::new(
119                        *node_id,
120                        DomEventData::MouseLeave(event.clone()),
121                    ));
122                }
123            }
124        }
125
126        if let Some(target) = hover_node_id {
127            self.handle_dom_event(DomEvent::new(
128                target,
129                DomEventData::PointerOver(event.clone()),
130            ));
131
132            if is_mouse {
133                self.handle_dom_event(DomEvent::new(
134                    target,
135                    DomEventData::MouseOver(event.clone()),
136                ));
137            }
138
139            // Send an mouseenter event to all new elements on the chain
140            for node_id in new_chain
141                .get(first_difference_index..)
142                .unwrap_or(&[])
143                .iter()
144            {
145                self.handle_dom_event(DomEvent::new(
146                    *node_id,
147                    DomEventData::PointerEnter(event.clone()),
148                ));
149
150                if is_mouse {
151                    self.handle_dom_event(DomEvent::new(
152                        *node_id,
153                        DomEventData::MouseEnter(event.clone()),
154                    ));
155                }
156            }
157        }
158
159        hover_node_id
160    }
161
162    pub fn handle_ui_event(&mut self, event: UiEvent) {
163        let doc = self.doc.inner();
164
165        let mut should_clear_hover = false;
166        let mut hover_node_id = doc.hover_node_id;
167        let focussed_node_id = doc.focus_node_id;
168        drop(doc);
169
170        // Update document input state (hover, focus, active, etc)
171        match &event {
172            UiEvent::PointerMove(event) => {
173                hover_node_id = self.handle_pointer_move(event);
174            }
175            UiEvent::PointerDown(event) => {
176                hover_node_id = self.handle_pointer_move(event);
177                let mut doc = self.doc.inner_mut();
178                doc.active_node();
179                doc.set_mousedown_node_id(hover_node_id);
180            }
181            UiEvent::PointerUp(event) => {
182                hover_node_id = self.handle_pointer_move(event);
183                let mut doc = self.doc.inner_mut();
184                doc.unactive_node();
185
186                if event.is_primary && matches!(event.id, BlissPointerId::Finger(_)) {
187                    should_clear_hover = true;
188                }
189            }
190            _ => {}
191        };
192
193        let target = match event {
194            UiEvent::PointerMove(_) => hover_node_id,
195            UiEvent::PointerUp(_) => hover_node_id,
196            UiEvent::PointerDown(_) => hover_node_id,
197            UiEvent::Wheel(_) => hover_node_id,
198            UiEvent::KeyUp(_) => focussed_node_id,
199            UiEvent::KeyDown(_) => focussed_node_id,
200            UiEvent::Ime(_) => focussed_node_id,
201        };
202        // D-2c-followup: root_element widened to Option<&Node>; degrade to a
203        // sentinel target id (0) instead of unwrap-panicking.
204        let target =
205            target.unwrap_or_else(|| self.doc.inner().root_element().map(|r| r.id).unwrap_or(0));
206
207        match event {
208            UiEvent::PointerMove(data) => {
209                self.handle_pointer_event(
210                    target,
211                    data,
212                    DomEventData::PointerMove,
213                    DomEventData::MouseMove,
214                );
215            }
216            UiEvent::PointerUp(data) => {
217                self.handle_pointer_event(
218                    target,
219                    data,
220                    DomEventData::PointerUp,
221                    DomEventData::MouseUp,
222                );
223            }
224            UiEvent::PointerDown(data) => {
225                self.handle_pointer_event(
226                    target,
227                    data,
228                    DomEventData::PointerDown,
229                    DomEventData::MouseDown,
230                );
231            }
232            UiEvent::Wheel(data) => {
233                self.handle_dom_event(DomEvent::new(target, DomEventData::Wheel(data)))
234            }
235            UiEvent::KeyUp(data) => {
236                self.handle_dom_event(DomEvent::new(target, DomEventData::KeyUp(data)))
237            }
238            UiEvent::KeyDown(data) => {
239                self.handle_dom_event(DomEvent::new(target, DomEventData::KeyDown(data)))
240            }
241            UiEvent::Ime(data) => {
242                self.handle_dom_event(DomEvent::new(target, DomEventData::Ime(data)))
243            }
244        };
245
246        // Update document input state (hover, focus, active, etc)
247        if should_clear_hover {
248            self.doc.inner_mut().clear_hover();
249        }
250    }
251
252    pub fn handle_dom_event(&mut self, event: DomEvent) {
253        self.queue.push_back(event);
254        self.process_queue();
255    }
256
257    fn handle_pointer_event(
258        &mut self,
259        target: usize,
260        data: BlissPointerEvent,
261        make_ptr_data: impl FnOnce(BlissPointerEvent) -> DomEventData,
262        make_mouse_data: impl FnOnce(BlissPointerEvent) -> DomEventData,
263    ) {
264        let mut ptr_event = DomEvent::new(target, make_ptr_data(data.clone()));
265        let mut event_state = EventState::default();
266        event_state = self.run_handler_event(&mut ptr_event, event_state);
267        if !event_state.is_cancelled() && data.is_mouse() {
268            let mut mouse_event = DomEvent::new(target, make_mouse_data(data));
269            event_state = self.run_handler_event(&mut mouse_event, event_state);
270        }
271        if !event_state.is_cancelled() {
272            self.run_default_action(&mut ptr_event);
273        }
274        self.process_queue();
275    }
276
277    fn process_queue(&mut self) {
278        while let Some(mut event) = self.queue.pop_front() {
279            let event_state = self.run_handler_event(&mut event, EventState::default());
280            if !event_state.is_cancelled() {
281                self.run_default_action(&mut event);
282            }
283        }
284    }
285
286    fn run_handler_event(
287        &mut self,
288        event: &mut DomEvent,
289        initial_event_state: EventState,
290    ) -> EventState {
291        let chain = if event.bubbles {
292            let doc = self.doc.inner();
293            doc.node_chain(event.target)
294        } else {
295            vec![event.target]
296        };
297
298        let mut event_state = initial_event_state;
299
300        for node_id in &chain {
301            self.handler.handle_event(
302                std::slice::from_ref(node_id),
303                event,
304                self.doc,
305                &mut event_state,
306            );
307
308            if event_state.propagation_is_stopped() {
309                break;
310            }
311        }
312
313        if let Some(sink) = &self.event_sink {
314            let doc_id = self.doc.id();
315            sink.on_dom_event(doc_id, event, EventPhase::Target, event.target);
316        }
317
318        event_state
319    }
320
321    fn run_default_action(&mut self, event: &mut DomEvent) {
322        let mut doc = self.doc.inner_mut();
323        doc.handle_dom_event(event, |new_evt| self.queue.push_back(new_evt));
324    }
325}