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