diff --git a/crates/ui-egui/src/shortcuts.rs b/crates/ui-egui/src/shortcuts.rs index b9d1874a1..c82be1bf2 100644 --- a/crates/ui-egui/src/shortcuts.rs +++ b/crates/ui-egui/src/shortcuts.rs @@ -297,12 +297,15 @@ fn matches(i: &egui::InputState, m: Modifiers, k: Key) -> bool { }) } -/// Default brackets rate in grids. Remapped brush keys retain their brush action, and a -/// saved assignment of either bracket to another command takes precedence over this default. -fn grid_bracket_command(keymap: &Keymap, grid: bool, id: &'static str, shortcut: (Modifiers, Key)) -> Option<&'static str> { +/// Default brackets rate in grids, and the default backslash shows / hides the Filter Bar there +/// (Lightroom Classic's Library keys; Detail keeps brush size and Show Original). Remapped brush and +/// Show Original keys retain their action, and a saved assignment of the key to another command +/// takes precedence over this default. +fn grid_key_command(keymap: &Keymap, grid: bool, id: &'static str, shortcut: (Modifiers, Key)) -> Option<&'static str> { let command = match (grid, id, shortcut) { (true, "brush.smaller", (m, Key::OpenBracket)) if m == Modifiers::NONE => "photo.decreaseRating", (true, "brush.larger", (m, Key::CloseBracket)) if m == Modifiers::NONE => "photo.increaseRating", + (true, "view.showOriginal", (m, Key::Backslash)) if m == Modifiers::NONE => "view.filterBar", _ => return Some(id), }; if keymap.iter().any(|(other, sc)| other != id && find_bindable(other).is_some() && parse(sc) == Some(shortcut)) { None } else { Some(command) } @@ -389,7 +392,7 @@ pub fn handle(app: &mut LightcraftApp, ctx: &egui::Context) { && !native(sc) && !(k == Key::Escape && popup_open) && matches(i, m, k) - && let Some(id) = grid_bracket_command(keymap, grid, b.id, (m, k)) + && let Some(id) = grid_key_command(keymap, grid, b.id, (m, k)) { fire.push(id.to_string()); } @@ -1269,3 +1272,7 @@ mod relative_rating_tests; #[cfg(test)] #[path = "shortcuts/tests_flag_cycle.rs"] mod flag_cycle_tests; + +#[cfg(test)] +#[path = "shortcuts/tests_filter_bar_key.rs"] +mod filter_bar_key_tests; diff --git a/crates/ui-egui/src/shortcuts/tests_filter_bar_key.rs b/crates/ui-egui/src/shortcuts/tests_filter_bar_key.rs new file mode 100644 index 000000000..cd05655ab --- /dev/null +++ b/crates/ui-egui/src/shortcuts/tests_filter_bar_key.rs @@ -0,0 +1,106 @@ +//! Backslash (\) shows / hides the Filter Bar in the library grids, as in Lightroom Classic's Library +//! module; in Detail it keeps showing the original (Develop's Before / After key). +use egui::{Key, Modifiers}; +use lightcraft_catalog::{Flag, Op, Photo, PhotoId, Source}; +use serde_json::json; + +use crate::LightcraftApp; +use crate::state::{BeforeAfter, ViewMode}; + +fn app() -> lightcraft_engine::Result { + let mut s = lightcraft_engine::Session::new(); + for id in 1..=2 { + let photo = Photo::new( + PhotoId(id), + Source::File { path: format!("/lightcraft-filter-bar-key/{id}.jpg") }, + &format!("{id}.jpg"), + "JPEG", + 40, + 30, + "2026-10-15", + ); + s.catalog.apply(Op::AddPhoto { photo: Box::new(photo) })?; + } + s.execute("library.sort", &json!({"key": "fileName", "ascending": true}))?; + s.execute("library.select", &json!({"ids": [1]}))?; + Ok(LightcraftApp::new(s, crate::Services { png: None, ..Default::default() })) +} + +fn frame(app: &mut LightcraftApp, ctx: &egui::Context, key: Option, text: Option<&mut String>) { + let events = key + .map(|key| egui::Event::Key { key, physical_key: Some(key), pressed: true, repeat: false, modifiers: Modifiers::NONE }) + .into_iter() + .collect(); + let mut text = text; + let mut out = ctx.run_ui( + egui::RawInput { events, screen_rect: Some(egui::Rect::from_min_size(egui::Pos2::ZERO, egui::vec2(800.0, 600.0))), ..Default::default() }, + |ui| { + if let Some(text) = text.as_deref_mut() { + ui.add(egui::TextEdit::singleline(text).id(egui::Id::new("filter-bar-key-search"))).request_focus(); + } + super::handle(app, ui.ctx()); + }, + ); + out.textures_delta.clear(); +} + +#[test] +fn backslash_toggles_the_filter_bar_in_the_grids() { + for view in [ViewMode::PhotoGrid, ViewMode::SquareGrid] { + let mut app = app().unwrap(); + app.ui.view = view; + let ctx = egui::Context::default(); + assert!(!app.ui.filter_bar); + frame(&mut app, &ctx, Some(Key::Backslash), None); + assert!(app.ui.filter_bar, "{view:?}: \\ shows the Filter Bar"); + // the grid's \ is not Show Original: nothing is left switched on for Detail + assert_eq!(app.ui.before_after, BeforeAfter::Off, "{view:?}"); + frame(&mut app, &ctx, Some(Key::Backslash), None); + assert!(!app.ui.filter_bar, "{view:?}: \\ hides it again"); + assert_eq!(app.ui.before_after, BeforeAfter::Off, "{view:?}"); + assert_eq!(app.ui.view, view); + } +} + +#[test] +fn backslash_in_detail_still_shows_the_original() { + let mut app = app().unwrap(); + app.ui.view = ViewMode::Detail; + let ctx = egui::Context::default(); + frame(&mut app, &ctx, Some(Key::Backslash), None); + assert_eq!(app.ui.before_after, BeforeAfter::Original); + assert!(!app.ui.filter_bar); + assert_eq!(app.ui.view, ViewMode::Detail); +} + +#[test] +fn saved_keymap_wins_over_the_grid_backslash() { + let mut app = app().unwrap(); + app.ui.view = ViewMode::PhotoGrid; + let ctx = egui::Context::default(); + // Show Original moved to F2: F2 keeps that meaning in the grid, \ does nothing + super::assign(&mut app.ui.settings.keymap, "view.showOriginal", Some("F2")).unwrap(); + frame(&mut app, &ctx, Some(Key::F2), None); + assert!(!app.ui.filter_bar, "a remapped Show Original key is not the Filter Bar key"); + assert_eq!(app.ui.before_after, BeforeAfter::Original); + frame(&mut app, &ctx, Some(Key::Backslash), None); + assert!(!app.ui.filter_bar); + // \ given to another command runs that command + super::reset(&mut app.ui.settings.keymap, "view.showOriginal").unwrap(); + super::assign(&mut app.ui.settings.keymap, "photo.pick", Some("\\")).unwrap(); + frame(&mut app, &ctx, Some(Key::Backslash), None); + assert_eq!(app.session.catalog.photo(PhotoId(1)).unwrap().flag, Flag::Pick); + assert!(!app.ui.filter_bar); +} + +#[test] +fn backslash_yields_to_a_focused_text_field() { + let mut app = app().unwrap(); + app.ui.view = ViewMode::PhotoGrid; + let ctx = egui::Context::default(); + let mut text = String::new(); + frame(&mut app, &ctx, None, Some(&mut text)); + frame(&mut app, &ctx, Some(Key::Backslash), Some(&mut text)); + assert!(ctx.egui_wants_keyboard_input()); + assert!(!app.ui.filter_bar); +} diff --git a/docs/gaps.md b/docs/gaps.md index 1b4a385fa..7063e4f87 100644 --- a/docs/gaps.md +++ b/docs/gaps.md @@ -1,6 +1,6 @@ # Gaps: where LightCraft falls short of Lightroom -> **Last reviewed:** 2026-10-11 · **Last updated:** 2026-10-15 · **Change:** minor (gap 15: Print Page Options — page numbers, page info, crop marks) +> **Last reviewed:** 2026-10-11 · **Last updated:** 2026-10-15 · **Change:** minor (gap 15: Print Page Options — page numbers, page info, crop marks; gap 28: `\` shows / hides the Filter Bar in the grids) Every known shortfall, one entry each, ranked by user impact (how many Lightroom users hit it, and how hard it blocks them), then by effort. **Agents pick work from the top** (the first entry nobody is @@ -43,7 +43,7 @@ Hours are Opus 5.5 agent wall-clock hours (see [target-app-parity.md](target-app | 26 | **Performance at scale**: 85k-photo library opens in 1.7–4.7 s; 100k grid test pending; colour NR at half resolution; at 100k photos stack and album lookups are indexed (an "In a Stack" or "Album" smart album counts in ~14 ms, was 0.6–2.7 s) | ROADMAP log, gpu-pipeline.md | large-catalog users | 15–30 | [target-app-parity](target-app-parity.md#by-dimension) | | 27 | **Windows / Linux runtime coverage**: Windows installer UI unverified on Windows (#79); GPU path proven on Apple and on one AMD GPU on Linux (Radeon 8060S, Vulkan); NVIDIA, Intel and DX12 unverified; the Linux riscv64 tarball (new in 0.6.0, #844) is cross-compiled and never run beyond a QEMU smoke test | ROADMAP, issues, `release.yml` | non-Mac users find bugs first | 13–27 | [hardware-parity](hardware-parity.md) | | 29 | **HDR merge leftovers** (LR-MERGE-HDR): AI Denoise doesn't run on merged (linear) DNGs; JPEG brackets are treated as linear (no camera response curve); every frame is held as 32-bit float, ~0.86 GB per 67 MP frame (half-float frames would halve it) | tested on Sony A7R VI brackets 2026-10-14 ([merge.md](merge.md)); Lightroom's Denoise supports HDR DNGs | HDR shooters who denoise their merges, merge JPEGs, or merge 7+ frames of high-resolution raws on 16 GB machines | 10–20 (+ denoise linear-RGB contract, gap 11) | [merge](merge.md) | -| 28 | **Small Classic shortcuts and keys**: rating `[` `]`, flag cycling, filter-bar keys, F1 help, panel keys (Tab, F5, F8; F6 and F7 toggle the filmstrip and the left panel) | [ui-parity](ui-parity.md#shortcuts) | Classic muscle memory | 4–8 | [ui-parity](ui-parity.md) | +| 28 | **Small Classic shortcuts and keys**: ⌘L (Enable Filters), panel keys (Tab, F5, F8; F6 and F7 toggle the filmstrip and the left panel) | [ui-parity](ui-parity.md#shortcuts) | Classic muscle memory | 4–8 | [ui-parity](ui-parity.md) | Beta-blocking gaps (B) total **~230–430 h**; with the stability and platform work they need around them, **~340–600 h** to beta (incl. 40–80 h for the ~92 open core-path user issues) (see [target-app-parity.md](target-app-parity.md#stage)). @@ -79,6 +79,7 @@ Beta-blocking gaps (B) total **~230–430 h**; with the stability and platform w |---|---|---| | 2026-10-18 | patch | Gap 1: six X-Trans CMOS 4 Fujifilm bodies (X-T30 …) take the X-T3's spectral matrices instead of the neutral matrix | | 2026-10-15 | minor | Gap 15 shrinks: the Page panel's Page Options (Page Numbers, Page Info, Crop Marks) print on Single Image and Contact Sheet pages; identity plate, watermark, photo info, Cut Guides, direct printing and JPEG output remain | +| 2026-10-15 | minor | Gap 28: `\` shows / hides the Filter Bar in the grids; the entry drops `[` `]` (#509), flag cycling (#1490) and F1 (Help), already on main; ⌘L is the filter-bar key left; hours unchanged | | 2026-10-14 | minor | Gap 26: at 100k photos stack and album lookups are indexed, so an "In a Stack" or "Album" smart album counts in ~14 ms (was 0.6–2.7 s); open time unchanged | | 2026-10-14 | minor | Gap 10: Camera-coverage sweep (#1327): 30 models verified on 40 CC0 files (coverage.py 515 → 545 verified); sensor verification does not establish colour parity (#1277) | | 2026-10-14 | minor | Gap 21: de, es, fr, ja and uk catalogs filled (97–99%); 55–90 h → 40–70 h | diff --git a/docs/library-shortcuts.md b/docs/library-shortcuts.md index 73322b2f0..515506cc9 100644 --- a/docs/library-shortcuts.md +++ b/docs/library-shortcuts.md @@ -16,6 +16,7 @@ Select photos in Photo Grid or Square Grid, then use: | `` ` `` (backtick) | Cycle the flag: unflagged → pick → reject → unflagged | | `Cmd`/`Ctrl` + `↑` / `↓` | Raise / lower flag status (reject < unflagged < pick; stops at either end) | | `Shift` + `0`–`9`, `P`, `X` or `U` | Apply the action and select the next photo | +| `\` (backslash) | Show / hide the Filter Bar | Enter opens the active photo without changing the selection. Text fields, dialogs and open popups keep the key; a custom Enter binding takes precedence. Enter has no additional action in Detail. @@ -39,6 +40,11 @@ step. AutoWrite uses the normal rating metadata path. In Detail, including Maski remapping and disabling the default brush bindings take precedence over their grid bracket actions. The separate Decrease Rating / Increase Rating commands can also be assigned in Help → Keyboard Shortcuts. +`\` shows and hides the Filter Bar in Photo Grid and Square Grid, as in Lightroom Classic's Library; in +Detail it keeps showing the original (Develop's Before / After key). View → Filter Bar (`Shift+F`) works +in every view. A Show Original moved to another key keeps its meaning in the grids, and `\` given to +another command runs that command. + Flag cycling and raise/lower use each photo's own flag, so a mixed selection steps together without being made uniform. Adobe's shortcut list names the backtick "Cycle flag settings" but does not state the order; unflagged → pick → reject is LightCraft's choice. The key is the logical grave key, so it follows the keyboard layout (on layouts where it is a dead accent key, assign another key in Help → Keyboard Shortcuts to `photo.cycleFlag`). `Home` and `End` make the first or last photo of the view the active, selected one. `Shift` + `←` / diff --git a/docs/parity-checklist.md b/docs/parity-checklist.md index 4e0531793..fdc20354b 100644 --- a/docs/parity-checklist.md +++ b/docs/parity-checklist.md @@ -1,6 +1,6 @@ # Lightroom parity checklist -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-15 · **Change:** minor (LRC-PRINT-PAGE: Print Page Options) · **Target:** Adobe Lightroom Classic 15.5 / Lightroom 9.6 +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-15 · **Change:** minor (LRC-PRINT-PAGE: Print Page Options; KEYC-RATING: `\` shows / hides the Filter Bar in the grids) · **Target:** Adobe Lightroom Classic 15.5 / Lightroom 9.6 The measured, row-by-row checklist: one row per Lightroom feature, menu item and shortcut, what we have and what is missing. It answers *does the feature exist?* (feature breadth). Whether it is good @@ -778,7 +778,7 @@ From `08-lightroom-classic-extras.md` (Classic-only features) and part 2 of `06- | KEYC-SECONDWINDOW | Classic secondary-window keys | P2 | ⬜ | | | | KEYC-CATALOG | Classic photo/catalog keys (⇧⌘I, ⌘', ⌘R, F2, ⌫, ⇧⌘E…) | P2 | ✅ | `cmd:library.import`, `cmd:photo.delete`, `cmd:photo.virtualCopy`, `cmd:app.showInFinder`, `cmd:dialog.rename`, `cmd:photo.editInExternal` | ⇧⌘I add, ⌘' virtual copy, ⌘R show in Finder, F2 rename, ⌫ delete, ⇧⌘E external editor | | KEYC-COMPARE | Classic grid/compare keys (Z, Home/End, =/−, ⌘⇧D, S…) | P2 | 🟡 | `cmd:view.zoomToggle`, `cmd:view.thumbSizeUp`, `cmd:view.thumbSizeDown`, `crates/ui-egui/src/tests_zoom_keys.rs`, `cmd:library.select`, `crates/ui-egui/src/shortcuts.rs`, `crates/ui-egui/src/tests_keymap.rs` (`home_and_end_select_the_ends_of_the_grid`, `shift_arrows_extend_the_grid_selection`) | Z toggles zoom; `=` / `-` (and `+`) step the grid thumbnail size by 30 pt within the bottom-bar slider's 90–480 range in Photo Grid, Square Grid and People (nothing in Detail, Compare, Survey or Reference; a text field keeps the keys; ⌘= / ⌘− still zoom); Home / End make the first / last photo of the view the active, selected one and ⇧← / ⇧→ add the previous / next photo to the selection (the added photo becomes active; nothing is ever removed; at either end nothing happens), in Photo Grid and Square Grid only: they wait in the other views, in the full-screen preview, while a text field or a dialog has the keyboard, and when the user gave the key to a command; no compare, stacks keys | -| KEYC-RATING | Classic rating/flag keys (1–5, ⇧1–5, 6–9, P, X, U, ⇧X, ⇧U, `[` `]`, \`, ⌘↑ ⌘↓) | P2 | 🟡 | `cmd:photo.rate`, `cmd:photo.pick`, `cmd:photo.flag`, `cmd:photo.cycleFlag`, `cmd:photo.increaseFlag`, `cmd:photo.decreaseFlag` | 0–5 / Shift+0–5 and 6–9 / Shift+6–9; P/X/U, Shift+X/U and grid Shift+P work; ` (backtick) cycles each selected photo's flag unflagged → pick → reject → unflagged and ⌘↑ / ⌘↓ (Ctrl on Windows/Linux) raise / lower it (reject < unflagged < pick, clamped); one undo step, Compare/Survey act on the active photo, Auto Advance follows; tests cover batch/undo, active Compare candidate and text focus. Missing: Shift+P outside grids (Presets), filter-bar keys | +| KEYC-RATING | Classic rating/flag keys (1–5, ⇧1–5, 6–9, P, X, U, ⇧X, ⇧U, `[` `]`, \`, ⌘↑ ⌘↓) | P2 | 🟡 | `cmd:photo.rate`, `cmd:photo.pick`, `cmd:photo.flag`, `cmd:photo.cycleFlag`, `cmd:photo.increaseFlag`, `cmd:photo.decreaseFlag` | 0–5 / Shift+0–5 and 6–9 / Shift+6–9; P/X/U, Shift+X/U and grid Shift+P work; ` (backtick) cycles each selected photo's flag unflagged → pick → reject → unflagged and ⌘↑ / ⌘↓ (Ctrl on Windows/Linux) raise / lower it (reject < unflagged < pick, clamped); one undo step, Compare/Survey act on the active photo, Auto Advance follows; tests cover batch/undo, active Compare candidate and text focus; `\` shows / hides the Filter Bar in the grids (Show Original in Detail). Missing: Shift+P outside grids (Presets), ⌘L Enable Filters | | KEYC-COLLECTIONS | Classic collection keys (⌘N, B…) | P2 | 🟡 | `cmd:dialog.newAlbum` | ⌘N new album; no quick collection | | KEYC-METADATA | Classic keyword/metadata keys (⌘K, ⌘S, ⌘⌥⇧C/V…) | P2 | 🟡 | `cmd:photo.saveMetadataToFile` | ⌘S saves metadata; no keyword sets, metadata copy/paste | | KEYC-DEVELOP | Classic develop keys (V, ⌘U, ⇧⌘U, R, Q, K, M, ⇧M, ⇧W, ⇧J, ⇧Q…) | P2 | 🟡 | `cmd:develop.treatment`, `cmd:develop.reset`, `cmd:crop.reset` | V, ⇧⌘R, ⌥⌘R, W, J, Y, ⇧Y, \ match; R/K/M/⇧M differ; no Classic keymap layer | @@ -801,6 +801,7 @@ Latin stays upright. Advanced Japanese composition remains open. Regression cove | 2026-10-15 | minor | LRC-PRINT-PAGE: Page Options (Page Numbers, Page Info, Crop Marks) on Single Image and Contact Sheet pages, in the Print dialog, `print.set` and templates; still 🟡 (no identity plate, watermark, photo info or Cut Guides) | | 2026-10-15 | minor | LR-IMP-FORMATS: Hasselblad 3FR and FFF show their uncompressed RGB preview (no JPEG in these files) in the grid and loupe until developed, and as the stand-in when a file fails to decode; status unchanged (🟡) | | 2026-10-15 | minor | LR-IMP-FORMATS: a Hasselblad FFF develops with the camera's colour matrix from the original 3FR header it embeds (tag `0xC51B`) instead of the neutral matrix; status unchanged (🟡) | +| 2026-10-15 | patch | KEYC-RATING: `\` shows / hides the Filter Bar in Photo Grid and Square Grid (Show Original in Detail); status unchanged (🟡) | | 2026-10-12 | minor | LR-EDIT-OPTICS-PROFILE: Sony ARW shading, CA and distortion tables decoded with settings and provenance (raw IFD, `SR2SubIFD` fallback); applied corrections unchanged (ILCE-7RM4A and ILCE-7RM6 distortion); status unchanged (🟡) | | 2026-10-14 | minor | LR-IMP-CAMERA-COVERAGE: Camera-coverage sweep (#1327): 30 models verified on 40 CC0 files (coverage.py 515 → 545 verified); sensor verification does not establish colour parity (#1277); status unchanged (🟡) | | 2026-10-13 | minor | LR-MERGE-PANO: a panorama's DNG takes its `AsShotNeutral` from the median of its frames' vendor white-balance multipliers (CR2, NEF, ARW…) instead of the first frame's tags, and frames now carry the multipliers (issue #1144); status unchanged (✅) | diff --git a/docs/ui-parity.md b/docs/ui-parity.md index e5e0c6e5f..586becb86 100644 --- a/docs/ui-parity.md +++ b/docs/ui-parity.md @@ -1,6 +1,6 @@ # UI parity -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-14 · **Change:** minor (zoom row: soft proofing sharp at 1:1; canvas tools by keyboard; focus-order test; ~50 unnamed hand-drawn widgets named) · **Target:** Adobe Lightroom Classic 15.5 / Lightroom 9.6 +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-15 · **Change:** patch (KEYC-RATING: `\` shows / hides the Filter Bar in the grids) · **Target:** Adobe Lightroom Classic 15.5 / Lightroom 9.6 How LightCraft's interaction compares with Lightroom's: views, panels, tools and handles, modifier keys, shortcuts, zoom, context menus and feel. Rows for individual menu items and shortcuts live in @@ -66,7 +66,7 @@ under the UI command that wraps it (a no-op error); the UI command now wins. | Create Version | ⌘⇧S (+ ⇧M) | ⇧M (Windows: Ctrl+⇧S) | — | | Select None | ⌘⇧A (+ ⌘D) | ⌘D | — | -**Library culling (KEYC-RATING):** `0–5`, `6–9` and `P/X/U` reach egui on macOS even when displayed in the native menu (adapted from PR #261; issue #283). `Shift+0–9` applies and advances once; `Shift+P` picks and advances in Photo Grid / Square Grid and retains Presets elsewhere. See [library shortcuts](library-shortcuts.md) for the verified Classic mapping and regression coverage. `` ` `` cycles the flag (unflagged → pick → reject → unflagged) and ⌘↑ / ⌘↓ raise / lower it; the native menu leaves ⌘↑ / ⌘↓ to egui so Compare/Survey act on the active photo. Remaining Classic gaps: filter-bar keys. +**Library culling (KEYC-RATING):** `0–5`, `6–9` and `P/X/U` reach egui on macOS even when displayed in the native menu (adapted from PR #261; issue #283). `Shift+0–9` applies and advances once; `Shift+P` picks and advances in Photo Grid / Square Grid and retains Presets elsewhere. See [library shortcuts](library-shortcuts.md) for the verified Classic mapping and regression coverage. `` ` `` cycles the flag (unflagged → pick → reject → unflagged) and ⌘↑ / ⌘↓ raise / lower it; the native menu leaves ⌘↑ / ⌘↓ to egui so Compare/Survey act on the active photo. `\` shows / hides the Filter Bar in Photo Grid / Square Grid and keeps Show Original in Detail. Remaining Classic gaps: ⌘L (Enable Filters). **Grid thumbnail size (KEYC-COMPARE):** Classic's `=` and `-` increase and decrease the Grid thumbnail size (same keys on macOS and Windows; `+` also works for the larger size here, as Shift+`=` or the keypad). They step the bottom-bar slider by 30 pt inside its 90–480 pt range, in Photo Grid, Square Grid and People only; Detail, Compare, Survey and Reference ignore them, and ⌘= / ⌘− stay Zoom In / Out. See [library shortcuts](library-shortcuts.md). @@ -130,6 +130,7 @@ a real screen reader on any platform yet. | Date | Change | Summary | |---|---|---| +| 2026-10-15 | patch | KEYC-RATING: `\` shows / hides the Filter Bar in Photo Grid and Square Grid (Show Original in Detail); ⌘L is the filter-bar key left | | 2026-10-14 | patch | Shortcuts: Visualize HDR loses its default ⇧H, which cycles the Tool Overlay (issue #224); both PRs had claimed it | | 2026-10-12 | minor | Accessibility: crop handles, spots, gradient handles and mask pins operable by keyboard with AccessKit names and values; Tab order test for the right panels; hand-drawn icons and rows named; 55% → 75%; UI remaining 34–58 h → 32–54 h | | 2026-10-13 | minor | Shortcuts: Tool Overlay modes for spot and mask pins on ⇧H (H stays Remove; issue #224), listed with the deliberate differences; dropped from the missing list |