Skip to main content

faststep/
system.rs

1use core::marker::PhantomData;
2
3use crate::{
4    DisplayPort, FsTheme, I18n, TouchEvent, UiView, ViewEnvironment, ViewEvent, ViewRedraw,
5    ViewRegistration,
6};
7
8/// Owns the root view, display, theme, localization, and registration state.
9pub struct UiSystem<'text, Display, Root, ViewId, Message, const N: usize>
10where
11    Display: DisplayPort,
12    Root: UiView<'text, ViewId, Message, N>,
13{
14    display: Display,
15    root: Root,
16    theme: FsTheme,
17    i18n: I18n<'text>,
18    registration: ViewRegistration<'text, ViewId, N>,
19    marker: PhantomData<Message>,
20}
21
22impl<'text, Display, Root, ViewId, Message, const N: usize>
23    UiSystem<'text, Display, Root, ViewId, Message, N>
24where
25    Display: DisplayPort,
26    Root: UiView<'text, ViewId, Message, N>,
27{
28    /// Creates a fully configured UI system and runs the root `configure` pass.
29    pub fn new(display: Display, root: Root, theme: FsTheme, i18n: I18n<'text>) -> Self {
30        let registration = ViewRegistration::new(display.bounds());
31        let mut system = Self {
32            display,
33            root,
34            theme,
35            i18n,
36            registration,
37            marker: PhantomData,
38        };
39        system.configure_root();
40        system
41    }
42
43    /// Re-runs the root configuration against the current display bounds.
44    pub fn configure_root(&mut self) {
45        self.registration.clear_children();
46        self.registration.set_frame(self.display.bounds());
47        self.root.configure(&mut self.registration);
48    }
49
50    /// Returns the root view.
51    pub const fn root(&self) -> &Root {
52        &self.root
53    }
54
55    /// Returns the root view mutably.
56    pub fn root_mut(&mut self) -> &mut Root {
57        &mut self.root
58    }
59
60    /// Returns the current root registration.
61    pub const fn registration(&self) -> &ViewRegistration<'text, ViewId, N> {
62        &self.registration
63    }
64
65    /// Returns the current root registration mutably.
66    pub fn registration_mut(&mut self) -> &mut ViewRegistration<'text, ViewId, N> {
67        &mut self.registration
68    }
69
70    /// Returns the active theme.
71    pub const fn theme(&self) -> &FsTheme {
72        &self.theme
73    }
74
75    /// Returns the active theme mutably.
76    pub fn theme_mut(&mut self) -> &mut FsTheme {
77        &mut self.theme
78    }
79
80    /// Returns the active localization tables.
81    pub const fn i18n(&self) -> &I18n<'text> {
82        &self.i18n
83    }
84
85    /// Returns the active localization tables mutably.
86    pub fn i18n_mut(&mut self) -> &mut I18n<'text> {
87        &mut self.i18n
88    }
89
90    /// Returns the display port.
91    pub const fn display(&self) -> &Display {
92        &self.display
93    }
94
95    /// Returns the display port mutably.
96    pub fn display_mut(&mut self) -> &mut Display {
97        &mut self.display
98    }
99
100    /// Borrows the display mutably and the root immutably for one closure.
101    pub fn with_display_and_root<R>(&mut self, apply: impl FnOnce(&mut Display, &Root) -> R) -> R {
102        let display = &mut self.display;
103        let root = &self.root;
104        apply(display, root)
105    }
106
107    /// Borrows the display and root mutably for one closure.
108    pub fn with_display_and_root_mut<R>(
109        &mut self,
110        apply: impl FnOnce(&mut Display, &mut Root) -> R,
111    ) -> R {
112        let display = &mut self.display;
113        let root = &mut self.root;
114        apply(display, root)
115    }
116
117    /// Runs one logical update tick on the root view.
118    pub fn update(&mut self, dt_ms: u32) -> ViewEvent<Message> {
119        let env = ViewEnvironment {
120            theme: &self.theme,
121            i18n: &self.i18n,
122        };
123        self.root.update(dt_ms, &self.registration, &env)
124    }
125
126    /// Routes one touch event into the root view.
127    pub fn handle_touch(&mut self, touch: TouchEvent) -> ViewEvent<Message> {
128        let env = ViewEnvironment {
129            theme: &self.theme,
130            i18n: &self.i18n,
131        };
132        self.root.handle_touch(touch, &self.registration, &env)
133    }
134
135    /// Draws a full frame through the display port.
136    pub fn draw(&mut self) -> Result<(), Display::Error> {
137        let env = ViewEnvironment {
138            theme: &self.theme,
139            i18n: &self.i18n,
140        };
141        self.display.draw_frame(|canvas| {
142            self.root.draw(canvas, &self.registration, &env);
143        })
144    }
145
146    /// Draws only what the supplied redraw request requires.
147    pub fn draw_redraw(&mut self, redraw: ViewRedraw) -> Result<(), Display::Error> {
148        match redraw {
149            ViewRedraw::None => Ok(()),
150            ViewRedraw::Full => self.draw(),
151            ViewRedraw::Dirty(area) => {
152                let env = ViewEnvironment {
153                    theme: &self.theme,
154                    i18n: &self.i18n,
155                };
156                self.display.draw_dirty(area, |canvas| {
157                    self.root.draw(canvas, &self.registration, &env);
158                })
159            }
160        }
161    }
162}