Skip to main content

ptsd/interface/
interfaces.rs

1use prism::drawable::{Component, Drawable, SizedTree, RequestTree, Rect, DynClone, clone_trait_object};
2use prism::{Context, IS_MOBILE};
3use prism::event::{OnEvent, Event, TickEvent};
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 event.downcast_mut::<NavigationEvent>().is_some() && let Interface::Mobile{keyboard, ..} = self {
37            keyboard.display(false);
38        }
39        
40        if let Some(NavigationEvent::Push(_, v)) = event.downcast_mut::<NavigationEvent>() {*v = if let Interface::Desktop{navigator,..} = self && navigator.is_some() {vec![0]} else {vec![]};}
41
42        if let Interface::Mobile{keyboard, ..} = self 
43        && let Some(ShowKeyboard(b)) = event.downcast_ref::<ShowKeyboard>() {
44            keyboard.display(*b);
45        }
46
47        if IS_MOBILE && event.downcast_ref::<TickEvent>().is_some() {
48            let is_root = self.pages().is_root();
49            if let Some(s) = self.navigator().as_mut() { s.display(is_root) }
50        }
51
52        vec![event]
53    }
54}
55
56impl Interface {
57    pub fn desktop(navigator: Option<Box<dyn Navigator>>, body: impl Body + 'static) -> Self {
58        Interface::Desktop {
59            layout: Row::start(0.0), 
60            navigator: navigator.map(|n| Opt::new(n, true)),
61            body: Box::new(body)
62        }
63    }
64
65    pub fn mobile(navigator: Option<Box<dyn Navigator>>, body: impl Body + 'static, keyboard: impl Drawable + 'static) -> Self {
66        Interface::Mobile {
67            layout: Column::new(0.0, Offset::Center, Size::Fit, Padding::default(), None),
68            body: Box::new(body),
69            keyboard: Opt::new(Box::new(keyboard), false),
70            navigator: navigator.map(|n| Opt::new(n, true)),
71        }
72    }
73
74    pub fn web(navigator: Option<Box<dyn Navigator>>, body: impl Body + 'static) -> Self {
75        let layout = Column::new(0.0, Offset::Start, Size::Fill, Padding::default(), None);
76        Interface::Web {
77            layout, 
78            navigator: navigator.map(|n| Opt::new(n, true)),
79            body: Box::new(body),
80        }
81    }
82
83    pub fn pages(&mut self) -> &mut Pages {
84        match self {
85            Interface::Desktop {body, ..} => body.pages(),
86            Interface::Mobile {body, ..} => body.pages(),
87            Interface::Web {body, ..} => body.pages(),
88        }
89    }
90
91    pub fn navigator(&mut self) -> &mut Option<Opt<Box<dyn Navigator>>> {
92        match self {
93            Interface::Desktop {navigator, ..} => navigator,
94            Interface::Mobile {navigator, ..} => navigator,
95            Interface::Web {navigator, ..} => navigator,
96        }
97    }
98}
99
100/// Event used to open or close keyboard.
101#[derive(Debug, Clone)]
102pub struct ShowKeyboard(pub bool);
103
104impl Event for ShowKeyboard {
105    fn pass(self: Box<Self>, _ctx: &mut Context, children: &[Area]) -> Vec<Option<Box<dyn Event>>> {
106        children.iter().map(|_| Some(self.clone() as Box<dyn Event>)).collect()
107    }
108}
109
110pub trait Body: Drawable + DynClone + std::fmt::Debug + 'static {
111    fn pages(&mut self) -> &mut Pages;
112}
113
114clone_trait_object!(Body);
115
116pub trait Navigator: Drawable + DynClone + std::fmt::Debug + 'static {}
117
118clone_trait_object!(Navigator);
119
120impl Drawable for Box<dyn Navigator> {
121    fn request_size(&self) -> RequestTree {Drawable::request_size(&**self)}
122    fn build(&self, size: (f32, f32), request: RequestTree) -> SizedTree {
123        Drawable::build(&**self, size, request)
124    }
125    fn draw(&self, sized: &SizedTree, offset: (f32, f32), bound: Rect) -> Vec<(CanvasArea, CanvasItem)> {
126        Drawable::draw(&**self, sized, offset, bound)
127    }
128
129    fn name(&self) -> String {Drawable::name(&**self)}
130
131    fn event(&mut self, ctx: &mut Context, sized: &SizedTree, event: Box<dyn Event>) {
132        Drawable::event(&mut **self, ctx, sized, event)
133    }
134}
135
136