ptsd/interactions/
slider.rs1use 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>>;