1use crate::scene::*;
2
3#[derive(Debug, Clone)]
4pub enum AppEvent {
5 Click(f32, f32),
6 MouseMove(f32, f32),
7 KeyPress(String),
8 Scroll(f32, f32, f32, f32), }
10
11#[derive(Debug, Clone)]
12pub struct EventResult {
13 pub target: NodeId,
14 pub event_type: String,
15 pub handler_code: String,
16}
17
18pub struct EventSystem {
19 pub hover_node: Option<NodeId>,
20 pub focus_node: Option<NodeId>,
21}
22
23impl Default for EventSystem {
24 fn default() -> Self {
25 Self::new()
26 }
27}
28
29impl EventSystem {
30 pub fn new() -> Self {
31 Self {
32 hover_node: None,
33 focus_node: None,
34 }
35 }
36
37 pub fn handle(&mut self, event: &AppEvent, scene: &mut SceneGraph) -> Vec<EventResult> {
38 match event {
39 AppEvent::Click(x, y) => self.handle_click(*x, *y, scene),
40 AppEvent::MouseMove(x, y) => self.handle_mouse_move(*x, *y, scene),
41 AppEvent::Scroll(x, y, dx, dy) => {
42 self.handle_scroll(*x, *y, *dx, *dy, scene);
43 Vec::new()
44 }
45 AppEvent::KeyPress(key) => self.handle_key(key, scene),
46 }
47 }
48
49 fn handle_click(&mut self, x: f32, y: f32, scene: &SceneGraph) -> Vec<EventResult> {
50 let mut results = Vec::new();
51
52 if let Some(hit) = self.hit_test(x, y, scene) {
53 let mut current = Some(hit);
55 while let Some(node_id) = current {
56 let node = scene.get(node_id);
57 if let Some(handler) = node.event_handlers.get("click") {
58 results.push(EventResult {
59 target: hit,
60 event_type: "click".to_string(),
61 handler_code: handler.clone(),
62 });
63 }
64 current = node.parent;
65 }
66 }
67
68 results
69 }
70
71 fn handle_mouse_move(&mut self, x: f32, y: f32, scene: &mut SceneGraph) -> Vec<EventResult> {
72 let mut results = Vec::new();
73 let new_hover = self.hit_test(x, y, scene);
74
75 if new_hover != self.hover_node {
76 if let Some(old) = self.hover_node {
78 let node = scene.get(old);
79 let handler = node.event_handlers.get("mouseleave").cloned();
80 let has_base = node.base_style.is_some();
81 let has_transition = node.style.transition_duration > 0.0;
82 if let Some(handler) = handler {
83 results.push(EventResult {
84 target: old,
85 event_type: "mouseleave".to_string(),
86 handler_code: handler,
87 });
88 }
89 if has_base {
90 let base = scene.get(old).base_style.clone().unwrap();
91 if has_transition {
92 let current = scene.get(old).style.clone();
94 let node = scene.get_mut(old);
95 node.transition_from = Some(current);
96 node.transition_to = Some(base);
97 node.transition_start = Some(std::time::Instant::now());
98 } else {
99 scene.get_mut(old).style = base;
100 }
101 scene.get_mut(old).is_hovered = false;
102 scene.get_mut(old).dirty = true;
103 }
104 }
105 if let Some(new) = new_hover {
107 let node = scene.get(new);
108 let handler = node.event_handlers.get("mouseenter").cloned();
109 let has_hover = node.hover_style.is_some();
110 let has_transition = node.style.transition_duration > 0.0
111 || node
112 .hover_style
113 .as_ref()
114 .map(|h| h.transition_duration > 0.0)
115 .unwrap_or(false);
116 if let Some(handler) = handler {
117 results.push(EventResult {
118 target: new,
119 event_type: "mouseenter".to_string(),
120 handler_code: handler,
121 });
122 }
123 if has_hover {
124 let hover = scene.get(new).hover_style.clone().unwrap();
125 if has_transition {
126 let current = scene.get(new).style.clone();
128 let node = scene.get_mut(new);
129 node.transition_from = Some(current);
130 node.transition_to = Some(hover);
131 node.transition_start = Some(std::time::Instant::now());
132 } else {
133 scene.get_mut(new).style = hover;
134 }
135 scene.get_mut(new).is_hovered = true;
136 scene.get_mut(new).dirty = true;
137 }
138 }
139 self.hover_node = new_hover;
140 }
141
142 results
143 }
144
145 fn handle_scroll(&mut self, x: f32, y: f32, _dx: f32, dy: f32, scene: &mut SceneGraph) {
146 if let Some(root) = scene.root {
148 if let Some(scroll_target) = self.find_scrollable(x, y, scene, root) {
149 let node = scene.get_mut(scroll_target);
150 let max_scroll = (node.content_height - node.layout.height).max(0.0);
151 node.scroll_offset.1 = (node.scroll_offset.1 + dy * 30.0).clamp(0.0, max_scroll);
152 }
153 }
154 }
155
156 fn handle_key(&self, _key: &str, scene: &SceneGraph) -> Vec<EventResult> {
157 let mut results = Vec::new();
158
159 if let Some(focus) = self.focus_node {
160 let node = scene.get(focus);
161 if let Some(handler) = node.event_handlers.get("keypress") {
162 results.push(EventResult {
163 target: focus,
164 event_type: "keypress".to_string(),
165 handler_code: handler.clone(),
166 });
167 }
168 }
169
170 results
171 }
172
173 fn hit_test(&self, x: f32, y: f32, scene: &SceneGraph) -> Option<NodeId> {
174 if let Some(root) = scene.root {
175 self.hit_test_recursive(x, y, scene, root)
176 } else {
177 None
178 }
179 }
180
181 fn hit_test_recursive(
182 &self,
183 x: f32,
184 y: f32,
185 scene: &SceneGraph,
186 node_id: NodeId,
187 ) -> Option<NodeId> {
188 let node = scene.get(node_id);
189
190 if node.style.display == Display::None {
191 return None;
192 }
193
194 let layout = &node.layout;
195 let scroll_y = node.scroll_offset.1;
197 let in_bounds = x >= layout.x
198 && x <= layout.x + layout.width
199 && y >= layout.y
200 && y <= layout.y + layout.height;
201
202 if !in_bounds && node.style.overflow != Overflow::Visible {
203 return None;
204 }
205
206 let child_y = y + scroll_y;
208
209 let children: Vec<NodeId> = node.children.clone();
211 for &child_id in children.iter().rev() {
212 if let Some(hit) = self.hit_test_recursive(x, child_y, scene, child_id) {
213 return Some(hit);
214 }
215 }
216
217 if in_bounds && !node.event_handlers.is_empty() {
218 return Some(node_id);
219 }
220
221 if in_bounds {
222 return Some(node_id);
223 }
224
225 None
226 }
227
228 fn find_scrollable(
229 &self,
230 x: f32,
231 y: f32,
232 scene: &SceneGraph,
233 node_id: NodeId,
234 ) -> Option<NodeId> {
235 let node = scene.get(node_id);
236 let layout = &node.layout;
237
238 let in_bounds = x >= layout.x
239 && x <= layout.x + layout.width
240 && y >= layout.y
241 && y <= layout.y + layout.height;
242
243 if !in_bounds {
244 return None;
245 }
246
247 let children: Vec<NodeId> = node.children.clone();
249 for &child_id in children.iter().rev() {
250 if let Some(found) = self.find_scrollable(x, y, scene, child_id) {
251 return Some(found);
252 }
253 }
254
255 if node.style.overflow == Overflow::Scroll {
256 return Some(node_id);
257 }
258
259 None
260 }
261}