Browse Source

Merge pull request #797 from zauberzeug/disableable

Disableable elements
Falko Schindler 2 năm trước cách đây
mục cha
commit
fe1eaab37b

+ 2 - 1
nicegui/elements/button.py

@@ -2,10 +2,11 @@ from typing import Callable, Optional
 
 from ..colors import set_background_color
 from ..events import ClickEventArguments, handle_event
+from .mixins.disableable_element import DisableableElement
 from .mixins.text_element import TextElement
 
 
-class Button(TextElement):
+class Button(TextElement, DisableableElement):
 
     def __init__(self,
                  text: str = '', *,

+ 2 - 1
nicegui/elements/checkbox.py

@@ -1,10 +1,11 @@
 from typing import Callable, Optional
 
+from .mixins.disableable_element import DisableableElement
 from .mixins.text_element import TextElement
 from .mixins.value_element import ValueElement
 
 
-class Checkbox(TextElement, ValueElement):
+class Checkbox(TextElement, ValueElement, DisableableElement):
 
     def __init__(self, text: str = '', *, value: bool = False, on_change: Optional[Callable] = None) -> None:
         """Checkbox

+ 2 - 1
nicegui/elements/color_input.py

@@ -3,10 +3,11 @@ from typing import Callable, Optional
 from nicegui import ui
 
 from .color_picker import ColorPicker
+from .mixins.disableable_element import DisableableElement
 from .mixins.value_element import ValueElement
 
 
-class ColorInput(ValueElement):
+class ColorInput(ValueElement, DisableableElement):
     LOOPBACK = False
 
     def __init__(self, label: Optional[str] = None, *,

+ 2 - 1
nicegui/elements/date.py

@@ -1,9 +1,10 @@
 from typing import Callable, Optional
 
+from .mixins.disableable_element import DisableableElement
 from .mixins.value_element import ValueElement
 
 
-class Date(ValueElement):
+class Date(ValueElement, DisableableElement):
     EVENT_ARGS = None
 
     def __init__(self,

+ 2 - 1
nicegui/elements/expansion.py

@@ -1,9 +1,10 @@
 from typing import Optional
 
+from .mixins.disableable_element import DisableableElement
 from .mixins.value_element import ValueElement
 
 
-class Expansion(ValueElement):
+class Expansion(ValueElement, DisableableElement):
 
     def __init__(self, text: Optional[str] = None, *, icon: Optional[str] = None, value: bool = False) -> None:
         '''Expansion Element

+ 2 - 1
nicegui/elements/input.py

@@ -1,10 +1,11 @@
 from typing import Any, Callable, Dict, Optional
 
 from .icon import Icon
+from .mixins.disableable_element import DisableableElement
 from .mixins.value_element import ValueElement
 
 
-class Input(ValueElement):
+class Input(ValueElement, DisableableElement):
     LOOPBACK = False
 
     def __init__(self,

+ 2 - 1
nicegui/elements/knob.py

@@ -2,10 +2,11 @@ from typing import Optional
 
 from ..colors import set_text_color
 from .label import Label
+from .mixins.disableable_element import DisableableElement
 from .mixins.value_element import ValueElement
 
 
-class Knob(ValueElement):
+class Knob(ValueElement, DisableableElement):
 
     def __init__(self,
                  value: float = 0.0,

+ 30 - 0
nicegui/elements/mixins/disableable_element.py

@@ -0,0 +1,30 @@
+from ...binding import BindableProperty
+from ...element import Element
+
+
+class DisableableElement(Element):
+    enabled = BindableProperty(on_change=lambda sender, value: sender.on_enabled_change(value))
+
+    def __init__(self, **kwargs) -> None:
+        super().__init__(**kwargs)
+        self.enabled = True
+
+    def enable(self) -> None:
+        """Enable the element."""
+        self.enabled = True
+
+    def disable(self) -> None:
+        """Disable the element."""
+        self.enabled = False
+
+    def set_enabled(self, value: bool) -> None:
+        """Set the enabled state of the element."""
+        self.enabled = value
+
+    def on_enabled_change(self, enabled: bool) -> None:
+        """Called when the element is enabled or disabled.
+
+        :param enabled: The new state.
+        """
+        self._props['disable'] = not enabled
+        self.update()

+ 2 - 1
nicegui/elements/number.py

@@ -1,9 +1,10 @@
 from typing import Any, Callable, Dict, Optional
 
+from .mixins.disableable_element import DisableableElement
 from .mixins.value_element import ValueElement
 
 
-class Number(ValueElement):
+class Number(ValueElement, DisableableElement):
     LOOPBACK = False
 
     def __init__(self,

+ 2 - 1
nicegui/elements/radio.py

@@ -1,9 +1,10 @@
 from typing import Any, Callable, Dict, List, Optional, Union
 
 from .choice_element import ChoiceElement
+from .mixins.disableable_element import DisableableElement
 
 
-class Radio(ChoiceElement):
+class Radio(ChoiceElement, DisableableElement):
 
     def __init__(self, options: Union[List, Dict], *, value: Any = None, on_change: Optional[Callable] = None):
         """Radio Selection

+ 2 - 1
nicegui/elements/select.py

@@ -5,11 +5,12 @@ from typing import Any, Callable, Dict, List, Optional, Union
 from nicegui.dependencies import register_component
 
 from .choice_element import ChoiceElement
+from .mixins.disableable_element import DisableableElement
 
 register_component('select', __file__, 'select.js')
 
 
-class Select(ChoiceElement):
+class Select(ChoiceElement, DisableableElement):
 
     def __init__(self, options: Union[List, Dict], *,
                  label: Optional[str] = None,

+ 2 - 1
nicegui/elements/slider.py

@@ -1,9 +1,10 @@
 from typing import Callable, Optional
 
+from .mixins.disableable_element import DisableableElement
 from .mixins.value_element import ValueElement
 
 
-class Slider(ValueElement):
+class Slider(ValueElement, DisableableElement):
 
     def __init__(self, *,
                  min: float,

+ 3 - 1
nicegui/elements/splitter.py

@@ -1,9 +1,11 @@
 from typing import Callable, Optional, Tuple
 
+from .mixins.disableable_element import DisableableElement
 from .mixins.value_element import ValueElement
 
 
-class Splitter(ValueElement):
+class Splitter(ValueElement, DisableableElement):
+
     def __init__(self, *,
                  horizontal: Optional[bool] = False,
                  reverse: Optional[bool] = False,

+ 2 - 1
nicegui/elements/switch.py

@@ -1,10 +1,11 @@
 from typing import Callable, Optional
 
+from .mixins.disableable_element import DisableableElement
 from .mixins.text_element import TextElement
 from .mixins.value_element import ValueElement
 
 
-class Switch(TextElement, ValueElement):
+class Switch(TextElement, ValueElement, DisableableElement):
 
     def __init__(self, text: str = '', *, value: bool = False, on_change: Optional[Callable] = None) -> None:
         """Switch

+ 5 - 5
nicegui/elements/tabs.py

@@ -1,7 +1,7 @@
 from typing import Any, Callable, Optional
 
 from .. import globals
-from ..element import Element
+from .mixins.disableable_element import DisableableElement
 from .mixins.value_element import ValueElement
 
 
@@ -22,7 +22,7 @@ class Tabs(ValueElement):
         self.panels: Optional[TabPanels] = None
 
 
-class Tab(Element):
+class Tab(DisableableElement):
 
     def __init__(self, name: str, label: Optional[str] = None, icon: Optional[str] = None) -> None:
         """Tab
@@ -34,7 +34,7 @@ class Tab(Element):
         :param label: label of the tab (default: `None`, meaning the same as `name`)
         :param icon: icon of the tab (default: `None`)
         """
-        super().__init__('q-tab')
+        super().__init__(tag='q-tab')
         self._props['name'] = name
         self._props['label'] = label if label is not None else name
         if icon:
@@ -65,7 +65,7 @@ class TabPanels(ValueElement):
         self._props['animated'] = animated
 
 
-class TabPanel(Element):
+class TabPanel(DisableableElement):
 
     def __init__(self, name: str) -> None:
         """Tab Panel
@@ -75,5 +75,5 @@ class TabPanel(Element):
 
         :param name: name of the tab panel (the value of the `TabPanels` element)
         """
-        super().__init__('q-tab-panel')
+        super().__init__(tag='q-tab-panel')
         self._props['name'] = name

+ 2 - 1
nicegui/elements/time.py

@@ -1,9 +1,10 @@
 from typing import Callable, Optional
 
+from .mixins.disableable_element import DisableableElement
 from .mixins.value_element import ValueElement
 
 
-class Time(ValueElement):
+class Time(ValueElement, DisableableElement):
 
     def __init__(self,
                  value: Optional[str] = None,

+ 2 - 1
nicegui/elements/toggle.py

@@ -1,9 +1,10 @@
 from typing import Any, Callable, Dict, List, Optional, Union
 
 from .choice_element import ChoiceElement
+from .mixins.disableable_element import DisableableElement
 
 
-class Toggle(ChoiceElement):
+class Toggle(ChoiceElement, DisableableElement):
 
     def __init__(self, options: Union[List, Dict], *, value: Any = None, on_change: Optional[Callable] = None) -> None:
         """Toggle

+ 3 - 3
nicegui/elements/upload.py

@@ -2,12 +2,12 @@ from typing import Callable, Optional
 
 from fastapi import Request, Response
 
-from ..element import Element
 from ..events import EventArguments, UploadEventArguments, handle_event
 from ..nicegui import app
+from .mixins.disableable_element import DisableableElement
 
 
-class Upload(Element):
+class Upload(DisableableElement):
 
     def __init__(self, *,
                  multiple: bool = False,
@@ -32,7 +32,7 @@ class Upload(Element):
         :param label: label for the uploader (default: `''`)
         :param auto_upload: automatically upload files when they are selected (default: `False`)
         """
-        super().__init__('q-uploader')
+        super().__init__(tag='q-uploader')
         self._props['multiple'] = multiple
         self._props['label'] = label
         self._props['auto-upload'] = auto_upload

+ 17 - 0
tests/test_button.py

@@ -16,3 +16,20 @@ def test_quasar_colors(screen: Screen):
     assert screen.find_by_id(b3.id).value_of_css_property('background-color') == 'rgba(239, 83, 80, 1)'
     assert screen.find_by_id(b4.id).value_of_css_property('background-color') == 'rgba(239, 68, 68, 1)'
     assert screen.find_by_id(b5.id).value_of_css_property('background-color') == 'rgba(255, 0, 0, 1)'
+
+
+def test_enable_disable(screen: Screen):
+    events = []
+    b = ui.button('Button', on_click=lambda: events.append(1))
+    ui.button('Enable', on_click=b.enable)
+    ui.button('Disable', on_click=b.disable)
+
+    screen.open('/')
+    screen.click('Button')
+    assert events == [1]
+    screen.click('Disable')
+    screen.click('Button')
+    assert events == [1]
+    screen.click('Enable')
+    screen.click('Button')
+    assert events == [1, 1]

+ 10 - 0
website/more_documentation/slider_documentation.py

@@ -35,3 +35,13 @@ def more() -> None:
         ui.slider(min=0, max=10, step=0.1, value=5).props('label-always') \
             .on('update:model-value', lambda msg: ui.notify(f'{msg["args"]}'),
                 throttle=1.0, leading_events=False)
+
+    @text_demo('Disable slider', '''
+        You can disable a slider with the `disable()` method.
+        This will prevent the user from moving the slider.
+        The slider will also be grayed out.
+    ''')
+    def disable_slider():
+        slider = ui.slider(min=0, max=100, value=50)
+        ui.button('Disable slider', on_click=slider.disable)
+        ui.button('Enable slider', on_click=slider.enable)