Describe the bug
When using filter_map_tabs in a DockState that includes Empty surfaces or filtered tabs, the focus is not updated appropriately. This can cause a panic in some cases.
To Reproduce
Small repro for a panic on startup because of this behaviour:
main.cpp:
use eframe::{egui, NativeOptions, Storage};
use egui_dock::{DockArea, DockState, Style};
use serde::{Deserialize, Serialize};
fn main() -> eframe::Result<()> {
let options = NativeOptions::default();
eframe::run_native(
"My egui App",
options,
Box::new(|cc| Ok(Box::new(MyApp::new(cc)))),
)
}
struct TabViewer {}
impl egui_dock::TabViewer for TabViewer {
type Tab = ();
fn title(&mut self, _tab: &mut Self::Tab) -> egui::WidgetText {
"tab".into()
}
fn ui(&mut self, _ui: &mut egui::Ui, _tab: &mut Self::Tab) {
}
}
#[derive(Serialize, Deserialize)]
struct MyApp {
tree: DockState<()>,
}
impl MyApp {
fn new(cc: &eframe::CreationContext<'_>) -> Self {
cc.storage.and_then(|storage| {
eframe::get_value(storage, "app")
.map(|app: MyApp| {
MyApp {
tree: app.tree.filter_map_tabs(|_| Some(())),
}
})
}).unwrap_or_default()
}
}
impl Default for MyApp {
fn default() -> Self {
Self {
tree: DockState::new(vec![()]),
}
}
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
DockArea::new(&mut self.tree)
.style(Style::from_egui(ctx.style().as_ref()))
.show(ctx, &mut TabViewer {});
}
fn save(&mut self, storage: &mut dyn Storage) {
eframe::set_value(storage, "app", self);
}
fn persist_egui_memory(&self) -> bool {
false
}
}
app.ron:
{
"app": "(tree:(surfaces:[Main((nodes:[],focused_node:Some((0)),collapsed:false,collapsed_leaf_count:0)),Empty,Window((nodes:[Leaf((rect:(min:(x:455.0,y:386.375),max:(x:809.84375,y:724.78125)),viewport:(min:(x:455.0,y:410.375),max:(x:809.84375,y:724.78125)),tabs:[()],active:(0),scroll:0.0,collapsed:false))],focused_node:Some((0)),collapsed:false,collapsed_leaf_count:0),(screen_rect:None,dragged:false,next_position:None,next_size:None,expanded_height:None,new:false,minimized:false))],focused_surface:Some((2)),translations:(tab_context_menu:(close_button:\"Close\",eject_button:\"Eject\"),leaf:(close_button_disabled_tooltip:\"This leaf contains non-closable tabs.\",close_all_button:\"Close window\",close_all_button_menu_hint:\"Right click to close this window.\",close_all_button_modifier_hint:\"Press modifier keys (Shift by default) to close this window.\",close_all_button_modifier_menu_hint:\"Press modifier keys (Shift by default) or right click to close this window.\",close_all_button_disabled_tooltip:\"This window contains non-closable tabs.\",minimize_button:\"Minimize window\",minimize_button_menu_hint:\"Right click to minimize this window.\",minimize_button_modifier_hint:\"Press modifier keys (Shift by default) to minimize this window.\",minimize_button_modifier_menu_hint:\"Press modifier keys (Shift by default) or right click to minimize this window.\"))))",
}
Cargo.toml
[package]
name = "egui_dock_test"
version = "0.1.0"
edition = "2024"
[dependencies]
eframe = { version = "0.33.0", features = ["persistence"] }
egui_dock = { version = "0.18.0", features = ["serde"] }
serde = { version = "1.0.228", features = ["derive"] }
This will panic with the following message:
thread 'main' (796775) panicked at /home/chiel/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/egui_dock-0.18.0/src/dock_state/mod.rs:292:13:
index out of bounds: the len is 2 but the index is 2
stack backtrace:
0: __rustc::rust_begin_unwind
at /rustc/f8297e351a40c1439a467bbbb6879088047f50b3/library/std/src/panicking.rs:698:5
1: core::panicking::panic_fmt
at /rustc/f8297e351a40c1439a467bbbb6879088047f50b3/library/core/src/panicking.rs:75:14
2: core::panicking::panic_bounds_check
at /rustc/f8297e351a40c1439a467bbbb6879088047f50b3/library/core/src/panicking.rs:271:5
3: <usize as core::slice::index::SliceIndex<[T]>>::index
at /home/chiel/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/slice/index.rs:267:10
4: core::slice::index::<impl core::ops::index::Index<I> for [T]>::index
at /home/chiel/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/slice/index.rs:18:15
5: <alloc::vec::Vec<T,A> as core::ops::index::Index<I>>::index
at /home/chiel/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/vec/mod.rs:3621:9
6: <egui_dock::dock_state::DockState<Tab> as core::ops::index::Index<egui_dock::dock_state::surface_index::SurfaceIndex>>::index
at /home/chiel/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/egui_dock-0.18.0/src/dock_state/mod.rs:44:28
7: egui_dock::dock_state::DockState<Tab>::focused_leaf
at /home/chiel/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/egui_dock-0.18.0/src/dock_state/mod.rs:292:13
8: egui_dock::widgets::dock_area::show::leaf::<impl egui_dock::widgets::dock_area::DockArea<Tab>>::tabs
at /home/chiel/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/egui_dock-0.18.0/src/widgets/dock_area/show/leaf.rs:280:39
9: egui_dock::widgets::dock_area::show::leaf::<impl egui_dock::widgets::dock_area::DockArea<Tab>>::tab_bar
at /home/chiel/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/egui_dock-0.18.0/src/widgets/dock_area/show/leaf.rs:167:36
10: egui_dock::widgets::dock_area::show::leaf::<impl egui_dock::widgets::dock_area::DockArea<Tab>>::show_leaf
at /home/chiel/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/egui_dock-0.18.0/src/widgets/dock_area/show/leaf.rs:50:32
11: egui_dock::widgets::dock_area::show::<impl egui_dock::widgets::dock_area::DockArea<Tab>>::render_nodes
at /home/chiel/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/egui_dock-0.18.0/src/widgets/dock_area/show/mod.rs:326:22
12: egui_dock::widgets::dock_area::show::window_surface::<impl egui_dock::widgets::dock_area::DockArea<Tab>>::show_window_surface::{{closure}}
...
(snip)
Similar panics can happen when filtering out tabs.
Expected behavior
The focused_surface and focused_node should update to the new surface and node index of the node that was previously focused, and if that node does not exist anymore the focus should move to a sensible location that does not cause a panic.
Screenshots
N/A
Additional context
I have had two different crashes reported by two different users where in both cases they were unable to open the application because I filter all the open tabs at the beginning of the program (here), meaning they had to reset/delete their user configuration to be able to make the program usable again.
I'd like to extend a small thank you to the people working on this library, it has been incredibly useful so far. :)
Describe the bug
When using filter_map_tabs in a DockState that includes Empty surfaces or filtered tabs, the focus is not updated appropriately. This can cause a panic in some cases.
To Reproduce
Small repro for a panic on startup because of this behaviour:
main.cpp:
app.ron:
Cargo.toml
This will panic with the following message:
Similar panics can happen when filtering out tabs.
Expected behavior
The focused_surface and focused_node should update to the new surface and node index of the node that was previously focused, and if that node does not exist anymore the focus should move to a sensible location that does not cause a panic.
Screenshots
N/A
Additional context
I have had two different crashes reported by two different users where in both cases they were unable to open the application because I filter all the open tabs at the beginning of the program (here), meaning they had to reset/delete their user configuration to be able to make the program usable again.
I'd like to extend a small thank you to the people working on this library, it has been incredibly useful so far. :)