1
0
mirror of https://github.com/emilk/egui.git synced 2026-09-03 07:10:04 -04:00

Drag to re-arrange horizontal layout

This commit is contained in:
Emil Ernerfeldt
2023-04-24 21:41:19 +02:00
parent 240989df8b
commit 0617b7d26d

View File

@@ -263,6 +263,10 @@ impl<Leaf> Nodes<Leaf> {
self.nodes.get(&node_id).map(|node| &node.layout) self.nodes.get(&node_id).map(|node| &node.layout)
} }
pub fn get_mut(&mut self, node_id: NodeId) -> Option<&mut NodeLayout<Leaf>> {
self.nodes.get_mut(&node_id).map(|node| &mut node.layout)
}
#[must_use] #[must_use]
pub fn insert_node(&mut self, node: NodeState<Leaf>) -> NodeId { pub fn insert_node(&mut self, node: NodeState<Leaf>) -> NodeId {
let id = NodeId::random(); let id = NodeId::random();
@@ -456,6 +460,20 @@ impl<Leaf> Dock<Leaf> {
Color32::LIGHT_BLUE.gamma_multiply(0.5), Color32::LIGHT_BLUE.gamma_multiply(0.5),
(1.0, Color32::LIGHT_BLUE), (1.0, Color32::LIGHT_BLUE),
); );
let preview_child = false;
if preview_child {
// Preview actual child?
if preview_rect.width() > 32.0 && preview_rect.height() > 32.0 {
if let Some(NodeLayout::Leaf(leaf)) = self.nodes.get_mut(dragged_node_id) {
let _ = behavior.leaf_ui(
&mut ui.child_ui(preview_rect, *ui.layout()),
dragged_node_id,
leaf,
);
}
}
}
} }
if ui.input(|i| i.pointer.any_released()) { if ui.input(|i| i.pointer.any_released()) {
@@ -530,6 +548,10 @@ fn is_possible_drag(ctx: &egui::Context) -> bool {
}) })
} }
fn is_being_dragged(ctx: &egui::Context, node_id: NodeId) -> bool {
ctx.memory(|mem| mem.is_being_dragged(node_id.id())) && is_possible_drag(ctx)
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// gc // gc
@@ -727,35 +749,39 @@ struct DropContext {
} }
impl DropContext { impl DropContext {
fn on_node(&mut self, parent_id: NodeId, rect: Rect) { fn on_node<Leaf>(&mut self, parent_id: NodeId, node: &NodeState<Leaf>) {
if !self.active { if !self.active {
return; return;
} }
self.suggest_point( let rect = node.rect;
if !matches!(node.layout, NodeLayout::Horizontal(_)) {
self.suggest_rect(
InsertionPoint::new(parent_id, LayoutType::Horizontal, 0), InsertionPoint::new(parent_id, LayoutType::Horizontal, 0),
rect.left_center(),
rect.split_left_right_at_fraction(0.5).0, rect.split_left_right_at_fraction(0.5).0,
); );
self.suggest_point( self.suggest_rect(
InsertionPoint::new(parent_id, LayoutType::Horizontal, usize::MAX), InsertionPoint::new(parent_id, LayoutType::Horizontal, usize::MAX),
rect.right_center(),
rect.split_left_right_at_fraction(0.5).1, rect.split_left_right_at_fraction(0.5).1,
); );
self.suggest_point( }
if !matches!(node.layout, NodeLayout::Vertical(_)) {
self.suggest_rect(
InsertionPoint::new(parent_id, LayoutType::Vertical, 0), InsertionPoint::new(parent_id, LayoutType::Vertical, 0),
rect.center_top(),
rect.split_top_bottom_at_fraction(0.5).0, rect.split_top_bottom_at_fraction(0.5).0,
); );
self.suggest_point( self.suggest_rect(
InsertionPoint::new(parent_id, LayoutType::Vertical, usize::MAX), InsertionPoint::new(parent_id, LayoutType::Vertical, usize::MAX),
rect.center_bottom(),
rect.split_top_bottom_at_fraction(0.5).1, rect.split_top_bottom_at_fraction(0.5).1,
); );
self.suggest_point( }
InsertionPoint::new(parent_id, LayoutType::Tabs, 1),
rect.center(), // self.suggest_rect(InsertionPoint::new(parent_id, LayoutType::Tabs, 1), rect);
rect, }
);
fn suggest_rect(&mut self, insertion: InsertionPoint, preview_rect: Rect) {
self.suggest_point(insertion, preview_rect.center(), preview_rect);
} }
fn suggest_point(&mut self, insertion: InsertionPoint, target_point: Pos2, preview_rect: Rect) { fn suggest_point(&mut self, insertion: InsertionPoint, target_point: Pos2, preview_rect: Rect) {
@@ -788,7 +814,14 @@ impl<Leaf> Nodes<Leaf> {
// Can't drag a node onto self or any children // Can't drag a node onto self or any children
drop_context.active = false; drop_context.active = false;
} }
drop_context.on_node(node_id, node.rect); drop_context.on_node(node_id, &node);
drop_context.suggest_rect(
InsertionPoint::new(node_id, LayoutType::Tabs, usize::MAX),
node.rect
.split_top_bottom_at_y(node.rect.top() + behavior.tab_bar_height(ui.style()))
.1,
);
match &mut node.layout { match &mut node.layout {
NodeLayout::Leaf(leaf) => { NodeLayout::Leaf(leaf) => {
@@ -833,18 +866,16 @@ impl<Leaf> Nodes<Leaf> {
// Show tab bar: // Show tab bar:
tab_bar_ui.horizontal(|ui| { tab_bar_ui.horizontal(|ui| {
let mut prev_tab_rect: Option<Rect> = None; let mut prev_tab_rect: Option<Rect> = None;
let mut insertion_index = 0; // skips over drag-source, if any let mut insertion_index = 0; // skips over drag-source, if any, beacuse it will be removed then re-inserted
for (child_index, &child_id) in tabs.children.iter().enumerate() { for (i, &child_id) in tabs.children.iter().enumerate() {
let selected = child_id == tabs.active; if is_being_dragged(ui.ctx(), child_id) {
let id = child_id.id();
let is_node_being_dragged =
ui.memory(|mem| mem.is_being_dragged(id)) && is_possible_drag(ui.ctx());
if is_node_being_dragged {
continue; // leave a gap! continue; // leave a gap!
} }
let selected = child_id == tabs.active;
let id = child_id.id();
let response = behavior.tab_ui(self, ui, id, child_id, selected); let response = behavior.tab_ui(self, ui, id, child_id, selected);
let response = response.on_hover_cursor(CursorIcon::Grab); let response = response.on_hover_cursor(CursorIcon::Grab);
if response.clicked() { if response.clicked() {
@@ -858,38 +889,33 @@ impl<Leaf> Nodes<Leaf> {
} }
} }
let rect = response.rect;
{ {
// suggest dropping before this tab: // suggest dropping before this tab:
let before_point = if let Some(prev_tab_rect) = prev_tab_rect { let before_point = if let Some(prev_tab_rect) = prev_tab_rect {
// between // between
prev_tab_rect prev_tab_rect.right_center().lerp(rect.left_center(), 0.5)
.right_center()
.lerp(response.rect.left_center(), 0.5)
} else { } else {
// before first // before first
response.rect.left_center() rect.left_center()
}; };
drop_context.suggest_point( drop_context.suggest_rect(
InsertionPoint::new(node_id, LayoutType::Tabs, insertion_index), InsertionPoint::new(node_id, LayoutType::Tabs, insertion_index),
before_point, Rect::from_center_size(before_point, vec2(4.0, rect.height())),
Rect::from_center_size(before_point, vec2(4.0, response.rect.height())),
); );
} }
if child_index + 1 == tabs.children.len() { if i + 1 == tabs.children.len() {
// suggest dropping after last tab: // suggest dropping after last tab:
drop_context.suggest_point( drop_context.suggest_rect(
InsertionPoint::new(node_id, LayoutType::Tabs, insertion_index + 1), InsertionPoint::new(node_id, LayoutType::Tabs, insertion_index + 1),
response.rect.right_center(), Rect::from_center_size(rect.right_center(), vec2(4.0, rect.height())),
Rect::from_center_size(
response.rect.right_center(),
vec2(4.0, response.rect.height()),
),
); );
} }
prev_tab_rect = Some(response.rect); prev_tab_rect = Some(rect);
insertion_index += 1; insertion_index += 1;
} }
}); });
@@ -910,8 +936,46 @@ impl<Leaf> Nodes<Leaf> {
parent_id: NodeId, parent_id: NodeId,
horizontal: &mut Horizontal, horizontal: &mut Horizontal,
) { ) {
for child in &horizontal.children { let mut prev_rect: Option<Rect> = None;
self.node_ui(behavior, drop_context, ui, *child); let mut insertion_index = 0; // skips over drag-source, if any, beacuse it will be removed then re-inserted
for (i, &child) in horizontal.children.iter().enumerate() {
let rect = self.nodes[&child].rect;
if is_being_dragged(ui.ctx(), child) {
// suggest self as drop-target:
drop_context.suggest_rect(
InsertionPoint::new(parent_id, LayoutType::Horizontal, i),
rect,
);
} else {
self.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, LayoutType::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, LayoutType::Horizontal, 0),
rect.split_left_right_at_fraction(0.66).0,
);
}
if i + 1 == horizontal.children.len() {
// Suggest dropping after the last child:
drop_context.suggest_rect(
InsertionPoint::new(parent_id, LayoutType::Horizontal, insertion_index + 1),
rect.split_left_right_at_fraction(0.33).1,
);
}
insertion_index += 1;
}
prev_rect = Some(rect);
} }
} }