mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-26 02:59:17 -06:00
KEYC-COMPARE: = and - make the grid thumbnails larger and smaller
View ▸ Increase / Decrease Grid Thumbnail Size (view.thumbSizeUp / view.thumbSizeDown) step the bottom-bar slider by 30 pt within its 90–480 range in Photo Grid, Square Grid and People, as Lightroom Classic's Library Grid keys do; + also enlarges. Detail, Compare, Survey and Reference ignore the keys, text fields keep them, and ⌘= / ⌘− still zoom the photo. The slider's range is now shared constants.
This commit is contained in:
@@ -123,6 +123,8 @@ const LAYOUT: &[(&str, &[&str])] = &[
|
||||
"view.photoGrid",
|
||||
"view.squareGrid",
|
||||
"@Grid Info",
|
||||
"view.thumbSizeUp",
|
||||
"view.thumbSizeDown",
|
||||
"view.detail",
|
||||
"view.compare",
|
||||
"view.survey",
|
||||
|
||||
@@ -86,6 +86,9 @@ pub const UI_COMMANDS: &[UiCommand] = &[
|
||||
("view.navigate", "Set Image Zoom and Pan", None, ""),
|
||||
("view.zoomIn", "Zoom In", Some("Cmd+="), "View"),
|
||||
("view.zoomOut", "Zoom Out", Some("Cmd+-"), "View"),
|
||||
// Library grids only (Photo Grid, Square Grid, People): the bottom-bar slider's step by key
|
||||
("view.thumbSizeUp", "Increase Grid Thumbnail Size", Some("="), "View"),
|
||||
("view.thumbSizeDown", "Decrease Grid Thumbnail Size", Some("-"), "View"),
|
||||
("view.clipping", "Show Clipping", Some("J"), "View"),
|
||||
("view.visualizeHdr", "Visualize HDR", None, "View"),
|
||||
// in grids S expands/collapses stacks (the engine command it shadows)
|
||||
@@ -737,6 +740,15 @@ pub fn run_ui_command(app: &mut LightcraftApp, id: &str, p: &Value) -> Option<Re
|
||||
app.ui.zoom = if next == 0.0 { Zoom::Fit } else { Zoom::Percent(next) };
|
||||
Ok(Value::Null)
|
||||
}
|
||||
"view.thumbSizeUp" | "view.thumbSizeDown" => {
|
||||
// the bottom-bar slider's range, one `THUMB_SIZE_STEP` per call; {} → {size}
|
||||
if !thumb_size_view(app) {
|
||||
return Some(Err(format!("{id}: only in Photo Grid, Square Grid or People")));
|
||||
}
|
||||
let step = if id == "view.thumbSizeUp" { crate::state::THUMB_SIZE_STEP } else { -crate::state::THUMB_SIZE_STEP };
|
||||
app.ui.thumb_size = (app.ui.thumb_size + step).clamp(crate::state::THUMB_SIZE_MIN, crate::state::THUMB_SIZE_MAX);
|
||||
Ok(json!({"size": app.ui.thumb_size}))
|
||||
}
|
||||
"view.navigate" => {
|
||||
// {zoom?: "fit"|"fill"|{percent: number}, pan?: [x, y]} (normalized image centre).
|
||||
// Validate the complete request before changing either part of the viewport.
|
||||
@@ -1845,8 +1857,14 @@ pub fn run_ui_command(app: &mut LightcraftApp, id: &str, p: &Value) -> Option<Re
|
||||
Some(r)
|
||||
}
|
||||
|
||||
/// Views whose bottom bar has the thumbnail-size slider and that draw tiles of that size.
|
||||
fn thumb_size_view(app: &LightcraftApp) -> bool {
|
||||
matches!(app.ui.view, ViewMode::PhotoGrid | ViewMode::SquareGrid | ViewMode::People)
|
||||
}
|
||||
|
||||
pub fn ui_enabled(app: &LightcraftApp, id: &str) -> bool {
|
||||
match id {
|
||||
"view.thumbSizeUp" | "view.thumbSizeDown" => thumb_size_view(app),
|
||||
"dialog.contactSheet" | "app.contactSheet" => !cfg!(target_arch = "wasm32") && app.session.active().is_some() && app.export.is_none(),
|
||||
s if s.starts_with("panel.") || s.starts_with("tool.") || s.starts_with("section.") => app.session.active().is_some() || s == "panel.close",
|
||||
"app.export" | "dialog.export" | "dialog.createPreset" | "dialog.rename" | "dialog.captureTime" | "dialog.copySettings" => {
|
||||
|
||||
@@ -239,13 +239,14 @@ fn right_side(app: &mut LightcraftApp, ui: &mut egui::Ui, full: Rect, compact_zo
|
||||
let p = child.painter();
|
||||
let y = r.center().y;
|
||||
p.line_segment([pos2(r.left(), y), pos2(r.right(), y)], egui::Stroke::new(2.0, t.track));
|
||||
let f = (app.ui.thumb_size - 90.0) / (480.0 - 90.0);
|
||||
let (min, max) = (crate::state::THUMB_SIZE_MIN, crate::state::THUMB_SIZE_MAX);
|
||||
let f = (app.ui.thumb_size - min) / (max - min);
|
||||
let x = r.left() + f * r.width();
|
||||
p.rect_filled(Rect::from_center_size(pos2(x, y), vec2(3.0, 14.0)), 1.0, t.thumb_hover);
|
||||
if let Some(pp) = resp.interact_pointer_pos()
|
||||
&& (resp.dragged() || resp.clicked())
|
||||
{
|
||||
app.ui.thumb_size = 90.0 + ((pp.x - r.left()) / r.width()).clamp(0.0, 1.0) * (480.0 - 90.0);
|
||||
app.ui.thumb_size = min + ((pp.x - r.left()) / r.width()).clamp(0.0, 1.0) * (max - min);
|
||||
}
|
||||
}
|
||||
if child.min_rect().width() > 0.0 { child.min_rect().left() } else { full.right() }
|
||||
|
||||
@@ -203,6 +203,9 @@ pub const ALIASES: &[(&str, &str, &str)] = &[
|
||||
("F6", "view.filmstrip", "{}"),
|
||||
("F7", "view.leftPanel", "{}"),
|
||||
("Shift+M", "version.create", "{}"),
|
||||
// grid thumbnail size: Classic's key is `=`; `+` (keypad, or Shift+= reported as Plus) agrees
|
||||
("Plus", "view.thumbSizeUp", "{}"),
|
||||
("Shift+Plus", "view.thumbSizeUp", "{}"),
|
||||
("Shift+X", "photo.flag", r#"{"flag": "reject", "advance": true}"#),
|
||||
("Shift+Z", "photo.flag", r#"{"flag": "pick", "advance": true}"#),
|
||||
("Shift+U", "photo.flag", r#"{"flag": "none", "advance": true}"#),
|
||||
|
||||
@@ -449,6 +449,12 @@ impl AppSettings {
|
||||
/// Click-zoom ratios offered (percent): 1:1, 2:1, 3:1, 4:1, 8:1.
|
||||
pub const CLICK_ZOOMS: [u32; 5] = [100, 200, 300, 400, 800];
|
||||
|
||||
/// Grid thumbnail size (points): the bottom-bar slider's range, and the `=` / `-` keys' step
|
||||
/// (`view.thumbSizeUp` / `view.thumbSizeDown`), about a thirteenth of the range.
|
||||
pub const THUMB_SIZE_MIN: f32 = 90.0;
|
||||
pub const THUMB_SIZE_MAX: f32 = 480.0;
|
||||
pub const THUMB_SIZE_STEP: f32 = 30.0;
|
||||
|
||||
/// Width limits of a side panel the user resizes (points).
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct PanelWidth {
|
||||
@@ -1193,7 +1199,7 @@ impl UiState {
|
||||
}
|
||||
/// Clamp values restored from disk.
|
||||
pub fn sanitized(mut self) -> Self {
|
||||
self.thumb_size = self.thumb_size.clamp(90.0, 480.0);
|
||||
self.thumb_size = self.thumb_size.clamp(THUMB_SIZE_MIN, THUMB_SIZE_MAX);
|
||||
self.left_width = LEFT_WIDTH.clamp(self.left_width);
|
||||
self.right_width = RIGHT_WIDTH.clamp(self.right_width);
|
||||
self.brush_size = self.brush_size.clamp(0.002, 0.5);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
//! Headless tests of the View ▸ Zoom shortcuts and modifier-wheel zoom: Cmd+= / Cmd+- / Cmd+0
|
||||
//! (Ctrl on Windows and Linux) zoom the photo and never egui's interface scale, which would
|
||||
//! otherwise take the same keys at the end of the frame; Ctrl+wheel over the photo in the Edit
|
||||
//! view zooms it.
|
||||
//! view zooms it. Also the grid thumbnail-size keys `=` / `-` (Classic's Library Grid keys), which
|
||||
//! share the physical keys with Cmd+= / Cmd+- but act on the grids only.
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
@@ -85,3 +86,139 @@ fn ctrl_wheel_over_the_photo_zooms_it_in_the_edit_view() {
|
||||
}
|
||||
assert!((h.app.image_rect.unwrap().width() - zoomed.width()).abs() < 0.01, "a plain wheel changed the zoom");
|
||||
}
|
||||
|
||||
fn grid_view(view: crate::state::ViewMode) -> Headless {
|
||||
let services = Services { png: None, ..Default::default() };
|
||||
let mut app = LightcraftApp::new(lightcraft_engine::Session::with_demo(), services);
|
||||
app.ui.settings.gpu = false;
|
||||
app.ui.view = view;
|
||||
let mut h = Headless::new(app, [1400.0, 900.0], 1.0);
|
||||
h.step();
|
||||
h.step();
|
||||
h
|
||||
}
|
||||
|
||||
fn press(h: &mut Headless, k: &str, shift: bool, cmd: bool) {
|
||||
let r = h.request("ui.key", json!({"key": k, "shift": shift, "cmd": cmd}), T);
|
||||
assert_eq!(r["ok"], true, "{r}");
|
||||
h.step();
|
||||
h.step();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn equals_and_minus_step_the_grid_thumbnail_size_and_clamp() {
|
||||
use crate::state::{THUMB_SIZE_MAX, THUMB_SIZE_MIN, THUMB_SIZE_STEP, ViewMode};
|
||||
for view in [ViewMode::PhotoGrid, ViewMode::SquareGrid, ViewMode::People] {
|
||||
let mut h = grid_view(view);
|
||||
h.app.ui.thumb_size = 220.0;
|
||||
press(&mut h, "=", false, false);
|
||||
assert_eq!(h.app.ui.thumb_size, 220.0 + THUMB_SIZE_STEP, "{view:?}: =");
|
||||
press(&mut h, "-", false, false);
|
||||
press(&mut h, "-", false, false);
|
||||
assert_eq!(h.app.ui.thumb_size, 220.0 - THUMB_SIZE_STEP, "{view:?}: - -");
|
||||
// `+` (Shift+= on a US layout, or the keypad) is the same key for the same job
|
||||
press(&mut h, "Plus", true, false);
|
||||
press(&mut h, "Plus", false, false);
|
||||
assert_eq!(h.app.ui.thumb_size, 220.0 + THUMB_SIZE_STEP, "{view:?}: +");
|
||||
// clamped at both ends of the bottom-bar slider's range, however many presses
|
||||
h.app.ui.thumb_size = THUMB_SIZE_MAX - 5.0;
|
||||
for _ in 0..3 {
|
||||
press(&mut h, "=", false, false);
|
||||
assert!(h.app.ui.thumb_size <= THUMB_SIZE_MAX);
|
||||
}
|
||||
assert_eq!(h.app.ui.thumb_size, THUMB_SIZE_MAX, "{view:?}");
|
||||
h.app.ui.thumb_size = THUMB_SIZE_MIN + 5.0;
|
||||
for _ in 0..3 {
|
||||
press(&mut h, "-", false, false);
|
||||
assert!(h.app.ui.thumb_size >= THUMB_SIZE_MIN);
|
||||
}
|
||||
assert_eq!(h.app.ui.thumb_size, THUMB_SIZE_MIN, "{view:?}");
|
||||
// the whole range is walked in whole steps from either end
|
||||
let mut presses = 0;
|
||||
while h.app.ui.thumb_size < THUMB_SIZE_MAX {
|
||||
press(&mut h, "=", false, false);
|
||||
presses += 1;
|
||||
assert!(presses <= 20, "never reached the maximum");
|
||||
}
|
||||
assert_eq!(presses, ((THUMB_SIZE_MAX - THUMB_SIZE_MIN) / THUMB_SIZE_STEP).ceil() as usize);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn thumbnail_size_keys_do_nothing_outside_the_grids() {
|
||||
use crate::state::ViewMode;
|
||||
for view in [ViewMode::Detail, ViewMode::Compare, ViewMode::Survey, ViewMode::Reference] {
|
||||
let mut h = grid_view(view);
|
||||
h.app.ui.thumb_size = 220.0;
|
||||
let zoom = h.app.ui.zoom;
|
||||
for (k, shift) in [("=", false), ("-", false), ("Plus", true)] {
|
||||
press(&mut h, k, shift, false);
|
||||
}
|
||||
assert_eq!(h.app.ui.thumb_size, 220.0, "{view:?}");
|
||||
assert_eq!(h.app.ui.zoom, zoom, "{view:?}: a bare = / - is not a zoom key");
|
||||
// the command says why, and the menu shows it unavailable
|
||||
let r = h.request("ui.menu.invoke", json!({"id": "view.thumbSizeUp"}), T);
|
||||
assert_eq!(r["ok"], false, "{view:?}: {r}");
|
||||
assert_eq!(h.app.ui.thumb_size, 220.0);
|
||||
let list = h.request("ui.menu.list", json!({}), T);
|
||||
let entry = list["result"].as_array().and_then(|a| a.iter().find(|e| e["id"] == "view.thumbSizeUp")).cloned().unwrap_or_default();
|
||||
assert_eq!(entry["enabled"], false, "{view:?}: {entry}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cmd_equals_and_minus_still_zoom_and_leave_the_thumbnail_size_alone() {
|
||||
// in the loupe: the photo zooms, the grid size is untouched
|
||||
let mut h = edit_view();
|
||||
h.app.ui.thumb_size = 220.0;
|
||||
key(&mut h, "=");
|
||||
assert_eq!(h.app.ui.zoom, Zoom::Percent(50.0));
|
||||
key(&mut h, "-");
|
||||
assert_eq!(h.app.ui.zoom, Zoom::Percent(25.0));
|
||||
assert_eq!(h.app.ui.thumb_size, 220.0);
|
||||
// in a grid Cmd+= / Cmd+- are View ▸ Zoom In / Out, not the size keys
|
||||
let mut h = grid_view(crate::state::ViewMode::PhotoGrid);
|
||||
h.app.ui.thumb_size = 220.0;
|
||||
key(&mut h, "=");
|
||||
key(&mut h, "-");
|
||||
assert_eq!(h.app.ui.thumb_size, 220.0, "Cmd+= / Cmd+- changed the grid size");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn search_field_keeps_equals_and_minus() {
|
||||
let mut h = grid_view(crate::state::ViewMode::PhotoGrid);
|
||||
h.app.ui.thumb_size = 220.0;
|
||||
let r = h.request("ui.clickWidget", json!({"id": "field:search"}), T);
|
||||
assert_eq!(r["ok"], true, "{r}");
|
||||
h.step();
|
||||
for (k, text) in [("-", "-"), ("=", "="), ("Plus", "+")] {
|
||||
press(&mut h, k, false, false);
|
||||
let r = h.request("ui.text", json!({"text": text}), T);
|
||||
assert_eq!(r["ok"], true, "{r}");
|
||||
h.step();
|
||||
}
|
||||
assert_eq!(h.app.ui.thumb_size, 220.0, "typing in the search field resized the grid");
|
||||
assert_eq!(h.app.ui.search, "-=+", "the search field did not receive the keys");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn thumbnail_size_commands_run_from_the_control_channel_and_persist() {
|
||||
let mut h = grid_view(crate::state::ViewMode::SquareGrid);
|
||||
h.app.ui.thumb_size = 120.0;
|
||||
let r = h.request("ui.menu.invoke", json!({"id": "view.thumbSizeUp"}), T);
|
||||
assert_eq!(r["ok"], true, "{r}");
|
||||
assert_eq!(r["result"]["size"], 150.0);
|
||||
let r = h.request("engine.execute", json!({"command": "view.thumbSizeDown"}), T);
|
||||
assert_eq!(r["ok"], true, "{r}");
|
||||
assert_eq!(h.app.ui.thumb_size, 120.0);
|
||||
let r = h.request("ui.menu.invoke", json!({"id": "view.thumbSizeUp"}), T);
|
||||
assert_eq!(r["ok"], true, "{r}");
|
||||
// the size is saved with the rest of the UI state, like the slider's, and restored clamped
|
||||
let saved = serde_json::to_value(&h.app.ui).unwrap();
|
||||
assert_eq!(saved["thumbSize"], 150.0);
|
||||
let loaded = serde_json::from_value::<crate::state::UiState>(saved).unwrap().sanitized();
|
||||
assert_eq!(loaded.thumb_size, 150.0);
|
||||
let mut wild = serde_json::to_value(&h.app.ui).unwrap();
|
||||
wild["thumbSize"] = json!(9000.0);
|
||||
assert_eq!(serde_json::from_value::<crate::state::UiState>(wild).unwrap().sanitized().thumb_size, crate::state::THUMB_SIZE_MAX);
|
||||
}
|
||||
|
||||
@@ -46,7 +46,17 @@ commit `4e012a59a6d2442ba749f109ea27aadb5c0b11a5` by Gardy, and addresses the ca
|
||||
[issue #283](https://github.com/storytold/lightcraft/issues/283). That PR was open when checked
|
||||
on 2026-10-08; this work extends its fix with library culling bindings and tests.
|
||||
|
||||
Public behaviour references, checked 2026-10-08:
|
||||
## Grid thumbnail size
|
||||
|
||||
`=` makes the grid thumbnails larger and `-` smaller (`+` also enlarges), as in Lightroom Classic. Each
|
||||
press moves the bottom-bar slider by 30 pt within its 90–480 pt range and stops at either end. The keys
|
||||
work in Photo Grid, Square Grid and People (the views with the slider), do nothing in Detail, Compare,
|
||||
Survey and Reference, and leave text fields alone, so the search box still types `-` and `=`. `⌘=` /
|
||||
`⌘−` remain Zoom In / Out. The same steps are the View ▸ Increase / Decrease Grid Thumbnail Size
|
||||
commands (`view.thumbSizeUp`, `view.thumbSizeDown`, reachable from the control channel and MCP, which
|
||||
return `{"size"}`); the size is saved with the other interface settings.
|
||||
|
||||
Public behaviour references, checked 2026-10-08 (thumbnail size: 2026-10-13):
|
||||
|
||||
- [Lightroom Classic keyboard shortcuts](https://helpx.adobe.com/lightroom-classic/help/keyboard-shortcuts.html)
|
||||
- [Lightroom Classic flagging, labelling and rating](https://helpx.adobe.com/lightroom-classic/help/flag-label-rate-photos.html)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Lightroom parity checklist
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-11 · **Change:** minor (LR-MERGE-HDR: merges of raws without colour matrices keep their colour (#965); rapid slider entry; LR-PROF-CAMERACOLOR: tone curve from black-and-white camera JPEGs; LR-VIEW-ZOOM, LR-VIEW-COMPARE: Compare and Reference zoom windows; LR-IMP-FORMATS, LR-IMP-CAMERA-COVERAGE: EOS R5 Mark II CR3 decodes; renamed from `parity.md`; Top gaps moved to gaps.md, shortcut notes to ui-parity.md; filesystem history retry/Undo/Redo evidence; renamed from `parity.md`; Top gaps moved to gaps.md, shortcut notes to ui-parity.md) · **Target:** Adobe Lightroom Classic 15.5 / Lightroom 9.6
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-13 · **Change:** minor (KEYC-COMPARE: `=` / `-` change the grid thumbnail size; LR-MERGE-HDR: merges of raws without colour matrices keep their colour (#965); rapid slider entry; LR-PROF-CAMERACOLOR: tone curve from black-and-white camera JPEGs; LR-VIEW-ZOOM, LR-VIEW-COMPARE: Compare and Reference zoom windows; LR-IMP-FORMATS, LR-IMP-CAMERA-COVERAGE: EOS R5 Mark II CR3 decodes; renamed from `parity.md`; Top gaps moved to gaps.md, shortcut notes to ui-parity.md; filesystem history retry/Undo/Redo evidence; renamed from `parity.md`; Top gaps moved to gaps.md, shortcut notes to ui-parity.md) · **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
|
||||
@@ -36,7 +36,7 @@ cited here still exists. Formerly docs/parity.md.
|
||||
| H. Crop & rotate (CROP) | 9 | 0 | 0 | 1 | 6/6 (100%) | 3/3 (100%) |
|
||||
| I. Remove / healing (REM) | 8 | 1 | 2 | 2 | 4/4 (100%) | 2/3 (67%) |
|
||||
| J. Red eye (EYE) | 2 | 0 | 0 | 0 | — | 1/1 (100%) |
|
||||
| K. Masking (MASK) | 13 | 5 | 5 | 0 | 7/8 (88%) | 5/5 (100%) |
|
||||
| K. Masking (MASK) | 14 | 5 | 5 | 0 | 7/8 (88%) | 6/6 (100%) |
|
||||
| L. Presets (PRE) | 6 | 0 | 1 | 1 | 2/2 (100%) | 2/2 (100%) |
|
||||
| M. Versions & history (VER) | 5 | 0 | 0 | 0 | 1/1 (100%) | 3/3 (100%) |
|
||||
| N. Copy / paste / sync (SYNC) | 5 | 0 | 0 | 0 | 3/3 (100%) | 1/1 (100%) |
|
||||
@@ -53,9 +53,9 @@ cited here still exists. Formerly docs/parity.md.
|
||||
| Y. Menus | 84 | 0 | 4 | 8 | 47/47 (100%) | 23/23 (100%) |
|
||||
| Z. Keyboard shortcuts (desktop) | 76 | 3 | 3 | 1 | 49/52 (94%) | 23/24 (96%) |
|
||||
| Lightroom Classic extras | 34 | 16 | 35 | 8 | — | 24/26 (92%) |
|
||||
| **Total** | 408 | 52 | 72 | 35 | 193/201 (96%) | 145/157 (92%) |
|
||||
| **Total** | 409 | 52 | 72 | 35 | 193/201 (96%) | 146/158 (92%) |
|
||||
|
||||
Weighted completion (✅ = 1, 🟡 = ½, 🚫 left out): **81.6%** of 532 in-scope rows — P0 98.0% of 201 · P1 95.2% of 157 · P2 50.0% of 173.
|
||||
Weighted completion (✅ = 1, 🟡 = ½, 🚫 left out): **81.6%** of 533 in-scope rows — P0 98.0% of 201 · P1 95.3% of 158 · P2 50.0% of 173.
|
||||
<!-- /parity:summary -->
|
||||
|
||||
## Top gaps and shortcut notes
|
||||
@@ -769,7 +769,7 @@ From `08-lightroom-classic-extras.md` (Classic-only features) and part 2 of `06-
|
||||
| KEYC-VIEWS | Classic view keys (E, G, C, N, L, F, I, ⇧R, ⌘⌥0) | P2 | 🟡 | `cmd:view.photoGrid`, `cmd:view.zoom100` | G works; E opens Edit (not loupe); no compare/survey/lights-out/screen modes |
|
||||
| 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` | Z toggles zoom; no compare, stacks, thumbnail-size keys |
|
||||
| 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` | 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); 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` | 0–5 / Shift+0–5 and 6–9 / Shift+6–9; P/X/U, Shift+X/U and grid Shift+P work; tests cover batch/undo, active Compare candidate and text focus. Missing: Shift+P outside grids (Presets), rating `[` / `]`, flag cycle and filter-bar keys |
|
||||
| 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 |
|
||||
@@ -814,3 +814,4 @@ Latin stays upright. Advanced Japanese composition remains open. Regression cove
|
||||
| 2026-10-10 | patch | LR-BEHAV-UNDO: file/XMP repair retries and merged rename Undo/Redo evidence; status and summary counts unchanged. |
|
||||
| 2026-10-10 | minor | Renamed from `parity.md` (progress-docs standard); Top gaps moved to gaps.md (its duplicated items 1–2 from a bad merge resolved there), shortcut notes moved to ui-parity.md. Rows unchanged; a recount of the rows gives 81.1% of 517 in-scope rows (P0 98.0%, P1 95.1%, P2 46.9%), so the generated summary above is due a `cargo xtask parity --write` |
|
||||
| 2026-09-30 – 2026-10-11 | — | Rows added and updated with each feature (see `git log -- docs/parity.md docs/parity-checklist.md`) |
|
||||
| 2026-10-13 | minor | KEYC-COMPARE: `=` / `-` (also `+`) increase / decrease the grid thumbnail size (`view.thumbSizeUp` / `view.thumbSizeDown`, View menu), grids only; status unchanged (🟡) |
|
||||
|
||||
+4
-1
@@ -1,6 +1,6 @@
|
||||
# UI parity
|
||||
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-12 · **Change:** minor (accessibility audit: test over the AccessKit tree; fields, sliders and dialogs named) · **Target:** Adobe Lightroom Classic 15.5 / Lightroom 9.6
|
||||
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-13 · **Change:** minor (`=` / `-` grid thumbnail size keys; accessibility audit: test over the AccessKit tree; fields, sliders and dialogs named) · **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
|
||||
@@ -67,6 +67,8 @@ under the UI command that wraps it (a no-op error); the UI command now wins.
|
||||
|
||||
**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. Remaining Classic gaps: rating `[` / `]`, flag cycling and filter-bar keys.
|
||||
|
||||
**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).
|
||||
|
||||
**Still missing / broken:**
|
||||
- No command yet: F1 help (verify the rest of the old list: full screen, settings, stacks,
|
||||
visualize spots and merges have commands now).
|
||||
@@ -105,6 +107,7 @@ left panel, canvas, right panel, which is sensible but not tuned).
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-13 | minor | KEYC-COMPARE: `=` / `-` grid thumbnail size keys noted in the shortcuts section |
|
||||
| 2026-10-12 | minor | Accessibility: an AccessKit tree audit test over every view, Develop tool and 13 dialogs; unnamed fields, slider ranges and the Auto Stack slider fixed; 30% → 55%; UI remaining 40–70 h → 34–58 h |
|
||||
| 2026-10-11 | minor | Zoom row: Compare and Reference get zoom windows; what remains of LR-VIEW-ZOOM is overlays and soft proofing |
|
||||
| 2026-10-10 | major | Created: measured command and shortcut counts, assessment by area, estimates; moved the shortcut conflicts section here from the checklist |
|
||||
|
||||
Reference in New Issue
Block a user