1use peniko::kurbo::{Point, Rect};
2use winit::keyboard::NamedKey;
3
4use crate::{app_state::AppState, id::ViewId, view::view_tab_navigation};
5
6pub(crate) fn view_arrow_navigation(key: NamedKey, app_state: &mut AppState, view: ViewId) {
7 let focused = match app_state.focus {
8 Some(id) => id,
9 None => {
10 view_tab_navigation(
11 view,
12 app_state,
13 matches!(key, NamedKey::ArrowUp | NamedKey::ArrowLeft),
14 );
15 return;
16 }
17 };
18 let rect = focused.layout_rect().inflate(10.0, 10.0);
19 let center = rect.center();
20 let intersect_target = match key {
21 NamedKey::ArrowUp => Rect::new(rect.x0, f64::NEG_INFINITY, rect.x1, center.y),
22 NamedKey::ArrowDown => Rect::new(rect.x0, center.y, rect.x1, f64::INFINITY),
23 NamedKey::ArrowLeft => Rect::new(f64::NEG_INFINITY, rect.y0, center.x, rect.y1),
24 NamedKey::ArrowRight => Rect::new(center.x, rect.y0, f64::INFINITY, rect.y1),
25 _ => panic!(),
26 };
27 let center_target = match key {
28 NamedKey::ArrowUp => {
29 Rect::new(f64::NEG_INFINITY, f64::NEG_INFINITY, f64::INFINITY, rect.y0)
30 }
31 NamedKey::ArrowDown => Rect::new(f64::NEG_INFINITY, rect.y1, f64::INFINITY, f64::INFINITY),
32 NamedKey::ArrowLeft => {
33 Rect::new(f64::NEG_INFINITY, f64::NEG_INFINITY, rect.x0, f64::INFINITY)
34 }
35 NamedKey::ArrowRight => Rect::new(rect.x1, f64::NEG_INFINITY, f64::INFINITY, f64::INFINITY),
36 _ => panic!(),
37 };
38 let mut keyboard_navigable: Vec<ViewId> =
39 app_state.keyboard_navigable.iter().copied().collect();
40 keyboard_navigable.retain(|id| {
41 let layout = id.layout_rect();
42
43 !layout.intersect(intersect_target).is_zero_area()
44 && center_target.contains(layout.center())
45 && app_state.can_focus(*id)
46 && *id != focused
47 });
48
49 let mut new_focus = None;
50 for id in keyboard_navigable {
51 let id_rect = id.layout_rect();
52 let id_center = id_rect.center();
53 let id_edge = match key {
54 NamedKey::ArrowUp => Point::new(id_center.x, id_rect.y1),
55 NamedKey::ArrowDown => Point::new(id_center.x, id_rect.y0),
56 NamedKey::ArrowLeft => Point::new(id_rect.x1, id_center.y),
57 NamedKey::ArrowRight => Point::new(id_rect.x0, id_center.y),
58 _ => panic!(),
59 };
60 let id_distance = center.distance_squared(id_edge);
61 if let Some((_, distance)) = new_focus {
62 if id_distance < distance {
63 new_focus = Some((id, id_distance));
64 }
65 } else {
66 new_focus = Some((id, id_distance));
67 }
68 }
69
70 if let Some((id, _)) = new_focus {
71 app_state.clear_focus();
72 app_state.update_focus(id, true);
73 }
74}