mirror of
https://github.com/storytold/lightcraft.git
synced 2026-11-03 06:59:53 -06:00
Issue #2980: Clear Color Label can be given a keyboard shortcut
Setting a colour label is photo.label with the colour as a parameter, and the keyboard shortcuts editor binds a key to a command, not to a parameter, so only 6-9 had keys and clearing a label could not be given one. photo.clearLabel is the same as photo.label with none, as a command of its own. The Photo > Set Color Label > None row runs it and shows its key.
This commit is contained in:
@@ -29,6 +29,10 @@ mod flag_cycle_tests;
|
||||
#[path = "library/tests_rated_out.rs"]
|
||||
mod rated_out_tests;
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "library/tests_clear_label.rs"]
|
||||
mod clear_label_tests;
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "library/tests_enable_filters.rs"]
|
||||
mod enable_filters_tests;
|
||||
|
||||
@@ -575,6 +575,16 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
cull(s, p, |s| for_targets(s, p, "Set Color Label", |id| Some(Op::SetLabel { id, label: l })))
|
||||
}
|
||||
),
|
||||
// `photo.label` takes the colour as a parameter, so a key can't be given to "none" alone
|
||||
cmd!(
|
||||
"photo.clearLabel",
|
||||
"Clear Color Label",
|
||||
["Photo", "Set Color Label"],
|
||||
None,
|
||||
"{ids?, advance?: bool} — `photo.label` with `none`; without `ids`, the selection moves on when this takes the active photo out of the view",
|
||||
has_selection,
|
||||
|s, p| { cull(s, p, |s| for_targets(s, p, "Set Color Label", |id| Some(Op::SetLabel { id, label: None }))) }
|
||||
),
|
||||
// ---- orientation
|
||||
cmd!("photo.rotateLeft", "Rotate Left", ["Photo"], Some("Cmd+["), "{ids?}", has_selection, |s, p| rotate(s, p, false)),
|
||||
cmd!("photo.rotateRight", "Rotate Right", ["Photo"], Some("Cmd+]"), "{ids?}", has_selection, |s, p| rotate(s, p, true)),
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
//! `photo.clearLabel`: the colour label taken off, as a command that can have a key of its own (#2980).
|
||||
use lightcraft_catalog::{ColorLabel, Op, Photo, PhotoId, Source};
|
||||
use serde_json::json;
|
||||
|
||||
use crate::{Result, Session};
|
||||
|
||||
fn session() -> Result<Session> {
|
||||
let mut s = Session::new();
|
||||
for (id, label) in [(1, Some(ColorLabel::Red)), (2, Some(ColorLabel::Purple)), (3, Some(ColorLabel::Blue)), (4, None)] {
|
||||
let mut photo = Photo::new(
|
||||
PhotoId(id),
|
||||
Source::File { path: format!("/lightcraft-clear-label/{id}.jpg") },
|
||||
&format!("{id}.jpg"),
|
||||
"JPEG",
|
||||
40,
|
||||
30,
|
||||
"2026-10-25",
|
||||
);
|
||||
photo.label = label;
|
||||
s.catalog.apply(Op::AddPhoto { photo: Box::new(photo) })?;
|
||||
}
|
||||
s.execute("library.sort", &json!({"key": "fileName", "ascending": true}))?;
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
fn labels(s: &Session) -> Vec<Option<ColorLabel>> {
|
||||
(1..=4).map(|id| s.catalog.photo(PhotoId(id)).unwrap().label).collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_selected_photos_lose_their_label_in_one_undo_step() {
|
||||
let mut s = session().unwrap();
|
||||
s.execute("library.select", &json!({"ids": [1, 2], "active": 2})).unwrap();
|
||||
s.execute("photo.clearLabel", &json!({})).unwrap();
|
||||
assert_eq!(labels(&s), [None, None, Some(ColorLabel::Blue), None]);
|
||||
assert_eq!(s.undo.len(), 1);
|
||||
s.execute("edit.undo", &json!({})).unwrap();
|
||||
assert_eq!(labels(&s), [Some(ColorLabel::Red), Some(ColorLabel::Purple), Some(ColorLabel::Blue), None]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_does_what_photo_label_none_does() {
|
||||
let mut a = session().unwrap();
|
||||
let mut b = session().unwrap();
|
||||
for s in [&mut a, &mut b] {
|
||||
s.execute("library.select", &json!({"ids": [3]})).unwrap();
|
||||
}
|
||||
a.execute("photo.clearLabel", &json!({})).unwrap();
|
||||
b.execute("photo.label", &json!({"label": "none"})).unwrap();
|
||||
assert_eq!(labels(&a), labels(&b));
|
||||
assert_eq!(a.undo.len(), b.undo.len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ids_name_the_photos_and_an_unlabelled_or_unknown_photo_is_handled() {
|
||||
let mut s = session().unwrap();
|
||||
s.execute("library.select", &json!({"ids": [4]})).unwrap();
|
||||
s.execute("photo.clearLabel", &json!({"ids": [1]})).unwrap();
|
||||
assert_eq!(labels(&s), [None, Some(ColorLabel::Purple), Some(ColorLabel::Blue), None]);
|
||||
// a photo without a label is left as it is, and a photo that does not exist is an error
|
||||
s.execute("photo.clearLabel", &json!({"ids": [4]})).unwrap();
|
||||
assert!(s.execute("photo.clearLabel", &json!({"ids": [999]})).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn it_has_no_key_of_its_own_and_is_listed_for_the_keyboard_shortcuts_editor() {
|
||||
let spec = crate::command_specs().iter().find(|c| c.id == "photo.clearLabel").expect("registered");
|
||||
assert_eq!(spec.shortcut, None, "the 6-9 keys are Lightroom's; none is given to clearing");
|
||||
assert_eq!(spec.label, "Clear Color Label");
|
||||
}
|
||||
@@ -65,6 +65,7 @@ fn flags_and_labels_that_leave_the_view_go_on_to_the_next_photo_too() {
|
||||
(json!({"flag": "pick"}), "photo.cycleFlag", json!({})),
|
||||
(json!({"flag": "pick"}), "photo.decreaseFlag", json!({})),
|
||||
(json!({"label": "red"}), "photo.label", json!({"label": "none"})),
|
||||
(json!({"label": "red"}), "photo.clearLabel", json!({})),
|
||||
(json!({}), "photo.increaseRating", json!({})),
|
||||
] {
|
||||
let mut s = one_star().unwrap();
|
||||
|
||||
Reference in New Issue
Block a user