mirror of
https://github.com/storytold/lightcraft.git
synced 2026-11-01 14:07:34 -06:00
LR-BEHAV-DRAGDROP: a right-click while photos are carried opens no context menu
This commit is contained in:
@@ -367,6 +367,8 @@ impl LightcraftApp {
|
||||
// Freeze this frame's notice barrier before `notices::show` can dismiss a prompt: the same
|
||||
// click or key must never be acted on again by the dialog drawn after it.
|
||||
let notice_blocks = panels::notices::blocks_input(self);
|
||||
// what the panels below read to refuse a right-click's menu while photos are carried
|
||||
widgets::set_carrying(&ctx, self.ui.dragging_photos.is_some() && ctx.input(|i| i.pointer.primary_down()));
|
||||
if std::mem::take(&mut self.ui.quit) {
|
||||
ctx.send_viewport_cmd(egui::ViewportCommand::Close);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ mod button;
|
||||
mod canvas_keys;
|
||||
mod canvas_pan;
|
||||
mod capture_time;
|
||||
mod carried_right_click;
|
||||
mod compare;
|
||||
mod copy_paste_dialogs;
|
||||
mod crop_rotate;
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
//! A right-click while photos are carried (the primary button held) opens no context menu on a
|
||||
//! sidebar row. What the right button's release does to the drag itself is not asserted here.
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use egui::{Pos2, Rect};
|
||||
use serde_json::json;
|
||||
|
||||
use crate::headless::Headless;
|
||||
use crate::{LightcraftApp, Services};
|
||||
|
||||
const T: std::time::Duration = std::time::Duration::from_secs(10);
|
||||
|
||||
/// Two photos in a fresh folder, an album and a keyword: a grid with Albums, Folders and Keywords
|
||||
/// in the sidebar, tall enough for all three.
|
||||
fn app(tag: &str) -> (Headless, PathBuf, [String; 3]) {
|
||||
use lightcraft_catalog::{Op, Photo, Source};
|
||||
let root = std::env::temp_dir().join(format!("lc-drag-right-click-{tag}-{}", std::process::id()));
|
||||
let _ = std::fs::remove_dir_all(&root);
|
||||
std::fs::create_dir_all(&root).unwrap();
|
||||
let mut session = lightcraft_engine::Session::new().with_fs();
|
||||
let mut ids = Vec::new();
|
||||
for file in ["beach.png", "garden.png"] {
|
||||
let img = lightcraft_raster::Rgba8 { width: 8, height: 8, data: vec![[90, 120, 160, 255]; 64] };
|
||||
let png = lightcraft_codecs::encode_png(&lightcraft_codecs::EncodeImage::rgba8(&img), &lightcraft_codecs::EncodeMeta::default()).unwrap();
|
||||
std::fs::write(root.join(file), png).unwrap();
|
||||
let id = session.catalog.alloc_photo_id();
|
||||
let p = Photo::new(id, Source::File { path: root.join(file).to_string_lossy().into() }, file, "PNG", 8, 8, "2026-01-01T10:00:00");
|
||||
session.catalog.apply(Op::AddPhoto { photo: Box::new(p) }).unwrap();
|
||||
ids.push(id.0);
|
||||
}
|
||||
let mut h = Headless::new(LightcraftApp::new(session, Services { png: None, ..Default::default() }), [1300.0, 1600.0], 1.0);
|
||||
let r = h.request("engine.execute", json!({"command": "album.create", "params": {"name": "Dropped"}}), T);
|
||||
let album = r["result"]["id"].as_u64().unwrap_or_else(|| panic!("{r}"));
|
||||
let r = h.request("engine.execute", json!({"command": "library.select", "params": {"ids": [ids[1]]}}), T);
|
||||
assert_eq!(r["ok"], true, "{r}");
|
||||
let r = h.request("engine.execute", json!({"command": "photo.setMeta", "params": {"ids": [ids[1]], "addKeywords": ["Travel"]}}), T);
|
||||
assert_eq!(r["ok"], true, "{r}");
|
||||
h.app.run("library.select", json!({"ids": []})).unwrap();
|
||||
let r = h.request("ui.set", json!({"view": "photoGrid", "leftPanel": true, "sidebar": ["albums", "folders", "keywords"]}), T);
|
||||
assert_eq!(r["ok"], true, "{r}");
|
||||
for _ in 0..8 {
|
||||
h.step();
|
||||
}
|
||||
let folder = format!("source:libfolder:{}", root.to_string_lossy().replace('\\', "/"));
|
||||
(h, root, [format!("source:album:{album}"), folder, "source:keyword:Travel".into()])
|
||||
}
|
||||
|
||||
fn widget(h: &Headless, id: &str) -> Rect {
|
||||
h.app.widgets.iter().find(|(w, _)| w == id).map(|(_, r)| *r).unwrap_or_else(|| panic!("no {id}"))
|
||||
}
|
||||
|
||||
fn button(h: &mut Headless, at: Pos2, button: egui::PointerButton, pressed: bool) {
|
||||
h.app.synthetic.push(egui::Event::PointerButton { pos: at, button, pressed, modifiers: egui::Modifiers::NONE });
|
||||
h.step();
|
||||
}
|
||||
|
||||
/// Carry the first photo (primary held) over `row`, then right-click there and let go of the
|
||||
/// right button, one frame at a time with the pointer resting in between, as a person does.
|
||||
fn right_click_while_carrying(h: &mut Headless, row: &str) {
|
||||
let first = h.app.session.visible_cloned()[0].0;
|
||||
let from = widget(h, &format!("thumb:{first}")).center();
|
||||
let over = widget(h, row).center();
|
||||
h.app.synthetic.push(egui::Event::PointerMoved(from));
|
||||
button(h, from, egui::PointerButton::Primary, true);
|
||||
for i in 1..=8 {
|
||||
h.app.synthetic.push(egui::Event::PointerMoved(from + (over - from) * (i as f32 / 8.0)));
|
||||
h.step();
|
||||
}
|
||||
h.step();
|
||||
assert_eq!(h.app.ui.dragging_photos, Some(vec![first]), "carrying the photo");
|
||||
button(h, over, egui::PointerButton::Secondary, true);
|
||||
h.step();
|
||||
button(h, over, egui::PointerButton::Secondary, false);
|
||||
h.step();
|
||||
h.step();
|
||||
}
|
||||
|
||||
fn check(row: usize, tag: &str) {
|
||||
let (mut h, root, rows) = app(tag);
|
||||
let id = &rows[row];
|
||||
right_click_while_carrying(&mut h, id);
|
||||
assert!(!egui::Popup::is_any_open(&h.view.ctx), "{id}: no context menu opens while photos are carried");
|
||||
let _ = std::fs::remove_dir_all(&root);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn right_click_on_an_album_row_while_carrying_opens_no_menu() {
|
||||
check(0, "album");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn right_click_on_a_folder_row_while_carrying_opens_no_menu() {
|
||||
check(1, "folder");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn right_click_on_a_keyword_row_while_carrying_opens_no_menu() {
|
||||
check(2, "keyword");
|
||||
}
|
||||
|
||||
/// Nothing changes without a drag: the same right-click opens the row's menu.
|
||||
#[test]
|
||||
fn right_click_on_rows_still_opens_the_menu_without_a_drag() {
|
||||
for (row, tag) in [(0, "a"), (1, "f"), (2, "k")] {
|
||||
let (mut h, root, rows) = app(&format!("plain-{tag}"));
|
||||
let r = h.request("ui.clickWidget", json!({"id": rows[row], "button": "right"}), T);
|
||||
assert_eq!(r["ok"], true, "{r}");
|
||||
for _ in 0..4 {
|
||||
h.step();
|
||||
}
|
||||
assert!(egui::Popup::is_any_open(&h.view.ctx), "{}: its context menu", rows[row]);
|
||||
let _ = std::fs::remove_dir_all(&root);
|
||||
}
|
||||
}
|
||||
|
||||
/// A drag left over without its button held (full screen skips the code that ends it) is not
|
||||
/// carrying: the row's menu still opens.
|
||||
#[test]
|
||||
fn a_drag_left_over_without_its_button_does_not_hold_back_the_menu() {
|
||||
let (mut h, root, rows) = app("leftover");
|
||||
let first = h.app.session.visible_cloned()[0].0;
|
||||
// the right-click is the first thing the frame sees, before anything ends the leftover drag
|
||||
let at = widget(&h, &rows[0]).center();
|
||||
h.app.synthetic.push(egui::Event::PointerMoved(at));
|
||||
h.step();
|
||||
h.step();
|
||||
h.app.ui.dragging_photos = Some(vec![first]);
|
||||
for pressed in [true, false] {
|
||||
h.app.synthetic.push(egui::Event::PointerButton {
|
||||
pos: at,
|
||||
button: egui::PointerButton::Secondary,
|
||||
pressed,
|
||||
modifiers: egui::Modifiers::NONE,
|
||||
});
|
||||
}
|
||||
h.step();
|
||||
h.step();
|
||||
assert!(egui::Popup::is_any_open(&h.view.ctx), "the album row's menu opens");
|
||||
let _ = std::fs::remove_dir_all(&root);
|
||||
}
|
||||
@@ -67,10 +67,26 @@ pub fn menu_button<'a, R>(ui: &mut Ui, atoms: impl egui::IntoAtoms<'a>, contents
|
||||
/// that by the menu's id: a right-click elsewhere on the same widget while its menu is open
|
||||
/// reopened the menu at the pointer and closed it again on the same frame, a one-frame flash.
|
||||
/// The click that opens (or moves) the menu is not the one that closes it.
|
||||
///
|
||||
/// While photos are carried (dragged from the grid, the primary button still held) a right-click
|
||||
/// opens nothing here: a menu is not what the person is doing with the pointer.
|
||||
pub fn context_menu(response: &Response, add_contents: impl FnOnce(&mut Ui)) -> Option<egui::InnerResponse<()>> {
|
||||
if response.secondary_clicked() && carrying(&response.ctx) {
|
||||
return None;
|
||||
}
|
||||
egui::Popup::context_menu(response).close_behavior(context_menu_close(response, egui::PopupCloseBehavior::CloseOnClick)).show(add_contents)
|
||||
}
|
||||
|
||||
/// Record whether photos are being carried as the frame starts, for [`context_menu`] to read. A
|
||||
/// drag left over without its button (full screen skips the code that ends it) is not carrying.
|
||||
pub fn set_carrying(ctx: &egui::Context, carrying: bool) {
|
||||
ctx.data_mut(|d| d.insert_temp(egui::Id::unique("lc-carrying"), carrying));
|
||||
}
|
||||
|
||||
fn carrying(ctx: &egui::Context) -> bool {
|
||||
ctx.data(|d| d.get_temp::<bool>(egui::Id::unique("lc-carrying"))).unwrap_or(false)
|
||||
}
|
||||
|
||||
/// How a context menu on `response` closes this frame: `default`, except on the frame of the
|
||||
/// right-click that opens or moves it, which must not close it (see [`context_menu`]).
|
||||
pub fn context_menu_close(response: &Response, default: egui::PopupCloseBehavior) -> egui::PopupCloseBehavior {
|
||||
|
||||
@@ -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-25 · **Change:** minor (LR-BEHAV-DRAGDROP: a right-click while photos are carried from the grid opens no context menu; 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
|
||||
@@ -466,7 +466,7 @@ differences and missing bindings are in [ui-parity.md](ui-parity.md#shortcuts).
|
||||
| LR-BEHAV-WEB-SAFETY | Library safety in the browser build | P1 | 🟡 | `cmd:file.backupLibrary`, `cmd:file.restoreLibrary`, `apps/lightcraft-web/src/safety.rs`, `apps/lightcraft-web/src/backup.rs`, `apps/lightcraft-web/src/files.rs` | web only (experimental): Back Up Library (zip of the catalog and every stored original) and a non-destructive Restore; failed saves show as unsaved and are retried; a photo that can't be stored isn't added; one tab per library (Web Locks); notices for storage that isn't persistent and for a library that can't open; `?reset` asks first; a panic shows a message. Missing: `?safe` start, deleting originals of removed photos, zip64 (backups > 4 GB) |
|
||||
| LR-BEHAV-GPU | GPU acceleration | P0 | ✅ | `crates/gpu/src/render.rs`, `cmd:app.gpu`, `docs/gpu-pipeline.md`, `crates/ui-egui/src/panels/notices.rs` | CPU fallback per render on device limits, out of memory, device errors / loss, incomplete or black results (`perf.gpuReason`, `perf.gpuFallback`; each render reports its own reason — `lightcraft_gpu::try_render`, `gpuFallback` per exported file — issue #675); short submissions for slow iGPUs; backend choice (DX12 only on Windows, `LIGHTCRAFT_GPU_BACKEND` / `WGPU_BACKEND`), device created after the window opens, crash sentinel (issue #136); a GPU lost while LightCraft runs (driver reset) stops it with that message and turns GPU rendering off for the next start, which says why (issue #1337; the window's renderer can't survive the lost device); quitting waits (up to 2 s) for renders in flight and starts no new GPU work, so none is inside the driver when the process exits (`crates/gpu/src/exit.rs`, issue #620; seen crashing only on Linux + NVIDIA, other drivers unverified); with GPU rendering on and no adapter found at all (e.g. no Vulkan loader on NixOS outside `nix develop`), the desktop app says once per session that it renders on the CPU and points to Help ▸ System Info (`gpu_notice`; not when the GPU is turned off or only a software adapter exists); no tiling beyond the buffer limit (CPU) |
|
||||
| LR-BEHAV-RENDER-FIDELITY | Rendering matches Lightroom | P1 | 🟡 | `crates/pipeline/src/lib.rs`, `crates/pipeline/src/tone.rs` | every slider exists and works, but the character of the result (tone curve shape, highlight recovery, texture / clarity / dehaze, noise reduction, sharpening, default look) is tuned by eye; there is no systematic side-by-side comparison against Lightroom on the same CC0 raws. Needs a fidelity suite: Lightroom reference renders kept only in the local `plan/` (never committed), compared per slider and preset with a perceptual metric. Tuning that changes how existing settings render ships as a new process version (LRC-DEV-PROCESS, `docs/process-versions.md`) |
|
||||
| LR-BEHAV-DRAGDROP | Drag and drop | P1 | ✅ | `crates/ui-egui/src/lib.rs`, `crates/ui-egui/src/panels/grid.rs` (`drag_feedback`), `crates/ui-egui/src/panels/left.rs` (`drop_target`, `album_drag_over`, `top_level_drop_target`, `drag_auto_scroll`) | files → app (a drop-target card while they hover, then the import review); grid photos → an album row (adds the selection, with a count badge while dragging); sidebar album / folder rows → a folder (moves it; its name follows the pointer); a drag of albums or grid photos near the top or bottom edge of the sidebar scrolls it (faster nearer the edge, only while the pointer is over the sidebar) |
|
||||
| LR-BEHAV-DRAGDROP | Drag and drop | P1 | ✅ | `crates/ui-egui/src/lib.rs`, `crates/ui-egui/src/panels/grid.rs` (`drag_feedback`), `crates/ui-egui/src/panels/left.rs` (`drop_target`, `album_drag_over`, `top_level_drop_target`, `drag_auto_scroll`), `crates/ui-egui/src/widgets.rs` (`context_menu`), `crates/ui-egui/src/tests/carried_right_click.rs` | a right-click while photos are carried opens no context menu; files → app (a drop-target card while they hover, then the import review); grid photos → an album row (adds the selection, with a count badge while dragging); sidebar album / folder rows → a folder (moves it; its name follows the pointer); a drag of albums or grid photos near the top or bottom edge of the sidebar scrolls it (faster nearer the edge, only while the pointer is over the sidebar) |
|
||||
| LR-BEHAV-TOAST | Toast notifications | P1 | ✅ | `crates/ui-egui/src/panels.rs` | |
|
||||
| LR-BEHAV-DIALOGS | Dialogs fit the window | P1 | ✅ | `crates/ui-egui/src/dialogs.rs` (`dialog_body`, `list_height`), `crates/ui-egui/src/tests/dialog_fit.rs`, `crates/ui-egui/src/tests/dialogs.rs` (`a_click_outside_closes_the_dialog_when_settings_allow_it`) | a dialog taller than the window (Export on a 1366×768 screen, issue #781) never runs off it: its options scroll while the title bar and the Cancel / OK row stay on screen; lists that scroll on their own (What's New, All Metadata, shortcuts, smart-album rules, credits) get shorter first; dialogs that fit look as before; Import keeps its own resizable, scrolling window; Settings → Dialogs → Close a dialog by clicking outside it (off by default, so a stray click never throws away a dialog's choices): a click pressed and released on the dimmed backdrop closes the dialog like Esc and doesn't reach the panels below, while a drag that ends outside (a slider pulled past the edge) or a click that closes a dropdown keeps it; the import review never closes this way (`clicked_backdrop`) |
|
||||
| LR-BEHAV-SIDEBAR-COLLAPSE | Collapsible left-sidebar sections | P2 | ✅ | `crates/ui-egui/src/panels/left.rs` (`section`, `section_header`), `crates/ui-egui/src/sidebar.rs` (`SidebarLayout`), `crates/ui-egui/src/tests/panels.rs` | click the Albums, Local, By Date, Folders or Keywords header (or drive `ui.clickWidget` `sidebarSection:<albums\|local\|byDate\|folders\|keywords>`) to fold or unfold the section; a chevron before the title shows the state; the choice is kept across restarts (`sidebar` in the UI state; the `collapsedSidebar` list of older settings files is still read). the click itself is UI-only, like the By Date / Keywords disclosure triangles, and `cmd:view.sidebarSection` `{section, collapsed}` folds and unfolds for agents; photos dropped on a folded Albums section have no target |
|
||||
@@ -959,3 +959,4 @@ Latin stays upright. Advanced Japanese composition remains open. Regression cove
|
||||
| 2026-10-23 | patch | LR-BEHAV-ACCESS: the name field of New Album, New Smart Album, Rename and the other one-field dialogs takes the keyboard focus once when the dialog opens instead of every frame, so Tab and Shift+Tab reach the check box, Cancel and OK; status unchanged (🟡) |
|
||||
| 2026-10-22 | minor | LR-CROP-AUTO: Auto straighten turns by at most 10° and only on at least 3 agreeing lines, and says when it finds nothing to level by; measured on 68 photos straightened by hand and 300 left as shot, unwanted turns of more than 1° fell from 79 to 19 of the 300. Downgraded ✅ → 🟡: it still leaves most tilted photos alone |
|
||||
| 2026-10-23 | patch | LRC-LIB-FILTERBAR: showing an album (`library.source`) while the filter holds an album drops the filter's album, as showing a library folder already dropped its folder filter; before, the old album stayed in the filter unseen (the filter bar has no album chip) and narrowed the next source such as All Photos; the row's note says so; status unchanged (✅) |
|
||||
| 2026-10-24 | patch | LR-BEHAV-DRAGDROP: a right-click on a sidebar album, folder or keyword row while photos are carried from the grid opens no context menu; status unchanged (✅) |
|
||||
|
||||
@@ -19,6 +19,10 @@
|
||||
photo, and the line can be dragged: pressing it picks the region under the pointer (Highlights, Lights, Darks or
|
||||
Shadows) and moving up or down changes that slider, as one undo step. Hovering the line names the region first.
|
||||
|
||||
### A right-click while you carry photos opens no menu
|
||||
- While you drag photos from the grid, a right-click opens no context menu, on an album, folder or keyword row in
|
||||
the sidebar or anywhere else. Before, the menu opened on the row the photos were over.
|
||||
|
||||
## 2026-10-23
|
||||
|
||||
### Tab leaves the name field in New Album, New Smart Album and the name prompts
|
||||
|
||||
Reference in New Issue
Block a user