Browse Source

#107: adding linear and circular progress components

Hannes Römer 2 years ago
parent
commit
78f3135368
5 changed files with 98 additions and 0 deletions
  1. 23 0
      api_docs_and_examples.py
  2. 17 0
      nicegui/auto_context.py
  3. 12 0
      nicegui/elements/div.py
  4. 44 0
      nicegui/elements/progress.py
  5. 2 0
      nicegui/ui.py

+ 23 - 0
api_docs_and_examples.py

@@ -7,6 +7,7 @@ import docutils.core
 
 from nicegui import ui
 from nicegui.auto_context import Context
+from nicegui.elements.div import Div
 from nicegui.task_logger import create_task
 
 REGEX_H4 = re.compile(r'<h4.*?>(.*?)</h4>')
@@ -315,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_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=67.0)
+
     with example(ui.scene):
         with ui.scene(width=225, height=225) as scene:
             scene.sphere().material('#4488ff')
@@ -540,6 +547,13 @@ Just pass a property of the model as parameter to these methods to create the bi
             def __init__(self):
                 self.number = 1
 
+            @property
+            def progress_float(self) -> float:
+                return (self.number - 1) / 2
+            @property
+            def progress(self) -> int:
+                return int(self.progress_float * 100)
+
         demo = Demo()
         v = ui.checkbox('visible', value=True)
         with ui.column().bind_visibility_from(v, 'value'):
@@ -547,6 +561,15 @@ 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.number().bind_value(demo, 'number')
 
+            with ui.linear_progress(target_object=demo, target_name='progress_float') as progress:
+                with Div() as progress_lbl:
+                    progress_lbl.classes(add='absolute-full flex flex-center')
+                    lbl = ui.label(text='number')
+                    lbl.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
 
 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
             except BaseException as 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()

+ 12 - 0
nicegui/elements/div.py

@@ -0,0 +1,12 @@
+import justpy as jp
+
+from .element import Element
+from ..auto_context import ContextMixin
+
+
+class Div(Element, ContextMixin):
+
+    def __init__(self, **kwargs):
+        """QDiv Container"""
+        view = jp.QDiv(temp=True, **kwargs)
+        super().__init__(view)

+ 44 - 0
nicegui/elements/progress.py

@@ -0,0 +1,44 @@
+import justpy as jp
+
+from .float_element import FloatElement
+from ..auto_context import ContextMixin
+
+
+class LinearProgress(FloatElement, ContextMixin):
+
+    def __init__(self, *, value: float = 0, target_object=None, target_name=None, **kwargs):
+        """LinearProgress
+
+        An element to create a linear progress bar wrapping
+        `Linear Progress <https://quasar.dev/vue-components/linear-progress>`_ component.
+
+        :param value: the initial value of the field
+        :param target_object: the object to data bind to
+        :param target_name: the field name of the data bound object
+        """
+        view = jp.QLinearProgress(color='primary', style="height: 6em;", 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, target_object=None, target_name=None, show_value: bool = True,
+                 **kwargs):
+        """CircularProgress
+
+        An element to create a linear progress bar wrapping
+        `Circular Progress <https://quasar.dev/vue-components/circular-progress>`_ component.
+
+        :param value: the initial value of the field
+        :param target_object: the object to data bind to
+        :param target_name: the field name of the data bound object
+        """
+        view = jp.QCircularProgress(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)

+ 2 - 0
nicegui/ui.py

@@ -41,6 +41,8 @@ class Ui:
     from .elements.notify import Notify as notify
     from .elements.number import Number as number
     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.row import Row as row
     from .elements.scene import Scene as scene