Repository: projectmesa/mesa (python)

Issue:
UX: Split UserSettableParameter into various classes
What if, instead of
```python
number_option = UserSettableParameter('number', 'My Number', value=123)
boolean_option = UserSettableParameter('checkbox', 'My Boolean', value=True)
slider_option = UserSettableParameter('slider', 'My Slider', value=123, min_value=10, max_value=200, step=0.1)
```

we do
```python
number_option = Number("My Number", 123)
boolean_option = Checkbox("My boolean", True)
slider_option = Slider("My slider", 123, min=10, max=200, step=0.1)
```

In addition to looking simpler, more importantly, this allows users to define their own UserParam class.

Pull request description:
feat: Implement NumberInput UserParam class
Fixes #1235.

Patch:
diff --git a/mesa/visualization/UserParam.py b/mesa/visualization/UserParam.py
index 62b187e8..3e391e7a 100644
--- a/mesa/visualization/UserParam.py
+++ b/mesa/visualization/UserParam.py
@@ -1,3 +1,7 @@
+from numbers import Number
+from warnings import warn
+
+
 NUMBER = "number"
 CHECKBOX = "checkbox"
 CHOICE = "choice"
@@ -63,6 +67,13 @@ class UserSettableParameter:
         choices=None,
         description=None,
     ):
+
+        warn(
+            "UserSettableParameter is deprecated in favor of UserParam objects "
+            "such as Slider, Checkbox, Choice, StaticText, NumberInput. "
+            "See the examples folder for how to use them. "
+            "UserSettableParameter will be removed in the next major release."
+        )
         if choices is None:
             choices = list()
         if param_type not in self.TYPES:
@@ -268,3 +279,19 @@ class StaticText(UserParam):
         self._value = value
         valid = isinstance(self.value, str)
         self.maybe_raise_error(valid)
+
+
+class NumberInput(UserParam):
+    """
+    a simple numerical input
+
+    Example:
+    number_option = NumberInput("My Number", value=123)
+    """
+
+    def __init__(self, name="", value=None, description=None):
+        self.param_type = NUMBER
+        self.name = name
+        self._value = value
+        valid = isinstance(self.value, Number)
+        self.maybe_raise_error(valid)


Test patch:
diff --git a/tests/test_usersettableparam.py b/tests/test_usersettableparam.py
index deb4da42..6dc52774 100644
--- a/tests/test_usersettableparam.py
+++ b/tests/test_usersettableparam.py
@@ -5,12 +5,14 @@ from mesa.visualization.UserParam import (
     Checkbox,
     Choice,
     StaticText,
+    NumberInput,
 )
 
 
 class TestOption(TestCase):
     def setUp(self):
         self.number_option = UserSettableParameter("number", value=123)
+        self.number_option_standalone = NumberInput("number", value=123)
         self.checkbox_option = UserSettableParameter("checkbox", value=True)
         self.checkbox_option_standalone = Checkbox(value=True)
         self.choice_option = UserSettableParameter(
@@ -29,9 +31,10 @@ class TestOption(TestCase):
         self.static_text_option = StaticText("Hurr, Durr Im'a Sheep")
 
     def test_number(self):
-        assert self.number_option.value == 123
-        self.number_option.value = 321
-        assert self.number_option.value == 321
+        for option in [self.number_option, self.number_option_standalone]:
+            assert option.value == 123
+            option.value = 321
+            assert option.value == 321
 
     def test_checkbox(self):
         for option in [self.checkbox_option, self.checkbox_option_standalone]: