Skip to content

Commit 60b155b

Browse files
committed
implement drag events
- dragenter/dragover/drageave/drop - dragstart/drag/dragend - outgoing drags - drop effect (not fully implemented) - internal drags (not fully implemented) - shell set_datatransfer (I don't think that get_datatransfer is necessary as drop will always be an ui event so custom widgets can use that)
1 parent dce796c commit 60b155b

22 files changed

Lines changed: 1737 additions & 39 deletions

File tree

‎.gitignore‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@
1010
/wpt/*.json
1111
/apps/wpt/output
1212
/sites
13-
.blitz-cache
13+
.blitz-cache
14+
/.zed

‎Cargo.lock‎

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Cargo.toml‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,8 @@ bytes = "1.7.1"
181181
slotmap = "1.0.7"
182182
tracing = "0.1.40"
183183
tracing-subscriber = "0.3"
184-
futures-util = "0.3.30"
184+
futures-core = "0.3.32"
185+
futures-util = "0.3.32"
185186
futures-intrusive = "0.5.0"
186187
pollster = "0.4"
187188
smol_str = "0.3"

‎examples/dnd.rs‎

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
use dioxus_native::prelude::*;
2+
3+
fn main() {
4+
dioxus_native::launch(app);
5+
}
6+
7+
fn app() -> Element {
8+
let mut drag_active = use_signal(|| false);
9+
let mut files = use_store(Vec::new);
10+
let mut texts = use_store(Vec::new);
11+
12+
rsx! {
13+
div {
14+
width: "200px",
15+
height: "50px",
16+
border: "1px solid black",
17+
draggable: "true",
18+
ondragstart: move |e| {
19+
println!("dragstart");
20+
if let Err(err) = e.data_transfer().set_data("text/plain", "Some text") {
21+
dbg!(err);
22+
}
23+
},
24+
ondrag: move |_| {
25+
//println!("drag");
26+
},
27+
ondragend: move |_| {
28+
println!("dragend");
29+
},
30+
"Drag me!"
31+
}
32+
div {
33+
width: "400px",
34+
height: "400px",
35+
border: if drag_active() { "2px solid black" } else {
36+
"2px solid gray"
37+
},
38+
ondragenter: move |_| {
39+
drag_active.set(true);
40+
println!("enter");
41+
},
42+
ondragover: move |evt| {
43+
evt.prevent_default();
44+
//println!("over");
45+
},
46+
ondragleave: move |_| {
47+
drag_active.set(false);
48+
println!("leave");
49+
},
50+
ondrop: move |evt| {
51+
evt.prevent_default();
52+
drag_active.set(false);
53+
println!("drop");
54+
for file in evt.data_transfer().files() {
55+
files.push( file.name());
56+
}
57+
if let Some(text) = evt.data_transfer().get_as_text() {
58+
texts.push(text);
59+
}
60+
if let Some(text) = evt.data_transfer().get_data("text/html") {
61+
texts.push(text);
62+
}
63+
if let Some(text) = evt.data_transfer().get_data("text/rtf") {
64+
texts.push(text);
65+
}
66+
},
67+
"Files"
68+
ul {
69+
for name in files.iter() {
70+
li {{name}}
71+
}
72+
}
73+
"Text"
74+
ul {
75+
for text in texts.iter() {
76+
li {{text}}
77+
}
78+
}
79+
DragArea{
80+
width: "200px",
81+
height: "200px",
82+
padding: "4px",
83+
color: "green",
84+
DragArea{
85+
width: "100px",
86+
height: "100px",
87+
color: "blue"
88+
}
89+
DragArea{
90+
width: "100px",
91+
height: "100px",
92+
color: "red"
93+
}
94+
}
95+
}
96+
}
97+
}
98+
99+
#[component]
100+
fn DragArea(
101+
color: String,
102+
#[props(extends=GlobalAttributes)] attributes: Vec<Attribute>,
103+
children: Element,
104+
) -> Element {
105+
let mut drag_active = use_signal(|| false);
106+
let color = use_signal(|| color);
107+
108+
rsx!(div {
109+
border: if drag_active() {
110+
"2px solid black"
111+
} else { "2px solid {color}"},
112+
ondragenter: move |evt| {
113+
evt.stop_propagation();
114+
drag_active.set(true);
115+
println!("enter {}", color);
116+
},
117+
ondragover: move |evt| {
118+
evt.prevent_default();
119+
//println!("over {}", color);
120+
},
121+
ondragleave: move |evt| {
122+
evt.stop_propagation();
123+
drag_active.set(false);
124+
println!("leave {}", color);
125+
},
126+
ondrop: move |_| {
127+
drag_active.set(false);
128+
println!("drop {}", color);
129+
},
130+
..attributes,
131+
{children}
132+
})
133+
}

‎packages/blitz-dom/src/document.rs‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2458,6 +2458,22 @@ impl BaseDocument {
24582458
Some((inline_root.id, byte_offset))
24592459
}
24602460

2461+
/// Checks if a point has landed on selection
2462+
pub fn is_text_selected_at_position(&self, x: f32, y: f32) -> bool {
2463+
if let Some((node, offset)) = self.find_text_position(x, y) {
2464+
self.is_selected_text(node, offset)
2465+
} else {
2466+
false
2467+
}
2468+
}
2469+
2470+
/// Checks if found node and offset are in selection
2471+
pub fn is_selected_text(&self, node: NodeId, offset: usize) -> bool {
2472+
let (parent, idx) = self.anonymous_block_location(node);
2473+
let parent = parent.unwrap_or(node);
2474+
self.text_selection.is_selected(parent, idx, offset)
2475+
}
2476+
24612477
/// Set the text selection range (creates a new selection from anchor to focus)
24622478
pub fn set_text_selection(
24632479
&mut self,
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
use std::any::Any;
2+
3+
use blitz_traits::events::BlitzDataTransferItemsTrait;
4+
5+
#[derive(Debug, Clone)]
6+
pub struct BlitzInternalDataTransferEntry {
7+
pub format: String,
8+
pub data: String,
9+
}
10+
11+
#[derive(Debug, Default)]
12+
pub struct BlitzInternalDataTransferItems {
13+
entries: Vec<BlitzInternalDataTransferEntry>,
14+
// todo when dragging images file is set
15+
_files: Vec<String>,
16+
}
17+
18+
impl BlitzDataTransferItemsTrait for BlitzInternalDataTransferItems {
19+
fn is_empty(&self) -> bool {
20+
self.entries.is_empty()
21+
}
22+
23+
fn get_data(&self, format: &str) -> Option<String> {
24+
self.entries
25+
.iter()
26+
.find(|entry| entry.format == format)
27+
.map(|entry| entry.data.clone())
28+
}
29+
30+
fn set_data(&mut self, format: &str, data: &str) -> Result<(), String> {
31+
if let Some(entry) = self.entries.iter_mut().find(|e| e.format == format) {
32+
entry.data = data.to_string();
33+
} else {
34+
self.entries.push(BlitzInternalDataTransferEntry {
35+
format: format.to_string(),
36+
data: data.to_string(),
37+
});
38+
}
39+
Ok(())
40+
}
41+
42+
fn clear_all(&mut self) {
43+
self.entries.clear();
44+
}
45+
46+
fn clear_format(&mut self, format: &str) {
47+
self.entries.retain(|entry| entry.format != format);
48+
}
49+
50+
fn types(&self) -> Vec<String> {
51+
self.entries
52+
.iter()
53+
.map(|entry| entry.format.clone())
54+
.collect()
55+
}
56+
57+
fn as_any(&self) -> &dyn Any {
58+
self as &dyn Any
59+
}
60+
}

0 commit comments

Comments
 (0)