Reference client for Bitmessage: a P2P encrypted decentralised communication protocol:
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

149 lines
4.8 KiB

# -*- coding: utf-8 -*-
from kivy.lang import Builder
from kivy.uix.widget import Widget
from kivy.properties import NumericProperty, ListProperty, BooleanProperty
from kivy.animation import Animation
from kivymd.theming import ThemableBehavior
from kivy.clock import Clock
Builder.load_string('''
<MDSpinner>:
canvas.before:
PushMatrix
Rotate:
angle: self._rotation_angle
origin: self.center
canvas:
Color:
rgba: self.color
a: self._alpha
Line:
circle: self.center_x, self.center_y, self.width / 2, \
self._angle_start, self._angle_end
cap: 'square'
width: dp(2)
canvas.after:
PopMatrix
''')
class MDSpinner(ThemableBehavior, Widget):
""":class:`MDSpinner` is an implementation of the circular progress
indicator in Google's Material Design.
It can be used either as an indeterminate indicator that loops while
the user waits for something to happen, or as a determinate indicator.
Set :attr:`determinate` to **True** to activate determinate mode, and
:attr:`determinate_time` to set the duration of the animation.
"""
determinate = BooleanProperty(False)
""":attr:`determinate` is a :class:`~kivy.properties.BooleanProperty` and
defaults to False
"""
determinate_time = NumericProperty(2)
""":attr:`determinate_time` is a :class:`~kivy.properties.NumericProperty`
and defaults to 2
"""
active = BooleanProperty(True)
"""Use :attr:`active` to start or stop the spinner.
:attr:`active` is a :class:`~kivy.properties.BooleanProperty` and
defaults to True
"""
color = ListProperty([])
""":attr:`color` is a :class:`~kivy.properties.ListProperty` and
defaults to 'self.theme_cls.primary_color'
"""
_alpha = NumericProperty(0)
_rotation_angle = NumericProperty(360)
_angle_start = NumericProperty(0)
_angle_end = NumericProperty(8)
def __init__(self, **kwargs):
super(MDSpinner, self).__init__(**kwargs)
Clock.schedule_interval(self._update_color, 5)
self.color = self.theme_cls.primary_color
self._alpha_anim_in = Animation(_alpha=1, duration=.8, t='out_quad')
self._alpha_anim_out = Animation(_alpha=0, duration=.3, t='out_quad')
self._alpha_anim_out.bind(on_complete=self._reset)
if self.determinate:
self._start_determinate()
else:
self._start_loop()
def _update_color(self, *args):
self.color = self.theme_cls.primary_color
def _start_determinate(self, *args):
self._alpha_anim_in.start(self)
_rot_anim = Animation(_rotation_angle=0,
duration=self.determinate_time * .7,
t='out_quad')
_rot_anim.start(self)
_angle_start_anim = Animation(_angle_end=360,
duration=self.determinate_time,
t='in_out_quad')
_angle_start_anim.bind(on_complete=lambda *x: \
self._alpha_anim_out.start(self))
_angle_start_anim.start(self)
def _start_loop(self, *args):
if self._alpha == 0:
_rot_anim = Animation(_rotation_angle=0,
duration=2,
t='linear')
_rot_anim.start(self)
self._alpha = 1
self._alpha_anim_in.start(self)
_angle_start_anim = Animation(_angle_end=self._angle_end + 270,
duration=.6,
t='in_out_cubic')
_angle_start_anim.bind(on_complete=self._anim_back)
_angle_start_anim.start(self)
def _anim_back(self, *args):
_angle_back_anim = Animation(_angle_start=self._angle_end - 8,
duration=.6,
t='in_out_cubic')
_angle_back_anim.bind(on_complete=self._start_loop)
_angle_back_anim.start(self)
def on__rotation_angle(self, *args):
if self._rotation_angle == 0:
self._rotation_angle = 360
if not self.determinate:
_rot_anim = Animation(_rotation_angle=0,
duration=2)
_rot_anim.start(self)
def _reset(self, *args):
Animation.cancel_all(self, '_angle_start', '_rotation_angle',
'_angle_end', '_alpha')
self._angle_start = 0
self._angle_end = 8
self._rotation_angle = 360
self._alpha = 0
self.active = False
def on_active(self, *args):
if not self.active:
self._reset()
else:
if self.determinate:
self._start_determinate()
else:
self._start_loop()