mirror of
https://github.com/emilk/egui.git
synced 2026-06-27 15:13:12 -04:00
Refactor: register grid drop-zones during the ui pass
This commit is contained in:
@@ -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<RangeInclusive<f32>> for Rangef {
|
||||
#[inline]
|
||||
fn from(range: RangeInclusive<f32>) -> Self {
|
||||
Self::new(*range.start(), *range.end())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&RangeInclusive<f32>> for Rangef {
|
||||
#[inline]
|
||||
fn from(range: &RangeInclusive<f32>) -> Self {
|
||||
Self::new(*range.start(), *range.end())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Rangef> for RangeInclusive<f32> {
|
||||
#[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<f32>,
|
||||
/// Share of the available height assigned to each row.
|
||||
pub row_shares: Vec<f32>,
|
||||
|
||||
/// ui point x ranges for each column, recomputed during layout
|
||||
#[serde(skip)]
|
||||
col_ranges: Vec<Rangef>,
|
||||
|
||||
/// ui point y ranges for each row, recomputed during layout
|
||||
#[serde(skip)]
|
||||
row_ranges: Vec<Rangef>,
|
||||
}
|
||||
|
||||
impl Grid {
|
||||
@@ -57,9 +103,7 @@ impl Grid {
|
||||
nodes: &mut Nodes<Leaf>,
|
||||
style: &egui::Style,
|
||||
behavior: &mut dyn Behavior<Leaf>,
|
||||
drop_context: &mut DropContext,
|
||||
rect: Rect,
|
||||
node_id: NodeId,
|
||||
) {
|
||||
let child_ids: HashSet<NodeId> = 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<Leaf>(
|
||||
&mut self,
|
||||
nodes: &mut Nodes<Leaf>,
|
||||
behavior: &mut dyn Behavior<Leaf>,
|
||||
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<Leaf>(
|
||||
&mut self,
|
||||
nodes: &mut Nodes<Leaf>,
|
||||
behavior: &mut dyn Behavior<Leaf>,
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,14 +37,13 @@ impl Linear {
|
||||
nodes: &mut Nodes<Leaf>,
|
||||
style: &egui::Style,
|
||||
behavior: &mut dyn Behavior<Leaf>,
|
||||
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<Leaf>,
|
||||
style: &egui::Style,
|
||||
behavior: &mut dyn Behavior<Leaf>,
|
||||
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<Leaf>,
|
||||
style: &egui::Style,
|
||||
behavior: &mut dyn Behavior<Leaf>,
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,20 +188,18 @@ impl Branch {
|
||||
nodes: &mut Nodes<Leaf>,
|
||||
style: &egui::Style,
|
||||
behavior: &mut dyn Behavior<Leaf>,
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,14 +24,13 @@ impl Tabs {
|
||||
nodes: &mut Nodes<Leaf>,
|
||||
style: &egui::Style,
|
||||
behavior: &mut dyn Behavior<Leaf>,
|
||||
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<Leaf>(
|
||||
|
||||
@@ -455,7 +455,6 @@ impl<Leaf> Dock<Leaf> {
|
||||
self.nodes.layout_node(
|
||||
ui.style(),
|
||||
behavior,
|
||||
&mut drop_context,
|
||||
ui.available_rect_before_wrap(),
|
||||
self.root,
|
||||
);
|
||||
@@ -675,7 +674,6 @@ impl<Leaf> Nodes<Leaf> {
|
||||
&mut self,
|
||||
style: &egui::Style,
|
||||
behavior: &mut dyn Behavior<Leaf>,
|
||||
drop_context: &mut DropContext,
|
||||
rect: Rect,
|
||||
node_id: NodeId,
|
||||
) {
|
||||
@@ -683,7 +681,7 @@ impl<Leaf> Nodes<Leaf> {
|
||||
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);
|
||||
|
||||
@@ -82,7 +82,12 @@ impl Rect {
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn from_x_y_ranges(x_range: RangeInclusive<f32>, y_range: RangeInclusive<f32>) -> Self {
|
||||
pub fn from_x_y_ranges(
|
||||
x_range: impl Into<RangeInclusive<f32>>,
|
||||
y_range: impl Into<RangeInclusive<f32>>,
|
||||
) -> 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()),
|
||||
|
||||
Reference in New Issue
Block a user