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

Improve dragging around tab labels

This commit is contained in:
Emil Ernerfeldt
2023-05-04 09:40:40 +02:00
parent 8267cf5f57
commit e2b1438977
2 changed files with 72 additions and 51 deletions

View File

@@ -122,7 +122,7 @@ impl Linear {
}
}
drop_zones(ui.ctx(), nodes, &self.children, self.dir, |rect, i| {
linear_drop_zones(ui.ctx(), nodes, &self.children, self.dir, |rect, i| {
drop_context.suggest_rect(
InsertionPoint::new(parent_id, LayoutInsertion::Horizontal(i)),
rect,
@@ -185,7 +185,7 @@ impl Linear {
}
}
drop_zones(ui.ctx(), nodes, &self.children, self.dir, |rect, i| {
linear_drop_zones(ui.ctx(), nodes, &self.children, self.dir, |rect, i| {
drop_context.suggest_rect(
InsertionPoint::new(parent_id, LayoutInsertion::Vertical(i)),
rect,
@@ -315,25 +315,18 @@ fn shrink_shares<Leaf>(
total_shares_lost
}
fn drop_zones<Leaf>(
fn linear_drop_zones<Leaf>(
egui_ctx: &egui::Context,
nodes: &Nodes<Leaf>,
children: &[NodeId],
dir: LinearDir,
mut add_drop_drect: impl FnMut(Rect, usize),
add_drop_drect: impl FnMut(Rect, usize),
) {
let preview_thickness = 12.0;
let dragged_index = children
.iter()
.position(|&child| is_being_dragged(egui_ctx, child));
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),
@@ -344,6 +337,37 @@ fn drop_zones<Leaf>(
rect.right_bottom(),
),
};
drop_zones(
preview_thickness,
children,
dragged_index,
dir,
|node_id| nodes.rect(node_id),
add_drop_drect,
afer_rect,
);
}
pub fn drop_zones(
preview_thickness: f32,
children: &[NodeId],
dragged_index: Option<usize>,
dir: LinearDir,
get_rect: impl Fn(NodeId) -> Rect,
mut add_drop_drect: impl FnMut(Rect, usize),
afer_rect: impl Fn(Rect) -> Rect,
) {
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 between_rects = |a: Rect, b: Rect| match dir {
LinearDir::Horizontal => Rect::from_center_size(
a.right_center().lerp(b.left_center(), 0.5),
@@ -355,15 +379,11 @@ fn drop_zones<Leaf>(
),
};
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);
let rect = get_rect(child);
if Some(i) == dragged_index {
// Suggest hole as a drop-target:

View File

@@ -1,3 +1,5 @@
use std::collections::HashMap;
use egui::{vec2, Rect};
use crate::dock::{
@@ -54,8 +56,8 @@ impl Tabs {
// Show tab bar:
tab_bar_ui.horizontal(|ui| {
let mut prev_tab_rect: Option<Rect> = None;
let mut insertion_index = 0; // skips over drag-source, if any, beacuse it will be removed then re-inserted
let mut button_rects = HashMap::new();
let mut dragged_index = None;
for (i, &child_id) in self.children.iter().enumerate() {
let is_being_dragged = is_being_dragged(ui.ctx(), child_id);
@@ -76,38 +78,37 @@ impl Tabs {
}
}
let rect = response.rect;
{
// suggest dropping before this tab:
let before_point = if let Some(prev_tab_rect) = prev_tab_rect {
// between
prev_tab_rect.right_center().lerp(rect.left_center(), 0.5)
} else {
// before first
rect.left_center()
};
drop_context.suggest_rect(
InsertionPoint::new(node_id, LayoutInsertion::Tabs(insertion_index)),
Rect::from_center_size(before_point, vec2(4.0, rect.height())),
);
}
if i + 1 == self.children.len() {
// suggest dropping after last tab:
drop_context.suggest_rect(
InsertionPoint::new(node_id, LayoutInsertion::Tabs(insertion_index + 1)),
Rect::from_center_size(rect.right_center(), vec2(4.0, rect.height())),
);
}
prev_tab_rect = Some(rect);
if !is_being_dragged {
insertion_index += 1;
button_rects.insert(child_id, response.rect);
if is_being_dragged {
dragged_index = Some(i);
}
}
let preview_thickness = 6.0;
let afer_rect = |rect: Rect| {
let dragged_size = if let Some(dragged_index) = dragged_index {
// We actually know the size of this thing
button_rects[&self.children[dragged_index]].size()
} else {
rect.size() // guess that the size is the same as the last button
};
Rect::from_min_size(
rect.right_top() + vec2(ui.spacing().item_spacing.x, 0.0),
dragged_size,
)
};
super::linear::drop_zones(
preview_thickness,
&self.children,
dragged_index,
super::LinearDir::Horizontal,
|node_id| button_rects[&node_id],
|rect, i| {
drop_context
.suggest_rect(InsertionPoint::new(node_id, LayoutInsertion::Tabs(i)), rect);
},
afer_rect,
);
});
// When dragged, don't show it (it is "being held")