Dialogs: keep dialog open on invalid Enter commit and prevent lock nesting in numeric widget

This commit is contained in:
Taha-Mahmoodi
2026-10-30 16:55:55 +07:00
committed by bflatastic
parent 5da8c8e495
commit e2828bc064
6 changed files with 30 additions and 12 deletions
+2 -1
View File
@@ -656,7 +656,8 @@ pub fn show(app: &mut VectorcraftApp, ctx: &egui::Context) {
}
});
});
if spec.ok.is_some() && ok_enabled && !after_panel && ctx.input(|i| i.key_pressed(egui::Key::Enter)) {
let rejected = ctx.data_mut(|d| d.remove_temp::<bool>(widgets::dialog_reject_commit_flag())).unwrap_or(false);
if spec.ok.is_some() && ok_enabled && !after_panel && !rejected && ctx.input(|i| i.key_pressed(egui::Key::Enter)) {
ok = true;
}
if discard {
+7 -6
View File
@@ -2534,14 +2534,15 @@ fn color_halftone_invalid_input_does_not_revert_to_sub_minimum_value() {
frame(&mut app, vec![egui::Event::Text("0.5 px".into())]);
frame(&mut app, vec![egui::Event::Key { key: egui::Key::Tab, physical_key: None, pressed: true, repeat: false, modifiers: Default::default() }]);
assert_eq!(app.ui.dialog.as_ref().unwrap().fields["maxRadius"], serde_json::json!(4.0));
// 2. Refocus Max Radius before typing invalid text
crate::widgets::arm_field_focus(&ctx, ("dlg-len", "maxRadius"));
// 2. Typing invalid text on Enter must NOT confirm/close the dialog; the dialog stays open
app.run("effect.dialog", json!({"effect": "pixelate.colorHalftone"})).unwrap();
frame(&mut app, vec![]);
frame(&mut app, vec![egui::Event::Text("1jgghgh".into())]);
frame(&mut app, vec![egui::Event::Key { key: egui::Key::Tab, physical_key: None, pressed: true, repeat: false, modifiers: Default::default() }]);
// The value remains the valid clamped minimum 4.0 pt, never 0.5 px, and rejection flash is set
assert_eq!(app.ui.dialog.as_ref().unwrap().fields["maxRadius"], serde_json::json!(4.0));
assert!(app.ui.dialog.as_ref().unwrap().fields["maxRadius"] == serde_json::json!(4.0));
frame(
&mut app,
vec![egui::Event::Key { key: egui::Key::Enter, physical_key: None, pressed: true, repeat: false, modifiers: Default::default() }],
);
assert!(app.ui.dialog.is_some(), "dialog must remain open on invalid Enter commit");
}
#[test]
+2 -1
View File
@@ -57,7 +57,8 @@ pub use numeric::{
use numeric::{decimal_point, share_of, spinner_step, step_through, step_to_multiple, within_a_millionth};
pub use panel_chrome::{bottom_bar, layout_button, list_box, orientation_button, tab_bar};
pub(crate) use text::{
arm_field_focus, dialog_focus_flag, disarm_field_focus, enter_modifiers, focus_field, own_field_shift_enter, set_dialog_open, take_dialog_focus,
arm_field_focus, dialog_focus_flag, dialog_reject_commit_flag, disarm_field_focus, enter_modifiers, focus_field, own_field_shift_enter,
reject_dialog_commit, set_dialog_open, take_dialog_focus,
};
pub use text::{
exact_text_field, exact_text_field_named, plain_field, plain_field_named, search_field, text_field, text_field_named, text_presets,
+6 -2
View File
@@ -117,8 +117,12 @@ fn unit_field(
Some(clamped)
}
None => {
ui.data_mut(|d| d.remove::<String>(id));
ui.data_mut(|d| d.insert_temp(id.with("invalid-flash"), ui.input(|i| i.time + 0.25)));
let end = ui.input(|i| i.time + 0.25);
ui.data_mut(|d| {
d.remove::<String>(id);
d.insert_temp(id.with("invalid-flash"), end);
});
crate::widgets::reject_dialog_commit(ui.ctx());
ui.ctx().request_repaint();
None
}
+12 -1
View File
@@ -87,6 +87,16 @@ fn dialog_open_flag() -> egui::Id {
egui::Id::unique("dialog-open")
}
/// The flag that tells the dialog runner a field rejected an invalid commit on Enter in this frame.
pub(crate) fn dialog_reject_commit_flag() -> egui::Id {
egui::Id::unique("dialog-reject-commit")
}
/// Suppress confirming an open dialog on Enter during this frame when an invalid value was committed.
pub(crate) fn reject_dialog_commit(ctx: &egui::Context) {
ctx.data_mut(|d| d.insert_temp(dialog_reject_commit_flag(), true));
}
/// The app sets this at the start of each frame: while a dialog is open, Shift+Enter in a field
/// applies its value and confirms the dialog as Enter does ([`shift_enter_keeps_focus`]).
pub(crate) fn set_dialog_open(ctx: &egui::Context, open: bool) {
@@ -279,7 +289,8 @@ pub(super) fn recessed_text(
d.insert_temp(id, buf.clone());
d.insert_temp(focus_id, focused);
});
let commit = resp.lost_focus() || kept;
let enter_commit = rows == 1 && editing && ui.input(|i| i.key_pressed(egui::Key::Enter));
let commit = resp.lost_focus() || kept || enter_commit;
(buf, commit, resp, rect)
}
+1 -1
View File
@@ -4,7 +4,7 @@
## Feature submission evidence
**Feature evidence last updated:** 2026-10-22.
**Feature evidence last updated:** 2026-10-30.
The shared assessment status line and revision history are current upstream; this dated section records the submission's feature evidence and revisions without rescoring upstream or claiming a new combined build or runtime measurement.