mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-29 04:27:30 -06:00
LR-BEHAV-TEXTFIELD: the unnamed faces' name field is a shared text field
It gets the Cut / Copy / Paste / Select All menu, and Esc in it now clears the selection as Clear does, as the code meant: it checked the field's focus on the Esc frame, which egui has already taken away, so Esc only left the field. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
7baf93ecdb
commit
a92c38fdd4
@@ -1241,6 +1241,45 @@ mod tests {
|
||||
assert_eq!(named(&h, ids[1], 0), None);
|
||||
}
|
||||
|
||||
/// The name field under the unnamed faces is a shared text field: right-click ▸ Paste puts the
|
||||
/// clipboard's name in, and Esc leaves the field and clears the selection, as Clear does.
|
||||
#[test]
|
||||
fn the_unnamed_faces_name_field_pastes_and_escape_clears() {
|
||||
use lightcraft_catalog::Op;
|
||||
let mut h = demo([1400.0, 900.0]);
|
||||
let t = Duration::from_secs(10);
|
||||
let id = h.app.session.catalog.photos().map(|p| p.id).next().unwrap();
|
||||
let mut meta = h.app.session.catalog.photo(id).unwrap().meta.clone();
|
||||
meta.regions = vec![lightcraft_meta::Region {
|
||||
rect: lightcraft_geom::Rect { x0: 0.3, y0: 0.2, x1: 0.5, y1: 0.55 },
|
||||
kind: lightcraft_meta::RegionKind::Face,
|
||||
name: None,
|
||||
description: None,
|
||||
}];
|
||||
h.app.session.commit("setup", Op::SetMeta { id, meta: Box::new(meta) }).unwrap();
|
||||
h.request("engine.execute", json!({"command": "view.people"}), t);
|
||||
h.settle(SETTLE);
|
||||
h.view.clipboard = "Wedding Guest".into();
|
||||
for (widget, button) in [
|
||||
(format!("unnamed-face:{}:0", id.0), "left"),
|
||||
("field:unnamedName".to_string(), "left"),
|
||||
("field:unnamedName".to_string(), "right"),
|
||||
("field:unnamedName:paste".to_string(), "left"),
|
||||
] {
|
||||
let r = h.request("ui.clickWidget", json!({"id": widget, "button": button}), t);
|
||||
assert_eq!(r["ok"], true, "{widget}: {r}");
|
||||
h.step();
|
||||
h.step();
|
||||
h.step();
|
||||
}
|
||||
assert_eq!(h.app.ui.unnamed_name, "Wedding Guest");
|
||||
assert_eq!(h.app.ui.unnamed_selected.len(), 1, "still naming");
|
||||
h.request("ui.key", json!({"key": "Escape"}), t);
|
||||
h.step();
|
||||
h.step();
|
||||
assert!(h.app.ui.unnamed_selected.is_empty() && h.app.ui.unnamed_name.is_empty(), "Esc cleared the selection and the name");
|
||||
}
|
||||
|
||||
/// A screenful of faces larger than the picture cache's usual budget (96) is all kept: with a fixed budget the same few
|
||||
/// tiles were evicted and re-requested every frame and stayed blank.
|
||||
#[test]
|
||||
|
||||
@@ -132,14 +132,14 @@ pub fn naming_bar(app: &mut LightcraftApp, ui: &mut egui::Ui) {
|
||||
let n = selected.len();
|
||||
ui.label(RichText::new(if n == 1 { "1 face selected".to_string() } else { format!("{n} faces selected") }).color(t.text));
|
||||
let hint = suggested.clone().unwrap_or_else(|| "Name…".to_string());
|
||||
let edit = ui.add(egui::TextEdit::singleline(&mut app.ui.unnamed_name).hint_text(hint).desired_width(240.0));
|
||||
register(ui.ctx(), "field:unnamedName", edit.rect);
|
||||
let field = crate::text_field::TextField::singleline("field:unnamedName", &mut app.ui.unnamed_name).hint(hint).width(240.0).show(ui);
|
||||
let edit = &field.response;
|
||||
if std::mem::take(&mut app.ui.unnamed_focus) {
|
||||
edit.request_focus();
|
||||
}
|
||||
let typed = app.ui.unnamed_name.trim().to_string();
|
||||
let chosen = if typed.is_empty() { suggested.clone().unwrap_or_default() } else { typed.clone() };
|
||||
if edit.lost_focus() && ui.input(|i| i.key_pressed(egui::Key::Enter)) && !chosen.is_empty() {
|
||||
if field.ending == Some(crate::text_field::Ending::Return) && !chosen.is_empty() {
|
||||
submit = Some(chosen.clone());
|
||||
}
|
||||
let label = if n == 1 { "Name face".to_string() } else { format!("Name {n} faces") };
|
||||
@@ -150,7 +150,7 @@ pub fn naming_bar(app: &mut LightcraftApp, ui: &mut egui::Ui) {
|
||||
}
|
||||
let c = ui.button("Clear");
|
||||
register(ui.ctx(), "unnamed:clear", c.rect);
|
||||
clear = c.clicked() || (edit.has_focus() && ui.input(|i| i.key_pressed(egui::Key::Escape)));
|
||||
clear = c.clicked() || field.cancelled();
|
||||
});
|
||||
// the people already named, matching what is typed (a click names the faces)
|
||||
let typed = app.ui.unnamed_name.trim().to_lowercase();
|
||||
|
||||
Reference in New Issue
Block a user