use crate::{application::{
states::{
clock::ClockState,
info::InfoState,
app::AppState,
uop::UopState,
mwatch::MWState,
notifications::NotificationState,
},
states::prelude::*
}, system::{input::InputEvent, System, Display}};
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Signal {
Next,
Previous,
Home
}
const MAX_STATES: i8 = 6;
pub struct DisplayManager
{
state_idx: i8,
clock_state: ClockState,
info_state: InfoState,
app_state: AppState,
uop_state: UopState,
mwatch_state: MWState,
notification_state: NotificationState,
}
impl Default for DisplayManager {
fn default() -> Self {
Self {
state_idx: 0,
clock_state: ClockState::default(),
info_state: InfoState::default(),
app_state: AppState::default(),
uop_state: UopState::default(),
mwatch_state: MWState::default(),
notification_state: NotificationState::default(),
}
}
}
impl DisplayManager
{
pub fn process(&mut self, system: &mut impl System, display: &mut impl Display) {
let signal = match self.state_idx {
0 => {
DisplayManager::static_state_render(&mut self.clock_state, system, display)
},
1 => {
DisplayManager::scoped_state_render(&mut self.app_state, system, display)
},
2 => {
DisplayManager::scoped_state_render(&mut self.notification_state, system, display)
},
3 => {
DisplayManager::static_state_render(&mut self.mwatch_state, system, display)
},
4 => {
DisplayManager::static_state_render(&mut self.uop_state, system, display)
},
5 => {
DisplayManager::static_state_render(&mut self.info_state, system, display)
},
_ => panic!("Unhandled state")
};
if let Some(signal) = signal {
self.handle_exit(signal);
}
}
pub fn service_input(&mut self, system: &mut impl System, input: InputEvent) {
let signal = match self.state_idx {
0 => {
DisplayManager::static_state_input(&mut self.clock_state, system, input)
},
1 => {
DisplayManager::scoped_state_input(&mut self.app_state, system, input)
}
2 => {
DisplayManager::scoped_state_input(&mut self.notification_state, system, input)
},
3 => {
DisplayManager::static_state_input(&mut self.mwatch_state, system, input)
},
4 => {
DisplayManager::static_state_input(&mut self.uop_state, system, input)
},
5 => {
DisplayManager::static_state_input(&mut self.info_state, system, input)
},
_ => panic!("Unhandled state")
};
if let Some(signal) = signal {
self.handle_exit(signal);
}
}
fn handle_exit(&mut self, code: Signal) {
match code {
Signal::Next => self.next(),
Signal::Previous => self.prev(),
Signal::Home => self.state_idx = 0,
}
}
fn prev(&mut self) {
self.state_idx -= 1;
if self.state_idx < 0 {
self.state_idx = MAX_STATES - 1;
}
}
fn next(&mut self) {
self.state_idx += 1;
if self.state_idx > MAX_STATES - 1 {
self.state_idx = 0;
}
}
fn static_state_render<S>(state: &mut S, system: &mut impl System, display: &mut impl Display) -> Option<Signal>
where S : StaticState
{
state.render(system, display)
}
fn scoped_state_render<S>(state: &mut S, system: &mut impl System, display: &mut impl Display) -> Option<Signal>
where S : ScopedState
{
if state.is_running(system) {
state.render(system, display)
} else {
state.preview(system, display)
}
}
fn static_state_input<S>(state: &mut S, system: &mut impl System, input: InputEvent) -> Option<Signal>
where S : StaticState
{
state.input(system, input)
}
fn scoped_state_input<S>(state: &mut S, system: &mut impl System, input: InputEvent) -> Option<Signal>
where S : ScopedState
{
if state.is_running(system) {
state.input(system, input)
} else {
match input {
InputEvent::Middle => {
state.start(system);
None
}
InputEvent::Left => Some(Signal::Previous),
InputEvent::Right => Some(Signal::Next),
_ => None
}
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn dm_state_wraps() {
let mut dm = DisplayManager::default();
for _ in 0..MAX_STATES {
dm.next();
}
assert_eq!(dm.state_idx, 0)
}
#[test]
fn dm_state_prev_wraps() {
let mut dm = DisplayManager::default();
dm.prev();
assert_eq!(dm.state_idx, MAX_STATES - 1)
}
}