Skip to main content

ptsd/interface/
navigation.rs

1use prism::drawable::{Component, Drawable, SizedTree, RequestTree, Rect, DynClone, clone_trait_object};
2use prism::{Context, Request, Hardware};
3use prism::canvas::{Area as CanvasArea, Item as CanvasItem};
4use prism::event::{OnEvent, Event};
5use prism::layout::{Area, Stack, Offset, Size, Padding};
6use prism::display::{EitherOr, Enum};
7
8// should this be a trait so that "FlowStorage" and other variables stay alive?
9#[derive(Debug, Component, Clone)]
10pub struct Flow {
11    layout: Stack,
12    pub current: Option<Box<dyn AppPage>>,
13    #[skip] pub stored: Vec<Box<dyn AppPage>>,
14    #[skip] pub index: usize
15}
16
17impl Flow {
18    pub fn new(mut pages: Vec<Box<dyn AppPage>>) -> Self {
19        Flow {
20            layout: Stack::default(),
21            current: Some(pages.remove(0)),
22            stored: pages,
23            index: 0
24        }
25    }
26}
27
28impl OnEvent for Flow {
29    fn on_event(&mut self, ctx: &mut Context, _sized: &SizedTree, mut event: Box<dyn Event>) -> Vec<Box<dyn Event>> {
30        if let Some(event) = event.downcast_mut::<NavigationEvent>() {
31            let i = self.index;
32            match event {
33                NavigationEvent::Pop => {
34                    if self.index == 0 {
35                        self.index = 0;
36                        ctx.send(Request::event(NavigationEvent::Reset));
37                    } else {
38                        self.index -= 1;
39                    }
40                },
41                NavigationEvent::Next if self.index < self.stored.len() => self.index += 1,
42                _ => {}
43            }
44            
45            self.stored.insert(i, self.current.take().unwrap()); 
46        
47            if self.stored.get(self.index).is_some() {
48                self.current = Some(self.stored.remove(self.index));
49            }
50        }
51        vec![event]
52    }
53}
54
55#[derive(Debug, Clone, Component)]
56pub struct History(Stack, Vec<Box<dyn FlowContainer>>);
57impl OnEvent for History {
58    fn on_event(&mut self, _ctx: &mut Context, _sized: &SizedTree, event: Box<dyn Event>) -> Vec<Box<dyn Event>> {
59        if event.downcast_ref::<NavigationEvent>().is_some() { return vec![]; }
60        vec![event]
61    }
62}
63
64// impl Component for History {
65//     fn children(&self) -> Vec<&dyn Drawable> {vec![]}
66//     fn children_mut(&mut self) -> Vec<&mut dyn Drawable> {vec![]}
67//     fn layout(&self) -> &dyn prism::layout::Layout {&self.0}
68// }
69
70impl History {
71    pub fn new(h: Vec<Box<dyn FlowContainer>>) -> Self {
72        History(Stack::new(Offset::Start, Offset::Start, Size::Static(0.0), Size::Static(0.0), Padding::default()), h)
73    }
74
75    pub fn inner(&mut self) -> &mut Vec<Box<dyn FlowContainer>> {&mut self.1}
76}
77
78#[derive(Debug, Component, Clone)]
79pub struct Pages {
80    layout: Stack,
81    #[allow(clippy::type_complexity)] inner: EitherOr<Enum<Box<dyn AppPage>>, Option<Box<dyn FlowContainer>>>,
82    history: History,
83}
84
85impl OnEvent for Pages {
86    fn on_event(&mut self, ctx: &mut Context, _sized: &SizedTree, mut event: Box<dyn Event>) -> Vec<Box<dyn Event>> {
87        if let Some(e) = event.downcast_mut::<NavigationEvent>() {
88            ctx.send(Request::Hardware(Hardware::StopCamera));
89            match e {
90                NavigationEvent::Push(flow, ..) => self.push(flow.take().unwrap()),
91                NavigationEvent::Reset => self.try_back(),
92                NavigationEvent::Root(root) => self.root(Some(root.to_string())),
93                _ => {return vec![event]}
94            }
95            return vec![];
96        }
97
98        vec![event]
99    }
100}
101
102impl Pages {
103    pub fn new(roots: Vec<(String, Box<dyn AppPage>)>) -> Self {
104        let first = roots[0].0.to_string();
105        let roots = Enum::new(roots, first);
106        Pages {
107            layout: Stack::default(),
108            inner: EitherOr::new(roots, None),
109            history: History::new(Vec::new()),
110        }
111    }
112
113    pub fn root(&mut self, page: Option<String>) {
114        self.inner.display_left(true);
115        if let Some(p) = page { self.inner.left().display(&p); }
116        *self.history.inner() = vec![];
117        *self.inner.right() = None;
118    }
119
120    pub fn try_back(&mut self) {
121        if let Some(flow) = self.history.inner().pop() {
122            self.inner.right().replace(flow);
123        } else {
124            self.root(None);
125        }
126    }
127
128    pub fn push(&mut self, flow: Box<dyn FlowContainer>) {
129        if let Some(old) = self.inner.right().replace(flow) { 
130            self.history.inner().push(old);
131        }
132        self.inner.display_left(false);
133    }
134
135    pub fn current(&mut self) -> &mut Box<dyn AppPage> {
136        if !self.history.inner().is_empty() || self.inner.right().is_some() {
137            self.inner.right().as_mut().unwrap().flow().current.as_mut().unwrap()
138        } else {
139            self.inner.left().drawable().inner()
140        }
141    }
142
143    pub fn is_root(&self) -> bool { self.inner.is_left() }
144}
145
146#[derive(Debug, Clone)]
147pub enum NavigationEvent {
148    Pop,
149    Push(Option<Box<dyn FlowContainer>>, Vec<usize>),
150    Reset,
151    Root(String),
152    Error(String),
153    Next,
154}
155
156impl NavigationEvent {
157    pub fn push(flow: impl FlowContainer + 'static) -> Self {
158        NavigationEvent::Push(Some(Box::new(flow)), vec![])
159    }
160}
161
162impl Event for NavigationEvent {
163    fn pass(self: Box<Self>, _ctx: &mut Context, children: &[Area]) -> Vec<Option<Box<dyn Event>>> {
164        let v = match self.as_ref() {
165            NavigationEvent::Push(Some(_), v) => Some(v.clone()),
166            _ => None
167        };
168
169        if v.is_none() { return children.iter().map(|_| Some(self.clone() as Box<dyn Event>)).collect(); }
170
171        let v = v.unwrap();
172
173        let mut x = Some(self as Box<dyn Event>);
174        children.iter().enumerate().map(|(i, _)| if v.contains(&i) {None} else {x.take()}).collect()
175    }
176}
177
178// impl Event for NavigationEvent {
179//     fn pass(self: Box<Self>, _ctx: &mut Context, children: &[Area]) -> Vec<Option<Box<dyn Event>>> {
180//         println!("Children {:?}", children.len());
181//         children.iter().enumerate().map(|(i, _)| match *self {
182//             NavigationEvent::Push(_, ref v) => {
183//                 (!v.contains(&i)).then(|| {
184//                     let mut e: NavigationEvent = (*self).clone();
185//                     if let NavigationEvent::Push(_, ref mut v2) = e {v2.clear();}
186//                     Box::new(e) as Box<dyn Event>
187//                 })
188//             },
189//             _ =>  Some(Box::new((*self).clone()) as Box<dyn Event>),
190//         }).collect()
191//     }
192// }
193
194pub trait FlowContainer: Drawable + DynClone + std::fmt::Debug + 'static {
195    fn flow(&mut self) -> &mut Flow;
196}
197
198clone_trait_object!(FlowContainer);
199
200impl Drawable for Box<dyn FlowContainer> {
201    fn request_size(&self) -> RequestTree {Drawable::request_size(&**self)}
202    fn build(&self, size: (f32, f32), request: RequestTree) -> SizedTree {
203        Drawable::build(&**self, size, request)
204    }
205    fn draw(&self, sized: &SizedTree, offset: (f32, f32), bound: Rect) -> Vec<(CanvasArea, CanvasItem)> {
206        Drawable::draw(&**self, sized, offset, bound)
207    }
208
209    fn name(&self) -> String {Drawable::name(&**self)}
210
211    fn event(&mut self, ctx: &mut Context, sized: &SizedTree, event: Box<dyn Event>) {
212        Drawable::event(&mut **self, ctx, sized, event)
213    }
214}
215
216pub trait AppPage: Drawable + DynClone + std::fmt::Debug + 'static {}
217downcast_rs::impl_downcast!(AppPage);
218impl Drawable for Box<dyn AppPage> {
219    fn request_size(&self) -> RequestTree {Drawable::request_size(&**self)}
220    fn build(&self, size: (f32, f32), request: RequestTree) -> SizedTree {
221        Drawable::build(&**self, size, request)
222    }
223    fn draw(&self, sized: &SizedTree, offset: (f32, f32), bound: Rect) -> Vec<(CanvasArea, CanvasItem)> {
224        Drawable::draw(&**self, sized, offset, bound)
225    }
226
227    fn name(&self) -> String {Drawable::name(&**self)}
228
229    fn event(&mut self, ctx: &mut Context, sized: &SizedTree, event: Box<dyn Event>) {
230        Drawable::event(&mut **self, ctx, sized, event)
231    }
232}
233
234clone_trait_object!(AppPage);