mirror of
https://github.com/emilk/egui.git
synced 2026-09-01 14:20:04 -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};
|
use egui::{pos2, vec2, Rect};
|
||||||
|
|
||||||
@@ -6,6 +9,41 @@ use crate::dock::{
|
|||||||
sizes_from_shares, Behavior, DropContext, InsertionPoint, LayoutInsertion, NodeId, Nodes,
|
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?
|
/// Where in a grid?
|
||||||
#[derive(
|
#[derive(
|
||||||
Clone,
|
Clone,
|
||||||
@@ -42,6 +80,14 @@ pub struct Grid {
|
|||||||
pub col_shares: Vec<f32>,
|
pub col_shares: Vec<f32>,
|
||||||
/// Share of the available height assigned to each row.
|
/// Share of the available height assigned to each row.
|
||||||
pub row_shares: Vec<f32>,
|
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 {
|
impl Grid {
|
||||||
@@ -57,9 +103,7 @@ impl Grid {
|
|||||||
nodes: &mut Nodes<Leaf>,
|
nodes: &mut Nodes<Leaf>,
|
||||||
style: &egui::Style,
|
style: &egui::Style,
|
||||||
behavior: &mut dyn Behavior<Leaf>,
|
behavior: &mut dyn Behavior<Leaf>,
|
||||||
drop_context: &mut DropContext,
|
|
||||||
rect: Rect,
|
rect: Rect,
|
||||||
node_id: NodeId,
|
|
||||||
) {
|
) {
|
||||||
let child_ids: HashSet<NodeId> = self.children.iter().copied().collect();
|
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 col_widths = sizes_from_shares(&self.col_shares, rect.width(), gap);
|
||||||
let row_heights = sizes_from_shares(&self.row_shares, rect.height(), 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 {
|
let mut x = rect.left();
|
||||||
col_x.push(col_x.last().unwrap() + width + gap);
|
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()];
|
let mut y = rect.top();
|
||||||
for &height in &row_heights {
|
self.row_ranges.clear();
|
||||||
row_y.push(row_y.last().unwrap() + height + gap);
|
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:
|
// 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:
|
// Place each child:
|
||||||
for &child in &self.children {
|
for &child in &self.children {
|
||||||
let loc = self.locations[&child];
|
let loc = self.locations[&child];
|
||||||
let child_rect = Rect::from_min_size(
|
let child_rect =
|
||||||
pos2(col_x[loc.col], row_y[loc.row]),
|
Rect::from_x_y_ranges(self.col_ranges[loc.col], self.row_ranges[loc.row]);
|
||||||
vec2(col_widths[loc.col], row_heights[loc.row]),
|
nodes.layout_node(style, behavior, child_rect, child);
|
||||||
);
|
}
|
||||||
nodes.layout_node(style, behavior, drop_context, 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:
|
// Register drop-zones:
|
||||||
for col in 0..num_cols {
|
for (col, &x_range) in self.col_ranges.iter().enumerate() {
|
||||||
for row in 0..num_rows {
|
for (row, &y_range) in self.row_ranges.iter().enumerate() {
|
||||||
let cell_rect = Rect::from_min_size(
|
let cell_rect = Rect::from_x_y_ranges(x_range, y_range);
|
||||||
pos2(col_x[col], row_y[row]),
|
|
||||||
vec2(col_widths[col], row_heights[row]),
|
|
||||||
);
|
|
||||||
drop_context.suggest_rect(
|
drop_context.suggest_rect(
|
||||||
InsertionPoint::new(
|
InsertionPoint::new(
|
||||||
node_id,
|
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>,
|
nodes: &mut Nodes<Leaf>,
|
||||||
style: &egui::Style,
|
style: &egui::Style,
|
||||||
behavior: &mut dyn Behavior<Leaf>,
|
behavior: &mut dyn Behavior<Leaf>,
|
||||||
drop_context: &mut DropContext,
|
|
||||||
rect: Rect,
|
rect: Rect,
|
||||||
) {
|
) {
|
||||||
match self.dir {
|
match self.dir {
|
||||||
LinearDir::Horizontal => {
|
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>,
|
nodes: &mut Nodes<Leaf>,
|
||||||
style: &egui::Style,
|
style: &egui::Style,
|
||||||
behavior: &mut dyn Behavior<Leaf>,
|
behavior: &mut dyn Behavior<Leaf>,
|
||||||
drop_context: &mut DropContext,
|
|
||||||
rect: Rect,
|
rect: Rect,
|
||||||
) {
|
) {
|
||||||
let num_gaps = self.children.len().saturating_sub(1);
|
let num_gaps = self.children.len().saturating_sub(1);
|
||||||
@@ -66,7 +64,7 @@ impl Linear {
|
|||||||
let mut x = rect.min.x;
|
let mut x = rect.min.x;
|
||||||
for (child, width) in self.children.iter().zip(widths) {
|
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()));
|
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;
|
x += width + gap_width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,7 +74,6 @@ impl Linear {
|
|||||||
nodes: &mut Nodes<Leaf>,
|
nodes: &mut Nodes<Leaf>,
|
||||||
style: &egui::Style,
|
style: &egui::Style,
|
||||||
behavior: &mut dyn Behavior<Leaf>,
|
behavior: &mut dyn Behavior<Leaf>,
|
||||||
drop_context: &mut DropContext,
|
|
||||||
rect: Rect,
|
rect: Rect,
|
||||||
) {
|
) {
|
||||||
let num_gaps = self.children.len().saturating_sub(1);
|
let num_gaps = self.children.len().saturating_sub(1);
|
||||||
@@ -89,7 +86,7 @@ impl Linear {
|
|||||||
let mut y = rect.min.y;
|
let mut y = rect.min.y;
|
||||||
for (child, height) in self.children.iter().zip(heights) {
|
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));
|
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;
|
y += height + gap_height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -188,20 +188,18 @@ impl Branch {
|
|||||||
nodes: &mut Nodes<Leaf>,
|
nodes: &mut Nodes<Leaf>,
|
||||||
style: &egui::Style,
|
style: &egui::Style,
|
||||||
behavior: &mut dyn Behavior<Leaf>,
|
behavior: &mut dyn Behavior<Leaf>,
|
||||||
drop_context: &mut DropContext,
|
|
||||||
rect: Rect,
|
rect: Rect,
|
||||||
node_id: NodeId,
|
|
||||||
) {
|
) {
|
||||||
if self.is_empty() {
|
if self.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
match self {
|
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) => {
|
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);
|
linear.ui(nodes, behavior, drop_context, ui, node_id);
|
||||||
}
|
}
|
||||||
Branch::Grid(grid) => {
|
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>,
|
nodes: &mut Nodes<Leaf>,
|
||||||
style: &egui::Style,
|
style: &egui::Style,
|
||||||
behavior: &mut dyn Behavior<Leaf>,
|
behavior: &mut dyn Behavior<Leaf>,
|
||||||
drop_context: &mut DropContext,
|
|
||||||
rect: Rect,
|
rect: Rect,
|
||||||
) {
|
) {
|
||||||
let mut active_rect = rect;
|
let mut active_rect = rect;
|
||||||
active_rect.min.y += behavior.tab_bar_height(style);
|
active_rect.min.y += behavior.tab_bar_height(style);
|
||||||
|
|
||||||
// Only lay out the active tab (saves CPU):
|
// 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>(
|
pub fn ui<Leaf>(
|
||||||
|
|||||||
@@ -455,7 +455,6 @@ impl<Leaf> Dock<Leaf> {
|
|||||||
self.nodes.layout_node(
|
self.nodes.layout_node(
|
||||||
ui.style(),
|
ui.style(),
|
||||||
behavior,
|
behavior,
|
||||||
&mut drop_context,
|
|
||||||
ui.available_rect_before_wrap(),
|
ui.available_rect_before_wrap(),
|
||||||
self.root,
|
self.root,
|
||||||
);
|
);
|
||||||
@@ -675,7 +674,6 @@ impl<Leaf> Nodes<Leaf> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
style: &egui::Style,
|
style: &egui::Style,
|
||||||
behavior: &mut dyn Behavior<Leaf>,
|
behavior: &mut dyn Behavior<Leaf>,
|
||||||
drop_context: &mut DropContext,
|
|
||||||
rect: Rect,
|
rect: Rect,
|
||||||
node_id: NodeId,
|
node_id: NodeId,
|
||||||
) {
|
) {
|
||||||
@@ -683,7 +681,7 @@ impl<Leaf> Nodes<Leaf> {
|
|||||||
self.rects.insert(node_id, rect);
|
self.rects.insert(node_id, rect);
|
||||||
|
|
||||||
if let Node::Branch(branch) = &mut node {
|
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);
|
self.nodes.insert(node_id, node);
|
||||||
|
|||||||
@@ -82,7 +82,12 @@ impl Rect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[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 {
|
Rect {
|
||||||
min: pos2(*x_range.start(), *y_range.start()),
|
min: pos2(*x_range.start(), *y_range.start()),
|
||||||
max: pos2(*x_range.end(), *y_range.end()),
|
max: pos2(*x_range.end(), *y_range.end()),
|
||||||
|
|||||||
Reference in New Issue
Block a user