1use core::convert::Infallible;
2
3use embedded_graphics::{
4 Drawable, Pixel,
5 draw_target::DrawTarget,
6 geometry::{OriginDimensions, Size},
7 pixelcolor::Rgb565,
8 prelude::{Point, Primitive, RgbColor},
9 primitives::Rectangle,
10};
11
12use faststep::{
13 ChildView, DisplayPort, FsTheme, I18n, ListDataSource, ListDelegate, ListRow, ListSelection,
14 ListView, Localized, TouchEvent, TouchPhase, UiCanvas, UiSystem, UiView, ViewEnvironment,
15 ViewEvent, ViewKind, ViewRedraw, ViewRegistration,
16};
17
18#[derive(Clone, Copy, Debug, PartialEq, Eq)]
19enum DemoViewId {
20 DevicesList,
21 AlertOverlay,
22}
23
24#[derive(Clone, Copy, Debug, PartialEq, Eq)]
25enum DemoMessage {
26 DeviceTapped(u8),
27}
28
29struct RootView {
30 list: ListView<DeviceDataSource, DeviceDelegate>,
31}
32
33impl RootView {
34 fn new() -> Self {
35 Self {
36 list: ListView::new(DeviceDataSource, DeviceDelegate),
37 }
38 }
39}
40
41impl UiView<'static, DemoViewId, DemoMessage, 2> for RootView {
42 fn configure(&mut self, registration: &mut ViewRegistration<'static, DemoViewId, 2>) {
43 registration.set_title(Localized::new("root.title", "Devices"));
44 registration.set_clips_to_bounds(true);
45 let list_frame = registration.frame();
46 let _ = registration.add_child(
47 ChildView::new(DemoViewId::DevicesList, list_frame)
48 .with_kind(ViewKind::List)
49 .with_title(Localized::new("devices.title", "Devices")),
50 );
51 let _ = registration.add_child(
52 ChildView::new(
53 DemoViewId::AlertOverlay,
54 Rectangle::new(Point::new(16, 16), Size::new(0, 0)),
55 )
56 .with_kind(ViewKind::AlertHost)
57 .with_hidden(true)
58 .with_alpha(0),
59 );
60 }
61
62 fn update(
63 &mut self,
64 dt_ms: u32,
65 registration: &ViewRegistration<'static, DemoViewId, 2>,
66 _env: &ViewEnvironment<'_, 'static>,
67 ) -> ViewEvent<DemoMessage> {
68 let list = registration.children()[0].frame;
69 ViewEvent::redraw(self.list.tick(dt_ms, list))
70 }
71
72 fn handle_touch(
73 &mut self,
74 touch: TouchEvent,
75 registration: &ViewRegistration<'static, DemoViewId, 2>,
76 _env: &ViewEnvironment<'_, 'static>,
77 ) -> ViewEvent<DemoMessage> {
78 self.list
79 .handle_touch(touch, registration.children()[0].frame)
80 .into_view_event()
81 }
82
83 fn draw<D>(
84 &self,
85 display: &mut D,
86 registration: &ViewRegistration<'static, DemoViewId, 2>,
87 env: &ViewEnvironment<'_, 'static>,
88 ) where
89 D: DrawTarget<Color = Rgb565>,
90 {
91 self.list
92 .draw(display, registration.children()[0].frame, env);
93 }
94}
95
96struct DeviceDataSource;
97
98impl ListDataSource for DeviceDataSource {
99 type ItemId = u8;
100
101 fn item_count(&self) -> usize {
102 3
103 }
104
105 fn item_id(&self, index: usize) -> Self::ItemId {
106 index as u8
107 }
108
109 fn item_height(&self, index: usize) -> u32 {
110 match index {
111 0 => 64,
112 1 => 88,
113 _ => 72,
114 }
115 }
116}
117
118struct DeviceDelegate;
119
120impl ListDelegate<'static, u8> for DeviceDelegate {
121 type Message = DemoMessage;
122
123 fn draw_row<D>(&self, display: &mut D, row: ListRow<u8>, _env: &ViewEnvironment<'_, 'static>)
124 where
125 D: DrawTarget<Color = Rgb565>,
126 {
127 let color = if row.state.highlighted {
128 Rgb565::WHITE
129 } else {
130 match row.item.id {
131 0 => Rgb565::RED,
132 1 => Rgb565::GREEN,
133 _ => Rgb565::BLUE,
134 }
135 };
136 row.item
137 .frame
138 .into_styled(embedded_graphics::primitives::PrimitiveStyle::with_fill(
139 color,
140 ))
141 .draw(display)
142 .ok();
143 }
144
145 fn did_select_item(&mut self, selection: ListSelection<u8>) -> Option<Self::Message> {
146 Some(DemoMessage::DeviceTapped(selection.id))
147 }
148}
149
150struct NullDisplay {
151 bounds: Rectangle,
152}
153
154impl NullDisplay {
155 fn new(bounds: Rectangle) -> Self {
156 Self { bounds }
157 }
158}
159
160struct NullCanvas {
161 size: Size,
162}
163
164impl OriginDimensions for NullCanvas {
165 fn size(&self) -> Size {
166 self.size
167 }
168}
169
170impl DrawTarget for NullCanvas {
171 type Color = Rgb565;
172 type Error = Infallible;
173
174 fn draw_iter<I>(&mut self, _pixels: I) -> Result<(), Self::Error>
175 where
176 I: IntoIterator<Item = Pixel<Self::Color>>,
177 {
178 Ok(())
179 }
180}
181
182impl UiCanvas for NullCanvas {
183 fn dim_rect(&mut self, _area: Rectangle, _alpha: u8) {}
184}
185
186impl DisplayPort for NullDisplay {
187 type Canvas = NullCanvas;
188 type Error = Infallible;
189
190 fn bounds(&self) -> Rectangle {
191 self.bounds
192 }
193
194 fn draw_frame<F>(&mut self, draw: F) -> Result<(), Self::Error>
195 where
196 F: FnOnce(&mut Self::Canvas),
197 {
198 let mut canvas = NullCanvas {
199 size: self.bounds.size,
200 };
201 draw(&mut canvas);
202 Ok(())
203 }
204}
205
206fn main() {
207 let bounds = Rectangle::new(Point::zero(), Size::new(320, 240));
208 let mut system = UiSystem::new(
209 NullDisplay::new(bounds),
210 RootView::new(),
211 FsTheme::default(),
212 I18n::new("en", "en", &[]),
213 );
214
215 let redraw = system.update(16).redraw;
216 let _ = system.draw_redraw(redraw);
217 let _ = system.handle_touch(TouchEvent::new(Point::new(24, 24), TouchPhase::Start, 1));
218 let _ = system.handle_touch(TouchEvent::new(Point::new(24, 24), TouchPhase::End, 2));
219 let _ = system.draw();
220 let _ = system.registration();
221 let _ = ViewRedraw::Full;
222}