mirror of
https://github.com/emilk/egui.git
synced 2026-06-27 23:13:13 -04:00
Drag-and-drop for vertical layouts
This commit is contained in:
@@ -8,7 +8,7 @@ use crate::dock::{
|
||||
|
||||
use super::Shares;
|
||||
|
||||
#[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, Copy, Debug, Default, serde::Serialize, serde::Deserialize)]
|
||||
pub enum LinearDir {
|
||||
#[default]
|
||||
Horizontal,
|
||||
@@ -116,54 +116,19 @@ impl Linear {
|
||||
ui: &mut egui::Ui,
|
||||
parent_id: NodeId,
|
||||
) {
|
||||
let mut prev_rect: Option<Rect> = None;
|
||||
let mut insertion_index = 0; // skips over drag-source, if any, beacuse it will be removed then re-inserted
|
||||
|
||||
for (i, &child) in self.children.iter().enumerate() {
|
||||
let rect = nodes.rect(child);
|
||||
|
||||
if is_being_dragged(ui.ctx(), child) {
|
||||
// Leave a hole, and suggest that hole as drop-target:
|
||||
drop_context.suggest_rect(
|
||||
InsertionPoint::new(parent_id, LayoutInsertion::Horizontal(i)),
|
||||
rect,
|
||||
);
|
||||
} else {
|
||||
for &child in &self.children {
|
||||
if !is_being_dragged(ui.ctx(), child) {
|
||||
nodes.node_ui(behavior, drop_context, ui, child);
|
||||
|
||||
if let Some(prev_rect) = prev_rect {
|
||||
// Suggest dropping between the rects:
|
||||
drop_context.suggest_rect(
|
||||
InsertionPoint::new(
|
||||
parent_id,
|
||||
LayoutInsertion::Horizontal(insertion_index),
|
||||
),
|
||||
Rect::from_min_max(prev_rect.center_top(), rect.center_bottom()),
|
||||
);
|
||||
} else {
|
||||
// Suggest dropping before the first child:
|
||||
drop_context.suggest_rect(
|
||||
InsertionPoint::new(parent_id, LayoutInsertion::Horizontal(0)),
|
||||
rect.split_left_right_at_fraction(0.66).0,
|
||||
);
|
||||
}
|
||||
|
||||
if i + 1 == self.children.len() {
|
||||
// Suggest dropping after the last child:
|
||||
drop_context.suggest_rect(
|
||||
InsertionPoint::new(
|
||||
parent_id,
|
||||
LayoutInsertion::Horizontal(insertion_index + 1),
|
||||
),
|
||||
rect.split_left_right_at_fraction(0.33).1,
|
||||
);
|
||||
}
|
||||
insertion_index += 1;
|
||||
}
|
||||
|
||||
prev_rect = Some(rect);
|
||||
}
|
||||
|
||||
drop_zones(ui.ctx(), nodes, &self.children, self.dir, |rect, i| {
|
||||
drop_context.suggest_rect(
|
||||
InsertionPoint::new(parent_id, LayoutInsertion::Horizontal(i)),
|
||||
rect,
|
||||
);
|
||||
});
|
||||
|
||||
// ------------------------
|
||||
// resizing:
|
||||
|
||||
@@ -214,11 +179,19 @@ impl Linear {
|
||||
ui: &mut egui::Ui,
|
||||
parent_id: NodeId,
|
||||
) {
|
||||
// TODO: drag-and-drop
|
||||
for child in &self.children {
|
||||
nodes.node_ui(behavior, drop_context, ui, *child);
|
||||
for &child in &self.children {
|
||||
if !is_being_dragged(ui.ctx(), child) {
|
||||
nodes.node_ui(behavior, drop_context, ui, child);
|
||||
}
|
||||
}
|
||||
|
||||
drop_zones(ui.ctx(), nodes, &self.children, self.dir, |rect, i| {
|
||||
drop_context.suggest_rect(
|
||||
InsertionPoint::new(parent_id, LayoutInsertion::Vertical(i)),
|
||||
rect,
|
||||
);
|
||||
});
|
||||
|
||||
// ------------------------
|
||||
// resizing:
|
||||
|
||||
@@ -341,3 +314,79 @@ fn shrink_shares<Leaf>(
|
||||
|
||||
total_shares_lost
|
||||
}
|
||||
|
||||
fn drop_zones<Leaf>(
|
||||
egui_ctx: &egui::Context,
|
||||
nodes: &Nodes<Leaf>,
|
||||
children: &[NodeId],
|
||||
dir: LinearDir,
|
||||
mut add_drop_drect: impl FnMut(Rect, usize),
|
||||
) {
|
||||
let preview_thickness = 12.0;
|
||||
|
||||
let before_rect = |rect: Rect| match dir {
|
||||
LinearDir::Horizontal => Rect::from_min_max(
|
||||
rect.left_top(),
|
||||
rect.left_bottom() + vec2(preview_thickness, 0.0),
|
||||
),
|
||||
LinearDir::Vertical => Rect::from_min_max(
|
||||
rect.left_top(),
|
||||
rect.right_top() + vec2(0.0, preview_thickness),
|
||||
),
|
||||
};
|
||||
let afer_rect = |rect: Rect| match dir {
|
||||
LinearDir::Horizontal => Rect::from_min_max(
|
||||
rect.right_top() - vec2(preview_thickness, 0.0),
|
||||
rect.right_bottom(),
|
||||
),
|
||||
LinearDir::Vertical => Rect::from_min_max(
|
||||
rect.left_bottom() - vec2(0.0, preview_thickness),
|
||||
rect.right_bottom(),
|
||||
),
|
||||
};
|
||||
let between_rects = |a: Rect, b: Rect| match dir {
|
||||
LinearDir::Horizontal => Rect::from_center_size(
|
||||
a.right_center().lerp(b.left_center(), 0.5),
|
||||
vec2(preview_thickness, a.height()),
|
||||
),
|
||||
LinearDir::Vertical => Rect::from_center_size(
|
||||
a.center_bottom().lerp(b.center_top(), 0.5),
|
||||
vec2(a.width(), preview_thickness),
|
||||
),
|
||||
};
|
||||
|
||||
let dragged_index = children
|
||||
.iter()
|
||||
.position(|&child| is_being_dragged(egui_ctx, child));
|
||||
|
||||
let mut prev_rect: Option<Rect> = None;
|
||||
let mut insertion_index = 0; // skips over drag-source, if any, beacuse it will be removed before its re-inserted
|
||||
|
||||
for (i, &child) in children.iter().enumerate() {
|
||||
let rect = nodes.rect(child);
|
||||
|
||||
if Some(i) == dragged_index {
|
||||
// Suggest hole as a drop-target:
|
||||
add_drop_drect(rect, i);
|
||||
} else {
|
||||
if let Some(prev_rect) = prev_rect {
|
||||
if Some(i - 1) != dragged_index {
|
||||
// Suggest dropping between the rects:
|
||||
add_drop_drect(between_rects(prev_rect, rect), insertion_index);
|
||||
}
|
||||
} else {
|
||||
// Suggest dropping before the first child:
|
||||
add_drop_drect(before_rect(rect), 0);
|
||||
}
|
||||
|
||||
insertion_index += 1;
|
||||
}
|
||||
|
||||
prev_rect = Some(rect);
|
||||
}
|
||||
|
||||
if let Some(last_rect) = prev_rect {
|
||||
// Suggest dropping after the last child:
|
||||
add_drop_drect(afer_rect(last_rect), insertion_index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// # TODO
|
||||
// * A new ui for each node, nested
|
||||
// * Better drag-and-drop around the "empty" drag source
|
||||
// * Resizing of vertical layouts and grids
|
||||
// * Better drag-and-drop around the "empty" tab
|
||||
// * Resizing of grids
|
||||
// * Styling
|
||||
// * Handle rects without a lot of unwraps
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
@@ -360,11 +359,13 @@ impl<Leaf> Nodes<Leaf> {
|
||||
if let Node::Branch(Branch::Tabs(tabs)) = &mut node {
|
||||
let index = index.min(tabs.children.len());
|
||||
tabs.children.insert(index, child_id);
|
||||
tabs.active = child_id;
|
||||
self.nodes.insert(parent_id, node);
|
||||
} else {
|
||||
let new_node_id = self.insert_node(node);
|
||||
let mut tabs = Tabs::new(vec![new_node_id]);
|
||||
tabs.children.insert(index.min(1), child_id);
|
||||
tabs.active = child_id;
|
||||
self.nodes
|
||||
.insert(parent_id, Node::Branch(Branch::Tabs(tabs)));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user