From 105dfa84d92e8464e3dd682ad57d48c83d6c66ec Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Sat, 24 Oct 2026 14:57:13 -0700 Subject: [PATCH] KEYC-METADATA: Cmd+Alt+K / Ctrl+Alt+K turns on keyword painting Lightroom Classic's keyboard shortcut page lists Command+Option+K (Ctrl+Alt+K on Windows) for Enable painting; LightCraft had no key for it, and painting started only from the Keywords panel's painter box (Paint, or Return in the box). Photo > Enable Painting (tool.enablePainting, Cmd+Alt+K) paints the keyword typed in the painter box. Pressed again while painting, it stops painting, as Esc does. With the box empty it opens the Keywords panel and asks for a keyword to paint. The painter box's text is kept in the UI state (keyword_painter_text) instead of egui's temporary data, so the command can read it, and the box shows the keyword that tool.keywordPainter paints. The command label and the new message have rows in every catalog. The KEYC-METADATA and LRC-LIB-KEYWORDS rows, docs/ui-parity.md and docs/library-shortcuts.md list the key. --- 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/menubar.rs | 1 + crates/ui-egui/src/menus.rs | 18 ++++++++++++++++++ crates/ui-egui/src/panels/right.rs | 5 ++--- crates/ui-egui/src/state.rs | 4 ++++ crates/ui-egui/src/tests_keywording.rs | 21 +++++++++++++++++++++ docs/library-shortcuts.md | 12 +++++++++++- docs/parity-checklist.md | 7 ++++--- docs/ui-parity.md | 5 ++++- 25 files changed, 99 insertions(+), 8 deletions(-) diff --git a/crates/ui-egui/locales/cs.json b/crates/ui-egui/locales/cs.json index 16095a43e..62793fb89 100644 --- a/crates/ui-egui/locales/cs.json +++ b/crates/ui-egui/locales/cs.json @@ -646,6 +646,7 @@ "Effects": "Efekty", "Empty Recently Deleted": "Vyprázdnit nedávno odstraněné", "Enable Lens Corrections": "Zapnout korekce objektivu", + "Enable Painting": "Zapnout nanášení", "Enable Profile Corrections": "Zapnout korekce podle profilu", "End Interaction": "Ukončit interakci", "English": "English", @@ -974,6 +975,7 @@ "Keyword Suggestions": "Návrhy klíčových slov", "Keyword Tag Options": "Možnosti značky klíčového slova", "Keyword to paint": "Klíčové slovo k nanášení", + "Type a keyword to paint in the Keywords panel": "Zadejte klíčové slovo k nanášení v panelu Klíčová slova", "Keywords": "Klíčová slova", "Keywords & People": "Klíčová slova a lidé", "Keywords (K)": "Klíčová slova (K)", diff --git a/crates/ui-egui/locales/de.json b/crates/ui-egui/locales/de.json index 679e3b00f..f579ad857 100644 --- a/crates/ui-egui/locales/de.json +++ b/crates/ui-egui/locales/de.json @@ -480,6 +480,7 @@ "Effects": "Effekte", "Empty Recently Deleted": "„Zuletzt gelöscht“ leeren", "Enable Lens Corrections": "Objektivkorrekturen aktivieren", + "Enable Painting": "Auftragen aktivieren", "Enable Profile Corrections": "Profilkorrekturen aktivieren", "End Interaction": "Interaktion beenden", "English": "English", @@ -764,6 +765,7 @@ "Keyword Sets": "Stichwortsätze", "Keyword Suggestions": "Stichwortvorschläge", "Keyword to paint": "Stichwort zum Auftragen", + "Type a keyword to paint in the Keywords panel": "Stichwort zum Auftragen im Bedienfeld Stichwörter eingeben", "Keywords": "Stichwörter", "Keywords (K)": "Stichwörter (K)", "Keywords you add appear here; ⌥1–⌥9 apply them.": "Hinzugefügte Stichwörter erscheinen hier; ⌥1–⌥9 wendet sie an.", diff --git a/crates/ui-egui/locales/es.json b/crates/ui-egui/locales/es.json index af22570ef..23c4c6960 100644 --- a/crates/ui-egui/locales/es.json +++ b/crates/ui-egui/locales/es.json @@ -472,6 +472,7 @@ "Effects": "Efectos", "Empty Recently Deleted": "Vaciar Eliminadas recientemente", "Enable Lens Corrections": "Activar correcciones de lente", + "Enable Painting": "Activar pintura", "Enable Profile Corrections": "Activar correcciones de perfil", "End Interaction": "Finalizar interacción", "English": "Inglés", @@ -765,6 +766,7 @@ "Keyword Sets": "Conjuntos de palabras clave", "Keyword Suggestions": "Sugerencias de palabras clave", "Keyword to paint": "Palabra clave para pintar", + "Type a keyword to paint in the Keywords panel": "Escribir una palabra clave para pintar en el panel Palabras clave", "Keywords": "Palabras clave", "Keywords (K)": "Palabras clave (K)", "Keywords you add appear here; ⌥1–⌥9 apply them.": "Las palabras clave añadidas aparecen aquí; ⌥1–⌥9 las aplican.", diff --git a/crates/ui-egui/locales/fi.json b/crates/ui-egui/locales/fi.json index 6456a6624..d6553c93b 100644 --- a/crates/ui-egui/locales/fi.json +++ b/crates/ui-egui/locales/fi.json @@ -609,6 +609,7 @@ "Effects": "Tehosteet", "Empty Recently Deleted": "Tyhjennä Äskettäin poistetut", "Enable Lens Corrections": "Ota objektiivikorjaukset käyttöön", + "Enable Painting": "Ota maalaus käyttöön", "Enable Profile Corrections": "Ota profiilikorjaukset käyttöön", "End": "Loppu", "End Interaction": "Lopeta vuorovaikutus", @@ -987,6 +988,7 @@ "Keyword Suggestions": "Avainsanaehdotukset", "Keyword Tag Options": "Avainsanatunnisteen asetukset", "Keyword to paint": "Maalattava avainsana", + "Type a keyword to paint in the Keywords panel": "Kirjoita maalattava avainsana Avainsanat-paneeliin", "Keywords": "Avainsanat", "Keywords & People": "Avainsanat ja henkilöt", "Keywords (K)": "Avainsanat (K)", diff --git a/crates/ui-egui/locales/fr.json b/crates/ui-egui/locales/fr.json index 33a892ecf..45bd7e4ed 100644 --- a/crates/ui-egui/locales/fr.json +++ b/crates/ui-egui/locales/fr.json @@ -450,6 +450,7 @@ "Effects": "Effets", "Empty Recently Deleted": "Vider Supprimées récemment", "Enable Lens Corrections": "Activer les corrections d'objectif", + "Enable Painting": "Activer le pinceau", "Enable Profile Corrections": "Activer les corrections de profil", "End Interaction": "Terminer l'interaction", "English": "Anglais", @@ -723,6 +724,7 @@ "Keyword Sets": "Jeux de mots-clés", "Keyword Suggestions": "Suggestions de mots-clés", "Keyword to paint": "Mot-clé à appliquer", + "Type a keyword to paint in the Keywords panel": "Saisissez un mot-clé à appliquer dans le panneau Mots-clés", "Keywords": "Mots-clés", "Keywords (K)": "Mots-clés (K)", "Keywords you add appear here; ⌥1–⌥9 apply them.": "Les mots-clés que vous ajoutez apparaissent ici ; ⌥1–⌥9 les appliquent.", diff --git a/crates/ui-egui/locales/id.json b/crates/ui-egui/locales/id.json index abb6a732e..c829beb5e 100644 --- a/crates/ui-egui/locales/id.json +++ b/crates/ui-egui/locales/id.json @@ -613,6 +613,7 @@ "Effects": "Efek", "Empty Recently Deleted": "Kosongkan Baru dihapus", "Enable Lens Corrections": "Aktifkan koreksi lensa", + "Enable Painting": "Aktifkan kuas", "Enable Profile Corrections": "Aktifkan koreksi profil", "End": "Akhir", "End Interaction": "Akhiri interaksi", @@ -990,6 +991,7 @@ "Keyword Suggestions": "Saran kata kunci", "Keyword Tag Options": "Opsi tag kata kunci", "Keyword to paint": "Kata kunci yang akan diterapkan", + "Type a keyword to paint in the Keywords panel": "Ketik kata kunci yang akan diterapkan di panel Kata kunci", "Keywords": "Kata kunci", "Keywords & People": "Kata kunci & orang", "Keywords (K)": "Kata kunci (K)", diff --git a/crates/ui-egui/locales/it.json b/crates/ui-egui/locales/it.json index a75448fbb..cfe0baf4f 100644 --- a/crates/ui-egui/locales/it.json +++ b/crates/ui-egui/locales/it.json @@ -451,6 +451,7 @@ "Effects": "Effetti", "Empty Recently Deleted": "Svuota Eliminate di recente", "Enable Lens Corrections": "Attiva correzioni obiettivo", + "Enable Painting": "Attiva pennello", "Enable Profile Corrections": "Attiva correzioni del profilo", "End Interaction": "Termina interazione", "English": "Inglese", @@ -725,6 +726,7 @@ "Keyword Sets": "Set di parole chiave", "Keyword Suggestions": "Suggerimenti di parole chiave", "Keyword to paint": "Parola chiave da applicare", + "Type a keyword to paint in the Keywords panel": "Digita una parola chiave da applicare nel pannello Parole chiave", "Keywords": "Parole chiave", "Keywords (K)": "Parole chiave (K)", "Keywords you add appear here; ⌥1–⌥9 apply them.": "Le parole chiave che aggiungi compaiono qui; ⌥1-⌥9 le applicano.", diff --git a/crates/ui-egui/locales/ja.json b/crates/ui-egui/locales/ja.json index c3f11e6e5..2dbd1591a 100644 --- a/crates/ui-egui/locales/ja.json +++ b/crates/ui-egui/locales/ja.json @@ -435,6 +435,7 @@ "Effects": "効果", "Empty Recently Deleted": "最近削除した写真を空にする", "Enable Lens Corrections": "レンズ補正を有効にする", + "Enable Painting": "キーワード付けを有効にする", "Enable Profile Corrections": "プロファイル補正を使用", "End Interaction": "操作を終了", "English": "English", @@ -860,6 +861,7 @@ "Keyword Sets": "キーワードセット", "Keyword Suggestions": "キーワード候補", "Keyword to paint": "写真に付けるキーワード", + "Type a keyword to paint in the Keywords panel": "キーワードパネルで写真に付けるキーワードを入力してください", "Keywords": "キーワード", "Keywords you add appear here; ⌥1–⌥9 apply them.": "追加したキーワードはここに表示されます(⌥1〜⌥9で適用)", "Landscape": "風景", diff --git a/crates/ui-egui/locales/ka.json b/crates/ui-egui/locales/ka.json index 13fd48d3c..7f0b36cca 100644 --- a/crates/ui-egui/locales/ka.json +++ b/crates/ui-egui/locales/ka.json @@ -681,6 +681,7 @@ "Effects": "ეფექტები", "Empty Recently Deleted": "ახლახან წაშლილის გასუფთავება", "Enable Lens Corrections": "ობიექტივის კორექციების ჩართვა", + "Enable Painting": "ფუნჯის ჩართვა", "Enable Profile Corrections": "პროფილის კორექციების ჩართვა", "End Interaction": "ურთიერთქმედების დასრულება", "English": "English", @@ -1065,6 +1066,7 @@ "Keyword sets": "საკვანძო სიტყვების ნაკრებები", "Keyword tag options decide what exported files carry: Include on Export, Export Containing Keywords, Export": "საკვანძო სიტყვის პარამეტრები განსაზღვრავს, რას შეიცავს ექსპორტირებული ფაილები: ექსპორტში ჩართვა, მშობელი საკვანძო სიტყვების ექსპორტი,", "Keyword to paint": "მისანიჭებელი საკვანძო სიტყვა", + "Type a keyword to paint in the Keywords panel": "აკრიფეთ მისანიჭებელი საკვანძო სიტყვა პანელში „საკვანძო სიტყვები“", "Keywording box": "საკვანძო სიტყვების ველი", "Keywords": "საკვანძო სიტყვები", "Keywords & People": "საკვანძო სიტყვები და ადამიანები", diff --git a/crates/ui-egui/locales/pl.json b/crates/ui-egui/locales/pl.json index f03a81762..2601a81b8 100644 --- a/crates/ui-egui/locales/pl.json +++ b/crates/ui-egui/locales/pl.json @@ -440,6 +440,7 @@ "Effects": "Efekty", "Empty Recently Deleted": "Opróżnij ostatnio usunięte", "Enable Lens Corrections": "Włącz korekcję obiektywu", + "Enable Painting": "Włącz pędzel", "Enable Profile Corrections": "Włącz korekcje profilu", "End Interaction": "Zakończ interakcję", "English": "Angielski", @@ -706,6 +707,7 @@ "Keyword Sets": "Zestawy słów kluczowych", "Keyword Suggestions": "Sugestie słów kluczowych", "Keyword to paint": "Słowo kluczowe do nanoszenia", + "Type a keyword to paint in the Keywords panel": "Wpisz słowo kluczowe do nanoszenia w panelu Słowa kluczowe", "Keywords": "Słowa kluczowe", "Keywords (K)": "Słowa kluczowe (K)", "Keywords you add appear here; ⌥1–⌥9 apply them.": "Dodane słowa kluczowe pojawiają się tutaj; skróty ⌥1–⌥9 przypisują je do zdjęć.", diff --git a/crates/ui-egui/locales/pt-br.json b/crates/ui-egui/locales/pt-br.json index 88e955d26..6f36f994d 100644 --- a/crates/ui-egui/locales/pt-br.json +++ b/crates/ui-egui/locales/pt-br.json @@ -458,6 +458,7 @@ "Effects": "Efeitos", "Empty Recently Deleted": "Esvaziar Excluídos recentemente", "Enable Lens Corrections": "Ativar correções de lente", + "Enable Painting": "Ativar pincel", "Enable Profile Corrections": "Ativar correções de perfil", "End Interaction": "Encerrar interação", "English": "Inglês", @@ -732,6 +733,7 @@ "Keyword Sets": "Conjuntos de palavras-chave", "Keyword Suggestions": "Sugestões de palavras-chave", "Keyword to paint": "Palavra-chave a pintar", + "Type a keyword to paint in the Keywords panel": "Digite uma palavra-chave a pintar no painel Palavras-chave", "Keywords": "Palavras-chave", "Keywords (K)": "Palavras-chave (K)", "Keywords you add appear here; ⌥1–⌥9 apply them.": "As palavras-chave que você adiciona aparecem aqui; ⌥1–⌥9 as aplicam.", diff --git a/crates/ui-egui/locales/ru.json b/crates/ui-egui/locales/ru.json index 5c8816c5e..3ae289c66 100644 --- a/crates/ui-egui/locales/ru.json +++ b/crates/ui-egui/locales/ru.json @@ -380,6 +380,7 @@ "Effect": "Эффект", "Effects": "Эффекты", "Enable Lens Corrections": "Включить коррекцию объектива", + "Enable Painting": "Включить кисть", "End Interaction": "Завершить взаимодействие", "English": "Английский", "Enter Full Screen": "Полноэкранный режим", @@ -610,6 +611,7 @@ "Keyword Sets": "Наборы ключевых слов", "Keyword Suggestions": "Подсказки ключевых слов", "Keyword to paint": "Ключевое слово для нанесения", + "Type a keyword to paint in the Keywords panel": "Введите ключевое слово для нанесения на панели «Ключевые слова»", "Keywords": "Ключевые слова", "Keywords (K)": "Ключевые слова (K)", "Keywords you add appear here; ⌥1–⌥9 apply them.": "Добавленные вами ключевые слова появятся здесь; ⌥1–⌥9 применяют их.", diff --git a/crates/ui-egui/locales/sv.json b/crates/ui-egui/locales/sv.json index d9af4b8e8..be3427445 100644 --- a/crates/ui-egui/locales/sv.json +++ b/crates/ui-egui/locales/sv.json @@ -662,6 +662,7 @@ "Effects": "Effekter", "Empty Recently Deleted": "Töm Nyligen raderade", "Enable Lens Corrections": "Aktivera linskorrigeringar", + "Enable Painting": "Aktivera målning", "Enable Profile Corrections": "Aktivera profilkorrigeringar", "End": "Slut", "End Interaction": "Avsluta interaktion", @@ -1088,6 +1089,7 @@ "Keyword Suggestions": "Nyckelordsförslag", "Keyword Tag Options": "Alternativ för nyckelordstaggar", "Keyword to paint": "Nyckelord att måla", + "Type a keyword to paint in the Keywords panel": "Skriv ett nyckelord att måla i panelen Nyckelord", "Keywords": "Nyckelord", "Keywords & People": "Nyckelord och människor", "Keywords (K)": "Nyckelord (K)", diff --git a/crates/ui-egui/locales/uk.json b/crates/ui-egui/locales/uk.json index 39090c0b3..d63e0c8ae 100644 --- a/crates/ui-egui/locales/uk.json +++ b/crates/ui-egui/locales/uk.json @@ -702,6 +702,7 @@ "Edited or not": "Відредаговано чи ні", "Empty Recently Deleted": "Очистити нещодавно видалені", "Enable Lens Corrections": "Увімкнути корекцію об’єктива", + "Enable Painting": "Увімкнути призначення", "Enable Profile Corrections": "Увімкнути корекцію профілю", "End Interaction": "Завершити взаємодію", "Enter Full Screen": "Увійти в повноекранний режим", @@ -1031,6 +1032,7 @@ "Keyword Sets": "Набори ключових слів", "Keyword Suggestions": "Пропозиції ключових слів", "Keyword to paint": "Ключове слово для призначення", + "Type a keyword to paint in the Keywords panel": "Введіть ключове слово для призначення на панелі «Ключові слова»", "Keywords you add appear here; ⌥1–⌥9 apply them.": "Додані ключові слова з’являються тут; ⌥1–⌥9 застосовують їх.", "Automatic renders the Detail view at the size it is shown, up to the photo's own pixels. Choose a size to cap it: smaller is faster.": "Автоматичний режим відтворює подання «Деталі» у відображуваному розмірі, до власних пікселів фото. Виберіть розмір для обмеження: менший працює швидше.", "Last view": "Останнє подання", diff --git a/crates/ui-egui/locales/vi.json b/crates/ui-egui/locales/vi.json index 98adc91b8..f46e364b9 100644 --- a/crates/ui-egui/locales/vi.json +++ b/crates/ui-egui/locales/vi.json @@ -570,6 +570,7 @@ "Effects": "Hiệu ứng", "Empty Recently Deleted": "Dọn Đã xóa gần đây", "Enable Lens Corrections": "Bật hiệu chỉnh ống kính", + "Enable Painting": "Bật cọ", "Enable Profile Corrections": "Bật hiệu chỉnh theo hồ sơ", "End Interaction": "Kết thúc tương tác", "English": "English", @@ -911,6 +912,7 @@ "Keyword Suggestions": "Gợi ý từ khóa", "Keyword Tag Options": "Tùy chọn thẻ từ khóa", "Keyword to paint": "Từ khóa để tô", + "Type a keyword to paint in the Keywords panel": "Nhập từ khóa để tô trong bảng Từ khóa", "Keywords": "Từ khóa", "Keywords & People": "Từ khóa và Người", "Keywords (K)": "Từ khóa (K)", diff --git a/crates/ui-egui/locales/zh-hans.json b/crates/ui-egui/locales/zh-hans.json index 73caf6407..8828560b3 100644 --- a/crates/ui-egui/locales/zh-hans.json +++ b/crates/ui-egui/locales/zh-hans.json @@ -455,6 +455,7 @@ "Effects": "效果", "Empty Recently Deleted": "清空“最近删除”", "Enable Lens Corrections": "启用镜头校正", + "Enable Painting": "启用画笔", "Enable Profile Corrections": "启用配置文件校正", "End Interaction": "结束交互", "English": "English", @@ -838,6 +839,7 @@ "Keyword Sets": "关键字集", "Keyword Suggestions": "关键字建议", "Keyword to paint": "要涂抹的关键字", + "Type a keyword to paint in the Keywords panel": "请在“关键字”面板中输入要涂抹的关键字", "Keywords": "关键字", "Keywords (K)": "关键字 (K)", "Keywords you add appear here; ⌥1–⌥9 apply them.": "您添加的关键字会显示在此处;按 ⌥1–⌥9 即可应用。", diff --git a/crates/ui-egui/locales/zh-hant.json b/crates/ui-egui/locales/zh-hant.json index 72cc3ab7f..adb8a7d5f 100644 --- a/crates/ui-egui/locales/zh-hant.json +++ b/crates/ui-egui/locales/zh-hant.json @@ -456,6 +456,7 @@ "Effects": "效果", "Empty Recently Deleted": "清空「最近刪除」", "Enable Lens Corrections": "啟用鏡頭校正", + "Enable Painting": "啟用筆刷", "Enable Profile Corrections": "啟用描述檔校正", "End Interaction": "結束互動", "English": "English", @@ -839,6 +840,7 @@ "Keyword Sets": "關鍵字集", "Keyword Suggestions": "關鍵字建議", "Keyword to paint": "要塗上的關鍵字", + "Type a keyword to paint in the Keywords panel": "請在「關鍵字」面板中輸入要塗上的關鍵字", "Keywords": "關鍵字", "Keywords (K)": "關鍵字(K)", "Keywords you add appear here; ⌥1–⌥9 apply them.": "新增的關鍵字會顯示於此;⌥1–⌥9 可套用。", diff --git a/crates/ui-egui/src/menubar.rs b/crates/ui-egui/src/menubar.rs index 30a3b474b..8e3c659e3 100644 --- a/crates/ui-egui/src/menubar.rs +++ b/crates/ui-egui/src/menubar.rs @@ -281,6 +281,7 @@ const LAYOUT: &[(&str, &[&str])] = &[ "dialog.rename", "dialog.captureTime", "photo.tagFromTracklog", + "tool.enablePainting", "---", "album.removePhotos", "photo.delete", diff --git a/crates/ui-egui/src/menus.rs b/crates/ui-egui/src/menus.rs index a162e6ca6..abeefdb69 100644 --- a/crates/ui-egui/src/menus.rs +++ b/crates/ui-egui/src/menus.rs @@ -198,6 +198,8 @@ pub const UI_COMMANDS: &[UiCommand] = &[ ("slideshow.end", "End Slideshow", None, ""), ("view.secondWindow", "Second Window", Some("Cmd+F11"), "Window"), ("tool.keywordPainter", "Keyword Painter", None, ""), + // paints the keyword in the Keywords panel's painter box, or stops painting + ("tool.enablePainting", "Enable Painting", Some("Cmd+Alt+K"), "Photo"), ("view.gridInfo", "Grid Info", None, ""), // {mode?: auto | light | dark}: Appearance Mode (cycles Auto, Light, Dark when omitted; the // top bar's appearance button). View ▸ Appearance lists the modes. @@ -486,10 +488,26 @@ pub fn run_ui_command(app: &mut LightcraftApp, id: &str, p: &Value) -> Option { + // stops painting; otherwise paints the painter box's keyword, and with the box empty + // shows the Keywords panel to type one in + let k = app.ui.keyword_painter_text.trim().to_string(); + if app.ui.keyword_painter.is_some() { + app.ui.keyword_painter = None; + Ok(json!({"keyword": null})) + } else if k.is_empty() { + app.ui.right = RightPanel::Keywords; + app.toast(&ctx, crate::i18n::tr("Type a keyword to paint in the Keywords panel")); + Ok(json!({"keyword": null})) + } else { + run_ui_command(app, "tool.keywordPainter", &json!({"keyword": k})).unwrap_or(Ok(Value::Null)) + } + } "view.secondWindow" => { app.ui.second_window = p.get("show").and_then(Value::as_bool).unwrap_or(!app.ui.second_window); Ok(json!({"show": app.ui.second_window})) diff --git a/crates/ui-egui/src/panels/right.rs b/crates/ui-egui/src/panels/right.rs index a29534be3..75b04e411 100644 --- a/crates/ui-egui/src/panels/right.rs +++ b/crates/ui-egui/src/panels/right.rs @@ -1081,9 +1081,8 @@ fn keywording(app: &mut LightcraftApp, ui: &mut egui::Ui) { ui.add_space(8.0); // the painter: click photos in the grid to give them (or take away) a keyword ui.horizontal(|ui| { - let pid = egui::Id::new("kw-painter"); let painting = app.ui.keyword_painter.clone(); - let mut k: String = ui.data(|d| d.get_temp(pid)).unwrap_or_else(|| painting.clone().unwrap_or_default()); + let mut k = app.ui.keyword_painter_text.clone(); // (fixed while painting: Stop first) let field = ui .add_enabled_ui(painting.is_none(), |ui| { @@ -1093,7 +1092,7 @@ fn keywording(app: &mut LightcraftApp, ui: &mut egui::Ui) { .show(ui) }) .inner; - ui.data_mut(|d| d.insert_temp(pid, k.clone())); + app.ui.keyword_painter_text = k.clone(); let label = if painting.is_some() { "Stop" } else { "Paint" }; let returned = field.ending == Some(crate::text_field::Ending::Return) && painting.is_none() && !k.trim().is_empty(); if text_button(ui, "keywordPaint", label, painting.is_some()) diff --git a/crates/ui-egui/src/state.rs b/crates/ui-egui/src/state.rs index 53d5b8718..05b1993ed 100644 --- a/crates/ui-egui/src/state.rs +++ b/crates/ui-egui/src/state.rs @@ -999,6 +999,9 @@ pub struct UiState { /// The keyword painter: clicking a photo in the grid toggles this keyword on it. #[serde(skip)] pub keyword_painter: Option, + /// The text of the Keywords panel's painter box: the keyword Enable Painting paints. + #[serde(skip)] + pub keyword_painter_text: String, /// What the Keywording box shows (Lightroom Classic's Keyword Tags views). pub keywording_view: KeywordingView, /// The Keywording box, grouped: every keyword of this selection (its hash) is shown, however @@ -1548,6 +1551,7 @@ impl Default for UiState { slideshow: None, second_window: false, keyword_painter: None, + keyword_painter_text: String::new(), keywording_view: KeywordingView::default(), keyword_chips_all: None, folded_sections: Vec::new(), diff --git a/crates/ui-egui/src/tests_keywording.rs b/crates/ui-egui/src/tests_keywording.rs index 076f25789..ddc53add9 100644 --- a/crates/ui-egui/src/tests_keywording.rs +++ b/crates/ui-egui/src/tests_keywording.rs @@ -147,6 +147,27 @@ fn the_painters_field_pastes_and_return_paints() { assert_eq!(h.app.ui.keyword_painter.as_deref(), Some("Weddings")); } +/// ⌘⌥K (Ctrl+Alt+K) is Enable Painting: with the painter's box empty it shows the Keywords panel to +/// type a keyword in, with a keyword in the box it paints that keyword, and pressed again it stops. +#[test] +fn cmd_alt_k_paints_the_painters_keyword_and_stops() { + let (mut h, _) = two_selected(); + let key = json!({"key": "K", "cmd": true, "alt": true}); + ask(&mut h, "ui.set", json!({"right": "none"})); + ask(&mut h, "ui.key", key.clone()); + assert_eq!(h.app.ui.right, crate::state::RightPanel::Keywords, "an empty box: the Keywords panel"); + assert!(h.app.ui.keyword_painter.is_none(), "nothing to paint yet"); + h.view.clipboard = "Weddings".into(); + ask(&mut h, "ui.clickWidget", json!({"id": "field:keywordPainter", "button": "right"})); + ask(&mut h, "ui.clickWidget", json!({"id": "field:keywordPainter:paste"})); + ask(&mut h, "ui.clickWidget", json!({"id": "keywordView:keywords"})); + ask(&mut h, "ui.key", key.clone()); + assert_eq!(h.app.ui.keyword_painter.as_deref(), Some("Weddings"), "the box's keyword"); + ask(&mut h, "ui.key", key); + assert!(h.app.ui.keyword_painter.is_none(), "pressed again: painting stops"); + assert_eq!(h.app.ui.keyword_painter_text, "Weddings", "the box keeps the keyword"); +} + /// Suggestions follow the selection: a keyword only some selected photos have is suggested, to give /// it to all of them; one every selected photo has isn't. #[test] diff --git a/docs/library-shortcuts.md b/docs/library-shortcuts.md index 81bc2cede..7a6ef6fe9 100644 --- a/docs/library-shortcuts.md +++ b/docs/library-shortcuts.md @@ -18,6 +18,7 @@ Select photos in Photo Grid or Square Grid, then use: | `Shift` + `0`–`9`, `P`, `X` or `U` | Apply the action and select the next photo | | `\` (backslash) | Show / hide the Filter Bar | | ⌘L / Ctrl+L | Enable Filters: switch the filter off and on | +| ⌘⌥K / Ctrl+Alt+K | Enable Painting: paint the painter box's keyword, or stop painting | 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. @@ -83,7 +84,16 @@ 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 painter + +`⌘⌥K` (`Ctrl+Alt+K` on Windows and Linux) is Photo ▸ Enable Painting (`tool.enablePainting`). It +paints the keyword typed in the Keywords panel's painter box: LightCraft shows the grid, and a click on a +photo there adds the keyword or takes it off. Pressed again while painting, the key stops painting, as `Esc` does. +With the box empty, the key opens the Keywords panel and asks for a keyword to paint. The shortcut list +names the key only; stopping on a second press and opening the panel are LightCraft's choice. The key +can be reassigned in Help → Keyboard Shortcuts. + +Public behavior references, checked 2026-10-08 (thumbnail size: 2026-10-13; keyword painter: 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..86386e363 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: ⌘⌥K / Ctrl+Alt+K Enable Painting; 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:tool.keywordPainter`, `cmd:tool.enablePainting` | 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; Photo ▸ Enable Painting, ⌘⌥K / Ctrl+Alt+K, paints the painter box's keyword, stops painting when pressed again, and with the box empty opens the Keywords panel). 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:tool.enablePainting` | ⌘S saves metadata; ⌘⌥K (Ctrl+Alt+K) Enable Painting paints the keyword in the Keywords panel's painter box, or stops painting; 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 | | 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: ⌘⌥K / Ctrl+Alt+K (`tool.enablePainting`, Photo ▸ Enable Painting) paints the painter box's keyword or stops painting; 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..135a6d12d 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: ⌘⌥K Enable Painting; 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 painter key (KEYC-METADATA):** `⌘⌥K` (`Ctrl+Alt+K` on Windows and Linux) is Photo → Enable Painting (`tool.enablePainting`): it paints the keyword in the Keywords panel's painter box, a second press stops painting, and with the box empty it opens the Keywords panel (the shortcut list does not say what a second press or an empty box does; stopping and opening the panel are LightCraft's choice). Covered by `crates/ui-egui/src/tests_keywording.rs`. + **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: ⌘⌥K / Ctrl+Alt+K (Photo ▸ Enable Painting) paints the painter box's keyword, stops painting when pressed again, and with the box empty opens the Keywords panel | | 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 |