Skip to main content

faststep/
stack_header.rs

1use embedded_graphics::{
2    draw_target::DrawTarget,
3    mono_font::MonoTextStyle,
4    pixelcolor::Rgb565,
5    prelude::*,
6    primitives::Rectangle,
7    text::{Text, TextStyle},
8};
9
10use crate::{Button, ButtonKind, ButtonSpec, Localized, NavHeaderAction, StackNav, lerp_i32};
11
12use super::stack::HeaderTransition;
13
14const BACK_BUTTON_WIDTH: u32 = 112;
15
16#[derive(Clone, Copy, Debug, PartialEq, Eq)]
17pub(super) struct HeaderTitle<'a> {
18    pub title: Localized<'a>,
19    pub center: Point,
20}
21
22pub(super) fn show_back_button<K: Copy, const N: usize>(nav: &StackNav<K, N>) -> bool {
23    nav.depth() > 1 || matches!(nav.header_transition(), Some(HeaderTransition::Pop { .. }))
24}
25
26pub(super) fn header_titles<'a, K: Copy, F, const N: usize>(
27    nav: &StackNav<K, N>,
28    header: Rectangle,
29    title_for: &F,
30    back_button: Option<&Button<'a, NavHeaderAction>>,
31) -> (
32    Option<Localized<'a>>,
33    HeaderTitle<'a>,
34    Option<HeaderTitle<'a>>,
35)
36where
37    F: Fn(K) -> Localized<'a>,
38{
39    let center = header.center();
40    let right = Point::new(center.x + header.size.width as i32, center.y);
41    let back = back_title_center(back_button);
42    match nav.header_transition() {
43        Some(HeaderTransition::Push { from, to, progress }) => (
44            None,
45            HeaderTitle {
46                title: title_for(from),
47                center: Point::new(lerp_i32(center.x, back.x, progress), center.y),
48            },
49            Some(HeaderTitle {
50                title: title_for(to),
51                center: Point::new(lerp_i32(right.x, center.x, progress), center.y),
52            }),
53        ),
54        Some(HeaderTransition::Pop { from, to, progress }) => (
55            None,
56            HeaderTitle {
57                title: title_for(to),
58                center: Point::new(lerp_i32(back.x, center.x, progress), center.y),
59            },
60            Some(HeaderTitle {
61                title: title_for(from),
62                center: Point::new(lerp_i32(center.x, right.x, progress), center.y),
63            }),
64        ),
65        None => (
66            nav.previous().map(title_for),
67            HeaderTitle {
68                title: title_for(nav.top()),
69                center,
70            },
71            None,
72        ),
73    }
74}
75
76pub(super) fn draw_title<D>(
77    display: &mut D,
78    title: &str,
79    center: Point,
80    style: MonoTextStyle<'_, Rgb565>,
81    text_style: TextStyle,
82) where
83    D: DrawTarget<Color = Rgb565>,
84{
85    Text::with_text_style(title, center, style, text_style)
86        .draw(display)
87        .ok();
88}
89
90pub(super) fn back_title_center(button: Option<&Button<'_, NavHeaderAction>>) -> Point {
91    if let Some(button) = button {
92        Point::new(
93            button.frame.top_left.x + 68,
94            button.frame.top_left.y + (button.frame.size.height / 2) as i32,
95        )
96    } else {
97        Point::zero()
98    }
99}
100
101pub(super) fn back_button<'a>(header: Rectangle) -> Button<'a, NavHeaderAction> {
102    Button::new(
103        Rectangle::new(
104            header.top_left + Point::new(16, 12),
105            Size::new(BACK_BUTTON_WIDTH, header.size.height.saturating_sub(24)),
106        ),
107        ButtonSpec {
108            key: NavHeaderAction::Back,
109            icon: None,
110            label: Localized::new("", ""),
111            kind: ButtonKind::Ghost,
112        },
113    )
114}