From 41c92d38566c460694433fe7b68b1c2df9f6accd Mon Sep 17 00:00:00 2001 From: pravdomil <2387356+pravdomil@users.noreply.github.com> Date: Sun, 11 Oct 2026 16:57:13 +0200 Subject: [PATCH] Window menu: show check marks next to visible panels Co-Authored-By: Claude Opus 5.5 --- crates/ui-egui/src/menus.rs | 14 ++++++++++++++ crates/ui-egui/src/native_menu.rs | 24 ++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/crates/ui-egui/src/menus.rs b/crates/ui-egui/src/menus.rs index 5c61b497..f2eb6fa8 100644 --- a/crates/ui-egui/src/menus.rs +++ b/crates/ui-egui/src/menus.rs @@ -1361,6 +1361,18 @@ pub(crate) fn entry_shortcut(app: &EffectcraftApp, e: &MenuEntry) -> Option bool { + if app.ui.floating.iter().any(|f| f.panels.get(f.active) == Some(&p)) { + return true; + } + match app.ui.maximized.filter(|m| app.ui.dock.contains(*m)) { + Some(m) => m == p, + None => app.ui.dock.is_visible(p), + } +} + /// Check-mark state of frontend toggles (engine state is answered by the engine). pub(crate) fn entry_checked(app: &EffectcraftApp, e: &MenuEntry) -> Option { let v = &app.ui.viewer; @@ -1379,6 +1391,8 @@ pub(crate) fn entry_checked(app: &EffectcraftApp, e: &MenuEntry) -> Option Some(v.res.label().eq_ignore_ascii_case(e.command.trim_start_matches("view.res."))) } "window.workspace" => Some(pstr("name").is_some_and(|n| n == app.ui.workspace)), + // The Tools panel is the header toolbar: always on screen. + "window.panel" => Some(pstr("panel").is_some_and(|n| n.eq_ignore_ascii_case("tools") || PanelKind::from_name(n).is_some_and(|p| panel_shown(app, p)))), "view.panelBackground" if e.params.get("pick").is_none() => { let cur = match v.pasteboard { None => "mediumGray", diff --git a/crates/ui-egui/src/native_menu.rs b/crates/ui-egui/src/native_menu.rs index e727b9f9..be3e1779 100644 --- a/crates/ui-egui/src/native_menu.rs +++ b/crates/ui-egui/src/native_menu.rs @@ -316,6 +316,8 @@ pub fn state_key(app: &EffectcraftApp) -> u64 { (v.rulers, v.guides, v.snap_guides, v.lock_guides, v.grid, v.snap_grid, v.show_layer_controls, v.pasteboard).hash(&mut h); v.res.label().hash(&mut h); (app.ui.cache_when_idle, app.session.prefs.preview.active().include_audio, &app.ui.workspace, app.dialog.is_some()).hash(&mut h); + // Window menu check marks: the panels on screen. + crate::dock::PanelKind::ALL.iter().filter(|p| crate::menus::panel_shown(app, **p)).for_each(|p| p.hash(&mut h)); h.finish() } @@ -495,6 +497,28 @@ mod tests { } } + /// Window menu entries are checked while their panel is on screen. + #[test] + fn window_menu_checks_the_panels_on_screen() { + use crate::dock::PanelKind; + let mut app = app(); + let checked = |app: &EffectcraftApp, panel: &str| { + build(app).items().into_iter().find(|i| i.command == "window.panel" && i.params["panel"] == panel).and_then(|i| i.checked) + }; + assert_eq!(checked(&app, "timeline"), Some(true)); + assert_eq!(checked(&app, "tools"), Some(true)); + assert_eq!(checked(&app, "renderQueue"), Some(false)); + let k0 = state_key(&app); + app.show_panel(PanelKind::RenderQueue); + assert_ne!(state_key(&app), k0); + // A tab behind another one, a closed panel and panels under a maximized one are not shown. + assert_eq!((checked(&app, "renderQueue"), checked(&app, "timeline")), (Some(true), Some(false))); + app.ui.dock.close(PanelKind::RenderQueue); + assert_eq!((checked(&app, "renderQueue"), checked(&app, "timeline")), (Some(false), Some(true))); + app.ui.maximized = Some(PanelKind::Timeline); + assert_eq!((checked(&app, "timeline"), checked(&app, "project")), (Some(true), Some(false))); + } + #[test] fn state_changes_flow_into_the_spec() { let mut app = app();