diff --git a/crates/gpu/src/render.rs b/crates/gpu/src/render.rs index 1ace48078..d0bd3aa45 100644 --- a/crates/gpu/src/render.rs +++ b/crates/gpu/src/render.rs @@ -690,14 +690,18 @@ pub fn render( }); // every visible mask's alpha, for `Overlay::AllMasks` (one tint over all masks at once) let all_overlay_alphas: Option> = if matches!(req.overlay, lightcraft_pipeline::Overlay::AllMasks { .. }) { - let list: Vec<_> = s.masks.iter().filter(|m| m.visible && !m.components.is_empty()).collect(); masks.as_ref().map(|all| { - list.iter().enumerate().map(|(mi, _)| { + let list: Vec<_> = s.masks.iter().filter(|m| m.visible && !m.components.is_empty()).collect(); + let mut alphas = Vec::with_capacity(list.len()); + for (mi, _) in list.iter().enumerate() { let b = cx.slice(all, mi * n, n); - cx.read_plane(&b, w, h) - }).collect() + alphas.push(cx.read_plane(&b, w, h)); + } + alphas }) - } else { None }; + } else { + None + }; let data: Vec<[u8; 4]> = cx.read(&out, n); let image = Rgba8 { width: w, height: h, data }; lap("finish + readback", &mut t, &mut cx); diff --git a/crates/ui-egui/locales/de.json b/crates/ui-egui/locales/de.json index 6520fb3e3..ca1013abe 100644 --- a/crates/ui-egui/locales/de.json +++ b/crates/ui-egui/locales/de.json @@ -1376,6 +1376,8 @@ "Show Luminance Map": "Luminanzkarte anzeigen", "Show Mask": "Maske anzeigen", "Show Mask Overlay": "Maskenüberlagerung anzeigen", + "Show All Mask Overlays": "Alle Maskenüberlagerungen anzeigen", + "Show all overlays": "Alle Überlagerungen anzeigen", "Show Mask Pins": "Maskenpins anzeigen", "Show Original": "Original anzeigen", "Show Photo Counts": "Fotoanzahl anzeigen", diff --git a/crates/ui-egui/locales/es.json b/crates/ui-egui/locales/es.json index fc53b6392..e379f2803 100644 --- a/crates/ui-egui/locales/es.json +++ b/crates/ui-egui/locales/es.json @@ -1323,6 +1323,8 @@ "Show Luminance Map": "Mostrar mapa de luminancia", "Show Mask": "Mostrar máscara", "Show Mask Overlay": "Mostrar superposición de máscara", + "Show All Mask Overlays": "Mostrar todas las superposiciones de máscara", + "Show all overlays": "Mostrar todas las superposiciones", "Show Mask Pins": "Mostrar chinchetas de máscara", "Show Original": "Mostrar original", "Show Photo Counts": "Mostrar recuento de fotos", diff --git a/crates/ui-egui/locales/fr.json b/crates/ui-egui/locales/fr.json index 53509a503..ce7a94733 100644 --- a/crates/ui-egui/locales/fr.json +++ b/crates/ui-egui/locales/fr.json @@ -1313,6 +1313,8 @@ "Show Luminance Map": "Afficher la carte de luminance", "Show Mask": "Afficher le masque", "Show Mask Overlay": "Afficher l'incrustation du masque", + "Show All Mask Overlays": "Afficher toutes les superpositions de masque", + "Show all overlays": "Afficher toutes les superpositions", "Show Mask Pins": "Afficher les épingles de masque", "Show Original": "Afficher l'original", "Show Photo Counts": "Afficher le nombre de photos", diff --git a/crates/ui-egui/locales/ja.json b/crates/ui-egui/locales/ja.json index 2babd30b6..b4243e701 100644 --- a/crates/ui-egui/locales/ja.json +++ b/crates/ui-egui/locales/ja.json @@ -1259,6 +1259,8 @@ "Show Luminance Map": "輝度マップを表示", "Show Mask": "マスクを表示", "Show Mask Overlay": "マスクの重ね表示", + "Show All Mask Overlays": "すべてのマスクオーバーレイを表示", + "Show all overlays": "すべてのオーバーレイを表示", "Show Mask Pins": "マスクのピンを表示", "Show Original": "元の写真を表示", "Show Photo Counts": "写真の枚数を表示", diff --git a/crates/ui-egui/locales/pt-br.json b/crates/ui-egui/locales/pt-br.json index dfe472818..63515b41f 100644 --- a/crates/ui-egui/locales/pt-br.json +++ b/crates/ui-egui/locales/pt-br.json @@ -1334,6 +1334,8 @@ "Show Luminance Map": "Mostrar mapa de luminância", "Show Mask": "Mostrar máscara", "Show Mask Overlay": "Mostrar sobreposição da máscara", + "Show All Mask Overlays": "Mostrar todas as sobreposições de máscara", + "Show all overlays": "Mostrar todas as sobreposições", "Show Mask Pins": "Mostrar pinos da máscara", "Show Original": "Mostrar original", "Show Photo Counts": "Mostrar contagem de fotos", diff --git a/crates/ui-egui/locales/ru.json b/crates/ui-egui/locales/ru.json index fafb65a14..fc0c7edea 100644 --- a/crates/ui-egui/locales/ru.json +++ b/crates/ui-egui/locales/ru.json @@ -1102,6 +1102,8 @@ "Show Luminance Map": "Показать карту яркости", "Show Mask": "Показать маску", "Show Mask Overlay": "Показать наложение маски", + "Show All Mask Overlays": "Показать все наложения масок", + "Show all overlays": "Показать все наложения", "Show Mask Pins": "Показать булавки масок", "Show Original": "Показать оригинал", "Show Photo Counts": "Показывать количество фото", diff --git a/crates/ui-egui/locales/uk.json b/crates/ui-egui/locales/uk.json index 7ebad5b10..56954b6b8 100644 --- a/crates/ui-egui/locales/uk.json +++ b/crates/ui-egui/locales/uk.json @@ -1326,6 +1326,8 @@ "Show Hidden Local Locations": "Показати приховані локальні розташування", "Show Luminance Map": "Показати карту яскравості", "Show Mask Overlay": "Показати накладання маски", + "Show All Mask Overlays": "Показати всі накладення масок", + "Show all overlays": "Показати всі накладення", "Show Mask Pins": "Показати маркери масок", "Show Original": "Показати оригінал", "Show Photo Counts": "Показати кількість фото", diff --git a/crates/ui-egui/locales/zh-hans.json b/crates/ui-egui/locales/zh-hans.json index 8a0e58b8e..795dc70ae 100644 --- a/crates/ui-egui/locales/zh-hans.json +++ b/crates/ui-egui/locales/zh-hans.json @@ -1321,6 +1321,8 @@ "Show Luminance Map": "显示明亮度图", "Show Mask": "显示蒙版", "Show Mask Overlay": "显示蒙版叠加", + "Show All Mask Overlays": "显示所有蒙版叠加", + "Show all overlays": "显示所有叠加", "Show Mask Pins": "显示蒙版图钉", "Show Original": "显示原图", "Show Photo Counts": "显示照片数量", diff --git a/crates/ui-egui/locales/zh-hant.json b/crates/ui-egui/locales/zh-hant.json index f1cbec3a0..c4a8ab1fd 100644 --- a/crates/ui-egui/locales/zh-hant.json +++ b/crates/ui-egui/locales/zh-hant.json @@ -1321,6 +1321,8 @@ "Show Luminance Map": "顯示明度圖", "Show Mask": "顯示遮色片", "Show Mask Overlay": "顯示遮色片疊加", + "Show All Mask Overlays": "顯示所有蒙版疊加", + "Show all overlays": "顯示所有疊加", "Show Mask Pins": "顯示遮色片控制點", "Show Original": "顯示原始照片", "Show Photo Counts": "顯示照片數量", diff --git a/crates/ui-egui/src/menus.rs b/crates/ui-egui/src/menus.rs index 5ae64e1a5..5f31025cb 100644 --- a/crates/ui-egui/src/menus.rs +++ b/crates/ui-egui/src/menus.rs @@ -91,8 +91,8 @@ pub const UI_COMMANDS: &[UiCommand] = &[ ("view.softProof", "Soft Proofing", Some("S"), "View"), ("view.histogram", "Histogram", Some("Cmd+Shift+H"), "View"), ("view.maskOverlay", "Show Mask Overlay", Some("O"), "View"), - // Ctrl+O / Cmd+O: every mask's region at once, not just the selected one - ("view.maskOverlayAll", "Show All Mask Overlays", Some("Cmd+O"), "View"), + // Ctrl+Shift+O / Cmd+Shift+O: every mask's region at once, not just the selected one + ("view.maskOverlayAll", "Show All Mask Overlays", Some("Cmd+Shift+O"), "View"), // Shift+O in the Masking panel (elsewhere it cycles the crop overlay) ("view.maskOverlayMode", "Cycle Mask Overlay Mode", None, "View"), ("view.maskOverlayColor", "Cycle Mask Overlay Color", None, "View"), diff --git a/crates/ui-egui/src/panels/detail.rs b/crates/ui-egui/src/panels/detail.rs index 24976d94e..f766fe663 100644 --- a/crates/ui-egui/src/panels/detail.rs +++ b/crates/ui-egui/src/panels/detail.rs @@ -1065,7 +1065,7 @@ pub(crate) fn view_overlay(app: &LightcraftApp, d: &DevelopSettings) -> lightcra if app.ui.fullscreen { return Overlay::None; } - // Show every visible mask's region at once (Ctrl+O / Cmd+O), ahead of the selected-mask overlay + // Show every visible mask's region at once (Ctrl+Shift+O / Cmd+Shift+O), ahead of the selected-mask overlay // so the shortcut is not shadowed by the always-on single-mask overlay. if app.ui.right == RightPanel::Masking && app.ui.mask_overlay_all diff --git a/crates/ui-egui/src/panels/masking.rs b/crates/ui-egui/src/panels/masking.rs index 47b96ee6d..4698a1655 100644 --- a/crates/ui-egui/src/panels/masking.rs +++ b/crates/ui-egui/src/panels/masking.rs @@ -198,7 +198,13 @@ pub fn show(app: &mut LightcraftApp, ui: &mut egui::Ui, id: PhotoId) { app.ui.mask_overlay = !on; } let all = app.ui.mask_overlay_all; - if icon_button(ui, "maskOverlayAll", Icon::Stack, vec2(24.0, 24.0), all, true, "Show all overlays (Ctrl+O)").clicked() { + let all_mac = ui.ctx().os() == egui::os::OperatingSystem::Mac; + let all_base = crate::i18n::tr("Show all overlays"); + let all_tip = match crate::shortcuts::shortcut_of(&app.ui.settings.keymap, "view.maskOverlayAll") { + Some(sc) => format!("{all_base} ({})", crate::menubar::shortcut_text(sc, all_mac)), + None => all_base.to_string(), + }; + if icon_button(ui, "maskOverlayAll", Icon::Stack, vec2(24.0, 24.0), all, true, &all_tip).clicked() { app.ui.mask_overlay_all = !all; } }); diff --git a/crates/ui-egui/src/tests_masking.rs b/crates/ui-egui/src/tests_masking.rs index db009e816..3ad52b8e5 100644 --- a/crates/ui-egui/src/tests_masking.rs +++ b/crates/ui-egui/src/tests_masking.rs @@ -168,13 +168,13 @@ fn mask_adjustments_hide_overlay_without_disabling_the_mask() { assert_eq!(develop(&h).masks[0], mask, "toggling the overlay leaves the mask and its effect unchanged"); assert!(matches!(crate::panels::detail::view_overlay(&h.app, &develop(&h)), Overlay::Mask { .. })); - // Ctrl+O shows every visible mask's region at once (the new command), ahead of the selected + // Ctrl+Shift+O / Cmd+Shift+O shows every visible mask's region at once (the new command), ahead of the selected // mask overlay so it is not shadowed by the always-on single-mask overlay. exec(&mut h, "view.maskOverlayAll", json!({})); - assert!(h.app.ui.mask_overlay_all, "Ctrl+O turns on the all-masks overlay"); + assert!(h.app.ui.mask_overlay_all, "the all-masks overlay command turns it on"); assert!(matches!(crate::panels::detail::view_overlay(&h.app, &develop(&h)), Overlay::AllMasks { .. })); exec(&mut h, "view.maskOverlayAll", json!({})); - assert!(!h.app.ui.mask_overlay_all, "Ctrl+O toggles the all-masks overlay off"); + assert!(!h.app.ui.mask_overlay_all, "the all-masks overlay command toggles it off"); assert!(!matches!(crate::panels::detail::view_overlay(&h.app, &develop(&h)), Overlay::AllMasks { .. })); // Failed edits and global adjustments must not hide the mask overlay. diff --git a/docs/parity-checklist.md b/docs/parity-checklist.md index 099411089..ec6991c4b 100644 --- a/docs/parity-checklist.md +++ b/docs/parity-checklist.md @@ -302,6 +302,7 @@ differences and missing bindings are in [ui-parity.md](ui-parity.md#shortcuts). | LR-MASK-FEATHER-EDGE | Refine mask edges | P2 | ✅ | `cmd:mask.refine`, `crates/pipeline/src/masks.rs` (`evaluate_one`) | Refine Edges slider per mask: guided filter on the photo's luminance snaps soft mask edges to the photo's edges (rendered on the CPU) | | LR-MASK-SLIDERS | Local adjustment sliders | P0 | ✅ | `cmd:mask.adjust`, `crates/pipeline/src/finish.rs` | every slider renders (CPU + GPU), incl. Noise, Moiré, Defringe (negative Defringe has no effect); no local curve or effect presets | | LR-MASK-OVERLAY | Mask overlay | P0 | ✅ | `cmd:view.maskOverlay`, `cmd:view.maskOverlayMode`, `cmd:view.maskOverlayColor`, `crates/pipeline/src/visualize.rs` | rendered alpha of the selected mask (CPU + GPU): colour, colour on B&W, image on black/white, white on black; ⇧O cycles while masking; successful local adjustments (including Amount) hide the overlay until manually shown again with O / the eye; shape/edge edits retain it; no auto-show on hover | +| LR-MASK-OVERLAYALL | Show all mask overlays | P1 | ✅ | `cmd:view.maskOverlayAll`, `crates/ui-egui/src/panels/masking.rs`, `crates/pipeline/src/visualize.rs` | one diagnostic tint over every visible mask at once (CPU + GPU): the masks still stack their adjustments as before — this only paints each mask's region together, so you can see all masked areas at a glance (⌘⇧O / Ctrl+Shift+O) | | LR-MASK-PINS | Pins | P1 | ✅ | `cmd:view.maskPins`, `crates/ui-egui/src/panels/detail.rs` | a pin per radial/linear/brush component: click selects its mask, drag moves it; no pins for range/AI components, no Auto mode | | LR-MASK-UPDATE | Recompute AI masks | P2 | ⬜ | | | | LR-MASK-SYNC | Copy masks to other photos | P1 | ✅ | `cmd:develop.copy` (`groups`) | |