Skip to main content

ptsd/interface/
interfaces.rs

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 (_left, _right, top, bottom) = ctx.send(Request::Hardware(Hardware::SafeAreaInsets));
58        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/// Event used to open or close keyboard.
96#[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