Sideband/sbapp/kivymd/uix/behaviors/motion_behavior.py

288 lines
7.2 KiB
Python

"""
Behaviors/Motion
================
.. rubric:: Use motion to make a UI expressive and easy to use.
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/motion.png
:align: center
.. versionadded:: 1.2.0
Classes of the `Motion` type implement the display behavior of widgets such
as dialogs, dropdown menu, snack bars, and so on.
"""
__all__ = (
"MotionBase",
"MotionDropDownMenuBehavior",
"MotionDialogBehavior",
"MotionShackBehavior",
)
from kivy.animation import Animation
from kivy.clock import Clock
from kivy.core.window import Window
from kivy.properties import StringProperty, NumericProperty
from kivymd.uix.behaviors.stencil_behavior import StencilBehavior
class MotionBase:
"""Base class for widget display movement behavior."""
show_transition = StringProperty("linear")
"""
The type of transition of the widget opening.
:attr:`show_transition` is a :class:`~kivy.properties.StringProperty`
and defaults to `'linear'`.
"""
show_duration = NumericProperty(0.2)
"""
Duration of widget display transition.
:attr:`show_duration` is a :class:`~kivy.properties.NumericProperty`
and defaults to `0.2`.
"""
hide_transition = StringProperty("linear")
"""
The type of transition of the widget closing.
:attr:`hide_transition` is a :class:`~kivy.properties.StringProperty`
and defaults to `'linear'`.
"""
hide_duration = NumericProperty(0.2)
"""
Duration of widget closing transition.
:attr:`hide_duration` is a :class:`~kivy.properties.NumericProperty`
and defaults to `0.2`.
"""
class MotionDropDownMenuBehavior(MotionBase):
"""
Base class for the dropdown menu movement behavior.
For more information, see in the :class:`~MotionBase` class documentation.
"""
show_transition = StringProperty("out_back")
"""
The type of transition of the widget opening.
:attr:`show_transition` is a :class:`~kivy.properties.StringProperty`
and defaults to `'out_back'`.
"""
show_duration = NumericProperty(0.4)
"""
Duration of widget display transition.
:attr:`show_duration` is a :class:`~kivy.properties.NumericProperty`
and defaults to `0.2`.
"""
hide_transition = StringProperty("out_cubic")
"""
The type of transition of the widget closing.
:attr:`hide_transition` is a :class:`~kivy.properties.StringProperty`
and defaults to `'out_cubic'`.
"""
_scale_x = NumericProperty(None)
"""
Default X-axis scaling values.
:attr:`_scale_x` is a :class:`~kivy.properties.NumericProperty`
and defaults to `None`.
"""
_scale_y = NumericProperty(None)
"""
Default Y-axis scaling values.
:attr:`_scale_y` is a :class:`~kivy.properties.NumericProperty`
and defaults to `None`.
"""
_opacity = NumericProperty(None)
"""
Menu transparency values.
:attr:`_opacity` is a :class:`~kivy.properties.NumericProperty`
and defaults to `None`.
"""
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.set_scale()
# self.set_opacity()
def set_opacity(self) -> None:
self._opacity = 0
def set_scale(self) -> None:
self._scale_x = 0
self._scale_y = 0
def on_dismiss(self) -> None:
Window.remove_widget(self)
# anim = Animation(
# _scale_x=0,
# _scale_y=0,
# # _opacity=0,
# duration=self.hide_duration,
# transition=self.hide_transition,
# )
# anim.bind(on_complete=lambda *args: Window.remove_widget(self))
# anim.start(self)
def on_open(self, *args):
pass
anim = Animation(
_scale_y=1,
# _opacity=1,
duration=0.0,
transition=self.show_transition,
)
anim &= Animation(
_scale_x=1,
duration=0.0,
transition="out_quad",
)
anim.start(self)
def on__opacity(self, instance, value):
self.opacity = value
def on__scale_x(self, instance, value):
self.scale_value_x = value
def on__scale_y(self, instance, value):
self.scale_value_y = value
class MotionDialogBehavior(MotionBase):
"""
Base class for dialog movement behavior.
For more information, see in the :class:`~MotionBase` class documentation.
"""
show_duration = NumericProperty(0.0)
"""
Duration of widget display transition.
:attr:`show_duration` is a :class:`~kivy.properties.NumericProperty`
and defaults to `0.1`.
"""
scale_x = NumericProperty(1.0)
"""
Default X-axis scaling values.
:attr:`scale_x` is a :class:`~kivy.properties.NumericProperty`
and defaults to `1.5`.
"""
scale_y = NumericProperty(1.0)
"""
Default Y-axis scaling values.
:attr:`scale_y` is a :class:`~kivy.properties.NumericProperty`
and defaults to `1.5`.
"""
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.set_default_values()
def set_default_values(self):
"""Sets default scaled and transparency values."""
self.scale_value_x = self.scale_x
self.scale_value_y = self.scale_y
self.opacity = 0
def on_dismiss(self, *args):
"""Called when a dialog closed."""
self.set_default_values()
def on_open(self, *args):
"""Called when a dialog opened."""
Animation(
opacity=1,
scale_value_x=1,
scale_value_y=1,
t=self.show_transition,
d=self.show_duration,
).start(self)
class MotionShackBehavior(StencilBehavior, MotionBase):
"""
The base class for the behavior of the movement of snack bars.
For more information, see in the
:class:`~MotionBase` class and
:class:`~kivy.uix.behaviors.stencil_behavior.StencilBehavior` class
documentation.
"""
_interval = 0
_height = 0
def on_dismiss(self, *args):
"""Called when a snackbar closed."""
def remove_snackbar(*args):
Window.parent.remove_widget(self)
self.height = self._height
self.dispatch("on_dismiss")
Clock.unschedule(self._wait_interval)
anim = Animation(
opacity=0,
height=0,
t=self.hide_transition,
d=self.hide_duration,
)
anim.bind(on_complete=remove_snackbar)
anim.start(self)
def on_open(self, *args):
"""Called when a snackbar opened."""
def open(*args):
self._height = self.height
self.height = 0
anim = Animation(
opacity=1,
height=self._height,
t=self.show_transition,
d=self.show_duration,
)
anim.bind(
on_complete=lambda *args: Clock.schedule_interval(
self._wait_interval, 1
)
)
anim.start(self)
Clock.schedule_once(open)
self.dispatch("on_open")
def _wait_interval(self, interval):
self._interval += interval
if self._interval > self.duration:
self.dismiss()
self._interval = 0