embedded_menu/items/
mod.rs1pub mod menu_item;
2
3pub use menu_item::MenuItem;
4
5use embedded_graphics::{
6 draw_target::DrawTarget,
7 mono_font::MonoTextStyle,
8 pixelcolor::BinaryColor,
9 prelude::{Point, Size},
10 primitives::Rectangle,
11 text::{renderer::TextRenderer, Baseline},
12 Drawable,
13};
14use embedded_layout::prelude::*;
15use embedded_text::{alignment::HorizontalAlignment, style::TextBoxStyleBuilder, TextBox};
16
17pub trait Marker {}
19
20pub trait MenuListItem<R>: Marker + View {
21 fn value_of(&self) -> R;
23
24 fn interact(&mut self) -> R;
25
26 fn set_style(&mut self, text_style: &MonoTextStyle<'_, BinaryColor>);
27
28 fn selectable(&self) -> bool {
33 true
34 }
35
36 fn draw_styled<D>(
37 &self,
38 text_style: &MonoTextStyle<'static, BinaryColor>,
39 display: &mut D,
40 ) -> Result<(), D::Error>
41 where
42 D: DrawTarget<Color = BinaryColor>;
43}
44
45pub struct MenuLine {
47 bounds: Rectangle,
48 value_width: u32,
49}
50
51impl MenuLine {
52 pub fn new(longest_value: &str, text_style: &MonoTextStyle<'_, BinaryColor>) -> Self {
53 let value_width = text_style
54 .measure_string(longest_value, Point::zero(), Baseline::Top)
55 .bounding_box
56 .size
57 .width;
58
59 MenuLine {
60 bounds: Rectangle::new(
61 Point::zero(),
62 Size::new(1, text_style.font.character_size.height - 1),
63 ),
64 value_width,
65 }
66 }
67
68 pub fn empty() -> Self {
69 MenuLine {
70 bounds: Rectangle::new(Point::zero(), Size::new(1, 0)),
71 value_width: 0,
72 }
73 }
74
75 pub fn draw_styled<D>(
76 &self,
77 title: &str,
78 value_text: &str,
79 text_style: &MonoTextStyle<'static, BinaryColor>, display: &mut D,
81 ) -> Result<(), D::Error>
82 where
83 D: DrawTarget<Color = BinaryColor>,
84 {
85 let display_area = display.bounding_box();
86
87 if self.bounds.intersection(&display_area).size.height == 0 {
88 return Ok(());
89 }
90
91 let mut text_bounds = Rectangle::new(
92 self.bounds.top_left,
93 Size::new(display_area.size.width, self.bounds.size.height + 1),
94 );
95
96 TextBox::with_textbox_style(
97 value_text,
98 text_bounds,
99 *text_style,
100 TextBoxStyleBuilder::new()
101 .alignment(HorizontalAlignment::Right)
102 .build(),
103 )
104 .draw(display)?;
105
106 text_bounds.size.width -= self.value_width;
107 TextBox::new(title, text_bounds, *text_style).draw(display)?;
108
109 Ok(())
110 }
111}
112
113impl View for MenuLine {
114 fn translate_impl(&mut self, by: Point) {
115 self.bounds.translate_mut(by);
116 }
117
118 fn bounds(&self) -> Rectangle {
119 self.bounds
120 }
121}