From eeb2ca2f6ad4de231f2d9d03191582f8a19a68a5 Mon Sep 17 00:00:00 2001 From: Matthew James Sivak Date: Mon, 12 Oct 2026 18:22:02 +0200 Subject: [PATCH] LR-EDIT-SECTION-SOLO: register section.calibration, refuse unknown sections MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calibration's header runs section.calibration, now a registered command (no menu item); section. refuses an id the Edit panel hasn't got instead of closing the real sections for a phantom one. "Solo Mode" sits with the other So… keys in the catalogs. Co-Authored-By: Claude Opus 5.5 --- crates/ui-egui/locales/de.json | 2 +- crates/ui-egui/locales/es.json | 2 +- crates/ui-egui/locales/fr.json | 2 +- crates/ui-egui/locales/ja.json | 2 +- crates/ui-egui/locales/pt-br.json | 2 +- crates/ui-egui/locales/ru.json | 2 +- crates/ui-egui/locales/uk.json | 2 +- crates/ui-egui/locales/zh-hans.json | 2 +- crates/ui-egui/locales/zh-hant.json | 2 +- crates/ui-egui/src/menus.rs | 9 +++++++-- crates/ui-egui/src/tests_solo_sections.rs | 8 +++++--- docs/parity-checklist.md | 2 +- 12 files changed, 22 insertions(+), 15 deletions(-) diff --git a/crates/ui-egui/locales/de.json b/crates/ui-egui/locales/de.json index 516d85101..16fa3050d 100644 --- a/crates/ui-egui/locales/de.json +++ b/crates/ui-egui/locales/de.json @@ -529,7 +529,6 @@ "Filmstrip (/)": "Filmstreifen (/)", "Filter": "Filter", "Filter Bar": "Filterleiste", - "Solo Mode": "Solo-Modus", "Filter Presets": "Filtervorgaben", "Filter bar": "Filterleiste", "Filter fields": "Filterfelder", @@ -1433,6 +1432,7 @@ "Soft Pastel": "Sanftes Pastell", "Soft Proofing": "Softproof", "Soft Skin": "Weiche Haut", + "Solo Mode": "Solo-Modus", "Sony ARWs from before about 2017 (RX100, RX100 II–V, RX10, NEX, SLT, ILCE-6000, A7 / A7 II / A7R II and their": "Sony-ARWs von vor etwa 2017, RX100, RX100 II–V, RX10, NEX, SLT, ILCE-6000, A7, A7 II, A7R II und verwandte", "Sony ILCE-7M4 downsized lossless ARWs now decode subsampled YCbCr tiles into linear RGB,": "Verkleinerte verlustfreie ARW-Dateien der Sony ILCE-7M4 werden jetzt aus unterabgetasteten YCbCr-Kacheln in lineares RGB decodiert.", "Sort": "Sortieren", diff --git a/crates/ui-egui/locales/es.json b/crates/ui-egui/locales/es.json index 444791c77..cd4026b58 100644 --- a/crates/ui-egui/locales/es.json +++ b/crates/ui-egui/locales/es.json @@ -511,7 +511,6 @@ "Filmstrip (/)": "Tira de película (/)", "Filter": "Filtro", "Filter Bar": "Barra de filtros", - "Solo Mode": "Modo solo", "Filter Presets": "Ajustes preestablecidos de filtro", "Filter bar": "Barra de filtros", "Filter fields": "Campos de filtro", @@ -1400,6 +1399,7 @@ "Soft Pastel": "Pastel suave", "Soft Proofing": "Prueba en pantalla", "Soft Skin": "Piel suave", + "Solo Mode": "Modo solo", "Sort": "Ordenar", "Sort Albums by Name": "Ordenar álbumes por nombre", "Sort by": "Ordenar por", diff --git a/crates/ui-egui/locales/fr.json b/crates/ui-egui/locales/fr.json index 1644721b1..5ca3561de 100644 --- a/crates/ui-egui/locales/fr.json +++ b/crates/ui-egui/locales/fr.json @@ -494,7 +494,6 @@ "Filmstrip (/)": "Pellicule (/)", "Filter": "Filtre", "Filter Bar": "Barre de filtres", - "Solo Mode": "Mode solo", "Filter Presets": "Préréglages de filtre", "Filter bar": "Barre de filtres", "Filter fields": "Champs de filtre", @@ -1366,6 +1365,7 @@ "Soft Pastel": "Pastel doux", "Soft Proofing": "Épreuvage à l'écran", "Soft Skin": "Peau douce", + "Solo Mode": "Mode solo", "Sort": "Trier", "Sort by": "Trier par", "Source": "Source", diff --git a/crates/ui-egui/locales/ja.json b/crates/ui-egui/locales/ja.json index 42e9f15e7..10e5e5558 100644 --- a/crates/ui-egui/locales/ja.json +++ b/crates/ui-egui/locales/ja.json @@ -709,7 +709,6 @@ "Filmstrip": "フィルムストリップ", "Filter": "フィルター", "Filter Bar": "フィルターバー", - "Solo Mode": "ソロモード", "Filter Presets": "フィルタープリセット", "Filter bar": "フィルターバー", "Filter fields": "項目を絞り込む", @@ -1311,6 +1310,7 @@ "Soft Pastel": "ソフトパステル", "Soft Proofing": "ソフト校正", "Soft Skin": "ソフトスキン", + "Solo Mode": "ソロモード", "Sort": "並べ替え", "Sort by": "並べ替え", "Source": "読み込み元", diff --git a/crates/ui-egui/locales/pt-br.json b/crates/ui-egui/locales/pt-br.json index 32b84bf99..d2972d761 100644 --- a/crates/ui-egui/locales/pt-br.json +++ b/crates/ui-egui/locales/pt-br.json @@ -502,7 +502,6 @@ "Filmstrip (/)": "Película (/)", "Filter": "Filtro", "Filter Bar": "Barra de filtros", - "Solo Mode": "Modo solo", "Filter Presets": "Predefinições de filtro", "Filter bar": "Barra de filtros", "Filter fields": "Campos de filtro", @@ -1389,6 +1388,7 @@ "Soft Pastel": "Pastel suave", "Soft Proofing": "Prova suave", "Soft Skin": "Pele suave", + "Solo Mode": "Modo solo", "Sort": "Classificar", "Sort by": "Classificar por", "Source": "Origem", diff --git a/crates/ui-egui/locales/ru.json b/crates/ui-egui/locales/ru.json index b8250c70d..7447a1307 100644 --- a/crates/ui-egui/locales/ru.json +++ b/crates/ui-egui/locales/ru.json @@ -412,7 +412,6 @@ "Filmstrip (/)": "Лента (/)", "Filter": "Фильтр", "Filter Bar": "Панель фильтров", - "Solo Mode": "Режим соло", "Filter Presets": "Пресеты фильтров", "Filter bar": "Панель фильтров", "Filter fields": "Поля фильтра", @@ -1153,6 +1152,7 @@ "Soft Pastel": "Мягкий пастельный", "Soft Proofing": "Экранная цветопроба", "Soft Skin": "Мягкая кожа", + "Solo Mode": "Режим соло", "Sort": "Сортировка", "Sort by": "Сортировать по", "Source": "Источник", diff --git a/crates/ui-egui/locales/uk.json b/crates/ui-egui/locales/uk.json index 960351baf..80e172946 100644 --- a/crates/ui-egui/locales/uk.json +++ b/crates/ui-egui/locales/uk.json @@ -915,7 +915,6 @@ "Fill Edges": "Заповнити краї", "Filmstrip": "Стрічка", "Filter Bar": "Панель фільтрів", - "Solo Mode": "Режим соло", "Filter Presets": "Набори налаштувань фільтрів", "Filter bar": "Панель фільтрів", "Filter fields": "Поля фільтрів", @@ -1375,6 +1374,7 @@ "Soft Pastel": "М’яка пастель", "Soft Proofing": "Екранна кольоропроба", "Soft Skin": "М’яка шкіра", + "Solo Mode": "Режим соло", "Sort by": "Сортувати за", "Spherical": "Сферична", "Split Stack": "Розділити стос", diff --git a/crates/ui-egui/locales/zh-hans.json b/crates/ui-egui/locales/zh-hans.json index b80b4f45b..78e27b459 100644 --- a/crates/ui-egui/locales/zh-hans.json +++ b/crates/ui-egui/locales/zh-hans.json @@ -652,7 +652,6 @@ "Filmstrip (/)": "胶片窗格 (/)", "Filter": "过滤器", "Filter Bar": "过滤器栏", - "Solo Mode": "单独模式", "Filter Presets": "过滤器预设", "Filter bar": "过滤器栏", "Filter fields": "过滤字段", @@ -1374,6 +1373,7 @@ "Soft Pastel": "柔和粉彩", "Soft Proofing": "软打样", "Soft Skin": "柔和肤质", + "Solo Mode": "单独模式", "Sort": "排序", "Sort by": "排序方式", "Source": "来源", diff --git a/crates/ui-egui/locales/zh-hant.json b/crates/ui-egui/locales/zh-hant.json index 5de08731f..50ef6020a 100644 --- a/crates/ui-egui/locales/zh-hant.json +++ b/crates/ui-egui/locales/zh-hant.json @@ -652,7 +652,6 @@ "Filmstrip (/)": "底片列(/)", "Filter": "篩選", "Filter Bar": "篩選列", - "Solo Mode": "單獨模式", "Filter Presets": "篩選預設集", "Filter bar": "篩選列", "Filter fields": "篩選欄位", @@ -1374,6 +1373,7 @@ "Soft Pastel": "柔和粉彩", "Soft Proofing": "軟式校樣", "Soft Skin": "柔和膚質", + "Solo Mode": "單獨模式", "Sort": "排序", "Sort by": "排序依據", "Source": "來源", diff --git a/crates/ui-egui/src/menus.rs b/crates/ui-egui/src/menus.rs index 1a41e4675..46c4bac7a 100644 --- a/crates/ui-egui/src/menus.rs +++ b/crates/ui-egui/src/menus.rs @@ -130,6 +130,7 @@ pub const UI_COMMANDS: &[UiCommand] = &[ ("section.effects", "Effects", Some("Cmd+3"), "Window>Edit Sections"), ("section.detail", "Detail", Some("Cmd+4"), "Window>Edit Sections"), ("section.optics", "Optics", Some("Cmd+5"), "Window>Edit Sections"), + ("section.calibration", "Calibration", None, ""), // {on?}; no params toggles. Opening one Edit section closes the others. ("view.soloSections", "Solo Mode", None, "Window>Edit Sections"), ("tool.brush", "Brush", Some("B"), "Window>Tools"), @@ -1040,7 +1041,11 @@ pub fn run_ui_command(app: &mut LightcraftApp, id: &str, p: &Value) -> Option bool_param(s, p, "solo").map(|solo| { + s if s.starts_with("section.") => bool_param(s, p, "solo").and_then(|solo| { + // only the Edit sections listed above: an unknown one would close the real ones + if !UI_COMMANDS.iter().any(|c| c.0 == s) { + return Err(format!("{s}: no such Edit section")); + } let sec = &s["section.".len()..]; if app.ui.right != RightPanel::Edit { app.ui.right = RightPanel::Edit; @@ -1050,7 +1055,7 @@ pub fn run_ui_command(app: &mut LightcraftApp, id: &str, p: &Value) -> Option { let tool = &s["tool.".len()..]; diff --git a/crates/ui-egui/src/tests_solo_sections.rs b/crates/ui-egui/src/tests_solo_sections.rs index cea569382..70d1a6aa6 100644 --- a/crates/ui-egui/src/tests_solo_sections.rs +++ b/crates/ui-egui/src/tests_solo_sections.rs @@ -80,15 +80,17 @@ fn option_click_opens_just_that_section() { click(&mut h, json!({"id": "section:detail", "alt": true})); assert_eq!(h.app.ui.open_sections, ["detail"], "⌥-click closes the others"); assert!(!h.app.ui.single_panel, "⌥-click doesn't turn Solo Mode on"); - // agents do the same with the section's command (Calibration has no menu item but runs too) + // agents do the same with the section's command (Calibration has one, though not in the menu) exec(&mut h, "section.calibration", json!({"solo": true})); assert_eq!(h.app.ui.open_sections, ["calibration"]); } #[test] -fn flags_that_are_not_true_or_false_are_refused() { +fn bad_flags_and_unknown_sections_are_refused() { let mut h = edit_open(); - for (command, params) in [("view.soloSections", json!({"on": "yes"})), ("section.color", json!({"solo": 1}))] { + for (command, params) in + [("view.soloSections", json!({"on": "yes"})), ("section.color", json!({"solo": 1})), ("section.typo", json!({"solo": true}))] + { let r = h.request("engine.execute", json!({"command": command, "params": params}), T); assert_eq!(r["ok"], false, "{command} {params}: {r}"); } diff --git a/docs/parity-checklist.md b/docs/parity-checklist.md index 1a9dc79b5..dea4434c9 100644 --- a/docs/parity-checklist.md +++ b/docs/parity-checklist.md @@ -222,7 +222,7 @@ differences and missing bindings are in [ui-parity.md](ui-parity.md#shortcuts). | LR-EDIT-LENSBLUR | Lens blur | P2 | ⬜ | | settings field reserved, not rendered | | LR-EDIT-CALIB | Calibration [Classic] | P1 | ✅ | `ctl:calibration.*` | shadows tint, red/green/blue primary hue and saturation; read/written in XMP | | LR-EDIT-SECTION-TOGGLE | Section on/off | P1 | ✅ | `cmd:develop.sectionEnabled`, `crates/develop/src/lib.rs` (`effective`) | the eye on a section header hides its adjustments: Light (with the curve), Color (white balance, presence, mixers, grading, point colour), Effects, Detail, Optics, Geometry, Calibration; masks stay on (issue #316 fixed Light, Color and Detail, which had no effect) | -| LR-EDIT-SECTION-SOLO | Solo Mode for Edit sections | P2 | ✅ | `cmd:view.soloSections`, `crates/ui-egui/src/state.rs` (`toggle_section`, `set_single_panel`, `solo_section`), `crates/ui-egui/src/panels/edit.rs` (`section`), `crates/ui-egui/src/tests_solo_sections.rs` | Lightroom Classic's panel Solo Mode: while it is on, opening one Edit section (a header click or ⌘1–⌘5) closes the others. Window ▸ Edit Sections ▸ Solo Mode (checked while on) or a right-click on any section header (`sectionMenu:solo`) turns it on and off; turning it on keeps only the section opened last. ⌥-click on a header opens just that section once, without turning the mode on (agents: `section.` `{solo: true}`; header clicks run `section.` too). `view.soloSections` `{on?}` (no params toggles) answers `{soloSections}`. Kept with the UI state (`singlePanel`) | +| LR-EDIT-SECTION-SOLO | Solo Mode for Edit sections | P2 | ✅ | `cmd:view.soloSections`, `cmd:section.calibration`, `crates/ui-egui/src/state.rs` (`toggle_section`, `set_single_panel`, `solo_section`), `crates/ui-egui/src/panels/edit.rs` (`section`), `crates/ui-egui/src/tests_solo_sections.rs` | Lightroom Classic's panel Solo Mode: while it is on, opening one Edit section (a header click or ⌘1–⌘5) closes the others. Window ▸ Edit Sections ▸ Solo Mode (checked while on) or a right-click on any section header (`sectionMenu:solo`) turns it on and off; turning it on keeps only the section opened last. ⌥-click on a header opens just that section once, without turning the mode on (agents: `section.` `{solo: true}`, refused for a section the Edit panel has not got; header clicks run `section.` too, Calibration included). `view.soloSections` `{on?}` (no params toggles) answers `{soloSections}`. Kept with the UI state (`singlePanel`) | | LR-EDIT-RESET | Reset all / section / slider | P0 | ✅ | `cmd:develop.reset`, `cmd:develop.resetSection`, `cmd:develop.resetControl`, `crates/ui-egui/src/widgets.rs` (double-click) | no "reset to open" | | LR-EDIT-SHOWORIG | Show original | P0 | ✅ | `cmd:view.showOriginal` | |