From b572dee19f98e125d2c15c7ad947f85cf6ebff8d Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Sat, 24 Oct 2026 12:23:40 -0700 Subject: [PATCH] KEYC-METADATA: Alt+0 / Alt+Shift+0 go to the next / previous keyword set Lightroom Classic's keyboard shortcut page lists Option+0 / Option+Shift+0 (Alt+0 / Alt+Shift+0 on Windows) for cycling forward and backward through the keyword sets; LightCraft had no key or command for it. Next Keyword Set (keyword.nextSet, Alt+0) and Previous Keyword Set (keyword.previousSet, Alt+Shift+0) make the set after or before the current one current, in the Keyword Set menu's order: Recent Keywords, then the saved sets. The keys wrap around at either end, and Alt+1 to Alt+9 then apply the new set's keywords. The two command labels have rows in every catalog. The KEYC-METADATA and LRC-LIB-KEYWORDS rows, docs/ui-parity.md and docs/library-shortcuts.md list the keys. --- crates/engine/src/cmd/keywords.rs | 28 +++++++++++++++++++++++++ crates/engine/src/tests_keyword_list.rs | 23 ++++++++++++++++++++ crates/ui-egui/locales/cs.json | 2 ++ crates/ui-egui/locales/de.json | 2 ++ crates/ui-egui/locales/es.json | 2 ++ crates/ui-egui/locales/fi.json | 2 ++ crates/ui-egui/locales/fr.json | 2 ++ crates/ui-egui/locales/id.json | 2 ++ crates/ui-egui/locales/it.json | 2 ++ crates/ui-egui/locales/ja.json | 2 ++ crates/ui-egui/locales/ka.json | 2 ++ crates/ui-egui/locales/pl.json | 2 ++ crates/ui-egui/locales/pt-br.json | 2 ++ crates/ui-egui/locales/ru.json | 2 ++ crates/ui-egui/locales/sv.json | 2 ++ crates/ui-egui/locales/uk.json | 2 ++ crates/ui-egui/locales/vi.json | 2 ++ crates/ui-egui/locales/zh-hans.json | 2 ++ crates/ui-egui/locales/zh-hant.json | 2 ++ crates/ui-egui/src/tests_keyword_set.rs | 17 +++++++++++++++ docs/library-shortcuts.md | 13 +++++++++++- docs/parity-checklist.md | 7 ++++--- docs/ui-parity.md | 5 ++++- 23 files changed, 122 insertions(+), 5 deletions(-) diff --git a/crates/engine/src/cmd/keywords.rs b/crates/engine/src/cmd/keywords.rs index 07dcbe0ec..ebed426fa 100644 --- a/crates/engine/src/cmd/keywords.rs +++ b/crates/engine/src/cmd/keywords.rs @@ -154,6 +154,16 @@ pub fn keyword_sets_json(s: &Session) -> Value { json!({"sets": sets, "current": s.keyword_set.clone().unwrap_or_else(|| RECENT.into()), "keywords": current_keywords(s)}) } +/// Make the set `step` places after the current one current, in the Keyword Set menu's order +/// (Recent Keywords, then the saved sets), wrapping around from the last to the first and back. +fn step_set(s: &mut Session, step: isize) -> Result { + let at = s.keyword_set.as_deref().and_then(|n| s.keyword_sets.iter().position(|x| same_set(&x.name, n))).map_or(0, |i| i + 1); + let next = (at as isize + step).rem_euclid(s.keyword_sets.len() as isize + 1) as usize; + s.keyword_set = next.checked_sub(1).and_then(|i| s.keyword_sets.get(i)).map(|x| x.name.clone()); + s.save_prefs()?; + Ok(keyword_sets_json(s)) +} + pub fn specs() -> Vec { vec![ cmd!(query "keyword.sets", "Keyword Sets", [], None, "{} → {sets: [{name, keywords}], current, keywords: the nine ⌥1–⌥9 apply}", always, |s, _| Ok(keyword_sets_json(s))), @@ -174,6 +184,24 @@ pub fn specs() -> Vec { s.save_prefs()?; Ok(keyword_sets_json(s)) }), + cmd!( + "keyword.nextSet", + "Next Keyword Set", + [], + Some("Alt+0"), + "{}: the set after the current one (after the last, Recent Keywords)", + always, + |s, _| step_set(s, 1) + ), + cmd!( + "keyword.previousSet", + "Previous Keyword Set", + [], + Some("Alt+Shift+0"), + "{}: the set before the current one (before Recent Keywords, the last)", + always, + |s, _| step_set(s, -1) + ), cmd!( "keyword.saveSet", "Save Keyword Set", diff --git a/crates/engine/src/tests_keyword_list.rs b/crates/engine/src/tests_keyword_list.rs index b98b45de8..94ff59988 100644 --- a/crates/engine/src/tests_keyword_list.rs +++ b/crates/engine/src/tests_keyword_list.rs @@ -263,6 +263,29 @@ fn set_names_match_whatever_their_case() { assert!(set_named(&mut s, "ÉTÉ").is_null(), "deleted"); } +/// Next / Previous Keyword Set (⌥0 / ⌥⇧0) step through the sets in the Keyword Set menu's order, +/// Recent Keywords first, and wrap around at either end; with no saved sets they stay on Recent +/// Keywords. +#[test] +fn next_and_previous_keyword_set_wrap_around_the_sets() { + let mut s = Session::with_demo(); + let current = |r: serde_json::Value| r["current"].as_str().unwrap_or_default().to_string(); + assert_eq!(current(s.execute("keyword.nextSet", &json!({})).unwrap()), "Recent Keywords", "no sets: nothing to go to"); + assert_eq!(current(s.execute("keyword.previousSet", &json!({})).unwrap()), "Recent Keywords"); + s.execute("keyword.saveSet", &json!({"name": "Weddings", "keywords": ["ceremony"]})).unwrap(); + s.execute("keyword.saveSet", &json!({"name": "Travel", "keywords": ["harbor"]})).unwrap(); + s.execute("keyword.useSet", &json!({"name": "Recent Keywords"})).unwrap(); + let forward: Vec = (0..3).map(|_| current(s.execute("keyword.nextSet", &json!({})).unwrap())).collect(); + assert_eq!(forward, ["Weddings", "Travel", "Recent Keywords"]); + let back: Vec = (0..3).map(|_| current(s.execute("keyword.previousSet", &json!({})).unwrap())).collect(); + assert_eq!(back, ["Travel", "Weddings", "Recent Keywords"]); + let r = s.execute("keyword.nextSet", &json!({})).unwrap(); + assert_eq!(r["keywords"], json!(["ceremony"]), "⌥1–⌥9 now apply the set's keywords"); + // a current set that is no longer there counts as Recent Keywords + s.keyword_set = Some("Gone".into()); + assert_eq!(current(s.execute("keyword.nextSet", &json!({})).unwrap()), "Weddings"); +} + /// Export Keywords writes the keyword list file, and names the keywords Capture One's importer /// refuses (it allows none of ; , < > in a list); without a path it gives the text. #[test] diff --git a/crates/ui-egui/locales/cs.json b/crates/ui-egui/locales/cs.json index 16095a43e..5d2f3f719 100644 --- a/crates/ui-egui/locales/cs.json +++ b/crates/ui-egui/locales/cs.json @@ -1193,6 +1193,7 @@ "New time": "Nový čas", "New…": "Nový…", "Next Appearance Mode": "Další režim vzhledu", + "Next Keyword Set": "Další sada klíčových slov", "Next Photo": "Další fotografie", "Next up for AI Denoise…": "Další na řadě pro redukci šumu pomocí AI…", "Night Blue": "Noční modř", @@ -1402,6 +1403,7 @@ "Preview size": "Velikost náhledu", "Preview unavailable": "Náhled není dostupný", "Previews": "Náhledy", + "Previous Keyword Set": "Předchozí sada klíčových slov", "Previous Photo": "Předchozí fotografie", "Primaries (x, y)": "Primární barvy (x, y)", "Print": "Tisk", diff --git a/crates/ui-egui/locales/de.json b/crates/ui-egui/locales/de.json index 679e3b00f..bd96833e8 100644 --- a/crates/ui-egui/locales/de.json +++ b/crates/ui-egui/locales/de.json @@ -950,6 +950,7 @@ "New name": "Neuer Name", "New time": "Neue Zeit", "New…": "Neu…", + "Next Keyword Set": "Nächster Stichwortsatz", "Next Photo": "Nächstes Foto", "Night Blue": "Nachtblau", "Nikon NEFs start from a colour and tone look fitted to the camera's own JPEG, as Sony ARWs do, instead of a muted,": "Nikon-NEFs beginnen mit einem Farb- und Tonwertbild, das wie bei Sony-ARWs an das Kamera-JPEG angepasst ist, statt mit einem gedämpften,", @@ -1112,6 +1113,7 @@ "Preview size": "Vorschaugröße", "Preview unavailable": "Vorschau nicht verfügbar", "Previews": "Vorschauen", + "Previous Keyword Set": "Vorheriger Stichwortsatz", "Previous Photo": "Vorheriges Foto", "Print": "Drucken", "Print…": "Drucken…", diff --git a/crates/ui-egui/locales/es.json b/crates/ui-egui/locales/es.json index af22570ef..b7011fa77 100644 --- a/crates/ui-egui/locales/es.json +++ b/crates/ui-egui/locales/es.json @@ -961,6 +961,7 @@ "New name": "Nuevo nombre", "New time": "Nueva hora", "New…": "Nuevo…", + "Next Keyword Set": "Conjunto de palabras clave siguiente", "Next Photo": "Foto siguiente", "Night Blue": "Azul nocturno", "No": "No", @@ -1117,6 +1118,7 @@ "Preview size": "Tamaño de la vista previa", "Preview unavailable": "Vista previa no disponible", "Previews": "Vistas previas", + "Previous Keyword Set": "Conjunto de palabras clave anterior", "Previous Photo": "Foto anterior", "Print": "Imprimir", "Print…": "Imprimir…", diff --git a/crates/ui-egui/locales/fi.json b/crates/ui-egui/locales/fi.json index 6456a6624..afb724797 100644 --- a/crates/ui-egui/locales/fi.json +++ b/crates/ui-egui/locales/fi.json @@ -1236,6 +1236,7 @@ "New…": "Uusi…", "Next Appearance Mode": "Seuraava ulkoasutila", "Next History Step": "Seuraava historiavaihe", + "Next Keyword Set": "Seuraava avainsanajoukko", "Next Photo": "Seuraava kuva", "Next Slide": "Seuraava dia", "Next page": "Seuraava sivu", @@ -1461,6 +1462,7 @@ "Preview unavailable": "Esikatselu ei käytettävissä", "Previews": "Esikatselut", "Previous History Step": "Edellinen historiavaihe", + "Previous Keyword Set": "Edellinen avainsanajoukko", "Previous Photo": "Edellinen kuva", "Previous Slide": "Edellinen dia", "Previous page": "Edellinen sivu", diff --git a/crates/ui-egui/locales/fr.json b/crates/ui-egui/locales/fr.json index 33a892ecf..8d28beee1 100644 --- a/crates/ui-egui/locales/fr.json +++ b/crates/ui-egui/locales/fr.json @@ -904,6 +904,7 @@ "New name": "Nouveau nom", "New time": "Nouvelle heure", "New…": "Nouveau…", + "Next Keyword Set": "Jeu de mots-clés suivant", "Next Photo": "Photo suivante", "Night Blue": "Bleu nuit", "No": "Non", @@ -1059,6 +1060,7 @@ "Preview size": "Taille de l'aperçu", "Preview unavailable": "Aperçu indisponible", "Previews": "Aperçus", + "Previous Keyword Set": "Jeu de mots-clés précédent", "Previous Photo": "Photo précédente", "Print": "Imprimer", "Print…": "Imprimer…", diff --git a/crates/ui-egui/locales/id.json b/crates/ui-egui/locales/id.json index abb6a732e..afad7fc07 100644 --- a/crates/ui-egui/locales/id.json +++ b/crates/ui-egui/locales/id.json @@ -1233,6 +1233,7 @@ "New…": "Baru…", "Next Appearance Mode": "Mode tampilan berikutnya", "Next History Step": "Langkah riwayat berikutnya", + "Next Keyword Set": "Set kata kunci berikutnya", "Next Photo": "Foto berikutnya", "Next Slide": "Slide berikutnya", "Next up for AI Denoise…": "Berikutnya dalam antrean pengurangan noise AI…", @@ -1445,6 +1446,7 @@ "Preview unavailable": "Pratinjau tidak tersedia", "Previews": "Pratinjau", "Previous History Step": "Langkah riwayat sebelumnya", + "Previous Keyword Set": "Set kata kunci sebelumnya", "Previous Photo": "Foto sebelumnya", "Previous Slide": "Slide sebelumnya", "Previous settings": "Pengaturan sebelumnya", diff --git a/crates/ui-egui/locales/it.json b/crates/ui-egui/locales/it.json index a75448fbb..f08aa2741 100644 --- a/crates/ui-egui/locales/it.json +++ b/crates/ui-egui/locales/it.json @@ -907,6 +907,7 @@ "New name": "Nuovo nome", "New time": "Nuova ora", "New…": "Nuovo…", + "Next Keyword Set": "Set di parole chiave successivo", "Next Photo": "Foto successiva", "Night Blue": "Blu notte", "No": "No", @@ -1068,6 +1069,7 @@ "Preview size": "Dimensione dell'anteprima", "Preview unavailable": "Anteprima non disponibile", "Previews": "Anteprime", + "Previous Keyword Set": "Set di parole chiave precedente", "Previous Photo": "Foto precedente", "Print": "Stampa", "Print…": "Stampa…", diff --git a/crates/ui-egui/locales/ja.json b/crates/ui-egui/locales/ja.json index c3f11e6e5..ee29a16e5 100644 --- a/crates/ui-egui/locales/ja.json +++ b/crates/ui-egui/locales/ja.json @@ -632,6 +632,7 @@ "Nested group": "入れ子のグループ", "New Album": "新しいアルバム", "New time": "新しい日時", + "Next Keyword Set": "次のキーワードセット", "Next Photo": "次の写真", "Night Blue": "ナイトブルー", "No contributor data was built into this copy.": "このビルドにはコントリビューターのデータが含まれていません", @@ -672,6 +673,7 @@ "Preview Build Progress": "プレビュー作成の進行状況", "Preview only: editing the camera's embedded JPEG": "プレビューのみ:カメラの埋め込みJPEGを編集中", "Preview unavailable": "プレビューを表示できません", + "Previous Keyword Set": "前のキーワードセット", "Previous Photo": "前の写真", "Profile Browser": "プロファイルブラウザー", "Profile Menu": "プロファイルメニュー", diff --git a/crates/ui-egui/locales/ka.json b/crates/ui-egui/locales/ka.json index 13fd48d3c..a363d0087 100644 --- a/crates/ui-egui/locales/ka.json +++ b/crates/ui-egui/locales/ka.json @@ -1310,6 +1310,7 @@ "New…": "ახალი…", "Next Appearance Mode": "შემდეგი იერსახის რეჟიმი", "Next History Step": "ისტორიის შემდეგი ნაბიჯი", + "Next Keyword Set": "საკვანძო სიტყვების შემდეგი ნაკრები", "Next Photo": "შემდეგი ფოტო", "Next up for AI Denoise…": "შემდეგია AI ხმაურის მოცილების რიგში…", "Night Blue": "ღამის ლურჯი", @@ -1534,6 +1535,7 @@ "Previews": "წინასწარი ხედები", "Previews match exports on Mac screens": "წინასწარი ხედები ემთხვევა ექსპორტს Mac-ის ეკრანებზე", "Previous History Step": "ისტორიის წინა ნაბიჯი", + "Previous Keyword Set": "საკვანძო სიტყვების წინა ნაკრები", "Previous Photo": "წინა ფოტო", "Primaries (x, y)": "ძირითადი ფერები (x, y)", "Print": "ბეჭდვა", diff --git a/crates/ui-egui/locales/pl.json b/crates/ui-egui/locales/pl.json index f03a81762..67a40ec57 100644 --- a/crates/ui-egui/locales/pl.json +++ b/crates/ui-egui/locales/pl.json @@ -886,6 +886,7 @@ "New name": "Nowa nazwa", "New time": "Nowy czas", "New…": "Nowy…", + "Next Keyword Set": "Następny zestaw słów kluczowych", "Next Photo": "Następne zdjęcie", "Night Blue": "Nocny błękit", "No": "Nie", @@ -1030,6 +1031,7 @@ "Preview only": "Tylko podgląd", "Preview size": "Rozmiar podglądu", "Previews": "Podglądy", + "Previous Keyword Set": "Poprzedni zestaw słów kluczowych", "Previous Photo": "Poprzednie zdjęcie", "Print": "Drukuj", "Print…": "Drukuj…", diff --git a/crates/ui-egui/locales/pt-br.json b/crates/ui-egui/locales/pt-br.json index 88e955d26..b82d3aa01 100644 --- a/crates/ui-egui/locales/pt-br.json +++ b/crates/ui-egui/locales/pt-br.json @@ -916,6 +916,7 @@ "New name": "Novo nome", "New time": "Novo horário", "New…": "Novo…", + "Next Keyword Set": "Próximo conjunto de palavras-chave", "Next Photo": "Próxima foto", "Night Blue": "Azul noturno", "No": "Não", @@ -1077,6 +1078,7 @@ "Preview size": "Tamanho da pré-visualização", "Preview unavailable": "Prévia indisponível", "Previews": "Pré-visualizações", + "Previous Keyword Set": "Conjunto de palavras-chave anterior", "Previous Photo": "Foto anterior", "Print": "Imprimir", "Print…": "Imprimir…", diff --git a/crates/ui-egui/locales/ru.json b/crates/ui-egui/locales/ru.json index 5c8816c5e..194ce6014 100644 --- a/crates/ui-egui/locales/ru.json +++ b/crates/ui-egui/locales/ru.json @@ -760,6 +760,7 @@ "New blank PDF": "Новый пустой PDF", "New name": "Новое имя", "New…": "Новый…", + "Next Keyword Set": "Следующий набор ключевых слов", "Next Photo": "Следующее фото", "Night Blue": "Ночной синий", "No": "Нет", @@ -897,6 +898,7 @@ "Preview size": "Размер просмотра", "Preview unavailable": "Просмотр недоступен", "Previews": "Просмотры", + "Previous Keyword Set": "Предыдущий набор ключевых слов", "Previous Photo": "Предыдущее фото", "Print": "Печать", "Print…": "Печать…", diff --git a/crates/ui-egui/locales/sv.json b/crates/ui-egui/locales/sv.json index d9af4b8e8..356487b9d 100644 --- a/crates/ui-egui/locales/sv.json +++ b/crates/ui-egui/locales/sv.json @@ -1362,6 +1362,7 @@ "New…": "Ny…", "Next Appearance Mode": "Nästa utseendeläge", "Next page": "Nästa sida", + "Next Keyword Set": "Nästa nyckelordsuppsättning", "Next Photo": "Nästa foto", "Next up for AI Denoise…": "Näst i tur för AI-brusreducering…", "Night Blue": "Nattblå", @@ -1599,6 +1600,7 @@ "Previews": "Förhandsgranskningar", "previews": "förhandsgranskningar", "Previous page": "Föregående sida", + "Previous Keyword Set": "Föregående nyckelordsuppsättning", "Previous Photo": "Föregående foto", "Previous settings": "Föregående inställningar", "Primaries (x, y)": "Primärfärger (x, y)", diff --git a/crates/ui-egui/locales/uk.json b/crates/ui-egui/locales/uk.json index 39090c0b3..9d07b67a5 100644 --- a/crates/ui-egui/locales/uk.json +++ b/crates/ui-egui/locales/uk.json @@ -855,6 +855,7 @@ "Nested group": "Вкладена група", "New Album": "Новий альбом", "New time": "Новий час", + "Next Keyword Set": "Наступний набір ключових слів", "Next Photo": "Наступне фото", "Night Blue": "Нічна синява", "No named people in these photos": "На цих фото немає людей з іменами", @@ -887,6 +888,7 @@ "Presets and profiles": "Набори налаштувань і профілі", "Preview Build Progress": "Перебіг створення переглядів", "Preview only: editing the camera's embedded JPEG": "Лише перегляд: редагування вбудованого JPEG камери", + "Previous Keyword Set": "Попередній набір ключових слів", "Previous Photo": "Попереднє фото", "Profile Browser": "Оглядач профілів", "Profile Menu": "Меню профілів", diff --git a/crates/ui-egui/locales/vi.json b/crates/ui-egui/locales/vi.json index 98adc91b8..a5b27d8ac 100644 --- a/crates/ui-egui/locales/vi.json +++ b/crates/ui-egui/locales/vi.json @@ -1136,6 +1136,7 @@ "New…": "Mới…", "Next Appearance Mode": "Chế độ giao diện tiếp theo", "Next History Step": "Bước lịch sử sau", + "Next Keyword Set": "Bộ từ khóa tiếp theo", "Next Photo": "Ảnh tiếp theo", "Next up for AI Denoise…": "Tiếp theo cho AI Khử nhiễu…", "Night Blue": "Xanh đêm", @@ -1338,6 +1339,7 @@ "Preview unavailable": "Không có xem trước", "Previews": "Xem trước", "Previous History Step": "Bước lịch sử trước", + "Previous Keyword Set": "Bộ từ khóa trước", "Previous Photo": "Ảnh trước", "Primaries (x, y)": "Màu gốc (x, y)", "Print": "In", diff --git a/crates/ui-egui/locales/zh-hans.json b/crates/ui-egui/locales/zh-hans.json index 73caf6407..7b4a2c615 100644 --- a/crates/ui-egui/locales/zh-hans.json +++ b/crates/ui-egui/locales/zh-hans.json @@ -981,6 +981,7 @@ "New blank PDF": "新建空白 PDF", "New name": "新名称", "New…": "新建…", + "Next Keyword Set": "下一个关键字集", "Next Photo": "下一张照片", "Night Blue": "夜色蓝调", "No": "否", @@ -1109,6 +1110,7 @@ "Preview only": "仅预览", "Preview size": "预览大小", "Previews": "预览", + "Previous Keyword Set": "上一个关键字集", "Previous Photo": "上一张照片", "Print": "打印", "Print…": "打印…", diff --git a/crates/ui-egui/locales/zh-hant.json b/crates/ui-egui/locales/zh-hant.json index 72cc3ab7f..d9e268335 100644 --- a/crates/ui-egui/locales/zh-hant.json +++ b/crates/ui-egui/locales/zh-hant.json @@ -982,6 +982,7 @@ "New blank PDF": "新增空白 PDF", "New name": "新名稱", "New…": "新增…", + "Next Keyword Set": "下一個關鍵字集", "Next Photo": "下一張照片", "Night Blue": "夜色藍調", "No": "否", @@ -1110,6 +1111,7 @@ "Preview only": "僅供預覽", "Preview size": "預覽尺寸", "Previews": "預覽", + "Previous Keyword Set": "上一個關鍵字集", "Previous Photo": "上一張照片", "Print": "列印", "Print…": "列印…", diff --git a/crates/ui-egui/src/tests_keyword_set.rs b/crates/ui-egui/src/tests_keyword_set.rs index 4667f5367..4874a58a9 100644 --- a/crates/ui-egui/src/tests_keyword_set.rs +++ b/crates/ui-egui/src/tests_keyword_set.rs @@ -160,3 +160,20 @@ fn save_as_a_new_set_keeps_the_original() { assert_eq!(names, ["Recent Keywords", "Weddings", "Ceremonies"]); assert_eq!(s["current"], "Ceremonies"); } + +/// ⌥0 / ⌥⇧0 (Alt+0 / Alt+Shift+0) go to the next and the previous keyword set, as in Lightroom +/// Classic's Library, and ⌥1 then applies the new set's first keyword. +#[test] +fn alt_0_and_alt_shift_0_cycle_the_keyword_sets() { + let mut h = keywords_panel(); + h.app.session.execute("keyword.saveSet", &json!({"name": "Weddings", "keywords": ["ceremony"]})).unwrap(); + h.app.session.execute("keyword.useSet", &json!({"name": "Recent Keywords"})).unwrap(); + h.settle(SETTLE); + ask(&mut h, "ui.key", json!({"key": "0", "alt": true})); + assert_eq!(sets(&mut h)["current"], "Weddings", "⌥0: the next set"); + ask(&mut h, "ui.key", json!({"key": "1", "alt": true})); + let id = h.app.session.selected()[0]; + assert!(h.app.session.catalog.photo(id).unwrap().meta.keywords.iter().any(|k| k == "ceremony"), "⌥1 applied the set's keyword"); + ask(&mut h, "ui.key", json!({"key": "0", "alt": true, "shift": true})); + assert_eq!(sets(&mut h)["current"], "Recent Keywords", "⌥⇧0: the previous set"); +} diff --git a/docs/library-shortcuts.md b/docs/library-shortcuts.md index 81bc2cede..b78f68960 100644 --- a/docs/library-shortcuts.md +++ b/docs/library-shortcuts.md @@ -83,7 +83,18 @@ Survey and Reference, and leave text fields alone, so the search box still types 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): +## Keyword sets + +`⌥1`–`⌥9` (`Alt+1`–`Alt+9` on Windows and Linux) add or remove the current keyword set's keywords on +the selected photos. `⌥0` makes the next keyword set current and `⌥⇧0` the previous one (`Alt+0` / +`Alt+Shift+0`), in the order of the Keywords panel's Keyword Set menu: Recent Keywords, then the saved +sets. After the last set comes Recent Keywords again, and before Recent Keywords comes the last set; +with no saved sets the keys leave Recent Keywords current. The shortcut list does not say what happens +past either end; wrapping around is LightCraft's choice. The same steps are the Next / Previous +Keyword Set commands (`keyword.nextSet`, `keyword.previousSet`), which return what `keyword.sets` +returns, and both keys can be reassigned in Help → Keyboard Shortcuts. + +Public behavior references, checked 2026-10-08 (thumbnail size: 2026-10-13; keyword sets: 2026-10-24): - [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) diff --git a/docs/parity-checklist.md b/docs/parity-checklist.md index d059494ce..6091e9d60 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-24 · **Change:** minor (LRC-DEV-HISTOGRAM-DRAG: the histogram's five tonal zones — hover for the value, drag to adjust the Basic control the press locked, double-click to reset; LR-VIEW-HISTOGRAM note updated; MENU-BAR: on macOS a menu item that yields its key to a focused text field or to shortcut recording really lets it go; LR-MERGE-HDR / LR-MERGE-PANO: Lanczos-3 warps; LR-IMP-LOCAL: browsing from the sidebar records the folder; LR-VIEW-ZOOM: only a full-size drag within 20 ms clears a slow-drag verdict; LR-IMP-ADD-DIALOG: hierarchical import album destination reconciled with main, #2362; KEY-SLIDER-NUDGE: vertical wheel nudges need a click or drag in the row; leaving it disarms them; LR-EDIT-OPTICS-PROFILE: Fujifilm nine-knot lens tables read at the plain radius; LR-VIEW-ZOOM: only a full-size drag within 20 ms clears a slow-drag verdict; LRC-LIB-LIBFOLDERS, LR-BEHAV-BG-TASKS: Synchronize Folder's scan shows its folder listing and stops it on ✕; LRC-LIB-LIBFOLDERS: Synchronize Folder says a folder is up to date; LR-LIB-STACK: filmstrip stack badge click; LRC-LIB-REFVIEW / CATALOG-SWITCH: Escape preserves edits; catalog-local pins; deleted and malformed references refused; LRC-LIB-COMPARE: the Info panel labels the active photo while culling, #2398; KEYC-RATING: `\` shows / hides the Filter Bar in the grids; LR-VIEW-PHOTOGRID: the grid reads only the photos an import batch or an edit touched, not the whole list; earlier: LRC-PRINT-PAGE: Print Page Options; LR-META-XMP: fewer false unimported-XMP warnings) · **Target:** Adobe Lightroom Classic 15.5 / Lightroom 9.6 +> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-24 · **Change:** minor (KEYC-METADATA, LRC-LIB-KEYWORDS: ⌥0 / ⌥⇧0 go to the next / previous keyword set; LRC-DEV-HISTOGRAM-DRAG: the histogram's five tonal zones — hover for the value, drag to adjust the Basic control the press locked, double-click to reset; LR-VIEW-HISTOGRAM note updated; MENU-BAR: on macOS a menu item that yields its key to a focused text field or to shortcut recording really lets it go; LR-MERGE-HDR / LR-MERGE-PANO: Lanczos-3 warps; LR-IMP-LOCAL: browsing from the sidebar records the folder; LR-VIEW-ZOOM: only a full-size drag within 20 ms clears a slow-drag verdict; LR-IMP-ADD-DIALOG: hierarchical import album destination reconciled with main, #2362; KEY-SLIDER-NUDGE: vertical wheel nudges need a click or drag in the row; leaving it disarms them; LR-EDIT-OPTICS-PROFILE: Fujifilm nine-knot lens tables read at the plain radius; LR-VIEW-ZOOM: only a full-size drag within 20 ms clears a slow-drag verdict; LRC-LIB-LIBFOLDERS, LR-BEHAV-BG-TASKS: Synchronize Folder's scan shows its folder listing and stops it on ✕; LRC-LIB-LIBFOLDERS: Synchronize Folder says a folder is up to date; LR-LIB-STACK: filmstrip stack badge click; LRC-LIB-REFVIEW / CATALOG-SWITCH: Escape preserves edits; catalog-local pins; deleted and malformed references refused; LRC-LIB-COMPARE: the Info panel labels the active photo while culling, #2398; KEYC-RATING: `\` shows / hides the Filter Bar in the grids; LR-VIEW-PHOTOGRID: the grid reads only the photos an import batch or an edit touched, not the whole list; earlier: LRC-PRINT-PAGE: Print Page Options; LR-META-XMP: fewer false unimported-XMP warnings) · **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 @@ -711,7 +711,7 @@ From `08-lightroom-classic-extras.md` (Classic-only features) and part 2 of `06- | LRC-LIB-STACKS | Stacks (full) | P1 | ✅ | `crates/catalog/src/stacks.rs`, `cmd:stack.group`, `cmd:stack.split`, `cmd:stack.moveUp`, `cmd:stack.moveDown` | group / ungroup / toggle / set top / remove / auto by time / split / move up and down | | LRC-LIB-VC | Virtual copies | P1 | ✅ | `cmd:photo.virtualCopy` | ⌘' | | LRC-LIB-LABELS | Colour-label sets | P1 | ✅ | `cmd:label.sets`, `cmd:label.applySet`, `cmd:label.saveSet`, `cmd:label.deleteSet`, `cmd:label.setNames`, `crates/engine/src/cmd/manage.rs` | built-in Colors / Review sets + user sets (Photo ▸ Set Color Label, Edit Label Names… dialog); names written to and read from `xmp:Label` | -| LRC-LIB-KEYWORDS | Hierarchical keywords, sets, painter, Keyword List | P1 | ✅ | `crates/catalog/src/keywords.rs`, `crates/ui-egui/src/panels/keyword_list.rs`, `cmd:keyword.list`, `cmd:keyword.create`, `cmd:keyword.edit`, `cmd:keyword.move`, `cmd:keyword.info`, `cmd:keyword.purgeUnused`, `cmd:keyword.setDefaultParent`, `cmd:keyword.sets`, `cmd:keyword.toggleFromSet`, `cmd:keyword.saveSet`, `cmd:tool.keywordPainter` | hierarchical `a\|b\|c` keywords (tree, parent filters include children, rename moves children); keyword sets + Recent Keywords (⌥1–⌥9); keyword painter (Keywords panel ▸ Paint: click photos in the grid to toggle a keyword, Esc stops). Keyword List (Keywords panel): every keyword, those without photos too (a keyword list in the catalog, format version 4), with counts, a filter box, a tri-state tick box for the selection and an arrow to show its photos; + / Create Keyword Tag (name, synonyms, put inside, add to selected photos), double-click / Edit Keyword Tag, − / Delete with confirmation, context menu (create inside, Put New Keywords Inside This Keyword, purge unused keywords); drag a keyword onto another to nest it or onto the list's title for the top level (a merge asks first), drag photos onto a keyword to tag them. The list is there without a selection too; Put New Keywords Inside This Keyword (kept with the keyword in the library, undoable) also places new keywords typed in the Keywords panel. Keyword tag options include on export, export containing keywords and export synonyms shape exported files (names in `dc:subject`, paths in `lr:hierarchicalSubject`), and files' `lr:hierarchicalSubject` paths come back as keywords on import and from sidecars; Person is stored only. Keywording box (`crates/ui-egui/src/panels/keywording.rs`): the selection's keywords as chips (one only some selected photos have marked with an asterisk; × only removes, from every selected photo; with no selection, the active photo's), a Keywords / & Containing / Will Export switch (Lightroom Classic's Keyword Tags views: the keywords to edit, them with their parents, what exported files carry), keyword-set buttons and suggestions that follow the selection, shared text fields for typing and painting. Settings ▸ Interface ▸ Keywords of the selection ▸ Grouped by parent (`keywordChips: grouped` in the app settings; Whole names stays the default): keywords inside the same keyword share a line naming it (`keywordGroup:`: the deepest keyword a chip shares with another) and their chips say only what is below it, side by side; a list of more than ten lines stops after eight with “+N more” (`keywordChipsMore`, then `keywordChipsFewer`); the whole list is for the selection it was asked of, another selection's is short again, and the suggestions say the keyword's own name (its whole path when two share a name, and in the tooltip). The titles of Keywords and of the Keyword List fold their sections shut (`section:keywording`, `section:keywordList`; kept in the UI state as `foldedSections`), and a selection without keywords says “No keywords yet”. The Add keyword box offers the library's keywords for what is being typed (after the last comma) right under itself (`kwComplete:`, at most eight, those every selected photo has left out, a keyword spelled two ways once; above the box where the window has no room under it, and not at all while the box is scrolled out of the panel): ↓ / ↑ without Shift or Alt move through them (`kwCompleteAt:`; the highlight stays with its keyword when the library changes), Return or a click gives the highlighted one with the keywords typed before it and leaves the cursor in the box; with none highlighted Return gives what was typed, as before. A name the library doesn't have is announced as a new keyword, with the keyword it would go inside (`kwCompleteCreate`). The suggestions below no longer change while typing. A refused add says why and keeps the text. With several photos selected the box says how many its keywords are of (`keywordScope`); a chip's × is a target as tall as the chip and 22 pt wide that lights up on its own, and taking a keyword off several photos (× or the chip's menu) says which keyword, from how many photos, and that Edit ▸ Undo puts it back; a refused removal says why. Chips and their × show the keyboard focus. Edit Keyword Set (Keyword Set ▸ Edit Set…): a set's name and nine slots typed in place, empty slots kept so each keyword stays on its ⌥ key, a set renamed in place (`cmd:keyword.saveSet` `replace`) or saved as a new set (`new`, a taken name refused). File ▸ Import Keywords… / Export Keywords… (`cmd:keyword.import`, `cmd:keyword.export`): keyword list files in Lightroom Classic's format (tab-indented, `{synonym}`, `[left out of export]`), which Capture One, darktable, Bridge and Photo Supreme (its Formatted Vocabulary File) read and write too; import adds what is missing in one undo step, export names the keywords Capture One refuses (; , < >). Not yet: synonyms in search, person keywords tied to faces, Keyword Shortcut, IPTC keywords in exported files (Piwigo, RawTherapee), hierarchy from digiKam / ACDSee / Microsoft XMP fields. In the Keyword List a keyword's empty box carries a dot when the selected photos have a keyword inside it (its tooltip names them), so a folded keyword shows that something in it is applied | +| LRC-LIB-KEYWORDS | Hierarchical keywords, sets, painter, Keyword List | P1 | ✅ | `crates/catalog/src/keywords.rs`, `crates/ui-egui/src/panels/keyword_list.rs`, `cmd:keyword.list`, `cmd:keyword.create`, `cmd:keyword.edit`, `cmd:keyword.move`, `cmd:keyword.info`, `cmd:keyword.purgeUnused`, `cmd:keyword.setDefaultParent`, `cmd:keyword.sets`, `cmd:keyword.toggleFromSet`, `cmd:keyword.saveSet`, `cmd:keyword.nextSet`, `cmd:keyword.previousSet`, `cmd:tool.keywordPainter` | hierarchical `a\|b\|c` keywords (tree, parent filters include children, rename moves children); keyword sets + Recent Keywords (⌥1–⌥9; ⌥0 / ⌥⇧0 go to the next / previous set and wrap around at either end); keyword painter (Keywords panel ▸ Paint: click photos in the grid to toggle a keyword, Esc stops). Keyword List (Keywords panel): every keyword, those without photos too (a keyword list in the catalog, format version 4), with counts, a filter box, a tri-state tick box for the selection and an arrow to show its photos; + / Create Keyword Tag (name, synonyms, put inside, add to selected photos), double-click / Edit Keyword Tag, − / Delete with confirmation, context menu (create inside, Put New Keywords Inside This Keyword, purge unused keywords); drag a keyword onto another to nest it or onto the list's title for the top level (a merge asks first), drag photos onto a keyword to tag them. The list is there without a selection too; Put New Keywords Inside This Keyword (kept with the keyword in the library, undoable) also places new keywords typed in the Keywords panel. Keyword tag options include on export, export containing keywords and export synonyms shape exported files (names in `dc:subject`, paths in `lr:hierarchicalSubject`), and files' `lr:hierarchicalSubject` paths come back as keywords on import and from sidecars; Person is stored only. Keywording box (`crates/ui-egui/src/panels/keywording.rs`): the selection's keywords as chips (one only some selected photos have marked with an asterisk; × only removes, from every selected photo; with no selection, the active photo's), a Keywords / & Containing / Will Export switch (Lightroom Classic's Keyword Tags views: the keywords to edit, them with their parents, what exported files carry), keyword-set buttons and suggestions that follow the selection, shared text fields for typing and painting. Settings ▸ Interface ▸ Keywords of the selection ▸ Grouped by parent (`keywordChips: grouped` in the app settings; Whole names stays the default): keywords inside the same keyword share a line naming it (`keywordGroup:`: the deepest keyword a chip shares with another) and their chips say only what is below it, side by side; a list of more than ten lines stops after eight with “+N more” (`keywordChipsMore`, then `keywordChipsFewer`); the whole list is for the selection it was asked of, another selection's is short again, and the suggestions say the keyword's own name (its whole path when two share a name, and in the tooltip). The titles of Keywords and of the Keyword List fold their sections shut (`section:keywording`, `section:keywordList`; kept in the UI state as `foldedSections`), and a selection without keywords says “No keywords yet”. The Add keyword box offers the library's keywords for what is being typed (after the last comma) right under itself (`kwComplete:`, at most eight, those every selected photo has left out, a keyword spelled two ways once; above the box where the window has no room under it, and not at all while the box is scrolled out of the panel): ↓ / ↑ without Shift or Alt move through them (`kwCompleteAt:`; the highlight stays with its keyword when the library changes), Return or a click gives the highlighted one with the keywords typed before it and leaves the cursor in the box; with none highlighted Return gives what was typed, as before. A name the library doesn't have is announced as a new keyword, with the keyword it would go inside (`kwCompleteCreate`). The suggestions below no longer change while typing. A refused add says why and keeps the text. With several photos selected the box says how many its keywords are of (`keywordScope`); a chip's × is a target as tall as the chip and 22 pt wide that lights up on its own, and taking a keyword off several photos (× or the chip's menu) says which keyword, from how many photos, and that Edit ▸ Undo puts it back; a refused removal says why. Chips and their × show the keyboard focus. Edit Keyword Set (Keyword Set ▸ Edit Set…): a set's name and nine slots typed in place, empty slots kept so each keyword stays on its ⌥ key, a set renamed in place (`cmd:keyword.saveSet` `replace`) or saved as a new set (`new`, a taken name refused). File ▸ Import Keywords… / Export Keywords… (`cmd:keyword.import`, `cmd:keyword.export`): keyword list files in Lightroom Classic's format (tab-indented, `{synonym}`, `[left out of export]`), which Capture One, darktable, Bridge and Photo Supreme (its Formatted Vocabulary File) read and write too; import adds what is missing in one undo step, export names the keywords Capture One refuses (; , < >). Not yet: synonyms in search, person keywords tied to faces, Keyword Shortcut, IPTC keywords in exported files (Piwigo, RawTherapee), hierarchy from digiKam / ACDSee / Microsoft XMP fields. In the Keyword List a keyword's empty box carries a dot when the selected photos have a keyword inside it (its tooltip names them), so a folded keyword shows that something in it is applied | | LRC-LIB-METADATA | Metadata panel & presets | P1 | ✅ | `cmd:photo.setMeta`, `cmd:metadata.savePreset`, `cmd:metadata.applyPreset`, `cmd:metadata.presets`, `cmd:metadata.deletePreset`, `cmd:dialog.captureTime` | IPTC core, accessibility, place, capture-time edit; copyright status (unknown / copyrighted / public domain), rights usage terms and copyright info URL (`photo.setMeta` `copyrightStatus`, `usageTerms`, `copyrightUrl`; XMP Rights Management fields, kept by "copyright only" exports, a smart-album rule); metadata presets (Photo → Metadata Preset, Save Metadata Preset… from the active photo; applied on import from Settings) | | LRC-LIB-QUICKDEV | Quick develop | P2 | ✅ | `cmd:develop.quickAdjust`, `crates/ui-egui/src/panels/edit.rs` (`quick_develop`) | grid with several photos selected: Edit panel ▸ Quick Develop steps (exposure ⅓ / 1 stop, contrast, highlights, shadows, whites, blacks, clarity, vibrance, temperature) added to each photo's own value, one undo step | | LRC-LIB-PEOPLE | People view | P2 | 🟡 | `cmd:view.people`, `cmd:view.person`, `cmd:faces.person`, `cmd:faces.unnamed`, `cmd:faces.nameFaces`, `crates/ui-egui/src/panels/people.rs`, `crates/ui-egui/src/panels/person.rs`, `crates/ui-egui/src/panels/unnamed.rs`, `crates/engine/src/face_tiles.rs` | Named People cards (face close-up, the photo count on the picture, name) for the photos the active filters let through, with the filter chips shown above them, sized by the thumbnail slider. Below them the **Unnamed faces**: every face nobody has named as a cropped picture, look-alikes next to each other once recognition has looked at them, a suggested name on a face the named ones recognise; click or Shift-click to select, type a name, Enter names the whole group in one undo step. A click on a person opens their page: only cropped faces, then **More** (unnamed faces that look like them, best first; click to confirm one, × to hide for the session, or ↑ / hovered-or-focused A key to confirm all currently shown non-hidden suggestions at or above that face's score, including ties, in one undo step). Every face is shown by the detector's box where the scan has one, so faces are equally close. Until recognition is set up a line at the top offers the next step (Settings ▸ Faces, or Turn on), as does the loupe's name box. Face pictures of unedited raws are cut from the largest embedded preview (planned read: header and JPEG only, never the sensor data) when it holds at least ¾ of the tile's pixels across the face, else developed as before; all are kept in the thumbnail disk cache at 16 px size steps, so a later launch shows them without reading the originals (#1440, `docs/faces.md`). No clusters with separators between groups, no persistent reject, no merge of two people @@ -782,7 +782,7 @@ From `08-lightroom-classic-extras.md` (Classic-only features) and part 2 of `06- | 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`, `cmd:library.toggleFilters` | 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); ⌘L (Ctrl+L) Enable Filters puts the filter aside and brings it back as it was. Missing: Shift+P outside grids (Presets) | | 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-METADATA | Classic keyword/metadata keys (⌘K, ⌘S, ⌘⌥⇧C/V…) | P2 | 🟡 | `cmd:photo.saveMetadataToFile`, `cmd:keyword.toggleFromSet`, `cmd:keyword.nextSet`, `cmd:keyword.previousSet` | ⌘S saves metadata; ⌥1–⌥9 toggle the current keyword set's keywords, ⌥0 / ⌥⇧0 go to the next / previous set. Missing: ⌘⌥⇧C / ⌘⌥⇧V metadata copy/paste, the ⌘K, ⌘⇧K, ⌘⌥⇧K, ⇧K and ⌘⌥K keyword and painting keys, ⌘⌥⇧F Visual Search, ⇧O Edit Face name (⇧O cycles the crop overlay here), and the macOS-only ⌘: / ⌘; spelling and ⌘⌥T Character palette | | 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 | | KEYC-MODULE-OUTPUT | Book / slideshow / print / map / web keys | P2 | ⬜ | | modules not implemented | | KEYC-HELP | Classic help keys (⌘/, F1) | P2 | 🟡 | `cmd:app.shortcuts` | ⌘/ only | @@ -799,6 +799,7 @@ Latin stays upright. Advanced Japanese composition remains open. Regression cove | Date | Change | Summary | |---|---|---| +| 2026-10-24 | minor | KEYC-METADATA, LRC-LIB-KEYWORDS: ⌥0 / ⌥⇧0 (`keyword.nextSet`, `keyword.previousSet`) go to the next / previous keyword set; status counts unchanged (KEYC-METADATA stays 🟡) | | 2026-10-24 | patch | LR-LIB-RATING, LR-LIB-DELETE: a slider drag still open when a rating, flag or label takes the photo out of the view, or when the photo is deleted, ends as its own undo step before the selection moves on, as moving to the next photo does; LR-BEHAV-LOCALIZE lists all 18 languages; status unchanged | | 2026-10-24 | patch | Integration batch 43: Integrated main 98702b5c, preserving the new fail-closed GPS metadata check for Original export. Watermark geometry/orientation and HDR JPEG size-limit fixes remain in their shared helpers; no feature-count changes. | | 2026-10-23 | patch | Export integration: Integrated main 5ca49b3e, retaining Width & Height resizing, export format/bit-depth validation and batch panic cancellation alongside the existing watermark and HDR JPEG size-limit fixes. No feature-count changes. | diff --git a/docs/ui-parity.md b/docs/ui-parity.md index 16665f3d4..c50116634 100644 --- a/docs/ui-parity.md +++ b/docs/ui-parity.md @@ -1,6 +1,6 @@ # UI parity -> **Last reviewed:** 2026-10-11 · **Last updated:** 2026-10-23 · **Change:** minor (KEYC-RATING: ⌘L Enable Filters; context menus: a right-click elsewhere on the same widget moves its open menu instead of flashing it, issue #1877; Reference Escape, catalog-local pins and deleted-photo handling verified on Windows; KEYC-RATING: `\` shows / hides the Filter Bar in the grids; earlier: 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-11 · **Last updated:** 2026-10-24 · **Change:** minor (KEYC-METADATA: ⌥0 / ⌥⇧0 next / previous keyword set; KEYC-RATING: ⌘L Enable Filters; context menus: a right-click elsewhere on the same widget moves its open menu instead of flashing it, issue #1877; Reference Escape, catalog-local pins and deleted-photo handling verified on Windows; KEYC-RATING: `\` shows / hides the Filter Bar in the grids; earlier: 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 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 @@ -72,6 +72,8 @@ under the UI command that wraps it (a no-op error); the UI command now wins. **Library navigation keys (KEYC-COMPARE):** in Photo Grid and Square Grid, `Home` / `End` make the first / last photo of the view the active, selected one, and `Shift+Left` / `Shift+Right` add the previous / next photo of the view to the selection (the added photo becomes active; the keys never remove a photo from the selection, and do nothing at either end of the view). They wait in the other views, in the full-screen preview, while a text field or a dialog has the keyboard, and when you gave the key to a command; they are listed under Fixed keys in Help → Keyboard Shortcuts. `Cmd+O` (`Ctrl+O` on Windows and Linux) runs File → Open Library… ; View → Visualize HDR has no default key (`Shift+H` cycles the Tool Overlay, issue #224; `Cmd+Shift+H` stays the Histogram). Covered by `crates/ui-egui/src/tests_keymap.rs`; the macOS native menu path for `Cmd+O` is not exercised by the headless tests. +**Keyword sets (KEYC-METADATA):** `⌥0` / `⌥⇧0` (`Alt+0` / `Alt+Shift+0` on Windows and Linux) make the next / previous keyword set current (`keyword.nextSet`, `keyword.previousSet`), in the Keyword Set menu's order: Recent Keywords, then the saved sets. After the last set comes Recent Keywords, and before Recent Keywords comes the last set (not documented by Adobe, our choice). `⌥1`–`⌥9` then apply the new set's keywords. Both keys can be reassigned in Help → Keyboard Shortcuts. + **Still missing / broken:** - Tab / ⇧Tab (hide the side panels / all panels): Tab moves the keyboard focus here (accessibility), so it is not bound; F5 (hide the top panel) is not bound either. @@ -148,6 +150,7 @@ establish OS keyboard delivery or cross-platform acceptance. | Date | Change | Summary | |---|---|---| +| 2026-10-24 | minor | KEYC-METADATA: ⌥0 / ⌥⇧0 (Alt+0 / Alt+Shift+0) go to the next / previous keyword set, Recent Keywords first, wrapping around at either end | | 2026-10-15 | patch | Context menus: a right-click elsewhere on the same widget while its menu is open moves the menu to the pointer; before it flashed at the new spot and closed (issue #1877); every site uses `widgets::context_menu`; 70% unchanged | | 2026-10-23 | patch | KEYC-RATING: ⌘L / Ctrl+L (Library ▸ Enable Filters) switches the filter off and on, restoring it as it was | | 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 |