248 lines
8.8 KiB
Python
248 lines
8.8 KiB
Python
|
# -*- coding: utf-8 -*-
|
||
|
|
||
|
from kivy.lang import Builder
|
||
|
from kivy.properties import StringProperty, ListProperty, NumericProperty,AliasProperty, BooleanProperty
|
||
|
from kivy.utils import get_color_from_hex
|
||
|
from kivy.metrics import dp, sp
|
||
|
from kivymd.color_definitions import colors
|
||
|
from kivymd.theming import ThemableBehavior
|
||
|
from kivy.uix.slider import Slider
|
||
|
|
||
|
|
||
|
Builder.load_string('''
|
||
|
#:import Thumb kivymd.selectioncontrols.Thumb
|
||
|
|
||
|
<MDSlider>:
|
||
|
id: slider
|
||
|
canvas:
|
||
|
Clear
|
||
|
Color:
|
||
|
rgba: self._track_color_disabled if self.disabled else (self._track_color_active if self.active \
|
||
|
else self._track_color_normal)
|
||
|
Rectangle:
|
||
|
size: (self.width - self.padding*2 - self._offset[0], dp(4)) if self.orientation == 'horizontal' \
|
||
|
else (dp(4),self.height - self.padding*2 - self._offset[1])
|
||
|
pos: (self.x + self.padding + self._offset[0], self.center_y - dp(4)) \
|
||
|
if self.orientation == 'horizontal' else (self.center_x - dp(4),self.y + self.padding + self._offset[1])
|
||
|
|
||
|
# If 0 draw circle
|
||
|
Color:
|
||
|
rgba: [0,0,0,0] if not self._is_off else (self._track_color_disabled if self.disabled \
|
||
|
else (self._track_color_active if self.active else self._track_color_normal))
|
||
|
Line:
|
||
|
width: 2
|
||
|
circle: (self.x+self.padding+dp(3),self.center_y-dp(2),8 if self.active else 6 ) \
|
||
|
if self.orientation == 'horizontal' else (self.center_x-dp(2),self.y+self.padding+dp(3),8 \
|
||
|
if self.active else 6)
|
||
|
|
||
|
Color:
|
||
|
rgba: [0,0,0,0] if self._is_off \
|
||
|
else (self.thumb_color_down if not self.disabled else self._track_color_disabled)
|
||
|
Rectangle:
|
||
|
size: ((self.width-self.padding*2)*self.value_normalized, sp(4)) \
|
||
|
if slider.orientation == 'horizontal' else (sp(4), (self.height-self.padding*2)*self.value_normalized)
|
||
|
pos: (self.x + self.padding, self.center_y - dp(4)) if self.orientation == 'horizontal' \
|
||
|
else (self.center_x - dp(4),self.y + self.padding)
|
||
|
Thumb:
|
||
|
id: thumb
|
||
|
size_hint: None, None
|
||
|
size: (dp(12), dp(12)) if root.disabled else ((dp(24), dp(24)) if root.active else (dp(16),dp(16)))
|
||
|
pos: (slider.value_pos[0] - dp(8), slider.center_y - thumb.height/2 - dp(2)) \
|
||
|
if slider.orientation == 'horizontal' \
|
||
|
else (slider.center_x - thumb.width/2 - dp(2), slider.value_pos[1]-dp(8))
|
||
|
color: [0,0,0,0] if slider._is_off else (root._track_color_disabled if root.disabled \
|
||
|
else root.thumb_color_down)
|
||
|
elevation: 0 if slider._is_off else (4 if root.active else 2)
|
||
|
|
||
|
''')
|
||
|
|
||
|
|
||
|
class MDSlider(ThemableBehavior, Slider):
|
||
|
# If the slider is clicked
|
||
|
active = BooleanProperty(False)
|
||
|
|
||
|
# Show the "off" ring when set to minimum value
|
||
|
show_off = BooleanProperty(True)
|
||
|
|
||
|
# Internal state of ring
|
||
|
_is_off = BooleanProperty(False)
|
||
|
|
||
|
# Internal adjustment to reposition sliders for ring
|
||
|
_offset = ListProperty((0, 0))
|
||
|
|
||
|
_thumb_color = ListProperty(get_color_from_hex(colors['Grey']['50']))
|
||
|
|
||
|
def _get_thumb_color(self):
|
||
|
return self._thumb_color
|
||
|
|
||
|
def _set_thumb_color(self, color, alpha=None):
|
||
|
if len(color) == 2:
|
||
|
self._thumb_color = get_color_from_hex(colors[color[0]][color[1]])
|
||
|
if alpha:
|
||
|
self._thumb_color[3] = alpha
|
||
|
elif len(color) == 4:
|
||
|
self._thumb_color = color
|
||
|
|
||
|
thumb_color = AliasProperty(_get_thumb_color, _set_thumb_color,
|
||
|
bind=['_thumb_color'])
|
||
|
|
||
|
_thumb_color_down = ListProperty([1, 1, 1, 1])
|
||
|
|
||
|
def _get_thumb_color_down(self):
|
||
|
return self._thumb_color_down
|
||
|
|
||
|
def _set_thumb_color_down(self, color, alpha=None):
|
||
|
if len(color) == 2:
|
||
|
self._thumb_color_down = get_color_from_hex(
|
||
|
colors[color[0]][color[1]])
|
||
|
if alpha:
|
||
|
self._thumb_color_down[3] = alpha
|
||
|
else:
|
||
|
self._thumb_color_down[3] = 1
|
||
|
elif len(color) == 4:
|
||
|
self._thumb_color_down = color
|
||
|
|
||
|
thumb_color_down = AliasProperty(_get_thumb_color_down,
|
||
|
_set_thumb_color_down,
|
||
|
bind=['_thumb_color_down'])
|
||
|
|
||
|
_thumb_color_disabled = ListProperty(
|
||
|
get_color_from_hex(colors['Grey']['400']))
|
||
|
|
||
|
def _get_thumb_color_disabled(self):
|
||
|
return self._thumb_color_disabled
|
||
|
|
||
|
def _set_thumb_color_disabled(self, color, alpha=None):
|
||
|
if len(color) == 2:
|
||
|
self._thumb_color_disabled = get_color_from_hex(
|
||
|
colors[color[0]][color[1]])
|
||
|
if alpha:
|
||
|
self._thumb_color_disabled[3] = alpha
|
||
|
elif len(color) == 4:
|
||
|
self._thumb_color_disabled = color
|
||
|
|
||
|
thumb_color_down = AliasProperty(_get_thumb_color_disabled,
|
||
|
_set_thumb_color_disabled,
|
||
|
bind=['_thumb_color_disabled'])
|
||
|
|
||
|
_track_color_active = ListProperty()
|
||
|
_track_color_normal = ListProperty()
|
||
|
_track_color_disabled = ListProperty()
|
||
|
_thumb_pos = ListProperty([0, 0])
|
||
|
|
||
|
def __init__(self, **kwargs):
|
||
|
super(MDSlider, self).__init__(**kwargs)
|
||
|
self.theme_cls.bind(theme_style=self._set_colors,
|
||
|
primary_color=self._set_colors,
|
||
|
primary_palette=self._set_colors)
|
||
|
self._set_colors()
|
||
|
|
||
|
def _set_colors(self, *args):
|
||
|
if self.theme_cls.theme_style == 'Dark':
|
||
|
self._track_color_normal = get_color_from_hex('FFFFFF')
|
||
|
self._track_color_normal[3] = .3
|
||
|
self._track_color_active = self._track_color_normal
|
||
|
self._track_color_disabled = self._track_color_normal
|
||
|
self.thumb_color = get_color_from_hex(colors['Grey']['400'])
|
||
|
self.thumb_color_down = get_color_from_hex(
|
||
|
colors[self.theme_cls.primary_palette]['200'])
|
||
|
self.thumb_color_disabled = get_color_from_hex(
|
||
|
colors['Grey']['800'])
|
||
|
else:
|
||
|
self._track_color_normal = get_color_from_hex('000000')
|
||
|
self._track_color_normal[3] = 0.26
|
||
|
self._track_color_active = get_color_from_hex('000000')
|
||
|
self._track_color_active[3] = 0.38
|
||
|
self._track_color_disabled = get_color_from_hex('000000')
|
||
|
self._track_color_disabled[3] = 0.26
|
||
|
self.thumb_color_down = self.theme_cls.primary_color
|
||
|
|
||
|
def on_value_normalized(self, *args):
|
||
|
""" When the value == min set it to "off" state and make slider a ring """
|
||
|
self._update_is_off()
|
||
|
|
||
|
def on_show_off(self, *args):
|
||
|
self._update_is_off()
|
||
|
|
||
|
def _update_is_off(self):
|
||
|
self._is_off = self.show_off and (self.value_normalized == 0)
|
||
|
|
||
|
def on__is_off(self, *args):
|
||
|
self._update_offset()
|
||
|
|
||
|
def on_active(self, *args):
|
||
|
self._update_offset()
|
||
|
|
||
|
def _update_offset(self):
|
||
|
""" Offset is used to shift the sliders so the background color
|
||
|
shows through the off circle.
|
||
|
"""
|
||
|
d = 2 if self.active else 0
|
||
|
self._offset = (dp(11+d), dp(11+d)) if self._is_off else (0, 0)
|
||
|
|
||
|
def on_touch_down(self, touch):
|
||
|
if super(MDSlider, self).on_touch_down(touch):
|
||
|
self.active = True
|
||
|
|
||
|
def on_touch_up(self,touch):
|
||
|
if super(MDSlider, self).on_touch_up(touch):
|
||
|
self.active = False
|
||
|
# thumb = self.ids['thumb']
|
||
|
# if thumb.collide_point(*touch.pos):
|
||
|
# thumb.on_touch_down(touch)
|
||
|
# thumb.on_touch_up(touch)
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
from kivy.app import App
|
||
|
from kivymd.theming import ThemeManager
|
||
|
|
||
|
class SliderApp(App):
|
||
|
theme_cls = ThemeManager()
|
||
|
|
||
|
def build(self):
|
||
|
return Builder.load_string("""
|
||
|
BoxLayout:
|
||
|
orientation:'vertical'
|
||
|
BoxLayout:
|
||
|
size_hint_y:None
|
||
|
height: '48dp'
|
||
|
Label:
|
||
|
text:"Toggle disabled"
|
||
|
color: [0,0,0,1]
|
||
|
CheckBox:
|
||
|
on_press: slider.disabled = not slider.disabled
|
||
|
BoxLayout:
|
||
|
size_hint_y:None
|
||
|
height: '48dp'
|
||
|
Label:
|
||
|
text:"Toggle active"
|
||
|
color: [0,0,0,1]
|
||
|
CheckBox:
|
||
|
on_press: slider.active = not slider.active
|
||
|
BoxLayout:
|
||
|
size_hint_y:None
|
||
|
height: '48dp'
|
||
|
Label:
|
||
|
text:"Toggle show off"
|
||
|
color: [0,0,0,1]
|
||
|
CheckBox:
|
||
|
on_press: slider.show_off = not slider.show_off
|
||
|
|
||
|
MDSlider:
|
||
|
id:slider
|
||
|
min:0
|
||
|
max:100
|
||
|
value: 40
|
||
|
|
||
|
MDSlider:
|
||
|
id:slider2
|
||
|
orientation:"vertical"
|
||
|
min:0
|
||
|
max:100
|
||
|
value: 40
|
||
|
|
||
|
""")
|
||
|
|
||
|
|
||
|
SliderApp().run()
|