Fix integer underflow in autosave mode after delay in the settings (#41898)

Ignasius created

Closes #41774 

Release Notes:

- settings_ui: Fixed an integer underflow panic when attempting to hit
the `-` sign on settings item that take delays in milliseconds

Change summary

crates/ui_input/src/number_field.rs | 48 ++++++++++++++++++++++++++----
1 file changed, 41 insertions(+), 7 deletions(-)

Detailed changes

crates/ui_input/src/number_field.rs 🔗

@@ -31,7 +31,7 @@ pub trait NumberFieldType: Display + Copy + Clone + Sized + PartialOrd + FromStr
     fn saturating_sub(self, rhs: Self) -> Self;
 }
 
-macro_rules! impl_newtype_numeric_stepper {
+macro_rules! impl_newtype_numeric_stepper_float {
     ($type:ident, $default:expr, $large:expr, $small:expr, $min:expr, $max:expr) => {
         impl NumberFieldType for $type {
             fn default_step() -> Self {
@@ -65,13 +65,47 @@ macro_rules! impl_newtype_numeric_stepper {
     };
 }
 
+macro_rules! impl_newtype_numeric_stepper_int {
+    ($type:ident, $default:expr, $large:expr, $small:expr, $min:expr, $max:expr) => {
+        impl NumberFieldType for $type {
+            fn default_step() -> Self {
+                $default.into()
+            }
+
+            fn large_step() -> Self {
+                $large.into()
+            }
+
+            fn small_step() -> Self {
+                $small.into()
+            }
+
+            fn min_value() -> Self {
+                $min.into()
+            }
+
+            fn max_value() -> Self {
+                $max.into()
+            }
+
+            fn saturating_add(self, rhs: Self) -> Self {
+                $type(self.0.saturating_add(rhs.0).min(Self::max_value().0))
+            }
+
+            fn saturating_sub(self, rhs: Self) -> Self {
+                $type(self.0.saturating_sub(rhs.0).max(Self::min_value().0))
+            }
+        }
+    };
+}
+
 #[rustfmt::skip]
-impl_newtype_numeric_stepper!(FontWeight, 50., 100., 10., FontWeight::THIN, FontWeight::BLACK);
-impl_newtype_numeric_stepper!(CodeFade, 0.1, 0.2, 0.05, 0.0, 0.9);
-impl_newtype_numeric_stepper!(InactiveOpacity, 0.1, 0.2, 0.05, 0.0, 1.0);
-impl_newtype_numeric_stepper!(MinimumContrast, 1., 10., 0.5, 0.0, 106.0);
-impl_newtype_numeric_stepper!(DelayMs, 100, 500, 10, 0, 2000);
-impl_newtype_numeric_stepper!(
+impl_newtype_numeric_stepper_float!(FontWeight, 50., 100., 10., FontWeight::THIN, FontWeight::BLACK);
+impl_newtype_numeric_stepper_float!(CodeFade, 0.1, 0.2, 0.05, 0.0, 0.9);
+impl_newtype_numeric_stepper_float!(InactiveOpacity, 0.1, 0.2, 0.05, 0.0, 1.0);
+impl_newtype_numeric_stepper_float!(MinimumContrast, 1., 10., 0.5, 0.0, 106.0);
+impl_newtype_numeric_stepper_int!(DelayMs, 100, 500, 10, 0, 2000);
+impl_newtype_numeric_stepper_float!(
     CenteredPaddingSettings,
     0.05,
     0.2,