LRC-LIB-KEYWORDS: the painter's keyword field is a shared text field

"Keyword to paint" gets the Cut / Copy / Paste / Select All menu and
Esc, and Return starts painting as the Paint button does. It stays
fixed while painting.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Nathaniel Ledford
2026-10-09 15:22:21 -04:00
co-authored by Claude Opus 5.5
parent f577ccf828
commit b501b7fffa
2 changed files with 23 additions and 5 deletions
+11 -5
View File
@@ -802,16 +802,22 @@ fn keywords(app: &mut LightcraftApp, ui: &mut egui::Ui, id: PhotoId) {
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 r = ui.add_enabled(
painting.is_none(),
egui::TextEdit::singleline(&mut k).hint_text(crate::i18n::tr("Keyword to paint")).desired_width(130.0),
);
register(ui.ctx(), "field:keywordPainter", r.rect);
// (fixed while painting: Stop first)
let field = ui
.add_enabled_ui(painting.is_none(), |ui| {
crate::text_field::TextField::singleline("field:keywordPainter", &mut k)
.hint(crate::i18n::tr("Keyword to paint"))
.width(130.0)
.show(ui)
})
.inner;
ui.data_mut(|d| d.insert_temp(pid, 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())
.on_hover_text(crate::i18n::tr("Click photos in the grid to toggle the keyword; Esc stops"))
.clicked()
|| returned
{
let _ = app.run("tool.keywordPainter", json!({"keyword": if painting.is_some() { serde_json::Value::Null } else { json!(k) }}));
}
+12
View File
@@ -134,3 +134,15 @@ fn will_export_shows_what_exports_carry() {
ask(&mut h, "ui.clickWidget", json!({"id": "keywordView:keywords"}));
assert!(has(&h, "keywordChip:beach") && !has(&h, "keywordExport:beach"));
}
/// The painter's keyword field is a shared text field: right-click ▸ Paste fills it, and Return
/// starts painting as the Paint button does.
#[test]
fn the_painters_field_pastes_and_return_paints() {
let (mut h, _) = two_selected();
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.key", json!({"key": "Enter"}));
assert_eq!(h.app.ui.keyword_painter.as_deref(), Some("Weddings"));
}