1use std::time::Duration;
4
5use densa_core::Point;
6
7use crate::ui::Press;
8use crate::{
9 Event, EventCx, Handled, Ime, Key, KeyEvent, NamedKey, Overflow, PointerEvent, PointerKind, Ui,
10 WidgetId,
11};
12
13const MULTI_CLICK_TIME: Duration = Duration::from_millis(500);
15const MULTI_CLICK_DISTANCE: f32 = 4.0;
17
18impl Ui {
19 pub fn pointer(&mut self, mut event: PointerEvent) -> Handled {
32 self.layout();
33 match event.kind {
34 PointerKind::Down(button) => event.clicks = self.count_clicks(&event, button),
35 PointerKind::Enter | PointerKind::Leave | PointerKind::Cancel => return Handled::No,
37 _ => {}
38 }
39 self.state.pointer = Some(event.position);
40 let hit = self.hit(self.state.root, event.position);
41 if self.state.capture.is_none() {
42 self.set_hover(hit, event.position);
43 }
44 let delivered = Event::Pointer(event);
45 let handled = match (event.kind, self.state.capture) {
46 (PointerKind::Up(_), holder) => {
47 let handled =
49 holder.is_some_and(|holder| self.deliver(holder, &delivered) == Handled::Yes);
50 self.state.capture = None;
51 self.set_hover(hit, event.position);
52 handled
53 }
54 (_, Some(holder)) => self.deliver(holder, &delivered) == Handled::Yes,
55 (PointerKind::Down(_), None) => {
56 self.focus_from(hit);
57 let handler = self.bubble(hit, &delivered);
58 self.state.capture = handler;
59 handler.is_some()
60 }
61 (_, None) => self.bubble(hit, &delivered).is_some(),
62 };
63 self.settle();
64 handled.into()
65 }
66
67 pub fn pointer_left(&mut self, position: Point) {
70 self.state.pointer = None;
71 if self.state.capture.is_none() {
72 self.set_hover(None, position);
73 }
74 }
75
76 pub fn cancel_pointer(&mut self) {
80 let at = self.state.pointer.unwrap_or(Point::ORIGIN);
81 if let Some(holder) = self.state.capture {
82 let cancel = PointerEvent::new(PointerKind::Cancel, at);
83 self.deliver(holder, &Event::Pointer(cancel));
84 self.state.capture = None;
85 }
86 self.state.pointer = None;
87 self.set_hover(None, at);
88 self.settle();
89 }
90
91 pub fn key(&mut self, event: &KeyEvent<'_>) -> Handled {
95 self.layout();
96 let target = self.state.focus.or(Some(self.state.root));
97 let mut handled = self.bubble(target, &Event::Key(*event)).is_some();
98 if !handled && event.pressed && event.key == Key::Named(NamedKey::Tab) {
99 let next = self.next_focus(!event.modifiers.shift());
100 if next.is_some() {
101 self.give_focus(next);
102 }
103 handled = true;
104 }
105 self.settle();
106 handled.into()
107 }
108
109 pub fn ime(&mut self, ime: &Ime<'_>) -> Handled {
111 self.layout();
112 let Some(focus) = self.state.focus else {
113 return Handled::No;
114 };
115 let handled = self.bubble(Some(focus), &Event::Ime(*ime)).is_some();
116 self.settle();
117 handled.into()
118 }
119
120 pub fn focus(&self) -> Option<WidgetId> {
122 self.state.focus
123 }
124
125 pub fn set_focus(&mut self, id: Option<WidgetId>) {
128 self.give_focus(id);
129 self.settle();
130 }
131
132 pub(crate) fn give_focus(&mut self, id: Option<WidgetId>) {
133 let id = id.filter(|id| self.state.is_shown(*id));
134 if id == self.state.focus {
135 return;
136 }
137 let old = std::mem::replace(&mut self.state.focus, id);
138 if let Some(old) = old {
139 self.deliver(old, &Event::FocusLost);
140 }
141 if let Some(new) = id {
142 self.deliver(new, &Event::FocusGained);
143 }
144 self.state.needs_paint = true;
145 }
146
147 pub fn hovered(&self) -> Option<WidgetId> {
149 self.state.hover
150 }
151
152 pub fn hit_test(&mut self, at: Point) -> Option<WidgetId> {
155 self.layout();
156 self.hit(self.state.root, at)
157 }
158
159 pub(crate) fn hit(&self, id: WidgetId, at: Point) -> Option<WidgetId> {
160 let node = &self.state.nodes[id.slot()];
161 if node.style.hidden {
162 return None;
163 }
164 let clips = node.style.overflow != Overflow::Visible;
165 if clips && !node.rect.contains(at) {
166 return None;
167 }
168 for &child in node.children.iter().rev() {
169 if let Some(hit) = self.hit(child, at) {
170 return Some(hit);
171 }
172 }
173 node.rect.contains(at).then_some(id)
174 }
175
176 fn deliver(&mut self, id: WidgetId, event: &Event<'_>) -> Handled {
177 if !self.state.is_live(id) {
178 return Handled::No;
179 }
180 let Some(widget) = self.widgets.get_mut(id.slot()).and_then(Option::as_mut) else {
181 return Handled::No;
182 };
183 let mut cx = EventCx {
184 state: &mut self.state,
185 id,
186 };
187 widget.event(&mut cx, event)
188 }
189
190 fn bubble(&mut self, mut target: Option<WidgetId>, event: &Event<'_>) -> Option<WidgetId> {
192 while let Some(id) = target.filter(|id| self.state.is_live(*id)) {
193 if self.deliver(id, event) == Handled::Yes {
194 return Some(id);
195 }
196 target = self.state.nodes[id.slot()].parent;
197 }
198 None
199 }
200
201 pub(crate) fn set_hover(&mut self, hover: Option<WidgetId>, position: Point) {
202 let old = self.state.hover;
203 if old == hover {
204 return;
205 }
206 self.mark_hovered(old, false);
207 self.mark_hovered(hover, true);
208 self.state.hover = hover;
209 if let Some(old) = old {
210 let leave = PointerEvent::new(PointerKind::Leave, position);
211 self.deliver(old, &Event::Pointer(leave));
212 }
213 if let Some(new) = hover {
214 let enter = PointerEvent::new(PointerKind::Enter, position);
215 self.deliver(new, &Event::Pointer(enter));
216 }
217 self.state.needs_paint = true;
218 }
219
220 pub(crate) fn mark_hovered(&mut self, from: Option<WidgetId>, hovered: bool) {
222 let mut at = from;
223 while let Some(id) = at.filter(|id| self.state.is_live(*id)) {
224 let node = &mut self.state.nodes[id.slot()];
225 node.hovered = hovered;
226 at = node.parent;
227 }
228 }
229
230 fn focus_from(&mut self, from: Option<WidgetId>) {
232 let mut at = from;
233 while let Some(id) = at.filter(|id| self.state.is_live(*id)) {
234 let widget = self.widgets.get(id.slot()).and_then(Option::as_deref);
235 if widget.is_some_and(|w| w.accepts_focus() && w.focus_on_press()) {
236 self.give_focus(Some(id));
237 return;
238 }
239 at = self.state.nodes[id.slot()].parent;
240 }
241 }
242
243 pub(crate) fn accepts_focus(&self, id: WidgetId) -> bool {
244 self.widgets
245 .get(id.slot())
246 .and_then(Option::as_deref)
247 .is_some_and(|w| w.accepts_focus())
248 }
249
250 fn count_clicks(&mut self, event: &PointerEvent, button: crate::PointerButton) -> u8 {
253 let near = MULTI_CLICK_DISTANCE * self.state.scale;
254 let clicks = match self.state.last_press {
255 Some(last)
256 if last.button == button
257 && event.time >= last.time
258 && event.time - last.time <= MULTI_CLICK_TIME
259 && (event.position.x - last.position.x).abs() <= near
260 && (event.position.y - last.position.y).abs() <= near =>
261 {
262 last.clicks.saturating_add(1)
263 }
264 _ => 1,
265 };
266 self.state.last_press = Some(Press {
267 time: event.time,
268 position: event.position,
269 button,
270 clicks,
271 });
272 clicks
273 }
274
275 fn next_focus(&self, forward: bool) -> Option<WidgetId> {
278 let current = self.state.focus;
279 let mut order = FocusOrder {
280 current,
281 seen: false,
282 first: None,
283 last: None,
284 before: None,
285 after: None,
286 };
287 self.visit_focusable(self.state.root, &mut order);
288 if forward {
289 order.after.or(order.first)
290 } else {
291 order.before.or(order.last)
292 }
293 }
294
295 fn visit_focusable(&self, id: WidgetId, order: &mut FocusOrder) {
296 let node = &self.state.nodes[id.slot()];
297 if node.style.hidden {
298 return;
299 }
300 if self.accepts_focus(id) {
301 order.visit(id);
302 }
303 for &child in &node.children {
304 self.visit_focusable(child, order);
305 }
306 }
307}
308
309struct FocusOrder {
311 current: Option<WidgetId>,
312 seen: bool,
313 first: Option<WidgetId>,
314 last: Option<WidgetId>,
315 before: Option<WidgetId>,
316 after: Option<WidgetId>,
317}
318
319impl FocusOrder {
320 fn visit(&mut self, id: WidgetId) {
321 self.first = self.first.or(Some(id));
322 self.last = Some(id);
323 if Some(id) == self.current {
324 self.seen = true;
325 } else if self.seen {
326 self.after = self.after.or(Some(id));
327 } else {
328 self.before = Some(id);
329 }
330 }
331}