From c3604425943d9c5f922a8b9aba8e5a5b89e785e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20G=C4=85sior?= Date: Thu, 23 Nov 2023 20:09:43 +0000 Subject: [PATCH] Release 0.9 (#201) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added DockState::iter_nodes_mut and DockState::iter_main_surface_nodes_mut (#195) * added iter_nodes_mut * finished adding iter_nodes_mut * added iter_main_surface_nodes_mut * ran cargo fmt * Bump crate version number to 0.9.0 * Iterators overhaul (#196) * Remove the deprecated `DockState::iter` * Rename `iter_nodes{,_mut}` to `iter_all_nodes{,_mut}` and deprecate `iter_nodes` * Add iterators over surfaces * Expand `iter_all_nodes{,_mut}` to include containing surface indices * Deprecated `iter_main_surface_nodes{,_mut}` * Add iterators for all tabs and containing surface and node indices * Update changelog * Add node and tab iterators to `Surface` * Add tab iterators to `Node` * Update changelog * Update changelog * Mapping over tab types (#199) * Implement mapping over tab types * Fix compile errors * Fix formatting --------- Co-authored-by: Adam Gąsior * Upgrade egui to 0.24.0 * Update changelog * Update changelog --------- Co-authored-by: Cassie‽ <124477590+eupraxia05@users.noreply.github.com> Co-authored-by: knoellle <33729490+knoellle@users.noreply.github.com> --- CHANGELOG.md | 19 ++++++ Cargo.toml | 8 +-- README.md | 10 +-- examples/hello.rs | 5 +- src/dock_state/mod.rs | 116 ++++++++++++++++++++++++++++---- src/dock_state/surface.rs | 60 +++++++++++++++-- src/dock_state/tree/mod.rs | 91 +++++++++++++++---------- src/dock_state/tree/node.rs | 53 +++++++++++++++ src/dock_state/tree/tab_iter.rs | 2 +- src/dock_state/window_state.rs | 2 +- 10 files changed, 298 insertions(+), 68 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f669cb..ff7dee9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # egui_dock changelog +## 0.9.0 - 2023-11-23 + +### Added +- `DockArea::surfaces_count` +- `DockArea::iter_surfaces[_mut]` +- `DockArea::iter_all_tabs[_mut]` +- `DockArea::iter_all_nodes[_mut]` +- `Node::iter_tabs[_mut]` +- `Surface::iter_nodes[_mut]` +- `Surface::iter_all_tabs[_mut]` + +### Breaking changes +- Upgraded to egui 0.24. +- Removed the deprecated `DockState::iter`. + +### Deprecated +- `DockState::iter_nodes` – use `iter_all_nodes` instead. +- `DockState::iter_main_surface_nodes[_mut]` – use `dock_state.main_surface().iter()` (and corresponding `mut` versions) instead. + ## 0.8.2 - 2023-11-02 ### Fixed diff --git a/Cargo.toml b/Cargo.toml index d830fac..fe130f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,9 +2,9 @@ name = "egui_dock" description = "Docking system for egui - an immediate-mode GUI library for Rust" authors = ["lain-dono", "Adam Gąsior (Adanos020)"] -version = "0.8.2" +version = "0.9.0" edition = "2021" -rust-version = "1.70" +rust-version = "1.72" license = "MIT" readme = "README.md" repository = "https://github.com/Adanos020/egui_dock" @@ -18,14 +18,14 @@ default = [] serde = ["dep:serde", "egui/serde"] [dependencies] -egui = { version = "0.23", default-features = false } +egui = { version = "0.24", default-features = false } serde = { version = "1", optional = true, features = ["derive"] } duplicate = "1.0" paste = "1.0" [dev-dependencies] -eframe = { version = "0.23", default-features = false, features = [ +eframe = { version = "0.24", default-features = false, features = [ "default_fonts", "glow", ] } diff --git a/README.md b/README.md index 385866f..a1c80f3 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ -# `egui_dock`: docking support for [egui](https://github.com/emilk/egui) +# `egui_dock`: docking system for [egui](https://github.com/emilk/egui) [![github](https://img.shields.io/badge/github-Adanos020/egui_dock-8da0cb?logo=github)](https://github.com/Adanos020/egui_dock) [![Crates.io](https://img.shields.io/crates/v/egui_dock)](https://crates.io/crates/egui_dock) [![docs.rs](https://img.shields.io/docsrs/egui_dock)](https://docs.rs/egui_dock/) -[![egui_version](https://img.shields.io/badge/egui-0.23-blue)](https://github.com/emilk/egui) +[![egui_version](https://img.shields.io/badge/egui-0.24-blue)](https://github.com/emilk/egui) -Originally created by [@lain-dono](https://github.com/lain-dono), this library provides docking support for `egui`. +Originally created by [@lain-dono](https://github.com/lain-dono), this library provides a docking system for `egui`. ## Contributing @@ -32,8 +32,8 @@ Add `egui` and `egui_dock` to your project's dependencies. ```toml [dependencies] -egui = "0.23" -egui_dock = "0.8" +egui = "0.24" +egui_dock = "0.9" ``` Then proceed by setting up `egui`, following its [quick start guide](https://github.com/emilk/egui#quick-start). diff --git a/examples/hello.rs b/examples/hello.rs index adb4c23..8b1c6b9 100644 --- a/examples/hello.rs +++ b/examples/hello.rs @@ -5,7 +5,8 @@ use std::collections::HashSet; use eframe::{egui, NativeOptions}; use egui::{ color_picker::{color_edit_button_srgba, Alpha}, - CentralPanel, ComboBox, Frame, Rounding, Slider, TopBottomPanel, Ui, WidgetText, + vec2, CentralPanel, ComboBox, Frame, Rounding, Slider, TopBottomPanel, Ui, ViewportBuilder, + WidgetText, }; use egui_dock::{ @@ -52,7 +53,7 @@ macro_rules! unit_slider { fn main() -> eframe::Result<()> { std::env::set_var("RUST_BACKTRACE", "1"); let options = NativeOptions { - initial_window_size: Some(egui::vec2(1024.0, 1024.0)), + viewport: ViewportBuilder::default().with_inner_size(vec2(1024.0, 1024.0)), ..Default::default() }; eframe::run_native( diff --git a/src/dock_state/mod.rs b/src/dock_state/mod.rs index 089d545..34dc822 100644 --- a/src/dock_state/mod.rs +++ b/src/dock_state/mod.rs @@ -77,16 +77,16 @@ impl DockState { self } - /// Get a mutable borrow to the tree at the main surface. - pub fn main_surface_mut(&mut self) -> &mut Tree { - &mut self[SurfaceIndex::main()] - } - /// Get an immutable borrow to the tree at the main surface. pub fn main_surface(&self) -> &Tree { &self[SurfaceIndex::main()] } + /// Get a mutable borrow to the tree at the main surface. + pub fn main_surface_mut(&mut self) -> &mut Tree { + &mut self[SurfaceIndex::main()] + } + /// Get the [`WindowState`] which corresponds to a [`SurfaceIndex`]. /// /// Returns `None` if the surface is [`Empty`](Surface::Empty), [`Main`](Surface::Main), or doesn't exist. @@ -186,7 +186,7 @@ impl DockState { &mut self, (surface_index, node_index, tab_index): (SurfaceIndex, NodeIndex, TabIndex), ) { - if let Some(Node::Leaf { active, .. }) = self[surface_index].tree.get_mut(node_index.0) { + if let Some(Node::Leaf { active, .. }) = self[surface_index].nodes.get_mut(node_index.0) { *active = tab_index; } } @@ -368,24 +368,112 @@ impl DockState { self[SurfaceIndex::main()].push_to_first_leaf(tab); } - /// Returns an `Iterator` of the underlying collection of nodes on the **main surface**. - #[deprecated = "Use `iter_main_surface_nodes` or `iter_nodes` instead"] - pub fn iter(&self) -> std::slice::Iter<'_, Node> { - self.iter_main_surface_nodes() + /// Returns the current number of surfaces. + pub fn surfaces_count(&self) -> usize { + self.surfaces.len() + } + + /// Returns an [`Iterator`] over all surfaces. + pub fn iter_surfaces(&self) -> impl Iterator> { + self.surfaces.iter() + } + + /// Returns a mutable [`Iterator`] over all surfaces. + pub fn iter_surfaces_mut(&mut self) -> impl Iterator> { + self.surfaces.iter_mut() + } + + /// Returns an [`Iterator`] of **all** underlying nodes in the dock state, + /// and the indices of containing surfaces. + pub fn iter_all_nodes(&self) -> impl Iterator)> { + self.iter_surfaces() + .enumerate() + .flat_map(|(surface_index, surface)| { + surface + .iter_nodes() + .map(move |node| (SurfaceIndex(surface_index), node)) + }) } - /// Returns an `Iterator` of the underlying collection of nodes on the main surface. - pub fn iter_main_surface_nodes(&self) -> std::slice::Iter<'_, Node> { + /// Returns a mutable [`Iterator`] of **all** underlying nodes in the dock state, + /// and the indices of containing surfaces. + pub fn iter_all_nodes_mut(&mut self) -> impl Iterator)> { + self.iter_surfaces_mut() + .enumerate() + .flat_map(|(surface_index, surface)| { + surface + .iter_nodes_mut() + .map(move |node| (SurfaceIndex(surface_index), node)) + }) + } + + /// Returns an [`Iterator`] of **all** tabs in the dock state, + /// and the indices of containing surfaces and nodes. + pub fn iter_all_tabs(&self) -> impl Iterator { + self.iter_surfaces() + .enumerate() + .flat_map(|(surface_index, surface)| { + surface + .iter_all_tabs() + .map(move |(node_index, tab)| ((SurfaceIndex(surface_index), node_index), tab)) + }) + } + + /// Returns a mutable [`Iterator`] of **all** tabs in the dock state, + /// and the indices of containing surfaces and nodes. + pub fn iter_all_tabs_mut( + &mut self, + ) -> impl Iterator { + self.iter_surfaces_mut() + .enumerate() + .flat_map(|(surface_index, surface)| { + surface + .iter_all_tabs_mut() + .map(move |(node_index, tab)| ((SurfaceIndex(surface_index), node_index), tab)) + }) + } + + /// Returns an [`Iterator`] of the underlying collection of nodes on the main surface. + #[deprecated = "Use `dock_state.main_surface().iter()` instead"] + pub fn iter_main_surface_nodes(&self) -> impl Iterator> { self[SurfaceIndex::main()].iter() } - /// Returns an `Iterator` of **all** underlying nodes in the dock state and all subsequent trees. + /// Returns a mutable [`Iterator`] of the underlying collection of nodes on the main surface. + #[deprecated = "Use `dock_state.main_surface_mut().iter_mut()` instead"] + pub fn iter_main_surface_nodes_mut(&mut self) -> impl Iterator> { + self[SurfaceIndex::main()].iter_mut() + } + + /// Returns an [`Iterator`] of **all** underlying nodes in the dock state and all subsequent trees. + #[deprecated = "Use `iter_all_nodes` instead"] pub fn iter_nodes(&self) -> impl Iterator> { self.surfaces .iter() - .filter_map(|tree| tree.node_tree()) + .filter_map(|surface| surface.node_tree()) .flat_map(|nodes| nodes.iter()) } + + /// Returns a new DockState while mapping the tab type + pub fn map_tabs(&self, function: F) -> DockState + where + F: FnMut(&Tab) -> NewTab + Clone, + { + let DockState { + surfaces, + focused_surface, + translations, + } = self; + let surfaces = surfaces + .iter() + .map(|surface| surface.map_tabs(function.clone())) + .collect(); + DockState { + surfaces, + focused_surface: *focused_surface, + translations: translations.clone(), + } + } } impl DockState diff --git a/src/dock_state/surface.rs b/src/dock_state/surface.rs index f8c9788..1fdf7e9 100644 --- a/src/dock_state/surface.rs +++ b/src/dock_state/surface.rs @@ -1,4 +1,4 @@ -use crate::{Tree, WindowState}; +use crate::{Node, NodeIndex, Tree, WindowState}; /// A [`Surface`] is the highest level component in a [`DockState`](crate::DockState). [`Surface`]s represent an area /// in which nodes are placed. Typically, you're only using one surface, which is the main surface. However, if you drag @@ -22,8 +22,8 @@ impl Surface { matches!(self, Self::Empty) } - /// Get mutable access to the node tree of this surface. - pub fn node_tree_mut(&mut self) -> Option<&mut Tree> { + /// Get access to the node tree of this surface. + pub fn node_tree(&self) -> Option<&Tree> { match self { Surface::Empty => None, Surface::Main(tree) => Some(tree), @@ -31,12 +31,62 @@ impl Surface { } } - /// Get access to the node tree of this surface. - pub fn node_tree(&self) -> Option<&Tree> { + /// Get mutable access to the node tree of this surface. + pub fn node_tree_mut(&mut self) -> Option<&mut Tree> { match self { Surface::Empty => None, Surface::Main(tree) => Some(tree), Surface::Window(tree, _) => Some(tree), } } + + /// Returns an [`Iterator`] of nodes in this surface's tree. + /// + /// If the surface is [`Empty`](Self::Empty), then the returned [`Iterator`] will be empty. + pub fn iter_nodes(&self) -> impl Iterator> { + match self.node_tree() { + Some(tree) => tree.iter(), + None => core::slice::Iter::default(), + } + } + + /// Returns a mutable [`Iterator`] of nodes in this surface's tree. + /// + /// If the surface is [`Empty`](Self::Empty), then the returned [`Iterator`] will be empty. + pub fn iter_nodes_mut(&mut self) -> impl Iterator> { + match self.node_tree_mut() { + Some(tree) => tree.iter_mut(), + None => core::slice::IterMut::default(), + } + } + + /// Returns an [`Iterator`] of **all** tabs in this surface's tree, + /// and indices of containing nodes. + pub fn iter_all_tabs(&self) -> impl Iterator { + self.iter_nodes() + .enumerate() + .flat_map(|(index, node)| node.iter_tabs().map(move |tab| (NodeIndex(index), tab))) + } + + /// Returns a mutable [`Iterator`] of **all** tabs in this surface's tree, + /// and indices of containing nodes. + pub fn iter_all_tabs_mut(&mut self) -> impl Iterator { + self.iter_nodes_mut() + .enumerate() + .flat_map(|(index, node)| node.iter_tabs_mut().map(move |tab| (NodeIndex(index), tab))) + } + + /// Returns a new Surface while mapping the tab type + pub fn map_tabs(&self, function: F) -> Surface + where + F: FnMut(&Tab) -> NewTab + Clone, + { + match self { + Surface::Empty => Surface::Empty, + Surface::Main(tree) => Surface::Main(tree.map_tabs(function)), + Surface::Window(tree, window_state) => { + Surface::Window(tree.map_tabs(function), window_state.clone()) + } + } + } } diff --git a/src/dock_state/tree/mod.rs b/src/dock_state/tree/mod.rs index 21b244c..1ff22ce 100644 --- a/src/dock_state/tree/mod.rs +++ b/src/dock_state/tree/mod.rs @@ -122,7 +122,7 @@ impl TabDestination { #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] pub struct Tree { // Binary tree vector - pub(super) tree: Vec>, + pub(super) nodes: Vec>, focused_node: Option, } @@ -135,7 +135,7 @@ impl fmt::Debug for Tree { impl Default for Tree { fn default() -> Self { Self { - tree: Vec::new(), + nodes: Vec::new(), focused_node: None, } } @@ -146,14 +146,14 @@ impl Index for Tree { #[inline(always)] fn index(&self, index: NodeIndex) -> &Self::Output { - &self.tree[index.0] + &self.nodes[index.0] } } impl IndexMut for Tree { #[inline(always)] fn index_mut(&mut self, index: NodeIndex) -> &mut Self::Output { - &mut self.tree[index.0] + &mut self.nodes[index.0] } } @@ -163,7 +163,7 @@ impl Tree { pub fn new(tabs: Vec) -> Self { let root = Node::leaf_with(tabs); Self { - tree: vec![root], + nodes: vec![root], focused_node: None, } } @@ -172,7 +172,7 @@ impl Tree { /// or `None` if no leaf exists in the [`Tree`]. #[inline] pub fn find_active(&mut self) -> Option<(Rect, &mut Tab)> { - self.tree.iter_mut().find_map(|node| match node { + self.nodes.iter_mut().find_map(|node| match node { Node::Leaf { tabs, active, @@ -188,13 +188,13 @@ impl Tree { /// This includes [`Empty`](Node::Empty) nodes. #[inline(always)] pub fn len(&self) -> usize { - self.tree.len() + self.nodes.len() } /// Returns `true` if the number of nodes in the tree is 0, otherwise `false`. #[inline(always)] pub fn is_empty(&self) -> bool { - self.tree.is_empty() + self.nodes.is_empty() } /// Returns an [`Iterator`] of the underlying collection of nodes. @@ -202,7 +202,7 @@ impl Tree { /// This includes [`Empty`](Node::Empty) nodes. #[inline(always)] pub fn iter(&self) -> Iter<'_, Node> { - self.tree.iter() + self.nodes.iter() } /// Returns [`IterMut`] of the underlying collection of nodes. @@ -210,13 +210,13 @@ impl Tree { /// This includes [`Empty`](Node::Empty) nodes. #[inline(always)] pub fn iter_mut(&mut self) -> IterMut<'_, Node> { - self.tree.iter_mut() + self.nodes.iter_mut() } /// Returns an [`Iterator`] of [`NodeIndex`] ordered in a breadth first manner. #[inline(always)] pub(crate) fn breadth_first_index_iter(&self) -> impl Iterator { - (0..self.tree.len()).map(NodeIndex) + (0..self.nodes.len()).map(NodeIndex) } /// Returns an iterator over all tabs in arbitrary order. @@ -243,7 +243,7 @@ impl Tree { #[inline] pub fn num_tabs(&self) -> usize { let mut count = 0; - for node in self.tree.iter() { + for node in self.nodes.iter() { if let Node::Leaf { tabs, .. } = node { count += tabs.len(); } @@ -264,7 +264,7 @@ impl Tree { /// assert_eq!(root_node.tabs(), Some(["single tab"].as_slice())); /// ``` pub fn root_node(&self) -> Option<&Node> { - self.tree.first() + self.nodes.first() } /// Acquire a mutable borrow to the [`Node`] at the root of the tree. @@ -282,7 +282,7 @@ impl Tree { /// assert_eq!(root_node.tabs(), Some(["single tab", "partner tab"].as_slice())); /// ``` pub fn root_node_mut(&mut self) -> Option<&mut Node> { - self.tree.first_mut() + self.nodes.first_mut() } /// Creates two new nodes by splitting a given `parent` node and assigns them as its children. The first (old) node @@ -476,9 +476,9 @@ impl Tree { assert_ne!(new.tabs_count(), 0); // Resize vector to fit the new size of the binary tree. { - let index = self.tree.iter().rposition(|n| !n.is_empty()).unwrap_or(0); + let index = self.nodes.iter().rposition(|n| !n.is_empty()).unwrap_or(0); let level = NodeIndex(index).level(); - self.tree + self.nodes .resize_with((1 << (level + 1)) - 1, || Node::Empty); } @@ -489,7 +489,7 @@ impl Tree { // If the node were splitting is a parent, all it's children need to be moved. if old.is_parent() { - let levels_to_move = NodeIndex(self.tree.len()).level() - index[0].level(); + let levels_to_move = NodeIndex(self.nodes.len()).level() - index[0].level(); // Level 0 is ourself, which is done when we assign self[index[0]] = old, so start at 1. for level in (1..levels_to_move).rev() { @@ -504,7 +504,7 @@ impl Tree { // Swap self[old_start..(old_start+len)] with self[new_start..(new_start+len)] // (the new part will only contain empty entries). let (old_range, new_range) = { - let (first_part, second_part) = self.tree.split_at_mut(new_start); + let (first_part, second_part) = self.nodes.split_at_mut(new_start); // Cut to length. ( &mut first_part[old_start..old_start + len], @@ -526,7 +526,7 @@ impl Tree { fn first_leaf(&self, top: NodeIndex) -> Option { let left = top.left(); let right = top.right(); - match (self.tree.get(left.0), self.tree.get(right.0)) { + match (self.nodes.get(left.0), self.nodes.get(right.0)) { (Some(&Node::Leaf { .. }), _) => Some(left), (_, Some(&Node::Leaf { .. })) => Some(right), @@ -547,7 +547,7 @@ impl Tree { /// Returns the viewport [`Rect`] and the `Tab` inside the focused leaf node or [`None`] if it does not exist. #[inline] pub fn find_active_focused(&mut self) -> Option<(Rect, &mut Tab)> { - match self.focused_node.and_then(|idx| self.tree.get_mut(idx.0)) { + match self.focused_node.and_then(|idx| self.nodes.get_mut(idx.0)) { Some(Node::Leaf { tabs, active, @@ -570,7 +570,7 @@ impl Tree { #[inline] pub fn set_focused_node(&mut self, node_index: NodeIndex) { self.focused_node = self - .tree + .nodes .get(node_index.0) .filter(|node| node.is_leaf()) .map(|_| node_index); @@ -585,7 +585,7 @@ impl Tree { assert!(self[node].is_leaf()); let Some(parent) = node.parent() else { - self.tree.clear(); + self.nodes.clear(); return; }; @@ -598,7 +598,7 @@ impl Tree { } else { parent.left() }; - if self.tree.get(next.0).is_some_and(|node| node.is_leaf()) { + if self.nodes.get(next.0).is_some_and(|node| node.is_leaf()) { self.focused_node = Some(next); break; } @@ -620,13 +620,13 @@ impl Tree { let dst = parent.children_at(level); let src = parent.children_right(level + 1); for (dst, src) in dst.zip(src) { - if src >= self.tree.len() { + if src >= self.nodes.len() { break 'left_end; } if Some(NodeIndex(src)) == self.focused_node { self.focused_node = Some(NodeIndex(dst)); } - self.tree[dst] = std::mem::replace(&mut self.tree[src], Node::Empty); + self.nodes[dst] = std::mem::replace(&mut self.nodes[src], Node::Empty); } level += 1; } @@ -635,13 +635,13 @@ impl Tree { let dst = parent.children_at(level); let src = parent.children_left(level + 1); for (dst, src) in dst.zip(src) { - if src >= self.tree.len() { + if src >= self.nodes.len() { break 'right_end; } if Some(NodeIndex(src)) == self.focused_node { self.focused_node = Some(NodeIndex(dst)); } - self.tree[dst] = std::mem::replace(&mut self.tree[src], Node::Empty); + self.nodes[dst] = std::mem::replace(&mut self.nodes[src], Node::Empty); } level += 1; } @@ -650,7 +650,7 @@ impl Tree { /// Pushes a tab to the first `Leaf` it finds or create a new leaf if an `Empty` node is encountered. pub fn push_to_first_leaf(&mut self, tab: Tab) { - for (index, node) in &mut self.tree.iter_mut().enumerate() { + for (index, node) in &mut self.nodes.iter_mut().enumerate() { match node { Node::Leaf { tabs, active, .. } => { *active = TabIndex(tabs.len()); @@ -666,15 +666,15 @@ impl Tree { _ => {} } } - assert!(self.tree.is_empty()); - self.tree.push(Node::leaf_with(vec![tab])); + assert!(self.nodes.is_empty()); + self.nodes.push(Node::leaf_with(vec![tab])); self.focused_node = Some(NodeIndex(0)); } /// Sets which is the active tab within a specific node. #[inline] pub fn set_active_tab(&mut self, node_index: NodeIndex, tab_index: TabIndex) { - if let Some(Node::Leaf { active, .. }) = self.tree.get_mut(node_index.0) { + if let Some(Node::Leaf { active, .. }) = self.nodes.get_mut(node_index.0) { *active = tab_index; } } @@ -687,8 +687,8 @@ impl Tree { pub fn push_to_focused_leaf(&mut self, tab: Tab) { match self.focused_node { Some(node) => { - if self.tree.is_empty() { - self.tree.push(Node::leaf(tab)); + if self.nodes.is_empty() { + self.nodes.push(Node::leaf(tab)); self.focused_node = Some(NodeIndex::root()); } else { match &mut self[node] { @@ -708,8 +708,8 @@ impl Tree { } } None => { - if self.tree.is_empty() { - self.tree.push(Node::leaf(tab)); + if self.nodes.is_empty() { + self.nodes.push(Node::leaf(tab)); self.focused_node = Some(NodeIndex::root()); } else { self.push_to_first_leaf(tab); @@ -731,6 +731,25 @@ impl Tree { } tab } + + /// Returns a new Tree while mapping the tab type + pub fn map_tabs(&self, function: F) -> Tree + where + F: FnMut(&Tab) -> NewTab + Clone, + { + let Tree { + focused_node, + nodes, + } = self; + let nodes = nodes + .iter() + .map(|node| node.map_tabs(function.clone())) + .collect(); + Tree { + nodes, + focused_node: *focused_node, + } + } } impl Tree @@ -745,7 +764,7 @@ where /// /// In case there are several hits, only the first is returned. pub fn find_tab(&self, needle_tab: &Tab) -> Option<(NodeIndex, TabIndex)> { - for (node_index, node) in self.tree.iter().enumerate() { + for (node_index, node) in self.nodes.iter().enumerate() { if let Some(tabs) = node.tabs() { for (tab_index, tab) in tabs.iter().enumerate() { if tab == needle_tab { diff --git a/src/dock_state/tree/node.rs b/src/dock_state/tree/node.rs index afc4521..cc1c4c7 100644 --- a/src/dock_state/tree/node.rs +++ b/src/dock_state/tree/node.rs @@ -191,6 +191,28 @@ impl Node { } } + /// Returns an [`Iterator`] of tabs in this node. + /// + /// If this node is not a [`Leaf`](Self::Leaf), then the returned [`Iterator`] will be empty. + #[inline] + pub fn iter_tabs(&self) -> impl Iterator { + match self.tabs() { + Some(tabs) => tabs.iter(), + None => core::slice::Iter::default(), + } + } + + /// Returns a mutable [`Iterator`] of tabs in this node. + /// + /// If this node is not a [`Leaf`](Self::Leaf), then the returned [`Iterator`] will be empty. + #[inline] + pub fn iter_tabs_mut(&mut self) -> impl Iterator { + match self.tabs_mut() { + Some(tabs) => tabs.iter_mut(), + None => core::slice::IterMut::default(), + } + } + /// Adds `tab` to the node and sets it as the active tab. /// /// # Panics @@ -266,4 +288,35 @@ impl Node { _ => Default::default(), } } + + /// Returns a new Node while mapping the tab type + pub fn map_tabs(&self, function: F) -> Node + where + F: FnMut(&Tab) -> NewTab, + { + match self { + Node::Leaf { + rect, + viewport, + tabs, + active, + scroll, + } => Node::Leaf { + rect: *rect, + viewport: *viewport, + tabs: tabs.iter().map(function).collect(), + active: *active, + scroll: *scroll, + }, + Node::Empty => Node::Empty, + Node::Vertical { rect, fraction } => Node::Vertical { + rect: *rect, + fraction: *fraction, + }, + Node::Horizontal { rect, fraction } => Node::Horizontal { + rect: *rect, + fraction: *fraction, + }, + } + } } diff --git a/src/dock_state/tree/tab_iter.rs b/src/dock_state/tree/tab_iter.rs index a514db6..4caf49e 100644 --- a/src/dock_state/tree/tab_iter.rs +++ b/src/dock_state/tree/tab_iter.rs @@ -22,7 +22,7 @@ impl<'a, Tab> Iterator for TabIter<'a, Tab> { fn next(&mut self) -> Option { loop { - match self.tree.tree.get(self.node_idx)?.tabs() { + match self.tree.nodes.get(self.node_idx)?.tabs() { Some(tabs) => match tabs.get(self.tab_idx) { Some(tab) => { self.tab_idx += 1; diff --git a/src/dock_state/window_state.rs b/src/dock_state/window_state.rs index 54809a0..fd3d1a2 100644 --- a/src/dock_state/window_state.rs +++ b/src/dock_state/window_state.rs @@ -82,7 +82,7 @@ impl WindowState { let new = self.new; let mut window_constructor = egui::Window::new("") .id(id) - .constraint_to(bounds) + .constrain_to(bounds) .title_bar(false); if let Some(position) = self.next_position() {