working condition

This commit is contained in:
Yura 2024-09-15 20:57:02 +03:00
parent 417e54da96
commit 511e0b0379
517 changed files with 29187 additions and 32696 deletions

View file

@ -1 +1 @@
from .slider import MDSlider # NOQA F401
from .slider import MDSlider, MDSliderHandle, MDSliderValueLabel # NOQA F401

View file

@ -1,169 +1,218 @@
#:import Thumb kivymd.uix.selectioncontrol.Thumb
#:import get_color_from_hex kivy.utils.get_color_from_hex
#:import colors kivymd.color_definitions.colors
<HintBoxContainer@MDCard>
<MDSlider>
canvas:
Clear
# Inactive track.
Color:
rgba:
( \
self.track_color_disabled \
if self.track_color_disabled else \
self.theme_cls.disabled_hint_text_color) \
if self.disabled else \
( \
( \
self.track_color_active \
if self.track_color_active else \
( \
get_color_from_hex(colors["Gray"]["400"]) \
if app.theme_cls.theme_style == "Light" else \
(1, 1, 1, .3) \
) \
) \
if self.active else \
( \
self.track_color_inactive \
if self.track_color_inactive else \
( \
self.theme_cls.disabled_hint_text_color \
if app.theme_cls.theme_style == "Light" else \
get_color_from_hex(colors["Gray"]["800"]) \
) \
) \
)
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 and self.track_color_disabled else \
( \
self.theme_cls.disabled_hint_text_color \
if app.theme_cls.theme_style == "Light" else \
get_color_from_hex(colors["Gray"]["800"]) \
) \
)
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.color if self.color else \
app.theme_cls.primary_color \
self.theme_cls.surfaceVariantColor \
if not self.track_inactive_color else \
self.track_inactive_color \
) \
if not self.disabled else \
( \
self.track_color_disabled \
if self.track_color_disabled else \
( \
(0, 0, 0, .26) \
if app.theme_cls.theme_style == "Light" else (1, 1, 1, .3) \
) \
) \
)
Rectangle:
self.theme_cls.onSurfaceColor[:-1] + [.12]
SmoothRectangle:
size:
((self.width - self.padding * 2) * self.value_normalized, sp(4)) \
if root.orientation == "horizontal" else \
(sp(4), (self.height - self.padding * 2) * self.value_normalized)
pos:
(self.x + self.padding, self.center_y - dp(4)) \
( \
self.width - self.padding * 2, \
self.track_inactive_width \
) \
if self.orientation == "horizontal" else \
(self.center_x - dp(4), self.y + self.padding)
( \
self.track_inactive_width, \
self.height - self.padding * 2 \
)
pos:
( \
self.x + self.padding, \
self.center_y - self.track_inactive_width \
) \
if self.orientation == "horizontal" else \
( \
self.center_x - self.track_inactive_width, \
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:
(root.value_pos[0] - dp(8), root.center_y - thumb.height / 2 - dp(2)) \
if root.orientation == "horizontal" \
else (root.center_x - thumb.width / 2 - dp(2), \
root.value_pos[1] - dp(8))
md_bg_color:
(0, 0, 0, 0) if root._is_off else \
( \
( \
root.thumb_color_disabled \
if root.thumb_color_disabled else \
get_color_from_hex(colors["Gray"]["800"]) \
) \
if root.disabled else \
( \
(root.thumb_color_active \
if root.thumb_color_active else \
root.theme_cls.primary_color \
) \
if root.active else \
( \
root.thumb_color_inactive \
if root.thumb_color_inactive else \
root.theme_cls.primary_color \
) \
) \
)
elevation: 0 if root._is_off else (3 if root.active else 1)
# Active track.
Color:
rgba:
( \
self.theme_cls.primaryColor \
if not self.track_active_color else \
self.track_active_color \
) \
if not self.disabled else \
self.theme_cls.onSurfaceColor[:-1] + [.38]
SmoothRectangle:
size:
( \
(self.width - self.padding * 2) * self.value_normalized, \
self.track_active_width \
) \
if self.orientation == "horizontal" else \
( \
self.track_active_width, \
(self.height - self.padding * 2) * self.value_normalized \
)
pos:
(self.x + self.padding, self.center_y - self.track_active_width) \
if self.orientation == "horizontal" else \
(self.center_x - self.track_active_width, self.y + self.padding)
HintBoxContainer:
id: hint_box
# Points of the inactive track when a step is used.
Color:
rgba:
( \
self.theme_cls.onPrimaryColor \
if not self.track_active_step_point_color else \
self.track_active_step_point_color \
) \
if not self.disabled else \
self.theme_cls.onPrimaryColor[:-1] + [.38]
Point:
points: self._inactive_points
pointsize: self.step_point_size
# Points of the active track when a step is used.
Color:
rgba:
( \
self.theme_cls.primaryColor \
if not self.track_inactive_step_point_color else \
self.track_inactive_step_point_color \
) \
if not self.disabled else \
self.theme_cls.onSurfaceColor[:-1] + [.38]
Point:
points: self._active_points
pointsize: self.step_point_size
# Label container.
BoxLayout:
id: value_container
size_hint: None, None
md_bg_color: root.hint_bg_color if root.hint_bg_color else [0, 0, 0, 0]
elevation: 1.5
opacity: 1 if root.active else 0
radius: root.hint_radius
padding: "6dp", "6dp", "6dp", "8dp"
shadow_color:
([0, 0, 0, 0.6] if root.hint_bg_color else [0, 0, 0, 0]) \
if root.active else \
[0, 0, 0, 0]
size:
lbl_value.width + self.padding[0] * 2, \
lbl_value.height + self.padding[0]
size: self.minimum_size
pos:
(root.value_pos[0] - dp(9), root.center_y - hint_box.height / 2 + dp(30)) \
handle_container.center_x - self.width / 2, \
root._value_container_y
# Handle container.
BoxLayout:
id: handle_container
size_hint: None, None
size: self.minimum_size
pos:
( \
root.value_pos[0] - dp(0), \
root.center_y - self.height / 2 - root.track_active_width / 2 \
) \
if root.orientation == "horizontal" else \
(root.center_x - hint_box.width / 2 + dp(30), root.value_pos[1] - dp(8))
( \
root.center_x - self.width / 2 - root.track_active_width / 2, \
root.value_pos[1] - root.track_active_width / 2 \
)
MDLabel:
id: lbl_value
font_style: "Caption"
halign: "center"
theme_text_color: "Custom"
-text_size: None, None
adaptive_size: True
pos_hint: {"center_x": .5, "center_y": .5}
text_color:
app.theme_cls.primary_color \
if not root.hint_text_color else root.hint_text_color
text:
str(root.value) \
if isinstance(root.step, float) else str(int(root.value))
<MDSliderHandle>
_state_layer: state_layer
size_hint: None, None
radius: self.radius
canvas:
Color:
rgba:
( \
self.theme_cls.primaryColor \
if self.theme_bg_color == "Primary" else \
self.md_bg_color \
) \
if not self.disabled else self.theme_cls.onSurfaceColor
SmoothRoundedRectangle:
radius: self.radius
size: self.size
pos: self.pos
MDSliderHandleStateLayer:
id: state_layer
canvas.before:
Color:
rgba:
( \
app.theme_cls.primaryColor \
if not root.state_layer_color else \
root.state_layer_color \
)[:-1] + [0.38]
SmoothRoundedRectangle:
radius: [root.state_layer_size[0] / 2, ]
size: root.state_layer_size
pos:
root.x - root.state_layer_size[0] / 4, \
root.y - root.state_layer_size[1] / 4
<MDSliderValueContainer>
canvas:
Color:
rgba: app.theme_cls.primaryColor
SmoothRoundedRectangle:
radius: [self.size[0] / 2, ]
pos: self.pos
size: self.size
SmoothTriangle:
points:
[ \
self.x + 18, self.y - 6, \
self.x + 32, self.y + 9, \
self.x + 5, self.y + 8 \
]
# Label texture.
Color:
group: "md-slider-label-value-color"
Rectangle:
group: "md-slider-label-value-rect"
texture:
self._slider._value_label.texture \
if self._slider and self._slider._value_label else \
None
pos:
( \
( \
# X.
self._slider.value_pos[0] \
- (self._slider._value_label.texture_size[0] / 2) + dp(10), \
# Y.
self._slider.center_y + dp(28) \
) \
if self._slider.orientation == "horizontal" else \
( \
# X.
self._slider.center_x \
- (self._slider._value_label.texture_size[0] / 2) - dp(2), \
# Y.
self._slider.value_pos[1] + \
self._slider._value_label.texture_size[1] \
+ self._slider._handle.state_layer_size[1] / 2, \
) \
) \
if self._slider and self._slider._value_label else (0, 0)
size:
self._slider._value_label.texture_size \
if self._slider and self._slider._value_label else (0, 0)
size_hint: None, None
size:
self._slider._value_label.size \
if self._slider and self._slider._value_label else \
(0, 0)
<MDSliderValueLabel>
font_style: "Label"
role: "medium"
size_hint: None, None
theme_text_color: "Custom"
text_color: self.theme_cls.onPrimaryColor
halign: "center"

View file

@ -4,29 +4,81 @@ Components/Slider
.. seealso::
`Material Design spec, Sliders <https://material.io/components/sliders>`_
`Material Design spec, Sliders <https://m3.material.io/components/sliders/overview>`_
.. rubric:: Sliders allow users to make selections from a range of values.
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/slider.png
:align: center
- Sliders should present the full range of choices that are available
- Two types: continuous and discrete
- The slider should immediately reflect any input made by a user
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/sliders-types.png
:align: center
1. Continuous slider
2. Discrete slider
Usage
-----
.. code-block:: python
MDSlider(
MDSliderHandle(
),
MDSliderValueLabel(
),
step=10,
value=50,
)
.. code-block:: kv
MDSlider:
step: 10
value: 50
MDSliderHandle:
MDSliderValueLabel:
Anatomy
-------
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/slider-anatomy.png
:align: center
"""
__all__ = ("MDSlider",)
__all__ = ("MDSlider", "MDSliderHandle", "MDSliderValueLabel")
import os
from kivy.animation import Animation
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.metrics import dp
from kivy.properties import (
BooleanProperty,
ColorProperty,
ListProperty,
VariableListProperty,
StringProperty,
NumericProperty,
ObjectProperty,
ColorProperty,
)
from kivy.uix.slider import Slider
from kivy.uix.widget import Widget
from kivymd.uix.label import MDLabel
from kivymd.uix.behaviors import (
ScaleBehavior,
DeclarativeBehavior,
BackgroundColorBehavior,
)
from kivymd.uix.behaviors.focus_behavior import FocusBehavior
from kivymd import uix_path
from kivymd.theming import ThemableBehavior
@ -36,282 +88,504 @@ with open(
Builder.load_string(kv_file.read())
class MDSlider(ThemableBehavior, Slider):
class MDSlider(DeclarativeBehavior, ThemableBehavior, Slider):
"""
Class for creating a Slider widget. See in the
:class:`~kivy.uix.slider.Slider` class documentation.
Slider class.
For more information, see in the
:class:`~kivymd.uix.behaviors.declarative_behavior.DeclarativeBehavior` and
:class:`~kivymd.theming.ThemableBehavior` and
:class:`~kivy.uix.slider.Slider`
classes documentation.
"""
active = BooleanProperty(False)
track_active_width = NumericProperty(dp(4))
"""
If the slider is clicked.
Width of the active track.
:attr:`active` is an :class:`~kivy.properties.BooleanProperty`
and defaults to `False`.
.. versionadded:: 2.0.0
:attr:`track_active_width` is an :class:`~kivy.properties.NumericProperty`
and defaults to `dp(4)`.
"""
color = ColorProperty(None)
track_inactive_width = NumericProperty(dp(4))
"""
Color slider in (r, g, b, a) or string format.
Width of the inactive track.
.. code-block:: kv
.. versionadded:: 2.0.0
MDSlider
color: "red"
:attr:`track_inactive_width` is an :class:`~kivy.properties.NumericProperty`
and defaults to `dp(4)`.
"""
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/slide-color.png
:align: center
step_point_size = NumericProperty(dp(1))
"""
Step point size.
:attr:`color` is an :class:`~kivy.properties.ColorProperty`
.. versionadded:: 2.0.0
:attr:`step_point_size` is an :class:`~kivy.properties.NumericProperty`
and defaults to `dp(1)`.
"""
track_active_color = ColorProperty(None)
"""
Color of the active track.
.. versionadded:: 2.0.0
.. versionchanged:: 2.0.0
Rename from `track_color_active` to `track_active_color`
:attr:`track_active_color` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
hint = BooleanProperty(True)
track_active_step_point_color = ColorProperty(None)
"""
If True, then the current value is displayed above the slider.
Color of step points on active track.
.. code-block:: kv
.. versionadded:: 2.0.0
MDSlider
hint: True
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/slide-hint.png
:align: center
:attr:`hint` is an :class:`~kivy.properties.BooleanProperty`
and defaults to `True`.
"""
hint_bg_color = ColorProperty(None)
"""
Hint rectangle color in (r, g, b, a) or string format.
.. code-block:: kv
MDSlider
hint: True
hint_bg_color: "red"
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/slide-hint-bg-color.png
:align: center
:attr:`hint_bg_color` is an :class:`~kivy.properties.ColorProperty`
and defaults to `[0, 0, 0, 0]`.
"""
hint_text_color = ColorProperty(None)
"""
Hint text color in in (r, g, b, a) or string format.
.. code-block:: kv
MDSlider
hint: True
hint_bg_color: "red"
hint_text_color: "white"
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/slide-hint-text-color.png
:align: center
:attr:`hint_text_color` is an :class:`~kivy.properties.ColorProperty`
:attr:`track_active_step_point_color` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
hint_radius = VariableListProperty([dp(4), dp(4), dp(4), dp(4)])
track_inactive_step_point_color = ColorProperty(None)
"""
Hint radius.
Color of step points on inactive track.
.. code-block:: kv
.. versionadded:: 2.0.0
MDSlider
hint: True
hint_bg_color: "red"
hint_text_color: "white"
hint_radius: [6, 0, 6, 0]
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/slide-hint-radius.png
:align: center
:attr:`hint_radius` is an :class:`~kivy.properties.VariableListProperty`
and defaults to `[dp(4), dp(4), dp(4), dp(4)]`.
:attr:`track_inactive_step_point_color` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
thumb_color_active = ColorProperty(None)
track_inactive_color = ColorProperty(None)
"""
The color in (r, g, b, a) or string format of the thumb when the slider is active.
Color of the inactive track.
.. versionadded:: 1.0.0
.. versionadded:: 2.0.0
.. code-block:: kv
.. versionchanged:: 2.0.0
MDSlider
thumb_color_active: "red"
Rename from `track_color_inactive` to `track_inactive_color`
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/slide-thumb-color-active.png
:align: center
:attr:`thumb_color_active` is an :class:`~kivy.properties.ColorProperty`
and default to `None`.
:attr:`track_active_color` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
thumb_color_inactive = ColorProperty(None)
value_container_show_anim_duration = NumericProperty(0.2)
"""
The color in (r, g, b, a) or string format of the thumb when the slider is inactive.
Duration of the animation opening of the label value.
.. versionadded:: 1.0.0
.. versionadded:: 2.0.0
.. code-block:: kv
MDSlider
thumb_color_inactive: "red"
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/slide-thumb-color-inactive.png
:align: center
:attr:`thumb_color_inactive` is an :class:`~kivy.properties.ColorProperty`
and default to `None`.
:attr:`value_container_show_anim_duration` is an :class:`~kivy.properties.NumericProperty`
and defaults to `0.2`.
"""
thumb_color_disabled = ColorProperty(None)
value_container_hide_anim_duration = NumericProperty(0.2)
"""
The color in (r, g, b, a) or string format of the thumb when the slider is
in the disabled state.
Duration of closing the animation of the label value.
.. versionadded:: 1.0.0
.. versionadded:: 2.0.0
.. code-block:: kv
MDSlider
value: 55
disabled: True
thumb_color_disabled: "red"
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/slide-thumb-color-disabled.png
:align: center
:attr:`thumb_color_disabled` is an :class:`~kivy.properties.ColorProperty`
and default to `None`.
:attr:`value_container_hide_anim_duration` is an :class:`~kivy.properties.NumericProperty`
and defaults to `0.2`.
"""
track_color_active = ColorProperty(None)
value_container_show_anim_transition = StringProperty("out_circ")
"""
The color in (r, g, b, a) or string format of the track when the slider is active.
The type of the opening animation of the label value.
.. versionadded:: 1.0.0
.. versionadded:: 2.0.0
.. code-block:: kv
MDSlider
track_color_active: "red"
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/slide-track-color-active.png
:align: center
:attr:`track_color_active` is an :class:`~kivy.properties.ColorProperty`
and default to `None`.
:attr:`value_container_show_anim_transition` is an :class:`~kivy.properties.StringProperty`
and defaults to `'out_circ'`.
"""
track_color_inactive = ColorProperty(None)
value_container_hide_anim_transition = StringProperty("out_circ")
"""
The color in (r, g, b, a) or string format of the track when the slider is inactive.
The type of the closing animation of the label value.
.. versionadded:: 1.0.0
.. versionadded:: 2.0.0
.. code-block:: kv
MDSlider
track_color_inactive: "red"
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/slide-track-color-inactive.png
:align: center
:attr:`track_color_inactive` is an :class:`~kivy.properties.ColorProperty`
and default to `None`.
:attr:`value_container_hide_anim_transition` is an :class:`~kivy.properties.StringProperty`
and defaults to `'out_circ'`.
"""
track_color_disabled = ColorProperty(None)
handle_anim_transition = StringProperty("out_circ")
"""
The color in (r, g, b, a) or string format of the track when the slider is
in the disabled state.
Handle animation type.
.. versionadded:: 1.0.0
.. versionadded:: 2.0.0
.. code-block:: kv
MDSlider
disabled: True
track_color_disabled: "red"
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/slide-track-color-disabled.png
:align: center
:attr:`track_color_disabled` is an :class:`~kivy.properties.ColorProperty`
and default to `None`.
:attr:`handle_anim_transition` is an :class:`~kivy.properties.StringProperty`
and defaults to `'out_circ'`.
"""
show_off = BooleanProperty(True)
handle_anim_duration = NumericProperty(0.2)
"""
Show the `'off'` ring when set to minimum value.
Handle animation duration.
:attr:`show_off` is an :class:`~kivy.properties.BooleanProperty`
and defaults to `True`.
.. versionadded:: 2.0.0
:attr:`handle_anim_duration` is an :class:`~kivy.properties.NumericProperty`
and defaults to `0.2`.
"""
_thumb_pos = ListProperty([0, 0])
# Internal state of ring.
_is_off = BooleanProperty(False)
# Internal adjustment to reposition sliders for ring.
_offset = ListProperty((0, 0))
_value_label_container_size = ListProperty([0, 0]) # value label texture
_value_label = ObjectProperty() # value label texture
_value_container = ObjectProperty() # MDSliderValueContainer object
_value_container_y = NumericProperty(0) # MDSliderValueContainer object
_handle = ObjectProperty() # MDSliderHandle object
# List of points displayed on the slider when using the `step` for th
# active/inactive tracks.
_active_points = ListProperty()
_inactive_points = ListProperty()
def __init__(self, **kwargs):
super().__init__(**kwargs)
Clock.schedule_once(self.set_thumb_icon)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
Clock.schedule_once(self._update_state_layer_pos, 0.5)
Clock.schedule_once(self.on_size)
def set_thumb_icon(self, *args) -> None:
self.ids.thumb.ids.icon.icon = "blank"
def add_widget(self, widget, index=0, canvas=None):
def set_value_container_y(*args):
self._value_container_y = self.ids.handle_container.y
def on_hint(self, instance, value) -> None:
def on_hint(*args):
if not value:
self.remove_widget(self.ids.hint_box)
if isinstance(widget, MDSliderValueLabel):
self._value_label = widget
self._value_container = MDSliderValueContainer(_slider=self)
self.ids.value_container.add_widget(self._value_container)
Clock.schedule_once(set_value_container_y)
elif isinstance(widget, MDSliderHandle):
widget._slider = self
self._handle = widget
self.ids.handle_container.add_widget(widget)
else:
return super().add_widget(widget)
# Schedule using for declarative style.
# Otherwise get AttributeError exception.
Clock.schedule_once(on_hint)
def update_points(self, instance, step) -> None:
"""Draws the step points on the slider."""
def on_value_normalized(self, *args) -> None:
"""
When the ``value == min`` set it to `'off'` state and make slider
a ring.
"""
def update_points(*args):
y = (
self.center_y
if self.orientation == "horizontal"
else self.center_x
) - self.track_active_width / 2
slider_length = (
self.width if self.orientation == "horizontal" else self.height
) - (self.padding * 2)
slider_max_value = int(self.max)
multiplier = slider_length / slider_max_value
active_track_width = (
(
self.width
if self.orientation == "horizontal"
else self.height
)
- self.padding * 2
) * self.value_normalized
self._update_is_off()
for i in range(0, slider_max_value + 1, step):
x = i * multiplier
def on_show_off(self, *args) -> None:
self._update_is_off()
if x < active_track_width:
points = self._inactive_points
else:
points = self._active_points
def on__is_off(self, *args) -> None:
self._update_offset()
if self.orientation == "vertical":
points.append(y)
def on_active(self, *args) -> None:
self._update_offset()
points.append(
(self.x if self.orientation == "horizontal" else self.y)
+ x
+ self.padding
+ (
(self.ids.handle_container.width / 2)
if i != self.max and i
else 0
)
)
if self.orientation == "horizontal":
points.append(y)
Clock.schedule_once(update_points)
def on_size(self, *args) -> None:
"""Fired when the widget is resized."""
self._update_points()
def on_touch_down(self, touch):
if super().on_touch_down(touch):
self.active = True
if self.disabled or not self.collide_point(*touch.pos):
return
if touch.is_mouse_scrolling:
if "down" in touch.button or "left" in touch.button:
if self.step:
self.value = min(self.max, self.value + self.step)
else:
self.value = min(
self.max, self.value + (self.max - self.min) / 20
)
if "up" in touch.button or "right" in touch.button:
if self.step:
self.value = max(self.min, self.value - self.step)
else:
self.value = max(
self.min, self.value - (self.max - self.min) / 20
)
elif self.sensitivity == "handle":
if self.children[0].collide_point(*touch.pos):
touch.grab(self)
else:
touch.grab(self)
Clock.schedule_once(self._update_state_layer_pos)
Animation(value_pos=touch.pos, d=0.2).start(self)
return True
def on_value_pos(self, *args) -> None:
"""
Fired when the `value_pos` value changes.
Sets a new value for the value label texture.
"""
self._update_points()
if self._value_label and self._value_container:
# FIXME: I do not know how else I can update the texture.
self._value_label.text = ""
self._value_label.text = f"{int(self.value)}"
self._value_label.texture_update()
label_value_rect = self._value_container.canvas.get_group(
"md-slider-label-value-rect"
)[0]
label_value_rect.texture = None
label_value_rect.texture = self._value_label.texture
label_value_rect.size = self._value_label.texture_size
def on_touch_up(self, touch):
if super().on_touch_up(touch):
self.active = False
if touch.grab_current == self:
if self._handle:
self._handle.on_leave()
return True
def _update_offset(self):
def on_touch_move(self, touch):
if self.collide_point(touch.x, touch.y):
if self._handle:
self._update_state_layer_pos()
if self._handle and not self._handle._active:
self._handle.on_enter()
return super().on_touch_move(touch)
def on_handle_enter(self) -> None:
"""Scales the container of the label value."""
if self._handle and self._value_label:
Animation(
scale_value_x=1,
scale_value_y=1,
t=self.value_container_show_anim_transition,
d=self.value_container_show_anim_duration,
).start(self._value_container)
Animation(
_value_container_y=self.ids.handle_container.y + dp(32),
t=self.value_container_show_anim_transition,
d=self.value_container_show_anim_duration,
).start(self)
def on_handle_leave(self) -> None:
"""Scales the container of the label value."""
if self._handle and self._value_label:
Animation(
scale_value_x=0,
scale_value_y=0,
d=self.value_container_hide_anim_duration,
t=self.value_container_hide_anim_transition,
).start(self._value_container)
Animation(
_value_container_y=self._value_container_y - dp(24),
t=self.value_container_hide_anim_transition,
d=self.value_container_hide_anim_duration,
).start(self)
def _update_points(self, *args) -> None:
if self.step:
self._active_points = []
self._inactive_points = []
self.update_points(self, self.step)
def _update_state_layer_pos(self, *args):
if self._handle:
self._handle.ids.state_layer.scale_value_center = (
self.ids.handle_container.center
)
class MDSliderHandle(
ThemableBehavior, BackgroundColorBehavior, FocusBehavior, Widget
):
"""
Handle class.
.. versionadded:: 2.0.0
For more information, see in the
:class:`~kivymd.theming.ThemableBehavior` and
:class:`~kivymd.uix.behaviors.backgroundcolor_behavior.BackgroundColorBehavior` and
:class:`~kivymd.uix.behaviors.focus_behavior.FocusBehavior` and
:class:`~kivy.uix.widget.Widget`
classes documentation.
"""
radius = VariableListProperty([dp(10)], length=4)
"""
Handle radius.
:attr:`radius` is an :class:`~kivy.properties.VariableListProperty`
and defaults to `[dp(10), dp(10), dp(10), dp(10)]`.
"""
size = ListProperty([dp(20), dp(20)])
"""
Handle size.
:attr:`size` is an :class:`~kivy.properties.ListProperty`
and defaults to `[dp(20), dp(20)]`.
"""
state_layer_size = ListProperty([dp(40), dp(40)])
"""
Handle state layer size.
:attr:`state_layer_size` is an :class:`~kivy.properties.ListProperty`
and defaults to `[dp(40), dp(40)]`.
"""
state_layer_color = ColorProperty(None)
"""
Handle state layer color.
:attr:`state_layer_color` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
_slider = ObjectProperty() # MDSlider object
_active = False # is the layer currently displayed
_state_layer = ObjectProperty() # MDSliderStateLayer object
def on_enter(self) -> None:
"""
Offset is used to shift the sliders so the background color
shows through the off circle.
Fired when mouse enter the bbox of the widget.
Animates the display of the slider handle layer.
"""
d = 2 if self.active else 0
self._offset = (dp(11 + d), dp(11 + d)) if self._is_off else (0, 0)
if self._slider:
if self._state_layer and not self._slider.disabled:
self._active = True
anim = Animation(scale_value_x=1, scale_value_y=1, d=0.2)
anim.bind(on_complete=self._slider._update_state_layer_pos)
anim.start(self._state_layer)
if not self._slider.disabled:
self._slider.on_handle_enter()
def _update_is_off(self):
self._is_off = self.show_off and (self.value_normalized == 0)
def on_leave(self) -> None:
"""
Fired when the mouse goes outside the widget border.
Animates the hiding of the slider handle layer.
"""
if self._slider:
if self._state_layer and not self._slider.disabled:
self._active = False
anim = Animation(scale_value_x=0, scale_value_y=0, d=0.2)
anim.bind(on_complete=self._slider._update_state_layer_pos)
anim.start(self._state_layer)
if not self._slider.disabled:
self._slider.on_handle_leave()
class MDSliderHandleStateLayer(ScaleBehavior, Widget):
"""
Slider state layer class.
.. versionadded:: 2.0.0
For more information, see in the
:class:`~kivymd.uix.behaviors.scale_behavior.ScaleBehavior` and
:class:`~kivy.uix.widget.Widget`
classes documentation.
"""
scale_value_x = NumericProperty(0)
"""
X-axis value.
:attr:`scale_value_x` is an :class:`~kivy.properties.NumericProperty`
and defaults to `1`.
"""
scale_value_y = NumericProperty(0)
"""
Y-axis value.
:attr:`scale_value_y` is an :class:`~kivy.properties.NumericProperty`
and defaults to `1`.
"""
class MDSliderValueLabel(MDLabel):
"""
Implements the value label.
For more information, see in the :class:`~kivymd.uix.label.label.MDLabel`
class documentation.
.. versionadded:: 2.0.0
"""
size = ListProperty([dp(36), dp(36)])
"""
Container size for the label value.
:attr:`handle_anim_transition` is an :class:`~kivy.properties.ListProperty`
and defaults to `[dp(36), dp(36)]`.
"""
class MDSliderValueContainer(ScaleBehavior, Widget):
"""
Implements the container for value label.
For more information, see in the
:class:`~kivymd.uix.behaviors.scale_behavior.ScaleBehavior` and
:class:`~kivy.uix.widget.Widget`
classes documentation.
.. versionadded:: 2.0.0
"""
scale_value_x = NumericProperty(0)
"""
X-axis value.
:attr:`scale_value_x` is an :class:`~kivy.properties.NumericProperty`
and defaults to `1`.
"""
scale_value_y = NumericProperty(0)
"""
Y-axis value.
:attr:`scale_value_y` is an :class:`~kivy.properties.NumericProperty`
and defaults to `1`.
"""
_slider = ObjectProperty() # MDSlider object