mirror of
https://github.com/emilk/egui.git
synced 2026-08-31 22:00:03 -04:00
Fix the bug!
This commit is contained in:
@@ -28,12 +28,17 @@ impl Tabs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn layout<Leaf>(
|
pub fn layout<Leaf>(
|
||||||
&self,
|
&mut self,
|
||||||
nodes: &mut Nodes<Leaf>,
|
nodes: &mut Nodes<Leaf>,
|
||||||
style: &egui::Style,
|
style: &egui::Style,
|
||||||
behavior: &mut dyn Behavior<Leaf>,
|
behavior: &mut dyn Behavior<Leaf>,
|
||||||
rect: Rect,
|
rect: Rect,
|
||||||
) {
|
) {
|
||||||
|
if !self.children.iter().any(|&child| child == self.active) {
|
||||||
|
// Make sure something is active:
|
||||||
|
self.active = self.children.first().copied().unwrap_or_default();
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
@@ -50,11 +55,6 @@ impl Tabs {
|
|||||||
rect: Rect,
|
rect: Rect,
|
||||||
node_id: NodeId,
|
node_id: NodeId,
|
||||||
) {
|
) {
|
||||||
if !self.children.iter().any(|&child| child == self.active) {
|
|
||||||
// Make sure something is active:
|
|
||||||
self.active = self.children.first().copied().unwrap_or_default();
|
|
||||||
}
|
|
||||||
|
|
||||||
let next_active = self.tab_bar_ui(behavior, ui, rect, nodes, drop_context, node_id);
|
let next_active = self.tab_bar_ui(behavior, ui, rect, nodes, drop_context, node_id);
|
||||||
|
|
||||||
// When dragged, don't show it (it is "being held")
|
// When dragged, don't show it (it is "being held")
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ impl std::fmt::Debug for NodeId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The top level type. Contains all persistent state, including layouts and sizes.
|
/// The top level type. Contains all persistent state, including layouts and sizes.
|
||||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Clone, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct Dock<Leaf> {
|
pub struct Dock<Leaf> {
|
||||||
pub root: NodeId,
|
pub root: NodeId,
|
||||||
pub nodes: Nodes<Leaf>,
|
pub nodes: Nodes<Leaf>,
|
||||||
@@ -64,6 +64,45 @@ impl<Leaf> Default for Dock<Leaf> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<Leaf: std::fmt::Debug> std::fmt::Debug for Dock<Leaf> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
fn format_node<Leaf: std::fmt::Debug>(
|
||||||
|
f: &mut std::fmt::Formatter<'_>,
|
||||||
|
nodes: &Nodes<Leaf>,
|
||||||
|
indent: usize,
|
||||||
|
node_id: NodeId,
|
||||||
|
) -> std::fmt::Result {
|
||||||
|
write!(f, "{} {node_id:?} ", " ".repeat(indent))?;
|
||||||
|
if let Some(node) = nodes.get(node_id) {
|
||||||
|
match node {
|
||||||
|
Node::Leaf(leaf) => writeln!(f, "Leaf {leaf:?}"),
|
||||||
|
Node::Branch(branch) => {
|
||||||
|
writeln!(
|
||||||
|
f,
|
||||||
|
"{}",
|
||||||
|
match branch {
|
||||||
|
Branch::Tabs(_) => "Tabs",
|
||||||
|
Branch::Linear(_) => "Linear",
|
||||||
|
Branch::Grid(_) => "Grid",
|
||||||
|
}
|
||||||
|
)?;
|
||||||
|
for &child in branch.children() {
|
||||||
|
format_node(f, nodes, indent + 1, child)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
write!(f, "DANGLING {node_id:?}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writeln!(f, "Dock {{")?;
|
||||||
|
format_node(f, &self.nodes, 1, self.root)?;
|
||||||
|
write!(f, "\n}}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Contains all node state, but no root.
|
/// Contains all node state, but no root.
|
||||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct Nodes<Leaf> {
|
pub struct Nodes<Leaf> {
|
||||||
@@ -362,6 +401,7 @@ impl<Leaf> Dock<Leaf> {
|
|||||||
self.nodes
|
self.nodes
|
||||||
.make_all_leaves_children_of_tabs(false, self.root);
|
.make_all_leaves_children_of_tabs(false, self.root);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.nodes.gc_root(behavior, self.root);
|
self.nodes.gc_root(behavior, self.root);
|
||||||
|
|
||||||
self.nodes.rects.clear();
|
self.nodes.rects.clear();
|
||||||
@@ -702,7 +742,13 @@ impl<Leaf> Nodes<Leaf> {
|
|||||||
ui: &mut Ui,
|
ui: &mut Ui,
|
||||||
node_id: NodeId,
|
node_id: NodeId,
|
||||||
) {
|
) {
|
||||||
let (Some(rect), Some(mut node)) = (self.try_rect(node_id), self.nodes.remove(&node_id)) else {
|
// NOTE: important that we get thr rect and node in two steps,
|
||||||
|
// otherwise we could loose the node when there is no rect.
|
||||||
|
let Some(rect) = self.try_rect(node_id) else {
|
||||||
|
log::warn!("Failed to find rect for node {node_id:?} during ui");
|
||||||
|
return
|
||||||
|
};
|
||||||
|
let Some(mut node) = self.nodes.remove(&node_id) else {
|
||||||
log::warn!("Failed to find node {node_id:?} during ui");
|
log::warn!("Failed to find node {node_id:?} during ui");
|
||||||
return
|
return
|
||||||
};
|
};
|
||||||
@@ -755,7 +801,10 @@ enum SimplifyAction {
|
|||||||
|
|
||||||
impl<Leaf> Nodes<Leaf> {
|
impl<Leaf> Nodes<Leaf> {
|
||||||
fn simplify(&mut self, options: &SimplificationOptions, it: NodeId) -> SimplifyAction {
|
fn simplify(&mut self, options: &SimplificationOptions, it: NodeId) -> SimplifyAction {
|
||||||
let Some(mut node) = self.nodes.remove(&it) else { return SimplifyAction::Remove; };
|
let Some(mut node) = self.nodes.remove(&it) else {
|
||||||
|
log::warn!("Failed to find node {it:?} during simplify");
|
||||||
|
return SimplifyAction::Remove;
|
||||||
|
};
|
||||||
|
|
||||||
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: join nested versions of the same horizontal/vertical layouts
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
|
||||||
|
|
||||||
use eframe::egui::{self, Style};
|
use eframe::egui;
|
||||||
use egui::Color32;
|
|
||||||
|
|
||||||
use egui_extras::dock;
|
use egui_extras::dock;
|
||||||
|
|
||||||
@@ -28,20 +27,23 @@ fn main() -> Result<(), eframe::Error> {
|
|||||||
|
|
||||||
#[derive(serde::Deserialize, serde::Serialize)]
|
#[derive(serde::Deserialize, serde::Serialize)]
|
||||||
pub struct View {
|
pub struct View {
|
||||||
title: String,
|
nr: usize,
|
||||||
color: Color32,
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for View {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_struct("View").field("nr", &self.nr).finish()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl View {
|
impl View {
|
||||||
pub fn with_nr(i: usize) -> Self {
|
pub fn with_nr(nr: usize) -> Self {
|
||||||
Self {
|
Self { nr }
|
||||||
title: format!("View {i}"),
|
|
||||||
color: egui::epaint::Hsva::new(0.1 * i as f32, 0.5, 0.5, 1.0).into(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ui(&mut self, ui: &mut egui::Ui) -> dock::UiResponse {
|
pub fn ui(&mut self, ui: &mut egui::Ui) -> dock::UiResponse {
|
||||||
ui.painter().rect_filled(ui.max_rect(), 0.0, self.color);
|
let color = egui::epaint::Hsva::new(0.1 * self.nr as f32, 0.5, 0.5, 1.0);
|
||||||
|
ui.painter().rect_filled(ui.max_rect(), 0.0, color);
|
||||||
let dragged = ui
|
let dragged = ui
|
||||||
.allocate_rect(ui.max_rect(), egui::Sense::drag())
|
.allocate_rect(ui.max_rect(), egui::Sense::drag())
|
||||||
.on_hover_cursor(egui::CursorIcon::Grab)
|
.on_hover_cursor(egui::CursorIcon::Grab)
|
||||||
@@ -118,7 +120,7 @@ impl dock::Behavior<View> for DockBehavior {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn tab_text_for_leaf(&mut self, view: &View) -> egui::WidgetText {
|
fn tab_text_for_leaf(&mut self, view: &View) -> egui::WidgetText {
|
||||||
view.title.clone().into()
|
format!("View {}", view.nr).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn top_bar_rtl_ui(&mut self, ui: &mut egui::Ui, node_id: dock::NodeId) {
|
fn top_bar_rtl_ui(&mut self, ui: &mut egui::Ui, node_id: dock::NodeId) {
|
||||||
@@ -130,11 +132,11 @@ impl dock::Behavior<View> for DockBehavior {
|
|||||||
// ---
|
// ---
|
||||||
// Settings:
|
// Settings:
|
||||||
|
|
||||||
fn tab_bar_height(&self, _style: &Style) -> f32 {
|
fn tab_bar_height(&self, _style: &egui::Style) -> f32 {
|
||||||
self.tab_bar_height
|
self.tab_bar_height
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gap_width(&self, _style: &Style) -> f32 {
|
fn gap_width(&self, _style: &egui::Style) -> f32 {
|
||||||
self.gap_width
|
self.gap_width
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,8 +149,11 @@ impl dock::Behavior<View> for DockBehavior {
|
|||||||
struct MyApp {
|
struct MyApp {
|
||||||
dock: dock::Dock<View>,
|
dock: dock::Dock<View>,
|
||||||
|
|
||||||
#[serde(skip, default)]
|
#[serde(skip)]
|
||||||
behavior: DockBehavior,
|
behavior: DockBehavior,
|
||||||
|
|
||||||
|
#[serde(skip)]
|
||||||
|
last_dock_debug: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for MyApp {
|
impl Default for MyApp {
|
||||||
@@ -163,38 +168,24 @@ impl Default for MyApp {
|
|||||||
let mut nodes = dock::Nodes::default();
|
let mut nodes = dock::Nodes::default();
|
||||||
|
|
||||||
let mut tabs = vec![];
|
let mut tabs = vec![];
|
||||||
tabs.push(nodes.insert_leaf(gen_view()));
|
let tab_node = {
|
||||||
|
let children = (0..7).map(|_| nodes.insert_leaf(gen_view())).collect();
|
||||||
|
nodes.insert_tab_node(children)
|
||||||
|
};
|
||||||
|
tabs.push(tab_node);
|
||||||
tabs.push({
|
tabs.push({
|
||||||
let a = nodes.insert_leaf(gen_view());
|
let children = (0..7).map(|_| nodes.insert_leaf(gen_view())).collect();
|
||||||
let b = nodes.insert_leaf(gen_view());
|
nodes.insert_horizontal_node(children)
|
||||||
let c = nodes.insert_leaf(gen_view());
|
|
||||||
let d = nodes.insert_leaf(gen_view());
|
|
||||||
let e = nodes.insert_leaf(gen_view());
|
|
||||||
nodes.insert_tab_node(vec![a, b, c, d, e])
|
|
||||||
});
|
});
|
||||||
tabs.push({
|
tabs.push({
|
||||||
let a = nodes.insert_leaf(gen_view());
|
let children = (0..7).map(|_| nodes.insert_leaf(gen_view())).collect();
|
||||||
let b = nodes.insert_leaf(gen_view());
|
nodes.insert_vertical_node(children)
|
||||||
let c = nodes.insert_leaf(gen_view());
|
|
||||||
let d = nodes.insert_leaf(gen_view());
|
|
||||||
let e = nodes.insert_leaf(gen_view());
|
|
||||||
nodes.insert_horizontal_node(vec![a, b, c, d, e])
|
|
||||||
});
|
});
|
||||||
tabs.push({
|
tabs.push({
|
||||||
let a = nodes.insert_leaf(gen_view());
|
let cells = (0..12).map(|_| nodes.insert_leaf(gen_view())).collect();
|
||||||
let b = nodes.insert_leaf(gen_view());
|
|
||||||
let c = nodes.insert_leaf(gen_view());
|
|
||||||
let d = nodes.insert_leaf(gen_view());
|
|
||||||
let e = nodes.insert_leaf(gen_view());
|
|
||||||
nodes.insert_vertical_node(vec![a, b, c, d, e])
|
|
||||||
});
|
|
||||||
tabs.push({
|
|
||||||
let mut cells = vec![];
|
|
||||||
for _ in 0..12 {
|
|
||||||
cells.push(nodes.insert_leaf(gen_view()));
|
|
||||||
}
|
|
||||||
nodes.insert_grid_node(cells)
|
nodes.insert_grid_node(cells)
|
||||||
});
|
});
|
||||||
|
tabs.push(nodes.insert_leaf(gen_view()));
|
||||||
|
|
||||||
let root = nodes.insert_tab_node(tabs);
|
let root = nodes.insert_tab_node(tabs);
|
||||||
|
|
||||||
@@ -203,6 +194,7 @@ impl Default for MyApp {
|
|||||||
Self {
|
Self {
|
||||||
dock,
|
dock,
|
||||||
behavior: Default::default(),
|
behavior: Default::default(),
|
||||||
|
last_dock_debug: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -217,8 +209,9 @@ impl eframe::App for MyApp {
|
|||||||
ui.separator();
|
ui.separator();
|
||||||
|
|
||||||
tree_ui(ui, &mut self.behavior, &mut self.dock.nodes, self.dock.root);
|
tree_ui(ui, &mut self.behavior, &mut self.dock.nodes, self.dock.root);
|
||||||
|
|
||||||
if let Some(parent) = self.behavior.add_child_to.take() {
|
if let Some(parent) = self.behavior.add_child_to.take() {
|
||||||
let new_child = self.dock.nodes.insert_leaf(View::with_nr(666));
|
let new_child = self.dock.nodes.insert_leaf(View::with_nr(100));
|
||||||
if let Some(dock::Node::Branch(dock::Branch::Tabs(tabs))) =
|
if let Some(dock::Node::Branch(dock::Branch::Tabs(tabs))) =
|
||||||
self.dock.nodes.get_mut(parent)
|
self.dock.nodes.get_mut(parent)
|
||||||
{
|
{
|
||||||
@@ -226,6 +219,15 @@ impl eframe::App for MyApp {
|
|||||||
tabs.set_active(new_child);
|
tabs.set_active(new_child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ui.separator();
|
||||||
|
ui.style_mut().wrap = Some(false);
|
||||||
|
let dock_debug = format!("{:#?}", self.dock);
|
||||||
|
ui.monospace(&dock_debug);
|
||||||
|
if self.last_dock_debug != dock_debug {
|
||||||
|
self.last_dock_debug = dock_debug;
|
||||||
|
log::debug!("{}", self.last_dock_debug);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
@@ -244,7 +246,7 @@ fn tree_ui(
|
|||||||
nodes: &mut dock::Nodes<View>,
|
nodes: &mut dock::Nodes<View>,
|
||||||
node_id: dock::NodeId,
|
node_id: dock::NodeId,
|
||||||
) {
|
) {
|
||||||
// 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_text_for_node(nodes, node_id).text()
|
||||||
|
|||||||
Reference in New Issue
Block a user