Skip to content

Commit

Permalink
Allow reordering of items in the drag-and-drop demo
Browse files Browse the repository at this point in the history
  • Loading branch information
emilk committed Jan 25, 2024
1 parent 4ae1b96 commit 590e2aa
Showing 1 changed file with 76 additions and 14 deletions.
90 changes: 76 additions & 14 deletions crates/egui_demo_lib/src/demo/drag_and_drop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ impl Default for DragAndDropDemo {
fn default() -> Self {
Self {
columns: vec![
vec!["Item A", "Item B", "Item C"],
vec!["Item D", "Item E"],
vec!["Item F", "Item G", "Item H"],
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())
Expand All @@ -39,39 +39,101 @@ impl super::Demo for DragAndDropDemo {
}

/// What is being dragged.
struct DragInfo {
col_idx: usize,
row_idx: usize,
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
struct Location {
col: usize,
row: usize,
}

impl super::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::<DragInfo>(frame, |ui| {

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 payload = DragInfo { col_idx, row_idx };
ui.dnd_drag_source(item_id, payload, |ui| {
ui.label(item);
});
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(source) = dropped_payload {
let item = self.columns[source.col_idx].remove(source.row_idx);
self.columns[col_idx].push(item);
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!());
});
Expand Down

0 comments on commit 590e2aa

Please sign in to comment.