use crate::Ssd1351;
use crate::system::system::System;
use crate::application::states::{
clock::ClockState,
app::AppState,
};
use mwatch_kernel_api::InputEvent;
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Signal {
Next,
Previous,
Home
}
pub trait State: Default {
fn render(&mut self, system: &mut System, display: &mut Ssd1351) -> Option<Signal>;
fn input(&mut self, system: &mut System, display: &mut Ssd1351, input: InputEvent) -> Option<Signal>; }
pub trait StaticState: State {
}
pub trait ScopedState: State {
fn preview(&mut self, system: &mut System, display: &mut Ssd1351) -> Option<Signal>;
fn start(&mut self, system: &mut System);
fn is_running(&self, system: &mut System) -> bool;
fn stop(&mut self, system: &mut System);
}
const MAX_STATES: i8 = 2;
pub struct WindowManager
{
state_idx: i8,
clock_state: ClockState,
app_state: AppState,
}
impl WindowManager
{
pub fn new() -> Self {
Self {
state_idx: 0,
clock_state: ClockState::default(),
app_state: AppState::default(),
}
}
pub fn process(&mut self, system: &mut System, display: &mut Ssd1351) {
let signal = match self.state_idx {
0 => {
WindowManager::static_state_render(&mut self.clock_state, system, display)
},
1 => {
WindowManager::scoped_state_render(&mut self.app_state, system, display)
},
_ => panic!("Unhandled state")
};
if let Some(signal) = signal {
self.handle_exit(signal);
}
}
pub fn service_input(&mut self, system: &mut System, display: &mut Ssd1351, input: InputEvent) {
let signal = match self.state_idx {
0 => {
WindowManager::static_state_input(&mut self.clock_state, system, display, input)
},
1 => {
WindowManager::scoped_state_input(&mut self.app_state, system, display, 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 System, display: &mut Ssd1351) -> Option<Signal>
where S : StaticState
{
state.render(system, display)
}
fn scoped_state_render<S>(state: &mut S, system: &mut System, display: &mut Ssd1351) -> 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 System, display: &mut Ssd1351, input: InputEvent) -> Option<Signal>
where S : StaticState
{
state.input(system, display, input)
}
fn scoped_state_input<S>(state: &mut S, system: &mut System, display: &mut Ssd1351, input: InputEvent) -> Option<Signal>
where S : ScopedState
{
if state.is_running(system) {
state.input(system, display, input)
} else {
match input {
InputEvent::Middle => {
state.start(system);
None
}
InputEvent::Left => Some(Signal::Previous),
InputEvent::Right => Some(Signal::Next),
_ => None
}
}
}
}