freya_components/
drag_drop.rs1use freya_core::{
2 prelude::*,
3 scope_id::ScopeId,
4};
5use torin::prelude::*;
6
7fn use_drag<T: 'static>() -> State<Option<T>> {
8 match try_consume_root_context() {
9 Some(s) => s,
10 None => {
11 let state = State::<Option<T>>::create_in_scope(None, ScopeId::ROOT);
12 provide_context_for_scope_id(state, ScopeId::ROOT);
13 state
14 }
15 }
16}
17
18#[derive(Clone, PartialEq)]
20pub struct DragZone<T: Clone + 'static + PartialEq> {
21 drag_element: Option<Element>,
23 children: Element,
25 data: T,
27 show_while_dragging: bool,
29}
30
31impl<T: Clone + PartialEq + 'static> DragZone<T> {
32 pub fn new(data: T, children: impl Into<Element>) -> Self {
33 Self {
34 data,
35 children: children.into(),
36 drag_element: None,
37 show_while_dragging: true,
38 }
39 }
40
41 pub fn show_while_dragging(mut self, show_while_dragging: bool) -> Self {
42 self.show_while_dragging = show_while_dragging;
43 self
44 }
45
46 pub fn drag_element(mut self, drag_element: impl Into<Element>) -> Self {
47 self.drag_element = Some(drag_element.into());
48 self
49 }
50}
51
52impl<T: Clone + PartialEq> Render for DragZone<T> {
53 fn render(&self) -> impl IntoElement {
54 let mut drags = use_drag::<T>();
55 let mut position = use_state::<Option<CursorPoint>>(|| None);
56 let data = self.data.clone();
57
58 let on_global_mouse_move = move |e: Event<MouseEventData>| {
59 if position.read().is_some() {
60 position.set(Some(e.global_location));
61 }
62 };
63
64 let on_pointer_down = move |e: Event<PointerEventData>| {
65 if e.data().button() != Some(MouseButton::Left) {
66 return;
67 }
68 position.set(Some(e.global_location()));
69 *drags.write() = Some(data.clone());
70 };
71
72 let on_global_mouse_up = move |_: Event<MouseEventData>| {
73 if position.read().is_some() {
74 position.set(None);
75 *drags.write() = None;
76 }
77 };
78
79 rect()
80 .on_global_mouse_up(on_global_mouse_up)
81 .on_global_mouse_move(on_global_mouse_move)
82 .on_pointer_down(on_pointer_down)
83 .maybe_child((position.read().zip(self.drag_element.clone())).map(
84 |(position, drag_element)| {
85 let (x, y) = position.to_f32().to_tuple();
86 rect()
87 .position(Position::new_global())
88 .width(Size::px(0.))
89 .height(Size::px(0.))
90 .offset_x(x + 1.)
92 .offset_y(y + 1.)
93 .child(drag_element)
94 },
95 ))
96 .maybe_child(
97 (self.show_while_dragging || position.read().is_none())
98 .then(|| self.children.clone()),
99 )
100 }
101}
102
103#[derive(PartialEq, Clone)]
104pub struct DropZone<T: 'static + PartialEq + Clone> {
105 children: Element,
106 on_drop: EventHandler<T>,
107 width: Size,
108 height: Size,
109}
110
111impl<T: PartialEq + Clone + 'static> DropZone<T> {
112 pub fn new(children: impl Into<Element>, on_drop: impl Into<EventHandler<T>>) -> Self {
113 Self {
114 children: children.into(),
115 on_drop: on_drop.into(),
116 width: Size::auto(),
117 height: Size::auto(),
118 }
119 }
120}
121
122impl<T: Clone + PartialEq + 'static> Render for DropZone<T> {
123 fn render(&self) -> impl IntoElement {
124 let mut drags = use_drag::<T>();
125 let on_drop = self.on_drop.clone();
126
127 let on_mouse_up = move |e: Event<MouseEventData>| {
128 e.stop_propagation();
129 if let Some(current_drags) = &*drags.read() {
130 on_drop.call(current_drags.clone());
131 }
132 if drags.read().is_some() {
133 *drags.write() = None;
134 }
135 };
136
137 rect()
138 .on_mouse_up(on_mouse_up)
139 .width(self.width.clone())
140 .height(self.height.clone())
141 .child(self.children.clone())
142 }
143}