Skip to main content

ptsd/interactions/
slider.rs

1use prism::event::{self, OnEvent, Event, TickEvent};
2use prism::drawable::{Drawable, Component, SizedTree};
3use prism::display::Bin;
4use prism::layout::{Stack, Size, Offset, Padding};
5use prism::{emitters, Context, Request, Hardware};
6
7use std::sync::{Arc, Mutex};
8
9#[derive(Component, Clone, Debug)]
10pub struct Slider(Stack, emitters::Slider<_Slider>);
11impl OnEvent for Slider {}
12impl Slider {
13    pub fn new(
14        start: f32, 
15        background: impl Drawable + 'static,
16        foreground: impl Drawable + 'static,
17        handle: impl Drawable + 'static,
18        callback: impl FnMut(&mut Context, f32) + Send + Sync + 'static
19    ) -> Self {
20        let slider = _Slider::new(start, background, foreground, handle, callback);
21        Self(Stack::default(), emitters::Slider::new(slider))
22    }
23}
24
25impl std::ops::Deref for Slider {
26    type Target = _Slider;
27    fn deref(&self) -> &Self::Target {&self.1.1}
28}
29
30impl std::ops::DerefMut for Slider {
31    fn deref_mut(&mut self) -> &mut Self::Target {&mut self.1.1}
32}
33
34#[derive(Component, Clone)]
35pub struct _Slider {
36    layout: Stack,
37    pub background: Bin<Stack, Box<dyn Drawable>>,
38    pub foreground: Bin<Stack, Box<dyn Drawable>>,
39    pub handle: Bin<Stack, Box<dyn Drawable>>,
40    #[skip] pub value: f32,
41    #[skip] closure: SliderClosure,
42}
43
44impl _Slider {
45    pub fn new(
46        start: f32, 
47        background: impl Drawable + 'static,
48        foreground: impl Drawable + 'static,
49        handle: impl Drawable + 'static,
50        callback: impl FnMut(&mut Context, f32) + Send + Sync + 'static
51    ) -> Self {
52        let min = Drawable::request_size(&handle).0.min_width();
53        let width = Size::custom(move |widths: Vec<(f32, f32)>| (widths[0].0.min(min), f32::MAX));
54        let b_layout = Stack(Offset::Start, Offset::Center, width, Size::Static(6.0), Padding::default());
55        let f_layout = Stack(Offset::Start, Offset::Start, Size::Static(30.0), Size::Static(6.0), Padding::default());
56        let k_layout = Stack(Offset::Start, Offset::Start, Size::Fit, Size::Fit, Padding::default());
57        let layout = Stack(Offset::Start, Offset::Center, Size::Fit, Size::Fit, Padding::default());
58
59        _Slider {
60            layout,
61            background: Bin(b_layout, Box::new(background)),
62            foreground: Bin(f_layout, Box::new(foreground)),
63            handle: Bin(k_layout, Box::new(handle)),
64            value: start, 
65            closure: Arc::new(Mutex::new(callback)),
66        }
67    }
68}
69
70impl OnEvent for _Slider {
71    fn on_event(&mut self, ctx: &mut Context, sized: &SizedTree, event: Box<dyn Event>) -> Vec<Box<dyn Event>> {
72        if let Some(event) = event.downcast_ref::<event::Slider>() {
73            if let Ok(mut cb) = self.closure.lock() { (cb)(ctx, self.value); }
74            match event {
75                event::Slider::Moved(x) => self.value = ((*x / sized.0.0) * 100.0).round() / 100.0,
76                event::Slider::Start(x) => {
77                    self.value = ((*x / sized.0.0) * 100.0).round() / 100.0;
78                    ctx.send(Request::Hardware(Hardware::Haptic));
79                },
80            }
81        } else if event.downcast_ref::<TickEvent>().is_some() {
82            let handle_size = Drawable::request_size(&(**self.handle.inner())).0.min_width() / 2.0;
83            let clamped_x = (sized.0.0 * self.value).clamp(0.0, sized.0.0);
84            self.handle.get_layout().0 = Offset::Static((clamped_x - handle_size).max(0.0));
85            self.foreground.get_layout().2 = Size::Static(clamped_x);
86        }
87
88        vec![event]
89    }
90}
91
92impl std::fmt::Debug for _Slider {
93    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94        write!(f, "_Slider")
95    }
96}
97
98type SliderClosure = Arc<Mutex<dyn FnMut(&mut Context, f32) + Send + Sync + 'static>>;