Skip to content

Commit afc4ab8

Browse files
anhoshdevxpainAvarelVickerinoxmkeeter
authored
Release 0.17 (#281)
* Updates to `TabViewer::{is_closable,on_close}`. * Update crate version * feat: add on_rect_changed callback and example for dock state (#265) * feat: add on_rect_changed callback to TabViewer This commit introduces the `on_rect_changed` callback to the `TabViewer` trait. This callback is triggered whenever the rectangle of a tab's content changes, allowing tabs to adjust their content based on the available space. This is particularly useful when the window is resized, panels are docked or undocked, or when the dock area layout changes. * feat: add example for saving and loading dock state This commit adds a new example that demonstrates how to save and load the dock state to a JSON file. This allows users to persist their preferred layout across sessions. * Make sure `TabViewer::on_close` is always called when the user tries to close the tab (#266) * Use close_tab_bg_fill for close buttons (#268) * Add more QOL methods to ``DockState``, and change the structure of ``Node`` (#272) * new concrete types for ``Node`` created ``LeafNode`` and ``SplitNode`` types. * add documentation, get rid of errors * adding ``iter_leaves``, ``iter_leaves_mut``, and cleaning up some code * cargo fmt * implement ``Index<NodeIndex>`` for ``Surface`` * fixed tests, overall improved docs * added ``is_empty`` method to ``LeafNode`` in accordance with clippy tests * run ``cargo fmt`` * Update CHANGELOG.md * A few minor stylistic changes * Test fix #1 --------- Co-authored-by: Adanos020 <adanos020@gmail.com> * Prevent `DockState::retain_tabs` from deleting main surface (#277) * Add another failing unit test * Don't delete the main surface * Just-in-time patching of surfaces * Update changelog for #277 * Add inner_margin and spacing to tab bar style (#270) * Add inner_margin to TabBarStyle * Add tab_spacing to TabStyle * Update changelog following #270 * Fix `retain_tabs` behavior with `Empty` nodes in the list (#275) * Add failing unit test * Add two fixes * Update to egui 0.32 (#280) * Update popup.rs update to egui main * Remove deprecated calls, and call `Memory::keep_popup_open` * Update to egui 0.32 - this does *not* update to use the new Popup API * Fix compiler errors and Clippy warnings. Retire widgets/popup.rs as it's now entirely replaced by `egui::Popup`. --------- Co-authored-by: Adam Gąsior <adanos020@gmail.com> * Update changelog following #275 * Update readme --------- Co-authored-by: DEV×PAIN <170700110+devxpain@users.noreply.github.com> Co-authored-by: Avarel <antranprm@gmail.com> Co-authored-by: Vikrinox <51887867+Vickerinox@users.noreply.github.com> Co-authored-by: Matt Keeter <matt.j.keeter@gmail.com> Co-authored-by: Jengamon <bob.hostern@gmail.com>
1 parent be9bedf commit afc4ab8

File tree

21 files changed

+864
-513
lines changed

21 files changed

+864
-513
lines changed

CHANGELOG.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,59 @@
11
# egui_dock changelog
22

3+
## egui_dock 0.17.0 - 2025/07/13
4+
5+
### Breaking changes
6+
7+
- From ([#272](https://github.com/Adanos020/egui_dock/pull/272)):
8+
- `Node`s underlying data has been split up into the `LeafNode` and `SplitNode` types, meaning that any match
9+
statements carried out on a node now needs to account for this.
10+
- Upgraded to egui 0.32 ([#280](https://github.com/Adanos020/egui_dock/pull/280/))
11+
12+
### Changed
13+
14+
- From ([#272](https://github.com/Adanos020/egui_dock/pull/272)):
15+
- `Tree::set_active_tab` now takes `impl Into<NodeIndex>` and `impl Into<TabIndex>` to make use slightly easier.
16+
- `Surface` now implements `Index<NodeIndex>`/`IndexMut<NodeIndex>` which tries to access the surfaces node tree and
17+
the node at the index. This will always panic when used on an empty surface as they do not have a node tree nor
18+
nodes.
19+
20+
### Added
21+
22+
- From ([#272](https://github.com/Adanos020/egui_dock/pull/272)):
23+
- `DockState::iter_leaves` and `DockState::iter_leaves_mut` - can be used to more efficiently iterate over leaf
24+
nodes without needing to "unwrap" them from the `Node` enum.
25+
- `DockState::find_tab_from`/`Tree::find_tab_from` - a more generalized version of the existing `find_tab` methods
26+
which doesn't require the tab type to implement `PartialEq`.
27+
- New type `LeafNode` which contains leaf node data and has the following methods:
28+
* `new`,
29+
* `set_active_tab`,
30+
* `set_rect`,
31+
* `rect`,
32+
* `len`,
33+
* `is_empty`,
34+
* `tabs`,
35+
* `tabs_mut`,
36+
* `append_tab`,
37+
* `insert_tab`,
38+
* `remove_tab`,
39+
* `retain_tabs`,
40+
* `active_focused`.
41+
- New type `SplitNode` which contains data about node splits and has the following methods:
42+
* `new`,
43+
* `set_rect`,
44+
* `rect`.
45+
- `Node::get_leaf`/`Node::get_leaf_mut` - an alternative way of trying to access leaf data in a node.
46+
- `TabBarStyle` now has two new fields: `inner_margin` and
47+
`spacing`. ([#270](https://github.com/Adanos020/egui_dock/pull/270))
48+
49+
### Fixed
50+
51+
- `DockState::retain_tabs` no longer deletes the main surface if it ends up
52+
empty ([#277](https://github.com/Adanos020/egui_dock/pull/277)).
53+
- From [#275](https://github.com/Adanos020/egui_dock/pull/275):
54+
- `{DockState,Tree}::remove_leaf` now removes unused empty node`s at the back of the tree.
55+
- `{DockState,Tree}::retain_tabs` no longer deletes leaf nodes it shouldn't delete.
56+
357
## egui_dock 0.16.0 - 2025-02-07
458

559
### Breaking changes

Cargo.toml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
name = "egui_dock"
33
description = "Docking system for egui - an immediate-mode GUI library for Rust"
44
authors = ["lain-dono", "Adam Gąsior (Adanos020)"]
5-
version = "0.16.0"
5+
version = "0.17.0"
66
edition = "2021"
7-
rust-version = "1.81"
7+
rust-version = "1.85"
88
license = "MIT"
99
readme = "README.md"
1010
repository = "https://github.com/Adanos020/egui_dock"
@@ -18,15 +18,20 @@ default = []
1818
serde = ["dep:serde", "egui/serde"]
1919

2020
[dependencies]
21-
egui = { version = "0.31", default-features = false }
21+
egui = { version = "0.32", default-features = false }
2222
serde = { version = "1", optional = true, features = ["derive"] }
2323

2424
duplicate = "2.0"
2525
paste = "1.0"
2626

2727
[dev-dependencies]
28-
eframe = { version = "0.31", default-features = false, features = [
28+
eframe = { version = "0.32", default-features = false, features = [
2929
"default",
3030
"default_fonts",
3131
"glow",
3232
] }
33+
serde_json = { version = "1" }
34+
35+
[[example]]
36+
name = "save_load_dock_state"
37+
required-features = ["serde"]

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
[![github](https://img.shields.io/badge/github-Adanos020/egui_dock-8da0cb?logo=github)](https://github.com/Adanos020/egui_dock)
44
[![crates.io](https://img.shields.io/crates/v/egui_dock)](https://crates.io/crates/egui_dock)
55
[![docs.rs](https://img.shields.io/docsrs/egui_dock)](https://docs.rs/egui_dock/)
6-
[![egui_version](https://img.shields.io/badge/egui-0.31-blue)](https://github.com/emilk/egui)
6+
[![egui_version](https://img.shields.io/badge/egui-0.32-blue)](https://github.com/emilk/egui)
77

88
Originally created by [@lain-dono](https://github.com/lain-dono), this library provides a docking system for `egui`.
99

@@ -32,8 +32,8 @@ Add `egui` and `egui_dock` to your project's dependencies.
3232

3333
```toml
3434
[dependencies]
35-
egui = "0.31"
36-
egui_dock = "0.16"
35+
egui = "0.32"
36+
egui_dock = "0.17"
3737
```
3838

3939
Then proceed by setting up `egui`, following its [quick start guide](https://github.com/emilk/egui#quick-start).

examples/hello.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use egui::{
99
WidgetText,
1010
};
1111

12+
use egui_dock::tab_viewer::OnCloseResponse;
1213
use egui_dock::{
1314
AllowedSplits, DockArea, DockState, NodeIndex, OverlayType, Style, SurfaceIndex,
1415
TabInteractionStyle, TabViewer,
@@ -119,13 +120,13 @@ impl TabViewer for MyContext {
119120
}
120121
}
121122

122-
fn closeable(&mut self, tab: &mut Self::Tab) -> bool {
123+
fn is_closeable(&self, tab: &Self::Tab) -> bool {
123124
["Inspector", "Style Editor"].contains(&tab.as_str())
124125
}
125126

126-
fn on_close(&mut self, tab: &mut Self::Tab) -> bool {
127+
fn on_close(&mut self, tab: &mut Self::Tab) -> OnCloseResponse {
127128
self.open_tabs.remove(tab);
128-
true
129+
OnCloseResponse::Close
129130
}
130131
}
131132

@@ -277,7 +278,7 @@ impl MyContext {
277278
ui.selectable_value(
278279
&mut style.buttons.add_tab_align,
279280
align,
280-
format!("{:?}", align),
281+
format!("{align:?}"),
281282
);
282283
}
283284
});
@@ -580,7 +581,7 @@ impl Default for MyApp {
580581
impl eframe::App for MyApp {
581582
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
582583
TopBottomPanel::top("egui_dock::MenuBar").show(ctx, |ui| {
583-
egui::menu::bar(ui, |ui| {
584+
egui::MenuBar::new().ui(ui, |ui| {
584585
ui.menu_button("View", |ui| {
585586
// allow certain tabs to be toggled
586587
for tab in &["File Browser", "Asset Manager"] {
@@ -596,7 +597,7 @@ impl eframe::App for MyApp {
596597
.push_to_focused_leaf(tab.to_string());
597598
}
598599

599-
ui.close_menu();
600+
ui.close();
600601
}
601602
}
602603
});

examples/save_load_dock_state.rs

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
2+
3+
use eframe::{egui, NativeOptions};
4+
use egui_dock::{DockArea, DockState, NodeIndex, Style};
5+
use std::fs;
6+
7+
const DOCK_STATE_FILE: &str = "target/dock_state.json";
8+
9+
fn main() -> eframe::Result<()> {
10+
let options = NativeOptions::default();
11+
eframe::run_native(
12+
"My egui App",
13+
options,
14+
Box::new(|_cc| Ok(Box::<MyApp>::default())),
15+
)
16+
}
17+
18+
struct TabViewer {
19+
modified: bool,
20+
}
21+
22+
impl egui_dock::TabViewer for TabViewer {
23+
type Tab = String;
24+
25+
fn title(&mut self, tab: &mut Self::Tab) -> egui::WidgetText {
26+
(&*tab).into()
27+
}
28+
29+
fn ui(&mut self, ui: &mut egui::Ui, tab: &mut Self::Tab) {
30+
ui.label(format!("Content of {tab}"));
31+
}
32+
33+
fn on_rect_changed(&mut self, _tab: &mut Self::Tab) {
34+
self.modified = true
35+
}
36+
}
37+
38+
struct MyApp {
39+
tree: DockState<String>,
40+
}
41+
42+
impl MyApp {
43+
fn save_json(&self) {
44+
if let Ok(json) = serde_json::to_string(&self.tree) {
45+
let _ = fs::write(DOCK_STATE_FILE, json);
46+
}
47+
}
48+
49+
fn load_json() -> Option<Self> {
50+
fs::read_to_string(DOCK_STATE_FILE)
51+
.ok()
52+
.and_then(|data| serde_json::from_str(&data).ok())
53+
.map(|tree| Self { tree })
54+
}
55+
}
56+
57+
impl Default for MyApp {
58+
fn default() -> Self {
59+
// Try loading from file, fallback to default layout
60+
Self::load_json().unwrap_or_else(|| {
61+
let mut tree = DockState::new(vec!["tab1".to_owned(), "tab2".to_owned()]);
62+
63+
let [a, b] =
64+
tree.main_surface_mut()
65+
.split_left(NodeIndex::root(), 0.3, vec!["tab3".to_owned()]);
66+
let [_, _] = tree
67+
.main_surface_mut()
68+
.split_below(a, 0.7, vec!["tab4".to_owned()]);
69+
let [_, _] = tree
70+
.main_surface_mut()
71+
.split_below(b, 0.5, vec!["tab5".to_owned()]);
72+
73+
Self { tree }
74+
})
75+
}
76+
}
77+
78+
impl eframe::App for MyApp {
79+
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
80+
let mut tab_viewer = TabViewer { modified: false };
81+
DockArea::new(&mut self.tree)
82+
.style(Style::from_egui(ctx.style().as_ref()))
83+
.show(ctx, &mut tab_viewer);
84+
if tab_viewer.modified {
85+
self.save_json();
86+
}
87+
}
88+
}

examples/simple.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use eframe::{egui, NativeOptions};
44

5+
use egui_dock::tab_viewer::OnCloseResponse;
56
use egui_dock::{DockArea, DockState, NodeIndex, Style};
67

78
fn main() -> eframe::Result<()> {
@@ -25,6 +26,11 @@ impl egui_dock::TabViewer for TabViewer {
2526
fn ui(&mut self, ui: &mut egui::Ui, tab: &mut Self::Tab) {
2627
ui.label(format!("Content of {tab}"));
2728
}
29+
30+
fn on_close(&mut self, _tab: &mut Self::Tab) -> OnCloseResponse {
31+
println!("Closed tab: {_tab}");
32+
OnCloseResponse::Close
33+
}
2834
}
2935

3036
struct MyApp {

0 commit comments

Comments
 (0)