UI: numeric forms open with their first number focused and selected
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
8e1d742a9d
commit
ffc481a4e4
|
|
@ -775,11 +775,16 @@ pub fn show_form(app: &mut EffectcraftApp, ctx: &egui::Context, t: &Tokens) {
|
|||
let r = match &mut fl.kind {
|
||||
FieldKind::Number { value, speed } => {
|
||||
let dec = if *speed < 0.01 { 5 } else { 3 };
|
||||
ui.add(crate::widgets::drag_value(egui::DragValue::new(value).speed(*speed).max_decimals(dec))).rect
|
||||
let r = ui.add(crate::widgets::drag_value(egui::DragValue::new(value).speed(*speed).max_decimals(dec)));
|
||||
// The first field takes the keyboard when the form opens. (A number edits
|
||||
// as text once focused; the selection is clamped to what it shows.)
|
||||
if !std::mem::replace(&mut focused, true) {
|
||||
crate::widgets::focus_on_open(ui.ctx(), &r, &" ".repeat(64));
|
||||
}
|
||||
r.rect
|
||||
}
|
||||
FieldKind::Text(s) => {
|
||||
let r = ui.add(egui::TextEdit::singleline(s).desired_width(220.0));
|
||||
// The first text field takes the keyboard when the form opens.
|
||||
if !std::mem::replace(&mut focused, true) {
|
||||
crate::widgets::focus_on_open(ui.ctx(), &r, s);
|
||||
}
|
||||
|
|
@ -956,6 +961,37 @@ mod tests {
|
|||
assert_eq!(f.params(), json!({"prop": "position", "value": [10.0, 20.0], "mode": "b"}));
|
||||
}
|
||||
|
||||
/// A numeric form (Layer ▸ Transform ▸ Position…) opens with its first number being edited
|
||||
/// and selected: typing replaces it, and one Enter confirms.
|
||||
#[test]
|
||||
fn a_numeric_form_opens_with_its_first_number_selected() {
|
||||
let mut app = EffectcraftApp::new(effectcraft_engine::Session::default());
|
||||
let ctx = egui::Context::default();
|
||||
crate::theme::install(&ctx, &app.tokens, crate::i18n::language(&app));
|
||||
app.dialog_state.form = Form {
|
||||
title: "Position".into(),
|
||||
command: "layer.setTransform".into(),
|
||||
base: json!({"prop": "position"}),
|
||||
fields: vec![Field::num("value[0]", "X", 960.0), Field::num("value[1]", "Y", 540.0)],
|
||||
};
|
||||
app.dialog = Some(Dialog::Form);
|
||||
let frame = |app: &mut EffectcraftApp, events: Vec<egui::Event>| {
|
||||
let raw = egui::RawInput { events, ..Default::default() };
|
||||
ctx.run_ui(raw, |ui| {
|
||||
app.auto.begin_frame();
|
||||
crate::panels::dialogs::show(app, ui.ctx());
|
||||
})
|
||||
.textures_delta
|
||||
.clear();
|
||||
};
|
||||
frame(&mut app, vec![]);
|
||||
frame(&mut app, vec![]);
|
||||
frame(&mut app, vec![egui::Event::Text("42".into())]);
|
||||
assert_eq!(app.dialog_state.form.params()["value"], json!([42.0, 540.0]));
|
||||
frame(&mut app, vec![egui::Event::Key { key: egui::Key::Enter, physical_key: None, pressed: true, repeat: false, modifiers: Default::default() }]);
|
||||
assert!(app.dialog.is_none(), "one Enter confirms");
|
||||
}
|
||||
|
||||
/// File ▸ Export ▸ Adobe Premiere Pro Project… opens a form that says it writes Final Cut Pro
|
||||
/// XML; its fields register automation ids and OK runs `file.exportTimeline`.
|
||||
#[test]
|
||||
|
|
|
|||
Loading…
Reference in New Issue