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#[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
64impl 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
178pub 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);