mirror of
https://github.com/emilk/egui.git
synced 2026-09-01 14:20:04 -04:00
Drag to re-arrange tabs
This commit is contained in:
@@ -440,7 +440,9 @@ impl<Leaf> Dock<Leaf> {
|
|||||||
.current_pos(mouse_pos)
|
.current_pos(mouse_pos)
|
||||||
.interactable(false)
|
.interactable(false)
|
||||||
.show(ui.ctx(), |ui| {
|
.show(ui.ctx(), |ui| {
|
||||||
egui::Frame::popup(ui.style()).show(ui, |ui| {
|
let mut frame = egui::Frame::popup(ui.style());
|
||||||
|
frame.fill = frame.fill.gamma_multiply(0.5); // Make see-through
|
||||||
|
frame.show(ui, |ui| {
|
||||||
// TODO: preview contents
|
// TODO: preview contents
|
||||||
let text = behavior.tab_text_for_node(&self.nodes, dragged_node_id);
|
let text = behavior.tab_text_for_node(&self.nodes, dragged_node_id);
|
||||||
ui.label(text);
|
ui.label(text);
|
||||||
@@ -704,6 +706,16 @@ struct InsertionPoint {
|
|||||||
index: usize,
|
index: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl InsertionPoint {
|
||||||
|
fn new(parent_id: NodeId, layout_type: LayoutType, index: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
parent_id,
|
||||||
|
layout_type,
|
||||||
|
index,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct DropContext {
|
struct DropContext {
|
||||||
active: bool,
|
active: bool,
|
||||||
dragged_node_id: Option<NodeId>,
|
dragged_node_id: Option<NodeId>,
|
||||||
@@ -716,48 +728,31 @@ struct DropContext {
|
|||||||
|
|
||||||
impl DropContext {
|
impl DropContext {
|
||||||
fn on_node(&mut self, parent_id: NodeId, rect: Rect) {
|
fn on_node(&mut self, parent_id: NodeId, rect: Rect) {
|
||||||
|
if !self.active {
|
||||||
|
return;
|
||||||
|
}
|
||||||
self.suggest_point(
|
self.suggest_point(
|
||||||
InsertionPoint {
|
InsertionPoint::new(parent_id, LayoutType::Horizontal, 0),
|
||||||
parent_id,
|
|
||||||
layout_type: LayoutType::Horizontal,
|
|
||||||
index: 0,
|
|
||||||
},
|
|
||||||
rect.left_center(),
|
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_point(
|
||||||
InsertionPoint {
|
InsertionPoint::new(parent_id, LayoutType::Horizontal, usize::MAX),
|
||||||
parent_id,
|
|
||||||
layout_type: LayoutType::Horizontal,
|
|
||||||
index: usize::MAX,
|
|
||||||
},
|
|
||||||
rect.right_center(),
|
rect.right_center(),
|
||||||
rect.split_left_right_at_fraction(0.5).1,
|
rect.split_left_right_at_fraction(0.5).1,
|
||||||
);
|
);
|
||||||
self.suggest_point(
|
self.suggest_point(
|
||||||
InsertionPoint {
|
InsertionPoint::new(parent_id, LayoutType::Vertical, 0),
|
||||||
parent_id,
|
|
||||||
layout_type: LayoutType::Vertical,
|
|
||||||
index: 0,
|
|
||||||
},
|
|
||||||
rect.center_top(),
|
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_point(
|
||||||
InsertionPoint {
|
InsertionPoint::new(parent_id, LayoutType::Vertical, usize::MAX),
|
||||||
parent_id,
|
|
||||||
layout_type: LayoutType::Vertical,
|
|
||||||
index: usize::MAX,
|
|
||||||
},
|
|
||||||
rect.center_bottom(),
|
rect.center_bottom(),
|
||||||
rect.split_top_bottom_at_fraction(0.5).1,
|
rect.split_top_bottom_at_fraction(0.5).1,
|
||||||
);
|
);
|
||||||
self.suggest_point(
|
self.suggest_point(
|
||||||
InsertionPoint {
|
InsertionPoint::new(parent_id, LayoutType::Tabs, 1),
|
||||||
parent_id,
|
|
||||||
layout_type: LayoutType::Tabs,
|
|
||||||
index: 1,
|
|
||||||
},
|
|
||||||
rect.center(),
|
rect.center(),
|
||||||
rect,
|
rect,
|
||||||
);
|
);
|
||||||
@@ -823,7 +818,7 @@ impl<Leaf> Nodes<Leaf> {
|
|||||||
drop_context: &mut DropContext,
|
drop_context: &mut DropContext,
|
||||||
ui: &mut Ui,
|
ui: &mut Ui,
|
||||||
rect: Rect,
|
rect: Rect,
|
||||||
parent_id: NodeId,
|
node_id: NodeId,
|
||||||
tabs: &mut Tabs,
|
tabs: &mut Tabs,
|
||||||
) {
|
) {
|
||||||
if !tabs.children.iter().any(|&child| child == tabs.active) {
|
if !tabs.children.iter().any(|&child| child == tabs.active) {
|
||||||
@@ -837,15 +832,18 @@ impl<Leaf> Nodes<Leaf> {
|
|||||||
|
|
||||||
// Show tab bar:
|
// Show tab bar:
|
||||||
tab_bar_ui.horizontal(|ui| {
|
tab_bar_ui.horizontal(|ui| {
|
||||||
for &child_id in &tabs.children {
|
let mut prev_tab_rect: Option<Rect> = None;
|
||||||
|
let mut insertion_index = 0; // skips over drag-source, if any
|
||||||
|
|
||||||
|
for (child_index, &child_id) in tabs.children.iter().enumerate() {
|
||||||
let selected = child_id == tabs.active;
|
let selected = child_id == tabs.active;
|
||||||
let id = child_id.id();
|
let id = child_id.id();
|
||||||
|
|
||||||
// let is_node_being_dragged = ui.memory(|mem| mem.is_being_dragged(id))
|
let is_node_being_dragged =
|
||||||
// && is_possible_drag(ui.ctx());
|
ui.memory(|mem| mem.is_being_dragged(id)) && is_possible_drag(ui.ctx());
|
||||||
// if is_node_being_dragged {
|
if is_node_being_dragged {
|
||||||
// continue; // leave a gap!
|
continue; // leave a gap!
|
||||||
// }
|
}
|
||||||
|
|
||||||
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);
|
||||||
@@ -859,10 +857,49 @@ impl<Leaf> Nodes<Leaf> {
|
|||||||
tabs.active = child_id;
|
tabs.active = child_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// suggest dropping before this tab:
|
||||||
|
let before_point = if let Some(prev_tab_rect) = prev_tab_rect {
|
||||||
|
// between
|
||||||
|
prev_tab_rect
|
||||||
|
.right_center()
|
||||||
|
.lerp(response.rect.left_center(), 0.5)
|
||||||
|
} else {
|
||||||
|
// before first
|
||||||
|
response.rect.left_center()
|
||||||
|
};
|
||||||
|
|
||||||
|
drop_context.suggest_point(
|
||||||
|
InsertionPoint::new(node_id, LayoutType::Tabs, insertion_index),
|
||||||
|
before_point,
|
||||||
|
Rect::from_center_size(before_point, vec2(4.0, response.rect.height())),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if child_index + 1 == tabs.children.len() {
|
||||||
|
// suggest dropping after last tab:
|
||||||
|
drop_context.suggest_point(
|
||||||
|
InsertionPoint::new(node_id, LayoutType::Tabs, insertion_index + 1),
|
||||||
|
response.rect.right_center(),
|
||||||
|
Rect::from_center_size(
|
||||||
|
response.rect.right_center(),
|
||||||
|
vec2(4.0, response.rect.height()),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
prev_tab_rect = Some(response.rect);
|
||||||
|
insertion_index += 1;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
self.node_ui(behavior, drop_context, ui, tabs.active);
|
// When dragged, don't show it (it is "being held")
|
||||||
|
let is_active_being_dragged =
|
||||||
|
ui.memory(|mem| mem.is_being_dragged(tabs.active.id())) && is_possible_drag(ui.ctx());
|
||||||
|
if !is_active_being_dragged {
|
||||||
|
self.node_ui(behavior, drop_context, ui, tabs.active);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn horizontal_ui(
|
fn horizontal_ui(
|
||||||
@@ -930,6 +967,7 @@ impl<Leaf> Nodes<Leaf> {
|
|||||||
|
|
||||||
NodeLayout::Horizontal(Horizontal { children, .. })
|
NodeLayout::Horizontal(Horizontal { children, .. })
|
||||||
| NodeLayout::Vertical(Vertical { children, .. }) => {
|
| NodeLayout::Vertical(Vertical { children, .. }) => {
|
||||||
|
// TODO: join nested versions of the same thing
|
||||||
children.retain_mut(|child| match self.simplify(options, *child) {
|
children.retain_mut(|child| match self.simplify(options, *child) {
|
||||||
SimplifyAction::Remove => false,
|
SimplifyAction::Remove => false,
|
||||||
SimplifyAction::Keep => true,
|
SimplifyAction::Keep => true,
|
||||||
|
|||||||
@@ -188,6 +188,14 @@ impl Pos2 {
|
|||||||
y: self.y.clamp(min.y, max.y),
|
y: self.y.clamp(min.y, max.y),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Linearly interpolate towards another point, so that `0.0 => self, 1.0 => other`.
|
||||||
|
pub fn lerp(&self, other: Pos2, t: f32) -> Pos2 {
|
||||||
|
Pos2 {
|
||||||
|
x: lerp(self.x..=other.x, t),
|
||||||
|
y: lerp(self.y..=other.y, t),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::ops::Index<usize> for Pos2 {
|
impl std::ops::Index<usize> for Pos2 {
|
||||||
|
|||||||
Reference in New Issue
Block a user