Browse / github.com/storytold/lightcraft / patch
MENU-HELP-HELP: on macOS Check for Updates… is in the app menu, and Help opens with LightCraft Help (⇧⌘?)
MENU-HELP-HELP: on macOS Check for Updates… is in the app menu, and Help opens with LightCraft Help (⇧⌘?) Off `main`. ## Problem The app menu and Help don't follow macOS conventions, as the macOS integration critique of 27 Oct found: - Check for Updates… is in Help; on a Mac it belongs in the app menu right under About LightCraft. - Help opens with Join the ArtCraft Discord…. LightCraft Help isn't listed in the layout at all, so it lands last, after About, and the sample-library and Debug rows follow it. - LightCraft Help is bound to F1 alone, which needs the fn key on a Mac keyboard. ## Change - **Check for Updates… (macOS).** A new pure `native_menu_split` (`crates/ui-egui/src/menus/menubar
- Status
- open
- Score
- 0.00
- Adopters
- 0 other operators
- Author
- nledford (imported from pull request #3202, open)
- Base
07bc2008d9457603bb77f6b3de33a901db75a8c4- Size
- +135 −20 in 7 files
- Review
- pending
- Shared
- 2026-10-28
- Id
19dc3826efdbc8b5b56ebece
How it went
No other operator has reported using it yet.
Diff
raw · apps/lightcraft/src/native_menu.rs crates/ui-egui/src/dialogs/updates_ui.rs crates/ui-egui/src/menus/menubar.rs crates/ui-egui/src/menus/menubar/tests.rs crates/ui-egui/src/menus/ui_commands.rs docs/parity-checklist.md docs/whats-new.md
@@ -22,7 +22,7 @@ use std::sync::mpsc::{Receiver, channel}; use lightcraft_ui_egui::LightcraftApp; use lightcraft_ui_egui::menubar::{- MenuNode, menu_bar, native_item_presentation, native_menu_delivers as menu_delivers, native_menu_structure as structure_of,+ MenuNode, menu_bar, native_item_presentation, native_menu_delivers as menu_delivers, native_menu_split, native_menu_structure as structure_of, }; use muda::accelerator::{Accelerator, Code, Modifiers}; use muda::{CheckMenuItem, Menu, MenuEvent, MenuItem, PredefinedMenuItem, Submenu};@@ -331,6 +331,7 @@ impl NativeMenu { fn rebuild(&mut self, app: &mut LightcraftApp) { let bar = menu_bar(app); self.structure = structure_of(&bar, &app.ui.settings.keymap);+ let (app_rows, menus) = native_menu_split(bar); self.menu = Menu::new(); self.items.clear(); self.app_items.clear();@@ -340,8 +341,11 @@ impl NativeMenu { let about = MenuItem::with_id("app.about", lightcraft_ui_egui::i18n::tr("About LightCraft"), true, None); let settings = MenuItem::with_id(SETTINGS, lightcraft_ui_egui::i18n::tr("Settings…"), true, accelerator(SETTINGS_KEY)); let quit = MenuItem::with_id(QUIT, lightcraft_ui_egui::i18n::tr("Quit LightCraft"), true, accelerator("Cmd+Q"));+ let _ = app_menu.append(&about);+ // Check for Updates… follows About LightCraft (Help keeps it on other platforms)+ let update_rows: Vec<MenuNode> = app_rows.into_iter().filter(|n| !matches!(n, MenuNode::Item { id, .. } if id == "app.about")).collect();+ self.append_nodes(&app_menu, &update_rows, &app.ui.settings.keymap, true); let _ = app_menu.append_items(&[- &about, &PredefinedMenuItem::separator(), &settings, &PredefinedMenuItem::separator(),@@ -371,7 +375,7 @@ impl NativeMenu { } let _ = self.menu.append(&app_menu); - for (title, nodes) in &bar {+ for (title, nodes) in &menus { let sub = Submenu::new(label_text(title), true); if title == "Window" { let _ = sub.append_items(&[@@ -380,13 +384,7 @@ impl NativeMenu { &PredefinedMenuItem::separator(), ]); }- // About and Settings live in the app menu on macOS- let nodes: Vec<MenuNode> = nodes- .iter()- .filter(|n| !matches!(n, MenuNode::Item { id, .. } if id == "app.about" || id == SETTINGS || id == QUIT))- .cloned()- .collect();- let nodes = tidy_separators(nodes);+ let nodes = tidy_separators(nodes.clone()); // Swapping an item in the Help menu leaves the old row in place and adds a second one // (measured on macOS 27 with muda 0.21): the Help menu is not addressed row for row. self.append_nodes(&sub, &nodes, &app.ui.settings.keymap, title != "Help");@@ -103,7 +103,8 @@ pub(crate) fn show(app: &mut LightcraftApp, ctx: &egui::Context) { Action::Close => ctx.send_viewport_cmd(egui::ViewportCommand::Close), Action::None => {} }- // The window answers Help ▸ Check for Updates, so it follows the updater's status.+ // The window answers Check for Updates (Help, or the LightCraft menu on macOS), so it follows the+ // updater's status. let rt = &mut app.updates_rt; (rt.manual_window_open, rt.status_message) = match rt.updater.status() { Status::Idle => (false, None),@@ -117,6 +117,38 @@ pub fn native_menu_structure(bar: &[(String, Vec<MenuNode>)], keymap: &crate::sh s } +/// The rows macOS puts in the application menu, in order (About LightCraft, then Check for+/// Updates…). The in-window bar (Windows, Linux, web) keeps them at the end of Help.+const APP_MENU_ROWS: &[&str] = &["app.about", "app.checkForUpdates"];++/// Rows the desktop host builds itself in the application menu (Settings…, Quit).+const HOST_APP_MENU_ROWS: &[&str] = &["app.settings", "app.quit"];++/// The macOS split of the bar: the application menu's rows from [`APP_MENU_ROWS`] in that order,+/// and the other menus without them and without the host's own rows.+pub fn native_menu_split(bar: Vec<(String, Vec<MenuNode>)>) -> (Vec<MenuNode>, Vec<(String, Vec<MenuNode>)>) {+ let mut app_rows: Vec<MenuNode> = Vec::new();+ let menus = bar+ .into_iter()+ .map(|(title, nodes)| {+ let mut rest = Vec::with_capacity(nodes.len());+ for node in nodes {+ match &node {+ MenuNode::Item { id, .. } if APP_MENU_ROWS.contains(&id.as_str()) => app_rows.push(node),+ MenuNode::Item { id, .. } if HOST_APP_MENU_ROWS.contains(&id.as_str()) => {}+ _ => rest.push(node),+ }+ }+ (title, rest)+ })+ .collect();+ app_rows.sort_by_key(|n| match n {+ MenuNode::Item { id, .. } => APP_MENU_ROWS.iter().position(|r| r == id),+ _ => None,+ });+ (app_rows, menus)+}+ /// Top-level menus in order (the macOS app menu is added by the host). pub const MENUS: &[&str] = &["File", "Edit", "View", "Photo", "Window", "Help"]; @@ -310,17 +342,21 @@ const LAYOUT: &[(&str, &[&str])] = &[ ( "Help", &[- "app.discord",+ "app.help",+ "---",+ "app.whatsNew",+ "app.shortcuts",+ "---", "app.feedback",+ "app.discord", "---", "app.website", "app.github", "app.artcraft", "---",- "app.whatsNew",- "app.shortcuts", "app.systemInfo", "app.openLogFolder",+ "@Debug", "---", "app.checkForUpdates", "app.about",@@ -823,3 +823,72 @@ fn no_two_menu_commands_share_a_label() { } assert!(clashes.is_empty(), "{clashes:#?}"); }++/// The ids of a menu's top-level rows, a submenu as `@Label`, separators left out.+fn row_ids(nodes: &[MenuNode]) -> Vec<String> {+ nodes+ .iter()+ .filter_map(|n| match n {+ MenuNode::Item { id, .. } => Some(id.clone()),+ MenuNode::Submenu { label, .. } => Some(format!("@{label}")),+ MenuNode::Separator => None,+ })+ .collect()+}++fn menu<'a>(bar: &'a [(String, Vec<MenuNode>)], title: &str) -> &'a [MenuNode] {+ &bar.iter().find(|(t, _)| t == title).unwrap_or_else(|| panic!("{title} menu")).1+}++/// macOS puts Check for Updates… in the application menu, right after About LightCraft.+#[test]+fn macos_app_menu_holds_about_then_check_for_updates() {+ let (app_rows, menus) = native_menu_split(menu_bar(&app()));+ assert_eq!(row_ids(&app_rows), ["app.about", "app.checkForUpdates"]);+ let help = row_ids(menu(&menus, "Help"));+ assert!(!help.contains(&"app.checkForUpdates".to_string()) && !help.contains(&"app.about".to_string()), "{help:?}");+ // the rows the host builds itself stay out of the menus too+ for (title, nodes) in &menus {+ assert!(find(nodes, "app.settings").is_none() && find(nodes, "app.quit").is_none(), "{title}");+ }+}++/// Windows, Linux and the web keep Check for Updates… in Help, last before About.+#[test]+fn in_window_help_keeps_check_for_updates_before_about() {+ let help = row_ids(menu(&menu_bar(&app()), "Help"));+ assert_eq!(&help[help.len() - 2..], ["app.checkForUpdates", "app.about"], "{help:?}");+}++/// Help reads like a Mac Help menu: the help page, what's new and the shortcuts first, then+/// feedback and the community, the websites, and the diagnostics last.+#[test]+fn help_menu_leads_with_help_then_whats_new_and_the_shortcuts() {+ let help = row_ids(menu(&menu_bar(&app()), "Help"));+ assert_eq!(+ help,+ [+ "app.help",+ "app.whatsNew",+ "app.shortcuts",+ "app.feedback",+ "app.discord",+ "app.website",+ "app.github",+ "app.artcraft",+ "app.systemInfo",+ "app.openLogFolder",+ "@Debug",+ "app.checkForUpdates",+ "app.about",+ ]+ );+}++/// LightCraft Help is ⇧⌘? on macOS (a function key needs fn on a Mac keyboard) and F1 elsewhere.+#[test]+fn help_shortcut_is_the_mac_one_on_macos_and_f1_elsewhere() {+ let keymap = crate::shortcuts::Keymap::new();+ let want = if cfg!(target_os = "macos") { "Cmd+Shift+/" } else { "F1" };+ assert_eq!(crate::shortcuts::shortcut_of(&keymap, "app.help"), Some(want));+}@@ -57,6 +57,9 @@ pub fn language_from_command(id: &str) -> Option<crate::i18n::Locale> { } } +/// LightCraft Help's shortcut: ⇧⌘? on macOS, where F1 needs the fn key, and F1 elsewhere.+const HELP_SHORTCUT: &str = if cfg!(target_os = "macos") { "Cmd+Shift+/" } else { "F1" };+ pub const UI_COMMANDS: &[UiCommand] = &[ ("ui.dock", "Arrange Panel", None, ""), ("ui.dock.reset", "Reset Panel Layout", None, "Window"),@@ -259,7 +262,7 @@ pub const UI_COMMANDS: &[UiCommand] = &[ ("view.frameRate", "Frame Rate", None, "Help>Debug"), ("app.whatsNew", "What's New", None, "Help"), ("dialog.cull", "Assisted Culling…", None, "Photo"),- ("app.help", "LightCraft Help", Some("F1"), "Help"),+ ("app.help", "LightCraft Help", Some(HELP_SHORTCUT), "Help"), ("app.discord", "Join the ArtCraft Discord…", None, "Help"), ("app.feedback", "Send Feedback…", None, "Help"), ("app.website", "LightCraft Website", None, "Help"),@@ -1,6 +1,6 @@ # Lightroom parity checklist -> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-10-25 · **Change:** minor (LR-BEHAV-TITLEBAR: a double-click follows the system setting, and a panel over the bar keeps the window still; 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; KEYC-METADATA: ⌘K / Ctrl+K Add Keywords; 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-27 · **Change:** minor (MENU-APP-ABOUT, MENU-HELP-HELP, KEY-HELP, KEYC-HELP: on macOS Check for Updates… sits in the app menu under About LightCraft, Help opens with LightCraft Help and is ⇧⌘? ; LR-BEHAV-TITLEBAR: a double-click follows the system setting, and a panel over the bar keeps the window still; 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; KEYC-METADATA: ⌘K / Ctrl+K Add Keywords; 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@@ -495,7 +495,7 @@ visible menu bar yet: the menu model is only exposed through the control channel | Id | Feature | Tier | Status | Evidence | Missing / notes | |---|---|---|---|---|---| | MENU-BAR | Menu bar rendering | P1 | ✅ | `crates/ui-egui/src/menus/menubar.rs`, `apps/lightcraft/src/native_menu.rs` | native macOS menu bar (muda) with live labels/enabled/checked; in-window menus on web/Windows/Linux (with one menu open, the pointer on another title switches to it, as in native menu bars); ⌫ and X stay egui-handled (contextual), so they show no key in the native menu; a scrolled menu draws no scrollbar over its rows: the ▲ / ▼ strips, the wheel and dragging scroll it (issue #691: egui's floating bar hid the shortcut text's last character; `crates/ui-egui/src/tests/menubar.rs`) |-| MENU-APP-ABOUT | About | P2 | ✅ | `cmd:app.about` | |+| MENU-APP-ABOUT | About | P2 | ✅ | `cmd:app.about` | macOS: first row of the app menu, Check for Updates… right under it; elsewhere the last rows of Help | | MENU-APP-SETTINGS | Settings… | P0 | ✅ | `cmd:app.settings` | app menu on macOS, Edit menu elsewhere | | MENU-APP-UPDATES | Check for updates | P2 | ⬜ | | | | MENU-APP-SYNC | Sync status / pause | OOS | 🚫 | | |@@ -576,7 +576,7 @@ visible menu bar yet: the menu model is only exposed through the control channel | MENU-WINDOW-MINIMIZE | Minimize / zoom | P1 | ✅ | `apps/lightcraft/src/native_menu.rs` | the system's Minimize (⌘M) and Zoom items at the top of Window | | MENU-WINDOW-PANELS | Panel switches | P0 | ✅ | `cmd:panel.edit`, `cmd:panel.crop`, `cmd:panel.remove`, `cmd:panel.masking`, `cmd:panel.presets`, `cmd:panel.versions` | | | MENU-WINDOW-BRINGFRONT | Bring all to front | P2 | ✅ | `apps/lightcraft/src/native_menu.rs` | the system's item at the end of Window |-| MENU-HELP-HELP | Help | P2 | ✅ | `cmd:app.help` | opens the documentation |+| MENU-HELP-HELP | Help | P2 | ✅ | `cmd:app.help` | opens the documentation; first row of Help, ⇧⌘? on macOS (⇧⌘/ on the key), F1 elsewhere; Help then lists What's New and Keyboard Shortcuts, feedback and community, the websites, and the diagnostics (System Info…, Open Log Folder, Debug) | | MENU-HELP-TUTORIALS | Tutorials | OOS | 🚫 | | | | MENU-HELP-WHATSNEW | What's new | P2 | ✅ | `cmd:app.whatsNew` | | | MENU-HELP-SHORTCUTS | Keyboard shortcuts | P1 | ✅ | `cmd:app.shortcuts` | |@@ -678,7 +678,7 @@ From `06-shortcuts.md` part 1. Evidence is our binding; conflicts are explained | KEY-SLIDER-TYPE | Type a slider value | P1 | ✅ | `crates/ui-egui/src/widgets.rs` (`typed_value`), `crates/ui-egui/src/widgets/text_field.rs`, `crates/ui-egui/src/widgets/tests_numeric_entry.rs` (`opening_release_honors_return_and_escape_immediately`, `a_long_click_keeps_the_field_open`), `crates/ui-egui/src/tests/keymap.rs` (`opening_numeric_release_keeps_keys_in_the_editor`) | click the value next to any slider's name and type one (`1.5`, `+0,25`, `-20`, `5600 K`): Return or clicking away applies it on the control's steps and range as one undo step, Esc keeps the old value; issue #322; Return/Escape take effect on the opening release, retaining the stored value on Escape; typing stays in the editor without triggering global shortcuts; the field stays open however long the click is held (a release over the value keeps it, issue #1435) | | KEY-SLIDER-SCRUB | Scrub a slider value — drag the number | P1 | ✅ | `crates/ui-egui/src/widgets.rs` (`slider`, `SCRUB_START`), `crates/ui-egui/src/widgets/tests_numeric_entry.rs` (`dragging_the_value_sideways_scrubs_it_like_the_thumb`, `scrubbing_back_and_with_shift`, `a_press_that_barely_moves_still_types`) | drag the value next to any slider's name sideways: it moves as dragging the thumb would (the pointer's travel over the track's width, ⇧ a tenth as far), on the control's steps and range, as one undo step; a press that moves less than 3 points sideways stays a click that types a value (KEY-SLIDER-TYPE); the pointer over the value is the horizontal-resize cursor, as Lightroom's scrubby value | | KEY-SHORTCUTS | Shortcut list — ⌘/ | P1 | ✅ | `cmd:app.shortcuts` | |-| KEY-HELP | Help — F1 | P2 | ✅ | `cmd:app.help` | |+| KEY-HELP | Help — F1 (⇧⌘? on macOS) | P2 | ✅ | `cmd:app.help` | F1 needs the fn key on a Mac keyboard, so macOS binds ⇧⌘? (`Cmd+Shift+/`) instead; F1 stays on Windows and Linux | | KEY-VIDEO-PLAY | Play/pause video — Space | P1 | ⬜ | | | | KEY-ESC | Leave tool / view — Esc | P0 | ✅ | `cmd:view.back`, `crates/ui-egui/src/icons.rs` (`navigation_arrowheads_have_both_halves`), `crates/ui-egui/src/tests/crop_tool.rs` | top-bar navigation arrowheads render both halves at 1× and 2× scale; in the crop tool Esc closes the tool first (the crop stays), the next Esc goes back to the grid; Esc that ends an edit in a text field does nothing else | | KEY-COMMIT | Commit tool — Return | P1 | ✅ | `cmd:tool.done` | Return closes Crop / Remove / Red Eye / Masking back to Edit (edits apply live, as in Lightroom) |@@ -785,7 +785,7 @@ From `08-lightroom-classic-extras.md` (Classic-only features) and part 2 of `06- | KEYC-METADATA | Classic keyword/metadata keys (⌘K, ⌘S, ⌘⌥⇧C/V…) | P2 | 🟡 | `cmd:photo.saveMetadataToFile`, `cmd:photo.copyMetadata`, `cmd:photo.pasteMetadata`, `cmd:panel.addKeywords`, `cmd:keyword.toggleFromSet`, `cmd:keyword.nextSet`, `cmd:keyword.previousSet`, `crates/ui-egui/src/tests/keymap.rs` (`cmd_alt_shift_c_and_v_copy_and_paste_metadata`) | ⌘S saves metadata; ⌘⌥⇧C / ⌘⌥⇧V (Ctrl+Alt+Shift+C / V on Windows/Linux) copy the active photo's metadata and paste it on the selection; ⌘K (Ctrl+K) Add Keywords shows the Keywords panel with the cursor in its Add keyword box; ⌥1–⌥9 toggle the current keyword set's keywords, ⌥0 / ⌥⇧0 go to the next / previous set. Missing: ⌘⇧K, ⌘⌥⇧K, ⇧K, ⌘⌥K painting, ⌘⌥⇧F Visual Search, ⇧O Edit Face name (⇧O cycles the crop overlay here, and the mask overlay color while masking), 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 |+| KEYC-HELP | Classic help keys (⌘/, F1) | P2 | 🟡 | `cmd:app.shortcuts` | ⌘/ opens Keyboard Shortcuts; ⇧⌘? opens LightCraft Help on macOS (F1 elsewhere) | ### Japanese text watermarks @@ -799,6 +799,7 @@ Latin stays upright. Advanced Japanese composition remains open. Regression cove | Date | Change | Summary | |---|---|---|+| 2026-10-27 | patch | MENU-APP-ABOUT, MENU-HELP-HELP, KEY-HELP, KEYC-HELP: on macOS Check for Updates… moves from Help to the app menu under About LightCraft; Help opens with LightCraft Help, then What's New and Keyboard Shortcuts, feedback and community, the websites and the diagnostics; LightCraft Help is ⇧⌘? on macOS and F1 elsewhere; status counts unchanged | | 2026-10-25 | patch | LR-BEHAV-TITLEBAR: the top bar's title-bar gestures come from craft-window's `title_bar`: a double-click follows the system setting, and a press on a button, the search field or a panel floating over the bar never moves the window; status counts unchanged | | 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 | minor | KEYC-METADATA: ⌘K / Ctrl+K (`panel.addKeywords`, Add Keywords) shows the Keywords panel, opens Keywording and puts the cursor in the Add keyword box; status counts unchanged (KEYC-METADATA stays 🟡) |@@ -1,5 +1,12 @@ # What's new in LightCraft +## 2026-10-27++### The app and Help menus follow the Mac's order+- On macOS, Check for Updates… is in the LightCraft menu right under About LightCraft, as in other Mac apps. It stays in Help on Windows and Linux.+- Help opens with LightCraft Help, then What's New and Keyboard Shortcuts, then Send Feedback… and the ArtCraft Discord, the websites, and System Info, Open Log Folder and Debug. Join the ArtCraft Discord… no longer leads the menu, and LightCraft Help is no longer the last row.+- LightCraft Help is ⇧⌘? on macOS, where F1 needs the fn key. Windows and Linux keep F1.+ ## 2026-10-24 ### Relative-date filters and smart albums follow the clock