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}