1use prism::drawable::{Component, Drawable, SizedTree, RequestTree, Rect, DynClone, clone_trait_object};
2use prism::{Context, Request};
3use prism::canvas::{Area as CanvasArea, Item as CanvasItem};
4use prism::event::{OnEvent, Event};
5use prism::layout::{Area, Stack};
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, Component, Clone)]
56pub struct Pages {
57 layout: Stack,
58 #[allow(clippy::type_complexity)] inner: EitherOr<Enum<Box<dyn AppPage>>, Option<Box<dyn FlowContainer>>>,
59 #[skip] history: Vec<Box<dyn FlowContainer>>
60}
61
62impl OnEvent for Pages {
63 fn on_event(&mut self, _ctx: &mut Context, _sized: &SizedTree, mut event: Box<dyn Event>) -> Vec<Box<dyn Event>> {
64 if let Some(e) = event.downcast_mut::<NavigationEvent>() {
65 match e {
66 NavigationEvent::Push(flow, ..) => self.push(flow.take().unwrap()),
67 NavigationEvent::Reset => self.try_back(),
68 NavigationEvent::Root(root) => self.root(Some(root.to_string())),
69 _ => {return vec![event]}
70 }
71 return vec![];
72 }
73
74 vec![event]
75 }
76}
77
78impl Pages {
79 pub fn new(roots: Vec<(String, Box<dyn AppPage>)>) -> Self {
80 let first = roots[0].0.to_string();
81 let roots = Enum::new(roots, first);
82 Pages {
83 layout: Stack::default(),
84 inner: EitherOr::new(roots, None),
85 history: Vec::new(),
86 }
87 }
88
89 pub fn root(&mut self, page: Option<String>) {
90 self.inner.display_left(true);
91 if let Some(p) = page { self.inner.left().display(&p); }
92 self.history = vec![];
93 *self.inner.right() = None;
94 }
95
96 pub fn try_back(&mut self) {
97 if let Some(flow) = self.history.pop() {
98 self.inner.right().replace(flow);
99 } else {
100 self.root(None);
101 }
102 }
103
104 pub fn push(&mut self, flow: Box<dyn FlowContainer>) {
105 if let Some(old) = self.inner.right().replace(flow) {
106 self.history.push(old);
107 }
108 self.inner.display_left(false);
109 }
110
111 pub fn current(&mut self) -> &mut Box<dyn AppPage> {
112 if !self.history.is_empty() || self.inner.right().is_some() {
113 self.inner.right().as_mut().unwrap().flow().current.as_mut().unwrap()
114 } else {
115 self.inner.left().drawable().inner()
116 }
117 }
118}
119
120#[derive(Debug, Clone)]
121pub enum NavigationEvent {
122 Pop,
123 Push(Option<Box<dyn FlowContainer>>, Vec<usize>),
124 Reset,
125 Root(String),
126 Error(String),
127 Next,
128}
129
130impl NavigationEvent {
131 pub fn push(flow: impl FlowContainer + 'static) -> Self {
132 NavigationEvent::Push(Some(Box::new(flow)), vec![])
133 }
134}
135
136impl Event for NavigationEvent {
137 fn pass(self: Box<Self>, _ctx: &mut Context, children: &[Area]) -> Vec<Option<Box<dyn Event>>> {
138 let v = match self.as_ref() {
139 NavigationEvent::Push(Some(_), v) => Some(v.clone()),
140 _ => None
141 };
142
143 if v.is_none() {
144 return children.iter().map(|_| Some(self.clone() as Box<dyn Event>)).collect();
145 }
146
147 let v = v.unwrap();
148
149 let mut x = Some(self as Box<dyn Event>);
150 children.iter().enumerate().map(|(i, _)| if v.contains(&i) {None} else {x.take()}).collect()
151 }
152}
153
154pub trait FlowContainer: Drawable + DynClone + std::fmt::Debug + 'static {
171 fn flow(&mut self) -> &mut Flow;
172}
173
174clone_trait_object!(FlowContainer);
175
176impl Drawable for Box<dyn FlowContainer> {
177 fn request_size(&self) -> RequestTree {Drawable::request_size(&**self)}
178 fn build(&self, size: (f32, f32), request: RequestTree) -> SizedTree {
179 Drawable::build(&**self, size, request)
180 }
181 fn draw(&self, sized: &SizedTree, offset: (f32, f32), bound: Rect) -> Vec<(CanvasArea, CanvasItem)> {
182 Drawable::draw(&**self, sized, offset, bound)
183 }
184
185 fn name(&self) -> String {Drawable::name(&**self)}
186
187 fn event(&mut self, ctx: &mut Context, sized: &SizedTree, event: Box<dyn Event>) {
188 Drawable::event(&mut **self, ctx, sized, event)
189 }
190}
191
192pub trait AppPage: Drawable + DynClone + std::fmt::Debug + 'static {}
193downcast_rs::impl_downcast!(AppPage);
194impl Drawable for Box<dyn AppPage> {
195 fn request_size(&self) -> RequestTree {Drawable::request_size(&**self)}
196 fn build(&self, size: (f32, f32), request: RequestTree) -> SizedTree {
197 Drawable::build(&**self, size, request)
198 }
199 fn draw(&self, sized: &SizedTree, offset: (f32, f32), bound: Rect) -> Vec<(CanvasArea, CanvasItem)> {
200 Drawable::draw(&**self, sized, offset, bound)
201 }
202
203 fn name(&self) -> String {Drawable::name(&**self)}
204
205 fn event(&mut self, ctx: &mut Context, sized: &SizedTree, event: Box<dyn Event>) {
206 Drawable::event(&mut **self, ctx, sized, event)
207 }
208}
209
210clone_trait_object!(AppPage);