freya_components/
draggable_canvas.rs

1use freya_core::prelude::*;
2use torin::prelude::{
3    Area,
4    CursorPoint,
5    Position,
6};
7
8#[derive(Clone)]
9struct DraggableCanvasLayout(State<Area>);
10
11#[derive(Clone)]
12struct DraggableCanvasRegistry(State<Vec<usize>>);
13
14#[derive(PartialEq)]
15pub struct DraggableCanvas {
16    children: Vec<Element>,
17    layout: LayoutData,
18    key: DiffKey,
19}
20
21impl KeyExt for DraggableCanvas {
22    fn write_key(&mut self) -> &mut DiffKey {
23        &mut self.key
24    }
25}
26
27impl Default for DraggableCanvas {
28    fn default() -> Self {
29        Self::new()
30    }
31}
32
33impl DraggableCanvas {
34    pub fn new() -> Self {
35        Self {
36            children: vec![],
37            layout: LayoutData::default(),
38            key: DiffKey::None,
39        }
40    }
41}
42
43impl LayoutExt for DraggableCanvas {
44    fn get_layout(&mut self) -> &mut LayoutData {
45        &mut self.layout
46    }
47}
48
49impl ContainerExt for DraggableCanvas {}
50
51impl ChildrenExt for DraggableCanvas {
52    fn get_children(&mut self) -> &mut Vec<Element> {
53        &mut self.children
54    }
55}
56
57impl Render for DraggableCanvas {
58    fn render(&self) -> impl IntoElement {
59        let mut layout = use_state(Area::default);
60        use_provide_context(move || DraggableCanvasLayout(layout));
61        use_provide_context(|| DraggableCanvasRegistry(State::create(Vec::new())));
62        rect()
63            .layout(self.layout.clone())
64            .on_sized(move |e: Event<SizedEventData>| layout.set(e.visible_area))
65            .children(self.children.clone())
66    }
67    fn render_key(&self) -> DiffKey {
68        self.key.clone().or(self.default_key())
69    }
70}
71
72#[derive(PartialEq)]
73pub struct Draggable {
74    initial_position: CursorPoint,
75    children: Vec<Element>,
76    key: DiffKey,
77}
78
79impl Default for Draggable {
80    fn default() -> Self {
81        Self::new()
82    }
83}
84
85impl Draggable {
86    pub fn new() -> Self {
87        Self {
88            initial_position: CursorPoint::zero(),
89            children: vec![],
90            key: DiffKey::None,
91        }
92    }
93
94    pub fn inital_position(mut self, initial_position: impl Into<CursorPoint>) -> Self {
95        self.initial_position = initial_position.into();
96        self
97    }
98}
99
100impl KeyExt for Draggable {
101    fn write_key(&mut self) -> &mut DiffKey {
102        &mut self.key
103    }
104}
105
106impl ChildrenExt for Draggable {
107    fn get_children(&mut self) -> &mut Vec<Element> {
108        &mut self.children
109    }
110}
111
112impl Render for Draggable {
113    fn render(&self) -> impl IntoElement {
114        let mut position = use_state(|| self.initial_position);
115        let mut dragging_position = use_state::<Option<CursorPoint>>(|| None);
116        let DraggableCanvasLayout(layout) = use_consume::<DraggableCanvasLayout>();
117        let DraggableCanvasRegistry(mut registry) = use_consume::<DraggableCanvasRegistry>();
118        let id = use_id::<DraggableCanvasLayout>();
119
120        use_hook(move || {
121            registry.write().push(id);
122        });
123
124        use_drop(move || {
125            registry.write().retain(|i| *i != id);
126        });
127
128        let on_global_mouse_move = move |e: Event<MouseEventData>| {
129            if let Some(dragging_position) = dragging_position() {
130                position.set(CursorPoint::new(
131                    e.global_location.x - dragging_position.x,
132                    e.global_location.y - dragging_position.y,
133                ));
134                e.stop_propagation();
135            }
136        };
137
138        let on_pointer_down = move |e: Event<PointerEventData>| {
139            dragging_position.set(Some(CursorPoint::new(
140                e.element_location().x + layout.read().min_x() as f64,
141                e.element_location().y + layout.read().min_y() as f64,
142            )));
143            e.stop_propagation();
144            let mut registry = registry.write();
145            registry.retain(|i| *i != id);
146            registry.insert(0, id);
147        };
148
149        let on_capture_global_mouse_up = move |e: Event<MouseEventData>| {
150            if dragging_position.read().is_some() {
151                e.stop_propagation();
152                e.prevent_default();
153                dragging_position.set(None);
154            }
155        };
156
157        let (left, top) = position().to_tuple();
158
159        let layer = registry
160            .read()
161            .iter()
162            .rev()
163            .position(|i| *i == id)
164            .map(|layer| layer * 1024)
165            .unwrap_or_default();
166
167        rect()
168            .on_global_mouse_move(on_global_mouse_move)
169            .on_pointer_down(on_pointer_down)
170            .on_capture_global_mouse_up(on_capture_global_mouse_up)
171            .position(Position::new_absolute().left(left as f32).top(top as f32))
172            .layer(layer as i16)
173            .children(self.children.clone())
174    }
175
176    fn render_key(&self) -> DiffKey {
177        self.key.clone().or(self.default_key())
178    }
179}