mirror of
https://github.com/emilk/egui.git
synced 2026-09-02 14:50:03 -04:00
Done
This commit is contained in:
@@ -1,4 +1,7 @@
|
|||||||
use std::collections::{HashMap, HashSet};
|
//! This demo is a stripped-down version of the drag-and-drop implementation in the
|
||||||
|
//! [rerun viewer](https://github.com/rerun-io/rerun).
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use eframe::{egui, egui::NumExt as _};
|
use eframe::{egui, egui::NumExt as _};
|
||||||
|
|
||||||
@@ -30,12 +33,6 @@ enum Item {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Command {
|
enum Command {
|
||||||
/// Set the selection to the given item.
|
|
||||||
SetSelection(ItemId),
|
|
||||||
|
|
||||||
/// Toggle the selected state of the given item.
|
|
||||||
ToggleSelected(ItemId),
|
|
||||||
|
|
||||||
/// Move the currently dragged item to the given container and position.
|
/// Move the currently dragged item to the given container and position.
|
||||||
MoveItem {
|
MoveItem {
|
||||||
moved_item_id: ItemId,
|
moved_item_id: ItemId,
|
||||||
@@ -43,7 +40,7 @@ enum Command {
|
|||||||
target_position_index: usize,
|
target_position_index: usize,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Specify the currently identifed target container to be highlighted.
|
/// Specify the currently identified target container to be highlighted.
|
||||||
HighlightTargetContainer(ItemId),
|
HighlightTargetContainer(ItemId),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,9 +51,6 @@ pub struct HierarchicalDragAndDrop {
|
|||||||
/// Id of the root item (not displayed in the UI)
|
/// Id of the root item (not displayed in the UI)
|
||||||
root_id: ItemId,
|
root_id: ItemId,
|
||||||
|
|
||||||
/// Set of all selected items
|
|
||||||
selected_items: HashSet<ItemId>,
|
|
||||||
|
|
||||||
/// If a drag is ongoing, this is the id of the destination container (if any was identified)
|
/// If a drag is ongoing, this is the id of the destination container (if any was identified)
|
||||||
///
|
///
|
||||||
/// This is used to highlight the target container.
|
/// This is used to highlight the target container.
|
||||||
@@ -79,7 +73,6 @@ impl Default for HierarchicalDragAndDrop {
|
|||||||
let mut res = Self {
|
let mut res = Self {
|
||||||
items: std::iter::once((root_id, root_item)).collect(),
|
items: std::iter::once((root_id, root_item)).collect(),
|
||||||
root_id,
|
root_id,
|
||||||
selected_items: HashSet::new(),
|
|
||||||
target_container: None,
|
target_container: None,
|
||||||
command_receiver,
|
command_receiver,
|
||||||
command_sender,
|
command_sender,
|
||||||
@@ -227,10 +220,6 @@ impl HierarchicalDragAndDrop {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn selected(&self, id: ItemId) -> bool {
|
|
||||||
self.selected_items.contains(&id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn send_command(&self, command: Command) {
|
fn send_command(&self, command: Command) {
|
||||||
// The only way this can fail is if the receiver has been dropped.
|
// The only way this can fail is if the receiver has been dropped.
|
||||||
self.command_sender.send(command).ok();
|
self.command_sender.send(command).ok();
|
||||||
@@ -252,17 +241,6 @@ impl HierarchicalDragAndDrop {
|
|||||||
while let Ok(command) = self.command_receiver.try_recv() {
|
while let Ok(command) = self.command_receiver.try_recv() {
|
||||||
//println!("Received command: {command:?}");
|
//println!("Received command: {command:?}");
|
||||||
match command {
|
match command {
|
||||||
Command::SetSelection(item_id) => {
|
|
||||||
self.selected_items.clear();
|
|
||||||
self.selected_items.insert(item_id);
|
|
||||||
}
|
|
||||||
Command::ToggleSelected(item_id) => {
|
|
||||||
if self.selected_items.contains(&item_id) {
|
|
||||||
self.selected_items.remove(&item_id);
|
|
||||||
} else {
|
|
||||||
self.selected_items.insert(item_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Command::MoveItem {
|
Command::MoveItem {
|
||||||
moved_item_id,
|
moved_item_id,
|
||||||
target_container_id,
|
target_container_id,
|
||||||
@@ -276,7 +254,7 @@ impl HierarchicalDragAndDrop {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn container_ui(&self, ui: &mut egui::Ui, item_id: ItemId, children: &Vec<ItemId>) {
|
fn container_ui(&self, ui: &mut egui::Ui, item_id: ItemId, children: &Vec<ItemId>) {
|
||||||
let (_, header_resp, body_resp) =
|
let (response, head_response, body_resp) =
|
||||||
egui::collapsing_header::CollapsingState::load_with_default_open(
|
egui::collapsing_header::CollapsingState::load_with_default_open(
|
||||||
ui.ctx(),
|
ui.ctx(),
|
||||||
item_id.into(),
|
item_id.into(),
|
||||||
@@ -293,11 +271,11 @@ impl HierarchicalDragAndDrop {
|
|||||||
self.container_children_ui(ui, children);
|
self.container_children_ui(ui, children);
|
||||||
});
|
});
|
||||||
|
|
||||||
self.handle_interaction(
|
self.handle_drag_and_drop_interaction(
|
||||||
ui,
|
ui,
|
||||||
item_id,
|
item_id,
|
||||||
true,
|
true,
|
||||||
&header_resp.inner,
|
&head_response.inner.union(response),
|
||||||
body_resp.as_ref().map(|r| &r.response),
|
body_resp.as_ref().map(|r| &r.response),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -322,16 +300,11 @@ impl HierarchicalDragAndDrop {
|
|||||||
.selectable(false)
|
.selectable(false)
|
||||||
.sense(egui::Sense::drag()),
|
.sense(egui::Sense::drag()),
|
||||||
);
|
);
|
||||||
// let response = re_ui
|
|
||||||
// .list_item(label)
|
|
||||||
// .selected(self.selected(item_id))
|
|
||||||
// .draggable(true)
|
|
||||||
// .show(ui);
|
|
||||||
|
|
||||||
self.handle_interaction(ui, item_id, false, &response, None);
|
self.handle_drag_and_drop_interaction(ui, item_id, false, &response, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_interaction(
|
fn handle_drag_and_drop_interaction(
|
||||||
&self,
|
&self,
|
||||||
ui: &egui::Ui,
|
ui: &egui::Ui,
|
||||||
item_id: ItemId,
|
item_id: ItemId,
|
||||||
@@ -340,31 +313,15 @@ impl HierarchicalDragAndDrop {
|
|||||||
body_response: Option<&egui::Response>,
|
body_response: Option<&egui::Response>,
|
||||||
) {
|
) {
|
||||||
//
|
//
|
||||||
// basic selection management
|
// handle start of drag
|
||||||
//
|
|
||||||
|
|
||||||
if response.clicked() {
|
|
||||||
if ui.input(|i| i.modifiers.command) {
|
|
||||||
self.send_command(Command::ToggleSelected(item_id));
|
|
||||||
} else {
|
|
||||||
self.send_command(Command::SetSelection(item_id));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// handle drag
|
|
||||||
//
|
//
|
||||||
|
|
||||||
if response.drag_started() {
|
if response.drag_started() {
|
||||||
// Here, we support dragging a single item at a time, so we set the selection to the dragged item
|
|
||||||
// if/when we're dragging it proper.
|
|
||||||
self.send_command(Command::SetSelection(item_id));
|
|
||||||
|
|
||||||
egui::DragAndDrop::set_payload(ui.ctx(), item_id);
|
egui::DragAndDrop::set_payload(ui.ctx(), item_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// handle drop
|
// handle candidate drop
|
||||||
//
|
//
|
||||||
|
|
||||||
// find the item being dragged
|
// find the item being dragged
|
||||||
@@ -397,11 +354,28 @@ impl HierarchicalDragAndDrop {
|
|||||||
previous_container_id,
|
previous_container_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// compute the drag target areas based on the item and body responses
|
||||||
|
//
|
||||||
|
|
||||||
|
// adjust the drop target to account for the spacing between items
|
||||||
|
let item_rect = response
|
||||||
|
.rect
|
||||||
|
.expand2(egui::Vec2::new(0.0, ui.spacing().item_spacing.y / 2.0));
|
||||||
|
let body_rect = body_response.map(|r| {
|
||||||
|
r.rect
|
||||||
|
.expand2(egui::Vec2::new(0.0, ui.spacing().item_spacing.y))
|
||||||
|
});
|
||||||
|
|
||||||
|
//
|
||||||
|
// find the candidate drop target
|
||||||
|
//
|
||||||
|
|
||||||
let drop_target = crate::drag_and_drop::find_drop_target(
|
let drop_target = crate::drag_and_drop::find_drop_target(
|
||||||
ui,
|
ui,
|
||||||
&item_desc,
|
&item_desc,
|
||||||
response.rect,
|
item_rect,
|
||||||
body_response.map(|r| r.rect),
|
body_rect,
|
||||||
response.rect.height(),
|
response.rect.height(),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -413,10 +387,13 @@ impl HierarchicalDragAndDrop {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// extend the cursor to the right of the enclosing container
|
||||||
|
let mut span_x = drop_target.indicator_span_x;
|
||||||
|
span_x.max = ui.cursor().right();
|
||||||
|
|
||||||
ui.painter().hline(
|
ui.painter().hline(
|
||||||
drop_target.indicator_span_x,
|
span_x,
|
||||||
drop_target.indicator_position_y,
|
drop_target.indicator_position_y,
|
||||||
//TODO: use style
|
|
||||||
(2.0, egui::Color32::BLACK),
|
(2.0, egui::Color32::BLACK),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -211,7 +211,7 @@ pub fn find_drop_target<ItemId: Copy>(
|
|||||||
);
|
);
|
||||||
ui.ctx().debug_painter().debug_rect(
|
ui.ctx().debug_painter().debug_rect(
|
||||||
body_insert_after_me_area,
|
body_insert_after_me_area,
|
||||||
egui::Color32::YELLOW,
|
egui::Color32::BLUE.gamma_multiply(0.5),
|
||||||
"bdy",
|
"bdy",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,6 @@ fn main() -> Result<(), eframe::Error> {
|
|||||||
eframe::run_native(
|
eframe::run_native(
|
||||||
"My egui App",
|
"My egui App",
|
||||||
options,
|
options,
|
||||||
Box::new(|cc| Box::<HierarchicalDragAndDrop>::default()),
|
Box::new(|_cc| Box::<HierarchicalDragAndDrop>::default()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user