From a7f7f1fd1e327fcddb2697f0f03236fc3db2c2cd Mon Sep 17 00:00:00 2001 From: Valentin Klein Date: Wed, 14 Oct 2026 19:07:28 +0200 Subject: [PATCH] =?UTF-8?q?Edit=20=E2=80=BA=20Menus:=20Menus,=20Keyboard?= =?UTF-8?q?=20Shortcuts,=20Preferences,=20Save=20and=20Exit=20can't=20be?= =?UTF-8?q?=20hidden=20(#5096)=20(#5183)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Hiding Edit › Menus (or Keyboard Shortcuts) left no way back into the dialog, and Save, Save As, Exit and Preferences could disappear too. edit.menus now refuses to hide them, the dialog greys their Visible box, and the menus keep them even when a preferences file lists them. Co-authored-by: Claude Opus 5.5 --- crates/engine/src/prefs.rs | 17 +++++++++++++++++ crates/engine/src/prefs/tests.rs | 13 +++++++++++++ crates/ui-egui/src/menus.rs | 2 +- crates/ui-egui/src/prefs_ui.rs | 16 ++++++++++++++-- 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/crates/engine/src/prefs.rs b/crates/engine/src/prefs.rs index b163d40d88..295870b3ca 100644 --- a/crates/engine/src/prefs.rs +++ b/crates/engine/src/prefs.rs @@ -954,6 +954,20 @@ pub struct MenuCustomization { pub colors: BTreeMap, } +impl MenuCustomization { + /// False for the items Edit › Menus can't hide (#5096): the way back into this dialog + /// (Edit › Menus, Edit › Keyboard Shortcuts), Preferences, Save, Save As and Exit. + pub fn hideable(id: &str) -> bool { + !matches!(id, "edit.menus" | "edit.keyboardShortcuts" | "file.save" | "file.saveAs" | "file.exit") && !id.starts_with("edit.preferences") + } + + /// Whether the menus leave `id` out. Items that can't be hidden stay shown even when an + /// older or hand-edited preferences file lists them. + pub fn is_hidden(&self, id: &str) -> bool { + Self::hideable(id) && self.hidden.iter().any(|h| h == id) + } +} + /// Edit › Toolbar: hidden tools and a custom order (tool names as in `ui.set {tool}`). #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] #[serde(default, rename_all = "camelCase")] @@ -1898,6 +1912,9 @@ fn menus(s: &mut Session, p: &Value) -> Result { } } let (hide, show) = (ids("hide"), ids("show")); + if let Some(id) = hide.iter().find(|id| !MenuCustomization::hideable(id)) { + return Err(bad("edit.menus", format!("`{id}` can't be hidden"))); + } s.edit_prefs(|pr| { if p.get("reset").and_then(Value::as_bool) == Some(true) { pr.menus = MenuCustomization::default(); diff --git a/crates/engine/src/prefs/tests.rs b/crates/engine/src/prefs/tests.rs index 6b56cbc7ba..7f5c863e7f 100644 --- a/crates/engine/src/prefs/tests.rs +++ b/crates/engine/src/prefs/tests.rs @@ -397,6 +397,19 @@ fn menus_and_toolbar_customisation_persist() { assert_eq!(back.toolbar.hidden, vec!["Sponge".to_string()]); } +/// #5096: Edit › Menus can't hide the way back into itself, Preferences, Save or Exit. +#[test] +fn menus_refuse_to_hide_essential_items() { + let mut s = session(); + for id in ["edit.menus", "edit.keyboardShortcuts", "edit.preferences.general", "file.save", "file.saveAs", "file.exit"] { + assert!(s.execute("edit.menus", json!({"hide": ["edit.fade", id]})).is_err(), "{id}"); + assert!(s.prefs().menus.hidden.is_empty(), "{id}: a refused call changes nothing"); + } + // A preferences file that lists them anyway still shows them. + let menus = MenuCustomization { hidden: vec!["file.exit".into(), "edit.fade".into()], ..Default::default() }; + assert!(!menus.is_hidden("file.exit") && menus.is_hidden("edit.fade")); +} + #[test] fn preference_sections_are_commands() { let mut s = Session::new(); diff --git a/crates/ui-egui/src/menus.rs b/crates/ui-egui/src/menus.rs index 403994ac10..d25d6a41de 100644 --- a/crates/ui-egui/src/menus.rs +++ b/crates/ui-egui/src/menus.rs @@ -1111,7 +1111,7 @@ pub fn menu_items(app: &PhotocraftApp) -> Vec { } } if !prefs.menus.hidden.is_empty() { - items.retain(|i| !prefs.menus.hidden.contains(&i.id)); + items.retain(|i| !prefs.menus.is_hidden(&i.id)); } if prefs.interface.show_menu_colors { for it in &mut items { diff --git a/crates/ui-egui/src/prefs_ui.rs b/crates/ui-egui/src/prefs_ui.rs index db908ae23f..497a7dba62 100644 --- a/crates/ui-egui/src/prefs_ui.rs +++ b/crates/ui-egui/src/prefs_ui.rs @@ -1753,8 +1753,10 @@ fn shortcuts_body(app: &mut PhotocraftApp, ui: &mut egui::Ui, f: &mut Map