floem/
nav.rs

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}