1use prism::drawable::{Component, Drawable, SizedTree, RequestTree, Rect, DynClone, clone_trait_object};
2use prism::Context;
3use prism::event::{OnEvent, Event};
4use prism::layout::{Area, Column, Offset, Padding, Size, Row};
5use prism::display::Opt;
6use prism::canvas::{Area as CanvasArea, Item as CanvasItem};
7
8use crate::interface::navigation::Pages;
9use crate::navigation::NavigationEvent;
10
11#[derive(Component, Clone, Debug)]
12pub enum Interface {
13 Mobile {
14 layout: Column,
15 body: Box<dyn Body>,
16 keyboard: Opt<Box<dyn Drawable>>,
17 navigator: Option<Opt<Box<dyn Navigator>>>,
18 },
19
20 Desktop {
21 layout: Row,
22 navigator: Option<Opt<Box<dyn Navigator>>>,
23 body: Box<dyn Body>
24 },
25
26 Web {
27 layout: Column,
28 navigator: Option<Opt<Box<dyn Navigator>>>,
29 body: Box<dyn Body>
30 }
31}
32
33
34impl OnEvent for Interface {
35 fn on_event(&mut self, _ctx: &mut Context, _sized: &SizedTree, mut event: Box<dyn Event>) -> Vec<Box<dyn Event>> {
36 if let Some(NavigationEvent::Push(_, v)) = event.downcast_mut::<NavigationEvent>() {*v = if let Interface::Desktop{navigator,..} = self && navigator.is_some() {vec![0]} else {vec![]};}
37
38 if let Interface::Mobile{keyboard, ..} = self
39 && let Some(ShowKeyboard(b)) = event.downcast_ref::<ShowKeyboard>() {
40 keyboard.display(*b);
41 }
42
43 vec![event]
44 }
45}
46
47impl Interface {
48 pub fn desktop(navigator: Option<Box<dyn Navigator>>, body: impl Body + 'static) -> Self {
49 Interface::Desktop {
50 layout: Row::start(0.0),
51 navigator: navigator.map(|n| Opt::new(n, true)),
52 body: Box::new(body)
53 }
54 }
55
56 pub fn mobile(navigator: Option<Box<dyn Navigator>>, body: impl Body + 'static, keyboard: impl Drawable + 'static) -> Self {
57 let (top, bottom) = (18.0, 18.0);
59 let layout = Column::new(0.0, Offset::Center, Size::Fit, Padding(0.0, top, 0.0, bottom), None);
60
61 Interface::Mobile {
62 layout,
63 body: Box::new(body),
64 keyboard: Opt::new(Box::new(keyboard), false),
65 navigator: navigator.map(|n| Opt::new(n, true)),
66 }
67 }
68
69 pub fn web(navigator: Option<Box<dyn Navigator>>, body: impl Body + 'static) -> Self {
70 let layout = Column::new(0.0, Offset::Start, Size::Fill, Padding::default(), None);
71 Interface::Web {
72 layout,
73 navigator: navigator.map(|n| Opt::new(n, true)),
74 body: Box::new(body),
75 }
76 }
77
78 pub fn pages(&mut self) -> &mut Pages {
79 match self {
80 Interface::Desktop {body, ..} => body.pages(),
81 Interface::Mobile {body, ..} => body.pages(),
82 Interface::Web {body, ..} => body.pages(),
83 }
84 }
85
86 pub fn navigator(&mut self) -> &mut Option<Opt<Box<dyn Navigator>>> {
87 match self {
88 Interface::Desktop {navigator, ..} => navigator,
89 Interface::Mobile {navigator, ..} => navigator,
90 Interface::Web {navigator, ..} => navigator,
91 }
92 }
93}
94
95#[derive(Debug, Clone)]
97pub struct ShowKeyboard(pub bool);
98
99impl Event for ShowKeyboard {
100 fn pass(self: Box<Self>, _ctx: &mut Context, children: &[Area]) -> Vec<Option<Box<dyn Event>>> {
101 children.iter().map(|_| Some(self.clone() as Box<dyn Event>)).collect()
102 }
103}
104
105pub trait Body: Drawable + DynClone + std::fmt::Debug + 'static {
106 fn pages(&mut self) -> &mut Pages;
107}
108
109clone_trait_object!(Body);
110
111pub trait Navigator: Drawable + DynClone + std::fmt::Debug + 'static {}
112
113clone_trait_object!(Navigator);
114
115impl Drawable for Box<dyn Navigator> {
116 fn request_size(&self) -> RequestTree {Drawable::request_size(&**self)}
117 fn build(&self, size: (f32, f32), request: RequestTree) -> SizedTree {
118 Drawable::build(&**self, size, request)
119 }
120 fn draw(&self, sized: &SizedTree, offset: (f32, f32), bound: Rect) -> Vec<(CanvasArea, CanvasItem)> {
121 Drawable::draw(&**self, sized, offset, bound)
122 }
123
124 fn name(&self) -> String {Drawable::name(&**self)}
125
126 fn event(&mut self, ctx: &mut Context, sized: &SizedTree, event: Box<dyn Event>) {
127 Drawable::event(&mut **self, ctx, sized, event)
128 }
129}
130
131