vizia_core/views/
xypad.rs1use crate::prelude::*;
2
3pub struct XYPad {
5 is_dragging: bool,
6
7 on_change: Option<Box<dyn Fn(&mut EventContext, f32, f32)>>,
8}
9
10impl XYPad {
11 pub fn new<R: Res<(f32, f32)> + 'static>(cx: &mut Context, value: R) -> Handle<Self> {
13 let value_state = value.to_signal(cx);
14 let left = Memo::new(move |_| Percentage(value_state.get().0 * 100.0));
15 let top = Memo::new(move |_| Percentage((1.0 - value_state.get().1) * 100.0));
16
17 Self { is_dragging: false, on_change: None }
18 .build(cx, |cx| {
19 Element::new(cx)
21 .position_type(PositionType::Absolute)
22 .left(left)
23 .top(top)
24 .translate(Translate::new(
25 Length::Value(LengthValue::Px(-6.0)),
26 Length::Value(LengthValue::Px(-6.0)),
27 ))
28 .size(Pixels(10.0))
29 .corner_radius(Percentage(50.0))
30 .border_width(Pixels(2.0))
31 .hoverable(false)
32 .class("thumb");
33 })
34 .overflow(Overflow::Hidden)
35 .border_width(Pixels(1.0))
36 .size(Pixels(200.0))
37 }
38}
39
40impl View for XYPad {
41 fn element(&self) -> Option<&'static str> {
42 Some("xypad")
43 }
44
45 fn event(&mut self, cx: &mut EventContext, event: &mut Event) {
46 event.map(|window_event, meta| match window_event {
47 WindowEvent::MouseDown(button) if *button == MouseButton::Left => {
48 if cx.is_disabled() {
49 return;
50 }
51 let current = cx.current();
52 cx.capture();
53 let mouse = cx.mouse();
54 if meta.target == current {
55 let mut dx = (mouse.left.pos_down.0 - cx.cache.get_posx(current))
56 / cx.cache.get_width(current);
57 let mut dy = (mouse.left.pos_down.1 - cx.cache.get_posy(current))
58 / cx.cache.get_height(current);
59
60 dx = dx.clamp(0.0, 1.0);
61 dy = dy.clamp(0.0, 1.0);
62
63 self.is_dragging = true;
64
65 if let Some(callback) = &self.on_change {
66 (callback)(cx, dx, 1.0 - dy);
67 }
68 }
69 }
70
71 WindowEvent::MouseUp(button) if *button == MouseButton::Left => {
72 cx.set_active(false);
73 cx.release();
74 self.is_dragging = false;
75 if meta.target == cx.current() {
76 cx.release();
77 }
78 }
79
80 WindowEvent::MouseMove(x, y) => {
81 if self.is_dragging {
82 let current = cx.current();
83 let mut dx = (*x - cx.cache.get_posx(current)) / cx.cache.get_width(current);
84 let mut dy = (*y - cx.cache.get_posy(current)) / cx.cache.get_height(current);
85
86 dx = dx.clamp(0.0, 1.0);
87 dy = dy.clamp(0.0, 1.0);
88
89 if let Some(callback) = &self.on_change {
90 (callback)(cx, dx, 1.0 - dy);
91 }
92 }
93 }
94
95 _ => {}
96 });
97 }
98}
99
100impl Handle<'_, XYPad> {
101 pub fn on_change<F: Fn(&mut EventContext, f32, f32) + 'static>(self, callback: F) -> Self {
103 self.modify(|xypad| xypad.on_change = Some(Box::new(callback)))
104 }
105}