diff --git a/crates/egui_extras/src/dock/branch/grid.rs b/crates/egui_extras/src/dock/branch/grid.rs index 24c365f61..c4aa8cf64 100644 --- a/crates/egui_extras/src/dock/branch/grid.rs +++ b/crates/egui_extras/src/dock/branch/grid.rs @@ -1,4 +1,7 @@ -use std::collections::{BTreeMap, HashMap, HashSet}; +use std::{ + collections::{BTreeMap, HashMap, HashSet}, + ops::RangeInclusive, +}; use egui::{pos2, vec2, Rect}; @@ -6,6 +9,41 @@ use crate::dock::{ sizes_from_shares, Behavior, DropContext, InsertionPoint, LayoutInsertion, NodeId, Nodes, }; +/// Includive range of floats, i.e. `min..=max`, but more ergonomic than [`RangeInclusive`]. +#[derive(Clone, Copy, Debug, PartialEq)] +struct Rangef { + pub min: f32, + pub max: f32, +} + +impl Rangef { + #[inline] + pub fn new(min: f32, max: f32) -> Self { + Self { min, max } + } +} + +impl From> for Rangef { + #[inline] + fn from(range: RangeInclusive) -> Self { + Self::new(*range.start(), *range.end()) + } +} + +impl From<&RangeInclusive> for Rangef { + #[inline] + fn from(range: &RangeInclusive) -> Self { + Self::new(*range.start(), *range.end()) + } +} + +impl From for RangeInclusive { + #[inline] + fn from(Rangef { min, max }: Rangef) -> Self { + min..=max + } +} + /// Where in a grid? #[derive( Clone, @@ -42,6 +80,14 @@ pub struct Grid { pub col_shares: Vec, /// Share of the available height assigned to each row. pub row_shares: Vec, + + /// ui point x ranges for each column, recomputed during layout + #[serde(skip)] + col_ranges: Vec, + + /// ui point y ranges for each row, recomputed during layout + #[serde(skip)] + row_ranges: Vec, } impl Grid { @@ -57,9 +103,7 @@ impl Grid { nodes: &mut Nodes, style: &egui::Style, behavior: &mut dyn Behavior, - drop_context: &mut DropContext, rect: Rect, - node_id: NodeId, ) { let child_ids: HashSet = self.children.iter().copied().collect(); @@ -114,14 +158,21 @@ impl Grid { let col_widths = sizes_from_shares(&self.col_shares, rect.width(), gap); let row_heights = sizes_from_shares(&self.row_shares, rect.height(), gap); - let mut col_x = vec![rect.left()]; - for &width in &col_widths { - col_x.push(col_x.last().unwrap() + width + gap); + { + let mut x = rect.left(); + self.col_ranges.clear(); + for &width in &col_widths { + self.col_ranges.push(Rangef::new(x, x + width)); + x += width + gap; + } } - - let mut row_y = vec![rect.top()]; - for &height in &row_heights { - row_y.push(row_y.last().unwrap() + height + gap); + { + let mut y = rect.top(); + self.row_ranges.clear(); + for &height in &row_heights { + self.row_ranges.push(Rangef::new(y, y + height)); + y += height + gap; + } } // Each child now has a location. Use this to order them, in case we will ater do auto-layouts: @@ -130,20 +181,30 @@ impl Grid { // Place each child: for &child in &self.children { let loc = self.locations[&child]; - let child_rect = Rect::from_min_size( - pos2(col_x[loc.col], row_y[loc.row]), - vec2(col_widths[loc.col], row_heights[loc.row]), - ); - nodes.layout_node(style, behavior, drop_context, child_rect, child); + let child_rect = + Rect::from_x_y_ranges(self.col_ranges[loc.col], self.row_ranges[loc.row]); + nodes.layout_node(style, behavior, child_rect, child); + } + } + + pub fn ui( + &mut self, + nodes: &mut Nodes, + behavior: &mut dyn Behavior, + drop_context: &mut DropContext, + ui: &mut egui::Ui, + node_id: NodeId, + ) { + // Grid drops are handled during layout. TODO: handle here instead. + + for &child in &self.children { + nodes.node_ui(behavior, drop_context, ui, child); } // Register drop-zones: - for col in 0..num_cols { - for row in 0..num_rows { - let cell_rect = Rect::from_min_size( - pos2(col_x[col], row_y[row]), - vec2(col_widths[col], row_heights[row]), - ); + for (col, &x_range) in self.col_ranges.iter().enumerate() { + for (row, &y_range) in self.row_ranges.iter().enumerate() { + let cell_rect = Rect::from_x_y_ranges(x_range, y_range); drop_context.suggest_rect( InsertionPoint::new( node_id, @@ -154,18 +215,4 @@ impl Grid { } } } - - pub fn ui( - &mut self, - nodes: &mut Nodes, - behavior: &mut dyn Behavior, - drop_context: &mut DropContext, - ui: &mut egui::Ui, - ) { - // Grid drops are handled during layout. TODO: handle here instead. - - for &child in &self.children { - nodes.node_ui(behavior, drop_context, ui, child); - } - } } diff --git a/crates/egui_extras/src/dock/branch/linear.rs b/crates/egui_extras/src/dock/branch/linear.rs index bbfe49673..38d1914f4 100644 --- a/crates/egui_extras/src/dock/branch/linear.rs +++ b/crates/egui_extras/src/dock/branch/linear.rs @@ -37,14 +37,13 @@ impl Linear { nodes: &mut Nodes, style: &egui::Style, behavior: &mut dyn Behavior, - drop_context: &mut DropContext, rect: Rect, ) { match self.dir { LinearDir::Horizontal => { - self.layout_horizontal(nodes, style, behavior, drop_context, rect); + self.layout_horizontal(nodes, style, behavior, rect); } - LinearDir::Vertical => self.layout_vertical(nodes, style, behavior, drop_context, rect), + LinearDir::Vertical => self.layout_vertical(nodes, style, behavior, rect), } } @@ -53,7 +52,6 @@ impl Linear { nodes: &mut Nodes, style: &egui::Style, behavior: &mut dyn Behavior, - drop_context: &mut DropContext, rect: Rect, ) { let num_gaps = self.children.len().saturating_sub(1); @@ -66,7 +64,7 @@ impl Linear { let mut x = rect.min.x; for (child, width) in self.children.iter().zip(widths) { let child_rect = Rect::from_min_size(pos2(x, rect.min.y), vec2(width, rect.height())); - nodes.layout_node(style, behavior, drop_context, child_rect, *child); + nodes.layout_node(style, behavior, child_rect, *child); x += width + gap_width; } } @@ -76,7 +74,6 @@ impl Linear { nodes: &mut Nodes, style: &egui::Style, behavior: &mut dyn Behavior, - drop_context: &mut DropContext, rect: Rect, ) { let num_gaps = self.children.len().saturating_sub(1); @@ -89,7 +86,7 @@ impl Linear { let mut y = rect.min.y; for (child, height) in self.children.iter().zip(heights) { let child_rect = Rect::from_min_size(pos2(rect.min.x, y), vec2(rect.width(), height)); - nodes.layout_node(style, behavior, drop_context, child_rect, *child); + nodes.layout_node(style, behavior, child_rect, *child); y += height + gap_height; } } diff --git a/crates/egui_extras/src/dock/branch/mod.rs b/crates/egui_extras/src/dock/branch/mod.rs index 4c07b0ec2..4e88359ff 100644 --- a/crates/egui_extras/src/dock/branch/mod.rs +++ b/crates/egui_extras/src/dock/branch/mod.rs @@ -188,20 +188,18 @@ impl Branch { nodes: &mut Nodes, style: &egui::Style, behavior: &mut dyn Behavior, - drop_context: &mut DropContext, rect: Rect, - node_id: NodeId, ) { if self.is_empty() { return; } match self { - Branch::Tabs(tabs) => tabs.layout(nodes, style, behavior, drop_context, rect), + Branch::Tabs(tabs) => tabs.layout(nodes, style, behavior, rect), Branch::Linear(linear) => { - linear.layout(nodes, style, behavior, drop_context, rect); + linear.layout(nodes, style, behavior, rect); } - Branch::Grid(grid) => grid.layout(nodes, style, behavior, drop_context, rect, node_id), + Branch::Grid(grid) => grid.layout(nodes, style, behavior, rect), } } } @@ -224,7 +222,7 @@ impl Branch { linear.ui(nodes, behavior, drop_context, ui, node_id); } Branch::Grid(grid) => { - grid.ui(nodes, behavior, drop_context, ui); + grid.ui(nodes, behavior, drop_context, ui, node_id); } } } diff --git a/crates/egui_extras/src/dock/branch/tabs.rs b/crates/egui_extras/src/dock/branch/tabs.rs index 3e7703d00..fc11834a4 100644 --- a/crates/egui_extras/src/dock/branch/tabs.rs +++ b/crates/egui_extras/src/dock/branch/tabs.rs @@ -24,14 +24,13 @@ impl Tabs { nodes: &mut Nodes, style: &egui::Style, behavior: &mut dyn Behavior, - drop_context: &mut DropContext, rect: Rect, ) { let mut active_rect = rect; active_rect.min.y += behavior.tab_bar_height(style); // Only lay out the active tab (saves CPU): - nodes.layout_node(style, behavior, drop_context, active_rect, self.active); + nodes.layout_node(style, behavior, active_rect, self.active); } pub fn ui( diff --git a/crates/egui_extras/src/dock/mod.rs b/crates/egui_extras/src/dock/mod.rs index 300f739a7..0dbb7b4a0 100644 --- a/crates/egui_extras/src/dock/mod.rs +++ b/crates/egui_extras/src/dock/mod.rs @@ -455,7 +455,6 @@ impl Dock { self.nodes.layout_node( ui.style(), behavior, - &mut drop_context, ui.available_rect_before_wrap(), self.root, ); @@ -675,7 +674,6 @@ impl Nodes { &mut self, style: &egui::Style, behavior: &mut dyn Behavior, - drop_context: &mut DropContext, rect: Rect, node_id: NodeId, ) { @@ -683,7 +681,7 @@ impl Nodes { self.rects.insert(node_id, rect); if let Node::Branch(branch) = &mut node { - branch.layout(self, style, behavior, drop_context, rect, node_id); + branch.layout(self, style, behavior, rect); } self.nodes.insert(node_id, node); diff --git a/crates/emath/src/rect.rs b/crates/emath/src/rect.rs index 5020b1218..c5c737fb2 100644 --- a/crates/emath/src/rect.rs +++ b/crates/emath/src/rect.rs @@ -82,7 +82,12 @@ impl Rect { } #[inline(always)] - pub fn from_x_y_ranges(x_range: RangeInclusive, y_range: RangeInclusive) -> Self { + pub fn from_x_y_ranges( + x_range: impl Into>, + y_range: impl Into>, + ) -> Self { + let x_range = x_range.into(); + let y_range = y_range.into(); Rect { min: pos2(*x_range.start(), *y_range.start()), max: pos2(*x_range.end(), *y_range.end()),