Jelajahi Sumber

Merge pull request #144 from hroemer/main

#107: providing ui.linear_progress and ui.circular_progress elements
Falko Schindler 2 tahun lalu
induk
melakukan
27c33bb0be

+ 17 - 0
api_docs_and_examples.py

@@ -316,6 +316,12 @@ To overlay an SVG, make the `viewBox` exactly the size of the image and provide
         line_updates = ui.timer(0.1, update_line_plot, active=False)
         line_updates = ui.timer(0.1, update_line_plot, active=False)
         line_checkbox = ui.checkbox('active').bind_value(line_updates, 'active')
         line_checkbox = ui.checkbox('active').bind_value(line_updates, 'active')
 
 
+    with example(ui.linear_progress):
+        ui.linear_progress(value=0.3)
+
+    with example(ui.circular_progress):
+        ui.circular_progress(value=0.67)
+
     with example(ui.scene):
     with example(ui.scene):
         with ui.scene(width=225, height=225) as scene:
         with ui.scene(width=225, height=225) as scene:
             scene.sphere().material('#4488ff')
             scene.sphere().material('#4488ff')
@@ -544,6 +550,10 @@ Just pass a property of the model as parameter to these methods to create the bi
             def __init__(self):
             def __init__(self):
                 self.number = 1
                 self.number = 1
 
 
+            @property
+            def progress(self) -> float:
+                return (self.number - 1) / 2
+
         demo = Demo()
         demo = Demo()
         v = ui.checkbox('visible', value=True)
         v = ui.checkbox('visible', value=True)
         with ui.column().bind_visibility_from(v, 'value'):
         with ui.column().bind_visibility_from(v, 'value'):
@@ -551,6 +561,13 @@ Just pass a property of the model as parameter to these methods to create the bi
             ui.toggle({1: 'a', 2: 'b', 3: 'c'}).bind_value(demo, 'number')
             ui.toggle({1: 'a', 2: 'b', 3: 'c'}).bind_value(demo, 'number')
             ui.number().bind_value(demo, 'number')
             ui.number().bind_value(demo, 'number')
 
 
+            with ui.linear_progress(target_object=demo, target_name='progress'):
+                with ui.container(classes='absolute-full flex flex-center'):
+                    lbl = ui.label(text='number').classes('text-center text-subtitle2 text-white')
+                    lbl.bind_text_from(demo, 'progress')
+
+            ui.circular_progress(target_object=demo, target_name='progress')
+
     ui_updates = '''#### UI Updates
     ui_updates = '''#### UI Updates
 
 
 NiceGUI tries to automatically synchronize the state of UI elements with the client, e.g. when a label text, an input value or style/classes/props of an element have changed.
 NiceGUI tries to automatically synchronize the state of UI elements with the client, e.g. when a label text, an input value or style/classes/props of an element have changed.

+ 17 - 0
nicegui/auto_context.py

@@ -74,3 +74,20 @@ class AutoUpdaterForAsyncs:
                 message = yield signal
                 message = yield signal
             except BaseException as err:
             except BaseException as err:
                 send, message = iter_throw, err
                 send, message = iter_throw, err
+
+
+class ContextMixin:
+    """
+    Mixin providing a context manager for additional components.
+    copied from nicegui.elements.group.Group
+    """
+
+    def __enter__(self):
+        self._child_count_on_enter = len(self.view)
+        get_view_stack().append(self.view)
+        return self
+
+    def __exit__(self, *_):
+        get_view_stack().pop()
+        if self._child_count_on_enter != len(self.view):
+            self.update()

+ 11 - 0
nicegui/elements/container.py

@@ -0,0 +1,11 @@
+import justpy as jp
+
+from .group import Group
+
+
+class Container(Group):
+
+    def __init__(self, **kwargs):
+        """QDiv Container"""
+        view = jp.QDiv(temp=True, **kwargs)
+        super().__init__(view)

+ 57 - 0
nicegui/elements/progress.py

@@ -0,0 +1,57 @@
+from .float_element import FloatElement
+from .quasarcommponents import QLinearProgressExtended, QCircularProgressExtended
+from ..auto_context import ContextMixin
+
+
+class LinearProgress(FloatElement, ContextMixin):
+
+    def __init__(self, *, value: float = 0.0, target_object=None, target_name=None, **kwargs):
+        """LinearProgress
+
+        An element to create a linear progress bar wrapping
+        `Linear Progress <https://v1.quasar.dev/vue-components/linear-progress>`_ component.
+
+        :param value: the initial value of the field (ratio 0.0 - 1.0)
+        :param target_object: the object to data bind to
+        :param target_name: the field name of the data bound object
+        """
+        view = QLinearProgressExtended(color='primary', size='1.4rem', value=value, temp=False)
+        super().__init__(view, value=value, on_change=None, **kwargs)
+        if target_object and target_name:
+            self.bind_value_from(target_object=target_object, target_name=target_name)
+
+
+class CircularProgress(FloatElement, ContextMixin):
+
+    def __init__(self, *, value: float = 0.0, target_object=None, target_name=None, show_value: bool = True,
+                 **kwargs):
+        """CircularProgress
+
+        An element to create a linear progress bar wrapping
+        `Circular Progress <https://v1.quasar.dev/vue-components/circular-progress>`_ component.
+
+        :param value: the initial value of the field (ratio 0.0 - 1.0)
+        :param target_object: the object to data bind to
+        :param target_name: the field name of the data bound object
+        """
+        value = self._convert_ratio(value)
+        view = QCircularProgressExtended(color='primary', value=value, temp=False,
+                                         track_color='grey-4',
+                                         center_color='transparent',
+                                         size='xl', show_value=show_value)
+        super().__init__(view, value=value, on_change=None, **kwargs)
+        if target_object and target_name:
+            self.bind_value_from(target_object=target_object, target_name=target_name)
+
+    @property
+    def value(self):
+        val = getattr(self, '_value')
+        return val
+
+    @value.setter
+    def value(self, value):
+        val = self._convert_ratio(value=value)
+        setattr(self, '_value', val)
+
+    def _convert_ratio(self, value: float) -> float:
+        return round(value * 100, 2) if 0.0 <= value <= 1.0 else float(value)

+ 18 - 0
nicegui/elements/quasarcommponents.py

@@ -0,0 +1,18 @@
+from justpy import parse_dict, QCircularProgress, QLinearProgress
+
+
+@parse_dict
+class QCircularProgressExtended(QCircularProgress):
+
+    def __init__(self, **kwargs):
+        super().__init__(**kwargs)
+        self.prop_list.extend(['instant-feedback'])
+
+
+@parse_dict
+class QLinearProgressExtended(QLinearProgress):
+
+    def __init__(self, **kwargs):
+        super().__init__(**kwargs)
+        # add upstream missing properties
+        self.prop_list.extend(['size'])

+ 3 - 0
nicegui/ui.py

@@ -22,6 +22,7 @@ class Ui:
     from .elements.color_picker import ColorPicker as color_picker
     from .elements.color_picker import ColorPicker as color_picker
     from .elements.colors import Colors as colors
     from .elements.colors import Colors as colors
     from .elements.column import Column as column
     from .elements.column import Column as column
+    from .elements.container import Container as container
     from .elements.dialog import Dialog as dialog
     from .elements.dialog import Dialog as dialog
     from .elements.expansion import Expansion as expansion
     from .elements.expansion import Expansion as expansion
     from .elements.html import Html as html
     from .elements.html import Html as html
@@ -41,6 +42,8 @@ class Ui:
     from .elements.notify import Notify as notify
     from .elements.notify import Notify as notify
     from .elements.number import Number as number
     from .elements.number import Number as number
     from .elements.open import open, open_async
     from .elements.open import open, open_async
+    from .elements.progress import LinearProgress as linear_progress
+    from .elements.progress import CircularProgress as circular_progress
     from .elements.radio import Radio as radio
     from .elements.radio import Radio as radio
     from .elements.row import Row as row
     from .elements.row import Row as row
     from .elements.scene import Scene as scene
     from .elements.scene import Scene as scene