diff --git a/crates/engine/src/shortcut_parity_tests.rs b/crates/engine/src/shortcut_parity_tests.rs index 3165cb4f1..7d145db39 100644 --- a/crates/engine/src/shortcut_parity_tests.rs +++ b/crates/engine/src/shortcut_parity_tests.rs @@ -278,7 +278,7 @@ static ROWS: &[Row] = &[ doc(Arrange, "Add auto layout", &["Shift+A"], &[], Bound("layout.add"), ""), doc(Arrange, "Remove auto layout", &["Alt+Shift+A"], &[], Bound("layout.remove"), ""), doc(Arrange, "Suggest auto layout", &["Ctrl+Shift+A"], &["Ctrl+Alt+Shift+A"], Bound("layout.suggest"), "was unbound"), - doc(Arrange, "Edit padding on all sides (from right panel)", &["Cmd"], &[], Gesture("Edit padding on all sides"), "held while clicking a padding field: the value typed goes to every side"), + doc(Arrange, "Edit padding on all sides (from right panel)", &["Cmd"], &["Ctrl"], Gesture("Edit padding on all sides"), "held while clicking a padding field: the value typed goes to every side"), pin(Arrange, "distribute.horizontal", &["Ctrl+Alt+H"], &["Alt+Shift+H"]), pin(Arrange, "distribute.vertical", &["Ctrl+Alt+V"], &["Alt+Shift+V"]), pin(Arrange, "arrange.tidy", &["Ctrl+Alt+T"], &["Ctrl+Alt+Shift+T"]), diff --git a/crates/ui-egui/src/widgets.rs b/crates/ui-egui/src/widgets.rs index 2a32ffd13..08d919781 100644 --- a/crates/ui-egui/src/widgets.rs +++ b/crates/ui-egui/src/widgets.rs @@ -352,11 +352,17 @@ fn number_field_impl( // The text the field would commit to no effect: what it showed when the edit began, or the // value the arrows last stepped it to. let kept_id = id.with("kept"); + // Whether Cmd/Ctrl was held while the button was down on the field: a click's modifier is + // read on its press, so letting go of the key before the release still counts. + let cmd_press_id = id.with("cmdpress"); + let cmd_held_before = ui.data(|d| d.get_temp::(cmd_press_id)).unwrap_or(false); + let (cmd_pressed, any_down) = ui.input(|i| (field_resp.is_pointer_button_down_on() && i.modifiers.command, i.pointer.any_down())); + ui.data_mut(|d| d.insert_temp(cmd_press_id, cmd_pressed || (cmd_held_before && any_down))); if started { editing = Some(if typed_now { String::new() } else { value.map(fmt_num).unwrap_or_default() }); // Whether Cmd/Ctrl was held on the click that began the edit: a padding field then sets - // every side ([`edit_began_with_command`]). - let with_command = !typed_now && ui.input(|i| i.modifiers.command); + // every side ([`edit_began_with_command`]). The flag lives as long as the edit. + let with_command = !typed_now && (cmd_pressed || cmd_held_before || ui.input(|i| i.modifiers.command)); ui.data_mut(|d| { d.insert_temp(editing_id, editing.clone().unwrap_or_default()); d.insert_temp(kept_id, value.map(fmt_num).unwrap_or_default()); @@ -364,6 +370,9 @@ fn number_field_impl( d.insert_temp(id.with("cmdstart"), with_command); }); ui.memory_mut(|m| m.request_focus(id.with("te"))); + } else if editing.is_none() { + // No edit under way: an arrow step on the focused field is its own side's. + ui.data_mut(|d| d.remove::(id.with("cmdstart"))); } match editing { Some(mut text) => { @@ -418,7 +427,10 @@ fn number_field_impl( // Enter, Tab or a click elsewhere commits what was typed (a field left as it was // commits nothing: no undo step, and a rounded display isn't written back). let kept: String = ui.data(|d| d.get_temp(kept_id)).unwrap_or_default(); - if text != kept + // An edit begun with Cmd/Ctrl commits the value even retyped as it was: the other + // sides are to take it ([`edit_began_with_command`]). + let for_all = ui.data(|d| d.get_temp::(id.with("cmdstart"))).unwrap_or(false); + if (text != kept || for_all) && let Some(e) = typed(&text) { out = Some(e);