globalforest/kivymd/uix/progressbar.py

314 lines
8.1 KiB
Python
Raw Permalink Normal View History

2020-10-14 00:19:43 -04:00
"""
Components/Progress Bar
=======================
.. seealso::
`Material Design spec, Progress indicators https://material.io/components/progress-indicators`_
.. rubric:: Progress indicators express an unspecified wait time or display
the length of a process.
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/progress-bar-preview.png
:align: center
`KivyMD` provides the following bars classes for use:
- MDProgressBar_
- Determinate_
- Indeterminate_
.. MDProgressBar:
MDProgressBar
-------------
.. code-block:: python
from kivy.lang import Builder
from kivymd.app import MDApp
KV = '''
BoxLayout:
padding: "10dp"
MDProgressBar:
value: 50
'''
class Test(MDApp):
def build(self):
return Builder.load_string(KV)
Test().run()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/progress-bar.png
:align: center
Vertical orientation
--------------------
.. code-block:: kv
MDProgressBar:
orientation: "vertical"
value: 50
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/progress-bar-vertical.png
:align: center
With custom color
-----------------
.. code-block:: kv
MDProgressBar:
value: 50
color: app.theme_cls.accent_color
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/progress-bar-custom-color.png
:align: center
.. Indeterminate:
Indeterminate
-------------
.. code-block:: python
from kivy.lang import Builder
from kivy.properties import StringProperty
from kivymd.app import MDApp
KV = '''
Screen:
MDProgressBar:
id: progress
pos_hint: {"center_y": .6}
type: "indeterminate"
MDRaisedButton:
text: "START"
pos_hint: {"center_x": .5, "center_y": .45}
on_press: app.state = "stop" if app.state == "start" else "start"
'''
class Test(MDApp):
state = StringProperty("stop")
def build(self):
return Builder.load_string(KV)
def on_state(self, instance, value):
{
"start": self.root.ids.progress.start,
"stop": self.root.ids.progress.stop,
}.get(value)()
Test().run()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/indeterminate-progress-bar.gif
:align: center
.. Determinate:
Determinate
-----------
.. code-block:: kv
MDProgressBar:
type: "determinate"
running_duration: 1
catching_duration: 1.5
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/determinate-progress-bar.gif
:align: center
"""
__all__ = ("MDProgressBar",)
from kivy.animation import Animation
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.properties import (
BooleanProperty,
ListProperty,
NumericProperty,
OptionProperty,
StringProperty,
)
from kivy.uix.progressbar import ProgressBar
from kivymd.theming import ThemableBehavior
Builder.load_string(
"""
<MDProgressBar>
canvas:
Clear
Color:
rgba: self.theme_cls.divider_color
Rectangle:
size:
(self.width, dp(4)) \
if self.orientation == "horizontal" \
else (dp(4), self.height)
pos:
(self.x, self.center_y - dp(4)) \
if self.orientation == "horizontal" \
else (self.center_x - dp(4),self.y)
Color:
rgba:
self.theme_cls.primary_color if not self.color else self.color
Rectangle:
size:
(self.width * self.value_normalized, sp(4)) \
if self.orientation == "horizontal" \
else (sp(4), self.height * self.value_normalized)
pos:
(self.width * (1 - self.value_normalized) + self.x \
if self.reversed else self.x + self._x, self.center_y - dp(4)) \
if self.orientation == "horizontal" \
else (self.center_x - dp(4),self.height \
* (1 - self.value_normalized) + self.y if self.reversed \
else self.y)
"""
)
class MDProgressBar(ThemableBehavior, ProgressBar):
reversed = BooleanProperty(False)
"""Reverse the direction the progressbar moves.
:attr:`reversed` is an :class:`~kivy.properties.BooleanProperty`
and defaults to `False`.
"""
orientation = OptionProperty(
"horizontal", options=["horizontal", "vertical"]
)
"""Orientation of progressbar. Available options are: `'horizontal '`,
`'vertical'`.
:attr:`orientation` is an :class:`~kivy.properties.OptionProperty`
and defaults to `'horizontal'`.
"""
color = ListProperty()
"""
Progress bar color in ``rgba`` format.
:attr:`color` is an :class:`~kivy.properties.OptionProperty`
and defaults to `[]`.
"""
running_transition = StringProperty("in_cubic")
"""Running transition.
:attr:`running_transition` is an :class:`~kivy.properties.StringProperty`
and defaults to `'in_cubic'`.
"""
catching_transition = StringProperty("out_quart")
"""Catching transition.
:attr:`catching_transition` is an :class:`~kivy.properties.StringProperty`
and defaults to `'out_quart'`.
"""
running_duration = NumericProperty(0.5)
"""Running duration.
:attr:`running_duration` is an :class:`~kivy.properties.NumericProperty`
and defaults to `0.5`.
"""
catching_duration = NumericProperty(0.8)
"""Catching duration.
:attr:`running_duration` is an :class:`~kivy.properties.NumericProperty`
and defaults to `0.8`.
"""
type = OptionProperty(
None, options=["indeterminate", "determinate"], allownone=True
)
"""Type of progressbar. Available options are: `'indeterminate '`,
`'determinate'`.
:attr:`type` is an :class:`~kivy.properties.OptionProperty`
and defaults to `None`.
"""
_x = NumericProperty(0)
def __init__(self, **kwargs):
self.catching_anim = None
self.running_anim = None
super().__init__(**kwargs)
def start(self):
"""Start animation."""
if self.type in ("indeterminate", "determinate"):
Clock.schedule_once(self._set_default_value)
if not self.catching_anim and not self.running_anim:
if self.type == "indeterminate":
self._create_indeterminate_animations()
else:
self._create_determinate_animations()
self.running_away()
def stop(self):
"""Stop animation."""
Animation.cancel_all(self)
self._set_default_value(0)
def running_away(self, *args):
self._set_default_value(0)
self.running_anim.start(self)
def catching_up(self, *args):
if self.type == "indeterminate":
self.reversed = True
self.catching_anim.start(self)
def _create_determinate_animations(self):
self.running_anim = Animation(
value=100,
opacity=1,
t=self.running_transition,
d=self.running_duration,
)
self.running_anim.bind(on_complete=self.catching_up)
self.catching_anim = Animation(
opacity=0,
t=self.catching_transition,
d=self.catching_duration,
)
self.catching_anim.bind(on_complete=self.running_away)
def _create_indeterminate_animations(self):
self.running_anim = Animation(
_x=self.width / 2,
value=50,
t=self.running_transition,
d=self.running_duration,
)
self.running_anim.bind(on_complete=self.catching_up)
self.catching_anim = Animation(
value=0, t=self.catching_transition, d=self.catching_duration
)
self.catching_anim.bind(on_complete=self.running_away)
def _set_default_value(self, interval):
self._x = 0
self.value = 0
self.reversed = False