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

Code cleanup

This commit is contained in:
Emil Ernerfeldt
2023-05-04 21:59:45 +02:00
parent aa30414caf
commit e84eef7815
5 changed files with 146 additions and 99 deletions

View File

@@ -1,4 +1,6 @@
use egui::{vec2, Color32, Id, Response, Rgba, Sense, Stroke, TextStyle, Ui, Visuals, WidgetText}; use egui::{
vec2, Color32, Id, Rect, Response, Rgba, Sense, Stroke, TextStyle, Ui, Visuals, WidgetText,
};
use super::{Node, NodeId, Nodes, ResizeState, SimplificationOptions, UiResponse}; use super::{Node, NodeId, Nodes, ResizeState, SimplificationOptions, UiResponse};
@@ -7,14 +9,22 @@ pub trait Behavior<Leaf> {
/// Show this leaf node in the given [`egui::Ui`]. /// Show this leaf node in the given [`egui::Ui`].
/// ///
/// If this is an unknown node, return [`NodeAction::Remove`] and the node will be removed. /// If this is an unknown node, return [`NodeAction::Remove`] and the node will be removed.
///
/// You can make the leaf draggable by returning [`UiResponse::DragStarted`]
/// when the user drags some handle.
fn leaf_ui(&mut self, _ui: &mut Ui, _node_id: NodeId, _leaf: &mut Leaf) -> UiResponse; fn leaf_ui(&mut self, _ui: &mut Ui, _node_id: NodeId, _leaf: &mut Leaf) -> UiResponse;
fn tab_text_for_leaf(&mut self, leaf: &Leaf) -> WidgetText; /// The title of a leaf tab.
fn tab_title_for_leaf(&mut self, leaf: &Leaf) -> WidgetText;
fn tab_text_for_node(&mut self, nodes: &Nodes<Leaf>, node_id: NodeId) -> WidgetText { /// The title of a general tab.
///
/// The default implementation uses the name of the layout for branches, and
/// calls [`Self::tab_text_for_leaf`] for leaves.
fn tab_title_for_node(&mut self, nodes: &Nodes<Leaf>, node_id: NodeId) -> WidgetText {
if let Some(node) = nodes.nodes.get(&node_id) { if let Some(node) = nodes.nodes.get(&node_id) {
match node { match node {
Node::Leaf(leaf) => self.tab_text_for_leaf(leaf), Node::Leaf(leaf) => self.tab_title_for_leaf(leaf),
Node::Branch(branch) => format!("{:?}", branch.get_layout()).into(), Node::Branch(branch) => format!("{:?}", branch.get_layout()).into(),
} }
} else { } else {
@@ -23,6 +33,8 @@ pub trait Behavior<Leaf> {
} }
/// Show the title of a tab as a button. /// Show the title of a tab as a button.
///
/// You can override the default implementation to add e.g. a close button.
fn tab_ui( fn tab_ui(
&mut self, &mut self,
nodes: &Nodes<Leaf>, nodes: &Nodes<Leaf>,
@@ -32,7 +44,7 @@ pub trait Behavior<Leaf> {
active: bool, active: bool,
is_being_dragged: bool, is_being_dragged: bool,
) -> Response { ) -> Response {
let text = self.tab_text_for_node(nodes, node_id); let text = self.tab_title_for_node(nodes, node_id);
let font_id = TextStyle::Button.resolve(ui.style()); let font_id = TextStyle::Button.resolve(ui.style());
let galley = text.into_galley(ui, Some(false), f32::INFINITY, font_id); let galley = text.into_galley(ui, Some(false), f32::INFINITY, font_id);
@@ -45,8 +57,8 @@ pub trait Behavior<Leaf> {
// Show a gap when dragged // Show a gap when dragged
if ui.is_rect_visible(rect) && !is_being_dragged { if ui.is_rect_visible(rect) && !is_being_dragged {
let bg_color = self.tab_bg_color(ui.visuals(), active); let bg_color = self.tab_bg_color(ui.visuals(), node_id, active);
let stroke = self.tab_outline_stroke(ui.visuals(), active); let stroke = self.tab_outline_stroke(ui.visuals(), node_id, active);
ui.painter().rect(rect.shrink(0.5), 0.0, bg_color, stroke); ui.painter().rect(rect.shrink(0.5), 0.0, bg_color, stroke);
if active { if active {
@@ -58,7 +70,7 @@ pub trait Behavior<Leaf> {
); );
} }
let text_color = self.tab_text_color(ui.visuals(), active); let text_color = self.tab_text_color(ui.visuals(), node_id, active);
ui.painter().galley_with_color( ui.painter().galley_with_color(
egui::Align2::CENTER_CENTER egui::Align2::CENTER_CENTER
.align_size_within_rect(galley.size(), rect) .align_size_within_rect(galley.size(), rect)
@@ -76,7 +88,7 @@ pub trait Behavior<Leaf> {
true true
} }
/// Adds some UI to the top right of the tab bar. /// Adds some UI to the top right of each tab bar.
/// ///
/// You can use this to, for instance, add a button for adding new tabs. /// You can use this to, for instance, add a button for adding new tabs.
/// ///
@@ -89,7 +101,7 @@ pub trait Behavior<Leaf> {
// -------- // --------
// Settings: // Settings:
/// The height of the bar holding tab names. /// The height of the bar holding tab titles.
fn tab_bar_height(&self, _style: &egui::Style) -> f32 { fn tab_bar_height(&self, _style: &egui::Style) -> f32 {
24.0 24.0
} }
@@ -100,15 +112,17 @@ pub trait Behavior<Leaf> {
1.0 1.0
} }
// No child should shrink below this size /// No child should shrink below this width nor height.
fn min_size(&self) -> f32 { fn min_size(&self) -> f32 {
32.0 32.0
} }
/// What are the rules for simplifying the tree?
fn simplification_options(&self) -> SimplificationOptions { fn simplification_options(&self) -> SimplificationOptions {
SimplificationOptions::default() SimplificationOptions::default()
} }
/// The stroke used for the lines in horizontal, vertical, and grid layouts.
fn resize_stroke(&self, style: &egui::Style, resize_state: ResizeState) -> egui::Stroke { fn resize_stroke(&self, style: &egui::Style, resize_state: ResizeState) -> egui::Stroke {
match resize_state { match resize_state {
ResizeState::Idle => egui::Stroke::NONE, // Let the gap speak for itself ResizeState::Idle => egui::Stroke::NONE, // Let the gap speak for itself
@@ -122,7 +136,7 @@ pub trait Behavior<Leaf> {
8.0 8.0
} }
/// The background color of the tab bar /// The background color of the tab bar.
fn tab_bar_color(&self, visuals: &Visuals) -> Color32 { fn tab_bar_color(&self, visuals: &Visuals) -> Color32 {
if visuals.dark_mode { if visuals.dark_mode {
Color32::BLACK Color32::BLACK
@@ -131,7 +145,8 @@ pub trait Behavior<Leaf> {
} }
} }
fn tab_bg_color(&self, visuals: &Visuals, active: bool) -> Color32 { /// The background color of a tab.
fn tab_bg_color(&self, visuals: &Visuals, _node_id: NodeId, active: bool) -> Color32 {
if active { if active {
visuals.window_fill() // same as the tab contents visuals.window_fill() // same as the tab contents
} else { } else {
@@ -140,7 +155,7 @@ pub trait Behavior<Leaf> {
} }
/// Stroke of the outline around a tab title. /// Stroke of the outline around a tab title.
fn tab_outline_stroke(&self, visuals: &Visuals, active: bool) -> Stroke { fn tab_outline_stroke(&self, visuals: &Visuals, _node_id: NodeId, active: bool) -> Stroke {
if active { if active {
Stroke::new(1.0, visuals.widgets.active.bg_fill) Stroke::new(1.0, visuals.widgets.active.bg_fill)
} else { } else {
@@ -153,11 +168,42 @@ pub trait Behavior<Leaf> {
Stroke::new(1.0, visuals.widgets.noninteractive.bg_stroke.color) Stroke::new(1.0, visuals.widgets.noninteractive.bg_stroke.color)
} }
fn tab_text_color(&self, visuals: &Visuals, active: bool) -> Color32 { /// The color of the title text of the tab.
fn tab_text_color(&self, visuals: &Visuals, _node_id: NodeId, active: bool) -> Color32 {
if active { if active {
visuals.widgets.active.text_color() visuals.widgets.active.text_color()
} else { } else {
visuals.widgets.noninteractive.text_color() visuals.widgets.noninteractive.text_color()
} }
} }
/// When drag-and-dropping a node, how do we preview what is about to happen?
fn paint_drag_preview(
&self,
visuals: &Visuals,
painter: &egui::Painter,
parent_rect: Option<Rect>,
preview_rect: Rect,
) {
let preview_stroke = visuals.selection.stroke;
let preview_color = preview_stroke.color;
if let Some(parent_rect) = parent_rect {
// Show which parent we will be dropped into
painter.rect_stroke(parent_rect, 1.0, preview_stroke);
}
painter.rect(
preview_rect,
1.0,
preview_color.gamma_multiply(0.5),
preview_stroke,
);
}
/// Show we preview leaves that are being dragged,
/// i.e. show their ui in the region where they will end up?
fn preview_dragged_leaves(&self) -> bool {
false
}
} }

View File

@@ -68,8 +68,6 @@ impl<Leaf: std::fmt::Debug> std::fmt::Debug for Dock<Leaf> {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Construction
impl<Leaf> Dock<Leaf> { impl<Leaf> Dock<Leaf> {
pub fn new(root: NodeId, nodes: Nodes<Leaf>) -> Self { pub fn new(root: NodeId, nodes: Nodes<Leaf>) -> Self {
Self { Self {
@@ -79,6 +77,10 @@ impl<Leaf> Dock<Leaf> {
} }
} }
pub fn root(&self) -> NodeId {
self.root
}
pub fn parent_of(&self, node_id: NodeId) -> Option<NodeId> { pub fn parent_of(&self, node_id: NodeId) -> Option<NodeId> {
self.nodes self.nodes
.nodes .nodes
@@ -92,15 +94,10 @@ impl<Leaf> Dock<Leaf> {
}) })
.map(|(id, _)| *id) .map(|(id, _)| *id)
} }
}
// Usage /// Show the dock in the given [`Ui`].
impl<Leaf> Dock<Leaf> { ///
pub fn root(&self) -> NodeId { /// The dock will use upp all the avilable space - nothing more, nothing less.
self.root
}
/// Show all the leaves in the dock.
pub fn ui(&mut self, behavior: &mut dyn Behavior<Leaf>, ui: &mut Ui) { pub fn ui(&mut self, behavior: &mut dyn Behavior<Leaf>, ui: &mut Ui) {
let options = behavior.simplification_options(); let options = behavior.simplification_options();
self.simplify(&options); self.simplify(&options);
@@ -133,6 +130,15 @@ impl<Leaf> Dock<Leaf> {
self.nodes self.nodes
.node_ui(behavior, &mut drop_context, ui, self.root); .node_ui(behavior, &mut drop_context, ui, self.root);
self.preview_dragged_node(behavior, &drop_context, ui);
}
fn preview_dragged_node(
&mut self,
behavior: &mut dyn Behavior<Leaf>,
drop_context: &DropContext,
ui: &mut Ui,
) {
if let (Some(mouse_pos), Some(dragged_node_id)) = if let (Some(mouse_pos), Some(dragged_node_id)) =
(drop_context.mouse_pos, drop_context.dragged_node_id) (drop_context.mouse_pos, drop_context.dragged_node_id)
{ {
@@ -147,8 +153,8 @@ impl<Leaf> Dock<Leaf> {
let mut frame = egui::Frame::popup(ui.style()); let mut frame = egui::Frame::popup(ui.style());
frame.fill = frame.fill.gamma_multiply(0.5); // Make see-through frame.fill = frame.fill.gamma_multiply(0.5); // Make see-through
frame.show(ui, |ui| { frame.show(ui, |ui| {
// TODO: preview contents // TODO(emilk): preview contents?
let text = behavior.tab_text_for_node(&self.nodes, dragged_node_id); let text = behavior.tab_title_for_node(&self.nodes, dragged_node_id);
ui.label(text); ui.label(text);
}); });
}); });
@@ -156,26 +162,14 @@ impl<Leaf> Dock<Leaf> {
if let Some(preview_rect) = drop_context.preview_rect { if let Some(preview_rect) = drop_context.preview_rect {
let preview_rect = self.smooth_preview_rect(ui.ctx(), preview_rect); let preview_rect = self.smooth_preview_rect(ui.ctx(), preview_rect);
let preview_stroke = ui.visuals().selection.stroke; let parent_rect = drop_context
let preview_color = preview_stroke.color; .best_insertion
.and_then(|insertion_point| self.nodes.try_rect(insertion_point.parent_id));
if let Some(insertion_point) = &drop_context.best_insertion { behavior.paint_drag_preview(ui.visuals(), ui.painter(), parent_rect, preview_rect);
if let Some(parent_rect) = self.nodes.try_rect(insertion_point.parent_id) {
// Show which parent we will be dropped into
ui.painter().rect_stroke(parent_rect, 1.0, preview_stroke);
}
}
ui.painter().rect( if behavior.preview_dragged_leaves() {
preview_rect, // TODO(emilk): add support for previewing branches too.
1.0,
preview_color.gamma_multiply(0.5),
preview_stroke,
);
let preview_child = false;
if preview_child {
// Preview actual child?
if preview_rect.width() > 32.0 && preview_rect.height() > 32.0 { if preview_rect.width() > 32.0 && preview_rect.height() > 32.0 {
if let Some(Node::Leaf(leaf)) = self.nodes.get_mut(dragged_node_id) { if let Some(Node::Leaf(leaf)) = self.nodes.get_mut(dragged_node_id) {
let _ = behavior.leaf_ui( let _ = behavior.leaf_ui(
@@ -200,6 +194,7 @@ impl<Leaf> Dock<Leaf> {
} }
} }
/// Take the preview rectangle and smooth it over time.
fn smooth_preview_rect(&mut self, ctx: &egui::Context, new_rect: Rect) -> Rect { fn smooth_preview_rect(&mut self, ctx: &egui::Context, new_rect: Rect) -> Rect {
let dt = ctx.input(|input| input.stable_dt).at_most(0.1); let dt = ctx.input(|input| input.stable_dt).at_most(0.1);
let t = egui::emath::exponential_smooth_factor(0.9, 0.05, dt); let t = egui::emath::exponential_smooth_factor(0.9, 0.05, dt);
@@ -228,7 +223,8 @@ impl<Leaf> Dock<Leaf> {
} }
} }
fn move_node(&mut self, moved_node_id: NodeId, insertion_point: InsertionPoint) { /// Move the given node to the given insertion point.
pub fn move_node(&mut self, moved_node_id: NodeId, insertion_point: InsertionPoint) {
log::debug!( log::debug!(
"Moving {moved_node_id:?} into {:?}", "Moving {moved_node_id:?} into {:?}",
insertion_point.insertion insertion_point.insertion
@@ -238,7 +234,7 @@ impl<Leaf> Dock<Leaf> {
} }
/// Find the currently dragged node, if any. /// Find the currently dragged node, if any.
fn dragged_id(&self, ctx: &egui::Context) -> Option<NodeId> { pub fn dragged_id(&self, ctx: &egui::Context) -> Option<NodeId> {
if !is_possible_drag(ctx) { if !is_possible_drag(ctx) {
// We're not sure we're dragging _at all_ yet. // We're not sure we're dragging _at all_ yet.
return None; return None;
@@ -246,7 +242,7 @@ impl<Leaf> Dock<Leaf> {
for &node_id in self.nodes.nodes.keys() { for &node_id in self.nodes.nodes.keys() {
if node_id == self.root { if node_id == self.root {
continue; // now allowed to drag root continue; // not allowed to drag root
} }
let id = node_id.id(); let id = node_id.id();
@@ -264,9 +260,12 @@ impl<Leaf> Dock<Leaf> {
None None
} }
/// Performs no simplifcations! /// Performs no simplifcations, nor does it remove the actual [`Node`].
fn remove_node_id_from_parent(&mut self, dragged_node_id: NodeId) { pub fn remove_node_id_from_parent(&mut self, remove_me: NodeId) {
self.nodes for parent in self.nodes.nodes.values_mut() {
.remove_node_id_from_parent(self.root, dragged_node_id); if let Node::Branch(branch) = parent {
branch.retain(|child| child != remove_me);
}
}
} }
} }

View File

@@ -16,21 +16,36 @@
//! The user needs to implement this in order to specify the `ui` of each `Leaf` and //! The user needs to implement this in order to specify the `ui` of each `Leaf` and
//! the tab name of leaves (if there are tab nodes). //! the tab name of leaves (if there are tab nodes).
//! //!
//! ## Implementation notes
//! In many places we want to recursively visit all noted, while also mutating them.
//! In order to not get into trouble with the borrow checker a trick is used:
//! each [`Node`] is removed, mutated, recursed, and then re-added.
//! You'll see this pattern many times reading the following code.
//!
//! ## Shortcomings //! ## Shortcomings
//! We use real recursion, so if your trees get too deep you will get a stack overflow. //! We use real recursion, so if your trees get too deep you will get a stack overflow.
//! //!
//!
//! ## Future improvements //! ## Future improvements
//! * A new ui for each node, nested //! * Easy per-tab close-buttons
//! * Per-tab close-buttons
//! * Scrolling of tab-bar //! * Scrolling of tab-bar
//! * Vertical tab bar //! * Vertical tab bar
//! * Auto-grid layouts (re-arange as parent is resized) //! * Auto-join nested horizontal/vertical layouts in the simplify step
// ## Implementation notes
// In many places we want to recursively visit all noted, while also mutating them.
// In order to not get into trouble with the borrow checker a trick is used:
// each [`Node`] is removed, mutated, recursed, and then re-added.
// You'll see this pattern many times reading the following code.
//
// Each frame consists of two passes: layout, and ui.
// The layout pass figures out where each node should be placed.
// The ui pass does all the painting.
// These two passes could be combined into one pass if we wanted to,
// but having them split up makes the code slightly simpler, and
// leaves the door open for more complex layout (e.g. min/max sizes per node).
//
// Everything is quite dynamic, so we have a bunch of defensive coding that call `warn!` on failure.
// These situations should not happen in normal use, but could happen if the user messes with
// the internals of the tree, putting it in an invalid state.
//
// ## TODO before release:
// * Auto-grid layouts (re-arange as parent is resized)
// * Clip tab titles to not cover "add new tab" button
use egui::{Id, Pos2, Rect}; use egui::{Id, Pos2, Rect};
@@ -96,6 +111,7 @@ pub enum UiResponse {
DragStarted, DragStarted,
} }
/// What are the rules for simplifying the tree?
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct SimplificationOptions { pub struct SimplificationOptions {
pub prune_empty_tabs: bool, pub prune_empty_tabs: bool,
@@ -143,7 +159,7 @@ pub struct InsertionPoint {
} }
impl InsertionPoint { impl InsertionPoint {
fn new(parent_id: NodeId, insertion: LayoutInsertion) -> Self { pub fn new(parent_id: NodeId, insertion: LayoutInsertion) -> Self {
Self { Self {
parent_id, parent_id,
insertion, insertion,
@@ -185,7 +201,14 @@ struct DropContext {
} }
impl DropContext { impl DropContext {
fn on_node<Leaf>(&mut self, parent_id: NodeId, rect: Rect, node: &Node<Leaf>) { fn on_node<Leaf>(
&mut self,
behavior: &mut dyn Behavior<Leaf>,
style: &egui::Style,
parent_id: NodeId,
rect: Rect,
node: &Node<Leaf>,
) {
if !self.enabled { if !self.enabled {
return; return;
} }
@@ -212,17 +235,18 @@ impl DropContext {
); );
} }
// self.suggest_rect(InsertionPoint::new(parent_id, LayoutType::Tabs, 1), rect); self.suggest_rect(
InsertionPoint::new(parent_id, LayoutInsertion::Tabs(usize::MAX)),
rect.split_top_bottom_at_y(rect.top() + behavior.tab_bar_height(style))
.1,
);
} }
fn suggest_rect(&mut self, insertion: InsertionPoint, preview_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) {
if !self.enabled { if !self.enabled {
return; return;
} }
let target_point = preview_rect.center();
if let Some(mouse_pos) = self.mouse_pos { if let Some(mouse_pos) = self.mouse_pos {
let dist_sq = mouse_pos.distance_sq(target_point); let dist_sq = mouse_pos.distance_sq(target_point);
if dist_sq < self.best_dist_sq { if dist_sq < self.best_dist_sq {

View File

@@ -14,7 +14,7 @@ pub struct Nodes<Leaf> {
/// Filled in by the layout step at the start of each frame. /// Filled in by the layout step at the start of each frame.
#[serde(default, skip)] #[serde(default, skip)]
pub rects: HashMap<NodeId, Rect>, pub(super) rects: HashMap<NodeId, Rect>,
} }
impl<Leaf> Default for Nodes<Leaf> { impl<Leaf> Default for Nodes<Leaf> {
@@ -29,11 +29,11 @@ impl<Leaf> Default for Nodes<Leaf> {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
impl<Leaf> Nodes<Leaf> { impl<Leaf> Nodes<Leaf> {
pub fn try_rect(&self, node_id: NodeId) -> Option<Rect> { pub(super) fn try_rect(&self, node_id: NodeId) -> Option<Rect> {
self.rects.get(&node_id).copied() self.rects.get(&node_id).copied()
} }
pub fn rect(&self, node_id: NodeId) -> Rect { pub(super) fn rect(&self, node_id: NodeId) -> Rect {
let rect = self.try_rect(node_id); let rect = self.try_rect(node_id);
debug_assert!(rect.is_some(), "Failed to find rect for {node_id:?}"); debug_assert!(rect.is_some(), "Failed to find rect for {node_id:?}");
rect.unwrap_or(egui::Rect::from_min_max(Pos2::ZERO, Pos2::ZERO)) rect.unwrap_or(egui::Rect::from_min_max(Pos2::ZERO, Pos2::ZERO))
@@ -90,23 +90,6 @@ impl<Leaf> Nodes<Leaf> {
self.insert_node(Node::Branch(Branch::new_grid(children))) self.insert_node(Node::Branch(Branch::new_grid(children)))
} }
/// Performs no simplifcations!
/// // TODO: remove ?
pub(super) fn remove_node_id_from_parent(&mut self, it: NodeId, remove: NodeId) -> GcAction {
if it == remove {
return GcAction::Remove;
}
let Some(mut node) = self.nodes.remove(&it) else {
log::warn!("Unexpected missing node during removal");
return GcAction::Remove;
};
if let Node::Branch(branch) = &mut node {
branch.retain(|child| self.remove_node_id_from_parent(child, remove) == GcAction::Keep);
}
self.nodes.insert(it, node);
GcAction::Keep
}
pub fn insert(&mut self, insertion_point: InsertionPoint, child_id: NodeId) { pub fn insert(&mut self, insertion_point: InsertionPoint, child_id: NodeId) {
let InsertionPoint { let InsertionPoint {
parent_id, parent_id,
@@ -257,7 +240,7 @@ impl<Leaf> Nodes<Leaf> {
ui: &mut Ui, ui: &mut Ui,
node_id: NodeId, node_id: NodeId,
) { ) {
// NOTE: important that we get thr rect and node in two steps, // NOTE: important that we get the rect and node in two steps,
// otherwise we could loose the node when there is no rect. // otherwise we could loose the node when there is no rect.
let Some(rect) = self.try_rect(node_id) else { let Some(rect) = self.try_rect(node_id) else {
log::warn!("Failed to find rect for node {node_id:?} during ui"); log::warn!("Failed to find rect for node {node_id:?} during ui");
@@ -273,14 +256,9 @@ 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.enabled = false; drop_context.enabled = false;
} }
drop_context.on_node(node_id, rect, &node); drop_context.on_node(behavior, ui.style(), node_id, rect, &node);
drop_context.suggest_rect(
InsertionPoint::new(node_id, LayoutInsertion::Tabs(usize::MAX)),
rect.split_top_bottom_at_y(rect.top() + behavior.tab_bar_height(ui.style()))
.1,
);
// Each node gets its own `Ui`, nested inside each other, with proper clip rectangles.
let mut ui = egui::Ui::new( let mut ui = egui::Ui::new(
ui.ctx().clone(), ui.ctx().clone(),
ui.layer_id(), ui.layer_id(),
@@ -314,7 +292,7 @@ impl<Leaf> Nodes<Leaf> {
}; };
if let Node::Branch(branch) = &mut node { if let Node::Branch(branch) = &mut node {
// TODO: join nested versions of the same horizontal/vertical layouts // TODO(emilk): join nested versions of the same horizontal/vertical layouts
branch.simplify_children(|child| self.simplify(options, child)); branch.simplify_children(|child| self.simplify(options, child));

View File

@@ -119,7 +119,7 @@ impl dock::Behavior<View> for DockBehavior {
view.ui(ui) view.ui(ui)
} }
fn tab_text_for_leaf(&mut self, view: &View) -> egui::WidgetText { fn tab_title_for_leaf(&mut self, view: &View) -> egui::WidgetText {
format!("View {}", view.nr).into() format!("View {}", view.nr).into()
} }
@@ -249,7 +249,7 @@ fn tree_ui(
// Get the name BEFORE we remove the node below! // Get the name BEFORE we remove the node below!
let text = format!( let text = format!(
"{} - {node_id:?}", "{} - {node_id:?}",
behavior.tab_text_for_node(nodes, node_id).text() behavior.tab_title_for_node(nodes, node_id).text()
); );
let Some(mut node) = nodes.nodes.remove(&node_id) else { let Some(mut node) = nodes.nodes.remove(&node_id) else {