mirror of
https://github.com/emilk/egui.git
synced 2026-09-01 14:20:04 -04:00
<!-- Please read the "Making a PR" section of [`CONTRIBUTING.md`](https://github.com/emilk/egui/blob/master/CONTRIBUTING.md) before opening a Pull Request! * Keep your PR:s small and focused. * The PR title is what ends up in the changelog, so make it descriptive! * If applicable, add a screenshot or gif. * If it is a non-trivial addition, consider adding a demo for it to `egui_demo_lib`, or a new example. * Do NOT open PR:s from your `master` branch, as that makes it hard for maintainers to test and add commits to your PR. * Remember to run `cargo fmt` and `cargo clippy`. * Open the PR as a draft until you have self-reviewed it and run `./scripts/check.sh`. * When you have addressed a PR comment, mark it as resolved. Please be patient! I will review your PR, but my time is limited! --> I removed (I hope so) all wildcard imports I found. For me on my pc this improved the build time: - for egui -5s - for eframe -12s * [x] I have followed the instructions in the PR template
142 lines
5.2 KiB
Rust
142 lines
5.2 KiB
Rust
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!());
|
|
});
|
|
}
|
|
}
|