-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
drag_and_drop.rs
141 lines (123 loc) · 5.19 KB
/
drag_and_drop.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
use egui::{vec2, Color32, Context, Frame, Id, Ui, Window};
#[derive(Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
pub struct DragAndDropDemo {
/// columns with items
columns: Vec<Vec<String>>,
}
impl Default for DragAndDropDemo {
fn default() -> Self {
Self {
columns: vec![
vec!["Item A", "Item B", "Item C", "Item D"],
vec!["Item E", "Item F", "Item G"],
vec!["Item H", "Item I", "Item J", "Item K"],
]
.into_iter()
.map(|v| v.into_iter().map(ToString::to_string).collect())
.collect(),
}
}
}
impl crate::Demo for DragAndDropDemo {
fn name(&self) -> &'static str {
"✋ Drag and Drop"
}
fn show(&mut self, ctx: &Context, open: &mut bool) {
use crate::View as _;
Window::new(self.name())
.open(open)
.default_size(vec2(256.0, 256.0))
.vscroll(false)
.resizable(false)
.show(ctx, |ui| self.ui(ui));
}
}
/// What is being dragged.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
struct Location {
col: usize,
row: usize,
}
impl crate::View for DragAndDropDemo {
fn ui(&mut self, ui: &mut Ui) {
ui.label("This is a simple example of drag-and-drop in egui.");
ui.label("Drag items between columns.");
// If there is a drop, store the location of the item being dragged, and the destination for the drop.
let mut from = None;
let mut to = None;
ui.columns(self.columns.len(), |uis| {
for (col_idx, column) in self.columns.clone().into_iter().enumerate() {
let ui = &mut uis[col_idx];
let frame = Frame::default().inner_margin(4.0);
let (_, dropped_payload) = ui.dnd_drop_zone::<Location, ()>(frame, |ui| {
ui.set_min_size(vec2(64.0, 100.0));
for (row_idx, item) in column.iter().enumerate() {
let item_id = Id::new(("my_drag_and_drop_demo", col_idx, row_idx));
let item_location = Location {
col: col_idx,
row: row_idx,
};
let response = ui
.dnd_drag_source(item_id, item_location, |ui| {
ui.label(item);
})
.response;
// Detect drops onto this item:
if let (Some(pointer), Some(hovered_payload)) = (
ui.input(|i| i.pointer.interact_pos()),
response.dnd_hover_payload::<Location>(),
) {
let rect = response.rect;
// Preview insertion:
let stroke = egui::Stroke::new(1.0, Color32::WHITE);
let insert_row_idx = if *hovered_payload == item_location {
// We are dragged onto ourselves
ui.painter().hline(rect.x_range(), rect.center().y, stroke);
row_idx
} else if pointer.y < rect.center().y {
// Above us
ui.painter().hline(rect.x_range(), rect.top(), stroke);
row_idx
} else {
// Below us
ui.painter().hline(rect.x_range(), rect.bottom(), stroke);
row_idx + 1
};
if let Some(dragged_payload) = response.dnd_release_payload() {
// The user dropped onto this item.
from = Some(dragged_payload);
to = Some(Location {
col: col_idx,
row: insert_row_idx,
});
}
}
}
});
if let Some(dragged_payload) = dropped_payload {
// The user dropped onto the column, but not on any one item.
from = Some(dragged_payload);
to = Some(Location {
col: col_idx,
row: usize::MAX, // Inset last
});
}
}
});
if let (Some(from), Some(mut to)) = (from, to) {
if from.col == to.col {
// Dragging within the same column.
// Adjust row index if we are re-ordering:
to.row -= (from.row < to.row) as usize;
}
let item = self.columns[from.col].remove(from.row);
let column = &mut self.columns[to.col];
to.row = to.row.min(column.len());
column.insert(to.row, item);
}
ui.vertical_centered(|ui| {
ui.add(crate::egui_github_link_file!());
});
}
}