-
Notifications
You must be signed in to change notification settings - Fork 1
/
mdbars.py
147 lines (128 loc) · 5.86 KB
/
mdbars.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
from kivymd.uix.floatlayout import MDFloatLayout
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.tooltip import MDTooltip
from kivy.graphics import Color
from kivy.graphics.vertex_instructions import RoundedRectangle, Line
from kivy.properties import ObjectProperty, ColorProperty, BoundedNumericProperty, ListProperty, NumericProperty
from typing import Optional, Union
from .utils import metrics
class MDBar(MDFloatLayout, MDTooltip):
percent = BoundedNumericProperty(0, min=0, max=1)
bar_background_color = ColorProperty((.5, .5, .5, .05))
bar_percent_color = ColorProperty((0, 0, 0, 1))
bar_border_color = ColorProperty((0, 0, 0, .5))
_bar_background = ObjectProperty()
_bar_percent = ObjectProperty()
_bar_border = ObjectProperty()
def __init__(self,
percent: Optional[Union[int, float]] = None,
bar_background_color: Optional[tuple] = None,
bar_percent_color: Optional[tuple] = None,
bar_border_color: Optional[tuple] = None,
**kwargs):
if percent is not None:
self.percent = percent
if bar_background_color is not None:
self.bar_background_color = bar_background_color
if bar_percent_color is not None:
self.bar_percent_color = bar_percent_color
if bar_border_color is not None:
self.bar_border_color = bar_border_color
super().__init__(**kwargs)
self.bar_percent_color = self.theme_cls.primary_color
c = self.create_bar
self.bind(percent=c, bar_background_color=c, bar_percent_color=c, size=c, pos=c, on_size=c, on_pos=c, width=c)
self.create_bar()
def create_bar(self, *args):
self.canvas.before.clear()
self.canvas.clear()
self.canvas.after.clear()
with self.canvas.before:
Color(*self.bar_background_color)
self._bar_background = RoundedRectangle(pos=self.pos, size_hint=(None, None),
size=(self.width, self.height),
radius=[self.width // 2, ])
with self.canvas:
Color(*self.bar_percent_color)
self._bar_percent = RoundedRectangle(pos=self.pos, size_hint=(None, None),
size=(self.width, self.height * self.percent),
radius=[self.width // 2, ])
with self.canvas.after:
Color(*self.bar_border_color)
self._bar_border = Line(
pos=self.pos, size_hint=(1, self.percent),
rounded_rectangle=(self.pos[0], self.pos[1], self.width, self.height, 100))
class MDBars(MDBoxLayout):
_max_value = NumericProperty(None)
values = ListProperty([])
descriptions = ListProperty([])
bars = ListProperty([])
bar_width = ObjectProperty('25dp')
bar_color = ColorProperty(None)
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.spacing = '20dp'
self.spacing = '20dp'
self.bind(values=self._value_changed, descriptions=self._description_changed, size=self._size_changed,
bar_width=self._size_changed, bar_color=self._color_changed)
def add_bar(self, value: int, description: str):
if self._max_value is None:
self._max_value = value
elif value > self._max_value:
self._max_value = value
__new_bar = MDBar(percent=0 if self._max_value == 0 else value / self._max_value,
size_hint=(None, 1), width=self.bar_width)
self.add_widget(__new_bar)
self.bars.append(__new_bar)
self.values.append(value)
self.descriptions.append(description)
def update_values(self, *args, **kwargs):
__list = args
__values = kwargs.get('values', None)
if isinstance(args[0], list):
__list = args[0]
elif __values is not None:
if isinstance(__values, list):
__list = __values
self.values = __list
def update_descriptions(self, *args, **kwargs):
__list = args
__values = kwargs.get('descriptions', None)
if isinstance(args[0], list):
__list = args[0]
elif __values is not None:
if isinstance(__values, list):
__list = __values
self.descriptions = __list
self._description_changed()
def _size_changed(self, *args):
__bar_width = metrics(self.bar_width)
__padding = self._is_list(self.padding)
__spacing = self._is_list(self.spacing)
__self_width = metrics(self.width) - __padding - __spacing * (len(self.bars) - 1)
_new_width = min(__bar_width, __self_width / len(self.bars))
for bar in self.bars:
bar.width = _new_width
def _color_changed(self, *args):
if self.bar_color is not None:
for bar in self.bars:
bar.bar_percent_color = self.bar_color
def _value_changed(self, *args):
if len(self.values) != len(self.bars):
raise Exception('The number of values is different from the bars quantity.')
self._max_value = max(self.values)
self._update()
def _description_changed(self, *args):
if len(self.descriptions) != len(self.bars):
raise Exception('The number of descriptions is different from the bars quantity.')
for idx, bar in enumerate(self.bars):
bar.tooltip_text = self.descriptions[idx]
def _update(self):
for idx, bar in enumerate(self.bars):
bar.percent = 0 if self._max_value == 0 else self.values[idx] / self._max_value
@staticmethod
def _is_list(value) -> Union[float, int]:
if isinstance(value, list):
return metrics(value[0]) + metrics(value[2])
else:
return metrics(value)