working condition
This commit is contained in:
parent
417e54da96
commit
511e0b0379
517 changed files with 29187 additions and 32696 deletions
|
@ -5,21 +5,11 @@ Behaviors
|
|||
Modules and classes implementing various behaviors for buttons etc.
|
||||
"""
|
||||
|
||||
from .backgroundcolor_behavior import (
|
||||
BackgroundColorBehavior,
|
||||
SpecificBackgroundColorBehavior,
|
||||
)
|
||||
from .backgroundcolor_behavior import BackgroundColorBehavior
|
||||
|
||||
# flake8: NOQA
|
||||
from .declarative_behavior import DeclarativeBehavior
|
||||
from .elevation import (
|
||||
CircularElevationBehavior,
|
||||
CommonElevationBehavior,
|
||||
FakeCircularElevationBehavior,
|
||||
FakeRectangularElevationBehavior,
|
||||
RectangularElevationBehavior,
|
||||
RoundedRectangularElevationBehavior,
|
||||
)
|
||||
from .elevation import CommonElevationBehavior
|
||||
from .motion_behavior import (
|
||||
MotionDialogBehavior,
|
||||
MotionShackBehavior,
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -7,7 +7,7 @@ Behaviors/Background Color
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
__all__ = ("BackgroundColorBehavior", "SpecificBackgroundColorBehavior")
|
||||
__all__ = ("BackgroundColorBehavior",)
|
||||
|
||||
from kivy.animation import Animation
|
||||
from kivy.lang import Builder
|
||||
|
@ -15,15 +15,10 @@ from kivy.properties import (
|
|||
ColorProperty,
|
||||
ListProperty,
|
||||
NumericProperty,
|
||||
OptionProperty,
|
||||
ReferenceListProperty,
|
||||
StringProperty,
|
||||
VariableListProperty,
|
||||
)
|
||||
from kivy.utils import get_color_from_hex
|
||||
|
||||
from kivymd.color_definitions import hue, palette, text_colors
|
||||
from kivymd.theming import ThemeManager
|
||||
|
||||
Builder.load_string(
|
||||
"""
|
||||
|
@ -37,8 +32,9 @@ Builder.load_string(
|
|||
angle: self.angle
|
||||
origin: self._background_origin
|
||||
Color:
|
||||
group: "backgroundcolor-behavior-bg-color"
|
||||
rgba: self._md_bg_color
|
||||
RoundedRectangle:
|
||||
SmoothRoundedRectangle:
|
||||
group: "Background_instruction"
|
||||
size: self.size
|
||||
pos: self.pos if not isinstance(self, RelativeLayout) else (0, 0)
|
||||
|
@ -49,11 +45,17 @@ Builder.load_string(
|
|||
source: root.background
|
||||
Color:
|
||||
rgba: self.line_color if self.line_color else (0, 0, 0, 0)
|
||||
# TODO: maybe we should use SmoothLine,
|
||||
# but this should be tested on all widgets.
|
||||
Line:
|
||||
SmoothLine:
|
||||
width: root.line_width
|
||||
rounded_rectangle:
|
||||
[ \
|
||||
0,
|
||||
0, \
|
||||
self.width, \
|
||||
self.height, \
|
||||
*self.radius, \
|
||||
] \
|
||||
if isinstance(self, RelativeLayout) else \
|
||||
[ \
|
||||
self.x,
|
||||
self.y, \
|
||||
|
@ -73,7 +75,7 @@ class BackgroundColorBehavior:
|
|||
Background image path.
|
||||
|
||||
:attr:`background` is a :class:`~kivy.properties.StringProperty`
|
||||
and defaults to `None`.
|
||||
and defaults to `''`.
|
||||
"""
|
||||
|
||||
radius = VariableListProperty([0], length=4)
|
||||
|
@ -93,7 +95,7 @@ class BackgroundColorBehavior:
|
|||
|
||||
# FIXME: in this case, we will not be able to animate this property
|
||||
# using the `Animation` class.
|
||||
md_bg_color = ColorProperty([1, 1, 1, 0])
|
||||
md_bg_color = ColorProperty([0, 0, 0, 0])
|
||||
"""
|
||||
The background color of the widget (:class:`~kivy.uix.widget.Widget`)
|
||||
that will be inherited from the :attr:`BackgroundColorBehavior` class.
|
||||
|
@ -118,12 +120,12 @@ class BackgroundColorBehavior:
|
|||
md_bg_color: 0, 1, 1, 1
|
||||
|
||||
:attr:`md_bg_color` is an :class:`~kivy.properties.ColorProperty`
|
||||
and defaults to `[1, 1, 1, 0]`.
|
||||
and defaults to `[0, 0, 0, 0]`.
|
||||
"""
|
||||
|
||||
line_color = ColorProperty([0, 0, 0, 0])
|
||||
"""
|
||||
If a custom value is specified for the `line_color parameter`, the border
|
||||
If a custom value is specified for the `line_color` parameter, the border
|
||||
of the specified color will be used to border the widget:
|
||||
|
||||
.. code-block:: kv
|
||||
|
@ -157,37 +159,18 @@ class BackgroundColorBehavior:
|
|||
_background_y = NumericProperty(0)
|
||||
_background_origin = ReferenceListProperty(_background_x, _background_y)
|
||||
_md_bg_color = ColorProperty([0, 0, 0, 0])
|
||||
_origin_line_color = ColorProperty(None)
|
||||
_origin_md_bg_color = ColorProperty(None)
|
||||
|
||||
def __init__(self, **kwarg):
|
||||
super().__init__(**kwarg)
|
||||
self.bind(
|
||||
pos=self.update_background_origin,
|
||||
disabled=self.restore_color_origin,
|
||||
)
|
||||
self.bind(pos=self.update_background_origin)
|
||||
|
||||
def restore_color_origin(self, instance_md_widget, value: bool) -> None:
|
||||
"""Called when the values of :attr:`disabled` change."""
|
||||
|
||||
if not value:
|
||||
if self._origin_line_color:
|
||||
self.line_color = self._origin_line_color
|
||||
if self._origin_md_bg_color:
|
||||
self.md_bg_color = self._origin_md_bg_color
|
||||
|
||||
def on_line_color(self, instance_md_widget, value: list | str) -> None:
|
||||
"""Called when the values of :attr:`line_color` change."""
|
||||
|
||||
if not self.disabled:
|
||||
self._origin_line_color = value
|
||||
|
||||
def on_md_bg_color(self, instance_md_widget, color: list | str):
|
||||
"""Called when the values of :attr:`md_bg_color` change."""
|
||||
def on_md_bg_color(self, instance, color: list | str):
|
||||
"""Fired when the values of :attr:`md_bg_color` change."""
|
||||
|
||||
if (
|
||||
hasattr(self, "theme_cls")
|
||||
and self.theme_cls.theme_style_switch_animation
|
||||
and self.__class__.__name__ != "MDDropdownMenu"
|
||||
):
|
||||
Animation(
|
||||
_md_bg_color=color,
|
||||
|
@ -197,94 +180,10 @@ class BackgroundColorBehavior:
|
|||
else:
|
||||
self._md_bg_color = color
|
||||
|
||||
if not self.disabled:
|
||||
self._origin_md_bg_color = color
|
||||
|
||||
def update_background_origin(self, instance_md_widget, pos: list) -> None:
|
||||
"""Called when the values of :attr:`pos` change."""
|
||||
def update_background_origin(self, instance, pos: list) -> None:
|
||||
"""Fired when the values of :attr:`pos` change."""
|
||||
|
||||
if self.background_origin:
|
||||
self._background_origin = self.background_origin
|
||||
else:
|
||||
self._background_origin = self.center
|
||||
|
||||
|
||||
class SpecificBackgroundColorBehavior(BackgroundColorBehavior):
|
||||
background_palette = OptionProperty(
|
||||
"Primary", options=["Primary", "Accent", *palette]
|
||||
)
|
||||
"""
|
||||
See :attr:`kivymd.color_definitions.palette`.
|
||||
|
||||
:attr:`background_palette` is an :class:`~kivy.properties.OptionProperty`
|
||||
and defaults to `'Primary'`.
|
||||
"""
|
||||
|
||||
background_hue = OptionProperty("500", options=hue)
|
||||
"""
|
||||
See :attr:`kivymd.color_definitions.hue`.
|
||||
|
||||
:attr:`background_hue` is an :class:`~kivy.properties.OptionProperty`
|
||||
and defaults to `'500'`.
|
||||
"""
|
||||
|
||||
specific_text_color = ColorProperty([0, 0, 0, 0.87])
|
||||
"""
|
||||
:attr:`specific_text_color` is an :class:`~kivy.properties.ColorProperty`
|
||||
and defaults to `[0, 0, 0, 0.87]`.
|
||||
"""
|
||||
|
||||
specific_secondary_text_color = ColorProperty([0, 0, 0, 0.87])
|
||||
"""
|
||||
:attr:`specific_secondary_text_color`is an :class:`~kivy.properties.ColorProperty`
|
||||
and defaults to `[0, 0, 0, 0.87]`.
|
||||
"""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
if hasattr(self, "theme_cls"):
|
||||
self.theme_cls.bind(
|
||||
primary_palette=self._update_specific_text_color,
|
||||
accent_palette=self._update_specific_text_color,
|
||||
theme_style=self._update_specific_text_color,
|
||||
)
|
||||
self.bind(
|
||||
background_hue=self._update_specific_text_color,
|
||||
background_palette=self._update_specific_text_color,
|
||||
)
|
||||
self._update_specific_text_color(None, None)
|
||||
|
||||
def _update_specific_text_color(
|
||||
self, instance_theme_manager: ThemeManager, theme_style: str
|
||||
) -> None:
|
||||
if hasattr(self, "theme_cls"):
|
||||
palette = {
|
||||
"Primary": self.theme_cls.primary_palette,
|
||||
"Accent": self.theme_cls.accent_palette,
|
||||
}.get(self.background_palette, self.background_palette)
|
||||
else:
|
||||
palette = {"Primary": "Blue", "Accent": "Amber"}.get(
|
||||
self.background_palette, self.background_palette
|
||||
)
|
||||
color = get_color_from_hex(text_colors[palette][self.background_hue])
|
||||
secondary_color = color[:]
|
||||
# Check for black text (need to adjust opacity).
|
||||
if (color[0] + color[1] + color[2]) == 0:
|
||||
color[3] = 0.87
|
||||
secondary_color[3] = 0.54
|
||||
else:
|
||||
secondary_color[3] = 0.7
|
||||
|
||||
if (
|
||||
hasattr(self, "theme_cls")
|
||||
and self.theme_cls.theme_style_switch_animation
|
||||
):
|
||||
Animation(
|
||||
specific_text_color=color,
|
||||
specific_secondary_text_color=secondary_color,
|
||||
d=self.theme_cls.theme_style_switch_animation_duration,
|
||||
t="linear",
|
||||
).start(self)
|
||||
else:
|
||||
self.specific_text_color = color
|
||||
self.specific_secondary_text_color = secondary_color
|
||||
|
|
|
@ -33,31 +33,35 @@ Imperative style
|
|||
.. code-block:: python
|
||||
|
||||
from kivymd.app import MDApp
|
||||
from kivymd.uix.bottomnavigation import MDBottomNavigation, MDBottomNavigationItem
|
||||
from kivymd.uix.label import MDLabel
|
||||
from kivymd.uix.navigationbar import (
|
||||
MDNavigationBar,
|
||||
MDNavigationItem,
|
||||
MDNavigationItemIcon,
|
||||
MDNavigationItemLabel,
|
||||
)
|
||||
from kivymd.uix.screen import MDScreen
|
||||
|
||||
|
||||
class Example(MDApp):
|
||||
def build(self):
|
||||
screen = MDScreen()
|
||||
bottom_navigation = MDBottomNavigation(
|
||||
panel_color="#eeeaea",
|
||||
selected_color_background="#97ecf8",
|
||||
text_color_active="white",
|
||||
)
|
||||
bottom_navigation = MDNavigationBar()
|
||||
|
||||
data = {
|
||||
"screen 1": {"text": "Mail", "icon": "gmail"},
|
||||
"screen 2": {"text": "Discord", "icon": "discord"},
|
||||
"screen 3": {"text": "LinkedIN", "icon": "linkedin"},
|
||||
}
|
||||
for key in data.keys():
|
||||
text = data[key]["text"]
|
||||
navigation_item = MDBottomNavigationItem(
|
||||
name=key, text=text, icon=data[key]["icon"]
|
||||
datas = [
|
||||
{"text": "Mail", "icon": "gmail"},
|
||||
{"text": "GitHub", "icon": "git"},
|
||||
{"text": "LinkedIN", "icon": "linkedin"},
|
||||
]
|
||||
for data in datas:
|
||||
text = data["text"]
|
||||
navigation_item = MDNavigationItem(
|
||||
MDNavigationItemIcon(
|
||||
icon=data["icon"],
|
||||
),
|
||||
MDNavigationItemLabel(
|
||||
text=text,
|
||||
),
|
||||
)
|
||||
navigation_item.add_widget(MDLabel(text=text, halign="center"))
|
||||
bottom_navigation.add_widget(navigation_item)
|
||||
|
||||
screen.add_widget(bottom_navigation)
|
||||
|
@ -66,9 +70,6 @@ Imperative style
|
|||
|
||||
Example().run()
|
||||
|
||||
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bottom-navigation-styles-programming.png
|
||||
:align: center
|
||||
|
||||
Take a look at the above code example. This is a very simple UI. But looking
|
||||
at this code, you will not be able to figure the widget tree and understand
|
||||
which UI this code implements. This is named imperative programming style,
|
||||
|
@ -87,51 +88,42 @@ Declarative style with KV language
|
|||
from kivymd.app import MDApp
|
||||
|
||||
|
||||
class Test(MDApp):
|
||||
class Example(MDApp):
|
||||
def build(self):
|
||||
return Builder.load_string(
|
||||
'''
|
||||
MDScreen:
|
||||
|
||||
MDBottomNavigation:
|
||||
panel_color: "#eeeaea"
|
||||
selected_color_background: "#97ecf8"
|
||||
text_color_active: "white"
|
||||
MDNavigationBar:
|
||||
|
||||
MDBottomNavigationItem:
|
||||
name: "screen 1"
|
||||
text: "Mail"
|
||||
icon: "gmail"
|
||||
MDNavigationItem:
|
||||
|
||||
MDLabel:
|
||||
MDNavigationItemIcon:
|
||||
icon: "gmail"
|
||||
|
||||
MDNavigationItemLabel:
|
||||
text: "Mail"
|
||||
halign: "center"
|
||||
|
||||
MDBottomNavigationItem:
|
||||
name: "screen 2"
|
||||
text: "Discord"
|
||||
icon: "discord"
|
||||
MDNavigationItem:
|
||||
|
||||
MDLabel:
|
||||
text: "Discord"
|
||||
halign: "center"
|
||||
MDNavigationItemIcon:
|
||||
icon: "git"
|
||||
|
||||
MDBottomNavigationItem:
|
||||
name: "screen 3"
|
||||
text: "LinkedIN"
|
||||
icon: "linkedin"
|
||||
MDNavigationItemLabel:
|
||||
text: "GitHub"
|
||||
|
||||
MDLabel:
|
||||
MDNavigationItem:
|
||||
|
||||
MDNavigationItemIcon:
|
||||
icon: "linkedin"
|
||||
|
||||
MDNavigationItemLabel:
|
||||
text: "LinkedIN"
|
||||
halign: "center"
|
||||
'''
|
||||
)
|
||||
|
||||
|
||||
Test().run()
|
||||
|
||||
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bottom-navigation-styles-programming.png
|
||||
:align: center
|
||||
Example().run()
|
||||
|
||||
Looking at this code, we can now clearly see the widget tree and their properties.
|
||||
We can quickly navigate through the components of the screen and quickly
|
||||
|
@ -146,48 +138,41 @@ Declarative style with Python code
|
|||
.. code-block:: python
|
||||
|
||||
from kivymd.app import MDApp
|
||||
from kivymd.uix.bottomnavigation import MDBottomNavigation, MDBottomNavigationItem
|
||||
from kivymd.uix.label import MDLabel
|
||||
from kivymd.uix.screen import MDScreen
|
||||
from kivymd.uix.navigationbar import (
|
||||
MDNavigationBar,
|
||||
MDNavigationItemIcon,
|
||||
MDNavigationItem,
|
||||
MDNavigationItemLabel,
|
||||
)
|
||||
|
||||
|
||||
class Example(MDApp):
|
||||
def build(self):
|
||||
return (
|
||||
MDScreen(
|
||||
MDBottomNavigation(
|
||||
MDBottomNavigationItem(
|
||||
MDLabel(
|
||||
text="Mail",
|
||||
halign="center",
|
||||
),
|
||||
name="screen 1",
|
||||
text="Mail",
|
||||
icon="gmail",
|
||||
),
|
||||
MDBottomNavigationItem(
|
||||
MDLabel(
|
||||
text="Discord",
|
||||
halign="center",
|
||||
),
|
||||
name="screen 2",
|
||||
text="Discord",
|
||||
icon="discord",
|
||||
),
|
||||
MDBottomNavigationItem(
|
||||
MDLabel(
|
||||
text="LinkedIN",
|
||||
halign="center",
|
||||
),
|
||||
name="screen 3",
|
||||
text="LinkedIN",
|
||||
icon="linkedin",
|
||||
),
|
||||
panel_color="#eeeaea",
|
||||
selected_color_background="#97ecf8",
|
||||
text_color_active="white",
|
||||
)
|
||||
)
|
||||
return MDNavigationBar(
|
||||
MDNavigationItem(
|
||||
MDNavigationItemIcon(
|
||||
icon="gmail",
|
||||
),
|
||||
MDNavigationItemLabel(
|
||||
text="Mail",
|
||||
),
|
||||
),
|
||||
MDNavigationItem(
|
||||
MDNavigationItemIcon(
|
||||
icon="twitter",
|
||||
),
|
||||
MDNavigationItemLabel(
|
||||
text="Twitter",
|
||||
),
|
||||
),
|
||||
MDNavigationItem(
|
||||
MDNavigationItemIcon(
|
||||
icon="linkedin",
|
||||
),
|
||||
MDNavigationItemLabel(
|
||||
text="LinkedIN",
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
|
@ -239,7 +224,7 @@ get to the desired id:
|
|||
|
||||
from kivymd.app import MDApp
|
||||
from kivymd.uix.boxlayout import MDBoxLayout
|
||||
from kivymd.uix.button import MDRaisedButton
|
||||
from kivymd.uix.button import MDButton, MDButtonText
|
||||
from kivymd.uix.floatlayout import MDFloatLayout
|
||||
|
||||
|
||||
|
@ -248,18 +233,22 @@ get to the desired id:
|
|||
return (
|
||||
MDBoxLayout(
|
||||
MDFloatLayout(
|
||||
MDRaisedButton(
|
||||
MDButton(
|
||||
MDButtonText(
|
||||
text="Button 1",
|
||||
),
|
||||
id="button_1",
|
||||
text="Button 1",
|
||||
pos_hint={"center_x": 0.5, "center_y": 0.5},
|
||||
),
|
||||
id="box_container_1",
|
||||
),
|
||||
MDBoxLayout(
|
||||
MDFloatLayout(
|
||||
MDRaisedButton(
|
||||
MDButton(
|
||||
MDButtonText(
|
||||
text="Button 2",
|
||||
),
|
||||
id="button_2",
|
||||
text="Button 2",
|
||||
pos_hint={"center_x": 0.5, "center_y": 0.5},
|
||||
),
|
||||
id="float_container",
|
||||
|
@ -271,13 +260,13 @@ get to the desired id:
|
|||
|
||||
def on_start(self):
|
||||
# {
|
||||
# 'box_container_1': <kivymd.uix.floatlayout.MDFloatLayout>,
|
||||
# 'box_container_2': <kivymd.uix.boxlayout.MDBoxLayout object>
|
||||
# 'button_1': <kivymd.uix.button.button.MDButton object at 0x11d93c9e0>,
|
||||
# 'button_2': <kivymd.uix.button.button.MDButton object at 0x11da128f0>,
|
||||
# 'float_container': <kivymd.uix.floatlayout.MDFloatLayout object at 0x11da228f0>,
|
||||
# 'box_container_1': <kivymd.uix.floatlayout.MDFloatLayout object at 0x11d9fc3c0>,
|
||||
# 'box_container_2': <kivymd.uix.boxlayout.MDBoxLayout object at 0x11dbf06d0>,
|
||||
# }
|
||||
print(self.root.ids)
|
||||
|
||||
# <kivymd.uix.button.button.MDRaisedButton>
|
||||
print(self.root.ids.box_container_2.ids.float_container.ids.button_2)
|
||||
print(self.root.get_ids())
|
||||
|
||||
|
||||
Example().run()
|
||||
|
@ -293,6 +282,15 @@ from kivy.properties import StringProperty
|
|||
from kivy.uix.widget import Widget
|
||||
|
||||
|
||||
class _Dict(dict):
|
||||
"""Implements access to dictionary values via a dot."""
|
||||
|
||||
def __getattr__(self, name):
|
||||
return self[name]
|
||||
|
||||
|
||||
# TODO: Add cleaning of the `__ids` collection when removing child widgets
|
||||
# from the parent.
|
||||
class DeclarativeBehavior:
|
||||
"""
|
||||
Implements the creation and addition of child widgets as declarative
|
||||
|
@ -307,6 +305,8 @@ class DeclarativeBehavior:
|
|||
and defaults to `''`.
|
||||
"""
|
||||
|
||||
__ids = _Dict()
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
|
@ -314,4 +314,12 @@ class DeclarativeBehavior:
|
|||
if issubclass(child.__class__, Widget):
|
||||
self.add_widget(child)
|
||||
if hasattr(child, "id") and child.id:
|
||||
self.ids[child.id] = child
|
||||
self.__ids[child.id] = child
|
||||
|
||||
def get_ids(self) -> dict:
|
||||
"""
|
||||
Returns a dictionary of widget IDs defined in Python
|
||||
code that is written in a declarative style.
|
||||
"""
|
||||
|
||||
return self.__ids
|
||||
|
|
|
@ -31,7 +31,7 @@ For example, let's create a button with a rectangular elevation effect:
|
|||
)
|
||||
|
||||
KV = '''
|
||||
<RectangularElevationButton>
|
||||
<ElevationWidget>
|
||||
size_hint: None, None
|
||||
size: "250dp", "50dp"
|
||||
|
||||
|
@ -39,19 +39,19 @@ For example, let's create a button with a rectangular elevation effect:
|
|||
MDScreen:
|
||||
|
||||
# With elevation effect
|
||||
RectangularElevationButton:
|
||||
ElevationWidget:
|
||||
pos_hint: {"center_x": .5, "center_y": .6}
|
||||
elevation: 4
|
||||
shadow_offset: 0, -6
|
||||
shadow_softness: 4
|
||||
|
||||
# Without elevation effect
|
||||
RectangularElevationButton:
|
||||
ElevationWidget:
|
||||
pos_hint: {"center_x": .5, "center_y": .4}
|
||||
'''
|
||||
|
||||
|
||||
class RectangularElevationButton(
|
||||
class ElevationWidget(
|
||||
RectangularRippleBehavior,
|
||||
CommonElevationBehavior,
|
||||
ButtonBehavior,
|
||||
|
@ -84,7 +84,7 @@ For example, let's create a button with a rectangular elevation effect:
|
|||
from kivymd.uix.screen import MDScreen
|
||||
|
||||
|
||||
class RectangularElevationButton(
|
||||
class ElevationWidget(
|
||||
RectangularRippleBehavior,
|
||||
CommonElevationBehavior,
|
||||
ButtonBehavior,
|
||||
|
@ -101,13 +101,13 @@ For example, let's create a button with a rectangular elevation effect:
|
|||
def build(self):
|
||||
return (
|
||||
MDScreen(
|
||||
RectangularElevationButton(
|
||||
ElevationWidget(
|
||||
pos_hint={"center_x": .5, "center_y": .6},
|
||||
elevation=4,
|
||||
shadow_softness=4,
|
||||
shadow_offset=(0, -6),
|
||||
),
|
||||
RectangularElevationButton(
|
||||
ElevationWidget(
|
||||
pos_hint={"center_x": .5, "center_y": .4},
|
||||
),
|
||||
)
|
||||
|
@ -271,7 +271,7 @@ Animating the elevation
|
|||
size: 100, 100
|
||||
md_bg_color: 0, 0, 1, 1
|
||||
elevation: 2
|
||||
radius: 18
|
||||
radius: dp(18)
|
||||
'''
|
||||
|
||||
|
||||
|
@ -306,6 +306,7 @@ Animating the elevation
|
|||
|
||||
from kivy.animation import Animation
|
||||
from kivy.uix.behaviors import ButtonBehavior
|
||||
from kivy.metrics import dp
|
||||
|
||||
from kivymd.app import MDApp
|
||||
from kivymd.uix.behaviors import CommonElevationBehavior, RectangularRippleBehavior
|
||||
|
@ -341,7 +342,7 @@ Animating the elevation
|
|||
size=(100, 100),
|
||||
md_bg_color="blue",
|
||||
elevation=2,
|
||||
radius=18,
|
||||
radius=dp(18),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -355,23 +356,17 @@ Animating the elevation
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
__all__ = (
|
||||
"CommonElevationBehavior",
|
||||
"RectangularElevationBehavior",
|
||||
"CircularElevationBehavior",
|
||||
"RoundedRectangularElevationBehavior",
|
||||
"FakeRectangularElevationBehavior",
|
||||
"FakeCircularElevationBehavior",
|
||||
)
|
||||
__all__ = ("CommonElevationBehavior",)
|
||||
|
||||
from kivy import Logger
|
||||
from kivy.lang import Builder
|
||||
from kivy.metrics import dp
|
||||
from kivy.properties import (
|
||||
BoundedNumericProperty,
|
||||
ColorProperty,
|
||||
ListProperty,
|
||||
NumericProperty,
|
||||
VariableListProperty,
|
||||
DictProperty,
|
||||
)
|
||||
from kivy.uix.widget import Widget
|
||||
|
||||
|
@ -393,18 +388,15 @@ Builder.load_string(
|
|||
axis: tuple(self.rotate_value_axis)
|
||||
origin: self.center
|
||||
Color:
|
||||
rgba:
|
||||
(0, 0, 0, 0) \
|
||||
if self.disabled or not self.elevation else \
|
||||
root.shadow_color
|
||||
rgba: root.shadow_color
|
||||
BoxShadow:
|
||||
pos: self.pos
|
||||
pos: self.pos if not isinstance(self, RelativeLayout) else (0, 0)
|
||||
size: self.size
|
||||
offset: root.shadow_offset
|
||||
spread_radius: -(root.shadow_softness), -(root.shadow_softness)
|
||||
blur_radius: root.elevation * 10
|
||||
blur_radius: root.elevation_levels[root.elevation_level]
|
||||
border_radius:
|
||||
(root.radius if hasattr(self, "radius") else [0, 0, 0, 0]) \
|
||||
(root.radius if hasattr(self, "radius") and root.radius else [0, 0, 0, 0]) \
|
||||
if root.shadow_radius == [0.0, 0.0, 0.0, 0.0] else \
|
||||
root.shadow_radius
|
||||
canvas.after:
|
||||
|
@ -421,6 +413,36 @@ class CommonElevationBehavior(Widget):
|
|||
class documentation.
|
||||
"""
|
||||
|
||||
elevation_level = BoundedNumericProperty(0, min=0, max=5)
|
||||
"""
|
||||
Elevation level (values from 0 to 5)
|
||||
|
||||
.. versionadded:: 1.2.0
|
||||
|
||||
:attr:`elevation_level` is an :class:`~kivy.properties.BoundedNumericProperty`
|
||||
and defaults to `0`.
|
||||
"""
|
||||
|
||||
elevation_levels = DictProperty(
|
||||
{
|
||||
0: 0,
|
||||
1: dp(8),
|
||||
2: dp(12),
|
||||
3: dp(16),
|
||||
4: dp(20),
|
||||
5: dp(24),
|
||||
}
|
||||
)
|
||||
"""
|
||||
Elevation is measured as the distance between components along the z-axis
|
||||
in density-independent pixels (dps).
|
||||
|
||||
.. versionadded:: 1.2.0
|
||||
|
||||
:attr:`elevation_levels` is an :class:`~kivy.properties.DictProperty`
|
||||
and defaults to `{0: dp(0), 1: dp(8), 2: dp(23), 3: dp(16), 4: dp(20), 5: dp(24)}`.
|
||||
"""
|
||||
|
||||
elevation = BoundedNumericProperty(0, min=0, errorvalue=0)
|
||||
"""
|
||||
Elevation of the widget.
|
||||
|
@ -449,7 +471,7 @@ class CommonElevationBehavior(Widget):
|
|||
MDScreen:
|
||||
|
||||
MDCard:
|
||||
radius: 12, 46, 12, 46
|
||||
radius: dp(12), dp(46), dp(12), dp(46)
|
||||
size_hint: .5, .3
|
||||
pos_hint: {"center_x": .5, "center_y": .5}
|
||||
elevation: 2
|
||||
|
@ -486,26 +508,26 @@ class CommonElevationBehavior(Widget):
|
|||
from kivymd.uix.behaviors import BackgroundColorBehavior, CommonElevationBehavior
|
||||
|
||||
KV = '''
|
||||
<RectangularElevationButton>
|
||||
<ElevationWidget>
|
||||
size_hint: None, None
|
||||
size: "250dp", "50dp"
|
||||
|
||||
|
||||
MDScreen:
|
||||
|
||||
RectangularElevationButton:
|
||||
ElevationWidget:
|
||||
pos_hint: {"center_x": .5, "center_y": .6}
|
||||
elevation: 6
|
||||
shadow_softness: 6
|
||||
|
||||
RectangularElevationButton:
|
||||
ElevationWidget:
|
||||
pos_hint: {"center_x": .5, "center_y": .4}
|
||||
elevation: 6
|
||||
shadow_softness: 12
|
||||
'''
|
||||
|
||||
|
||||
class RectangularElevationButton(CommonElevationBehavior, BackgroundColorBehavior):
|
||||
class ElevationWidget(CommonElevationBehavior, BackgroundColorBehavior):
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.md_bg_color = "blue"
|
||||
|
@ -522,19 +544,7 @@ class CommonElevationBehavior(Widget):
|
|||
:align: center
|
||||
|
||||
:attr:`shadow_softness` is an :class:`~kivy.properties.NumericProperty`
|
||||
and defaults to `12`.
|
||||
"""
|
||||
|
||||
shadow_softness_size = BoundedNumericProperty(2, min=2, deprecated=True)
|
||||
"""
|
||||
The value of the softness of the shadow.
|
||||
|
||||
.. versionadded:: 1.1.0
|
||||
|
||||
.. deprecated:: 1.2.0
|
||||
|
||||
:attr:`shadow_softness_size` is an :class:`~kivy.properties.NumericProperty`
|
||||
and defaults to `2`.
|
||||
and defaults to `0.0`.
|
||||
"""
|
||||
|
||||
shadow_offset = ListProperty((0, 0))
|
||||
|
@ -551,23 +561,23 @@ class CommonElevationBehavior(Widget):
|
|||
from kivymd.uix.behaviors import BackgroundColorBehavior, CommonElevationBehavior
|
||||
|
||||
KV = '''
|
||||
<RectangularElevationButton>
|
||||
<ElevationWidget>
|
||||
size_hint: None, None
|
||||
size: "100dp", "100dp"
|
||||
|
||||
|
||||
MDScreen:
|
||||
|
||||
RectangularElevationButton:
|
||||
ElevationWidget:
|
||||
pos_hint: {"center_x": .5, "center_y": .5}
|
||||
elevation: 6
|
||||
shadow_radius: 6
|
||||
shadow_radius: dp(6)
|
||||
shadow_softness: 12
|
||||
shadow_offset: -12, -12
|
||||
'''
|
||||
|
||||
|
||||
class RectangularElevationButton(CommonElevationBehavior, BackgroundColorBehavior):
|
||||
class ElevationWidget(CommonElevationBehavior, BackgroundColorBehavior):
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.md_bg_color = "blue"
|
||||
|
@ -585,7 +595,7 @@ class CommonElevationBehavior(Widget):
|
|||
|
||||
.. code-block:: kv
|
||||
|
||||
RectangularElevationButton:
|
||||
ElevationWidget:
|
||||
shadow_offset: 12, -12
|
||||
|
||||
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/shadow-offset-2.png
|
||||
|
@ -593,7 +603,7 @@ class CommonElevationBehavior(Widget):
|
|||
|
||||
.. code-block:: kv
|
||||
|
||||
RectangularElevationButton:
|
||||
ElevationWidget:
|
||||
shadow_offset: 12, 12
|
||||
|
||||
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/shadow-offset-3.png
|
||||
|
@ -601,7 +611,7 @@ class CommonElevationBehavior(Widget):
|
|||
|
||||
.. code-block:: kv
|
||||
|
||||
RectangularElevationButton:
|
||||
ElevationWidget:
|
||||
shadow_offset: -12, 12
|
||||
|
||||
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/shadow-offset-4.png
|
||||
|
@ -619,7 +629,7 @@ class CommonElevationBehavior(Widget):
|
|||
|
||||
.. code-block:: python
|
||||
|
||||
RectangularElevationButton:
|
||||
ElevationWidget:
|
||||
shadow_color: 0, 0, 1, .8
|
||||
|
||||
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/shadow-color.png
|
||||
|
@ -691,82 +701,10 @@ class CommonElevationBehavior(Widget):
|
|||
and defaults to `(0, 0, 1)`.
|
||||
"""
|
||||
|
||||
_elevation = 0
|
||||
# _elevation = 0
|
||||
_elevation_level = 0
|
||||
_shadow_softness = 0
|
||||
_shadow_color = (0, 0, 0, 0)
|
||||
|
||||
def on_elevation(self, instance, value) -> None:
|
||||
self._elevation = value
|
||||
|
||||
|
||||
class RectangularElevationBehavior(CommonElevationBehavior):
|
||||
"""
|
||||
.. deprecated:: 1.1.0
|
||||
Use :class:`~CommonElevationBehavior` class instead.
|
||||
"""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
Logger.warning(
|
||||
"KivyMD: "
|
||||
"The `RectangularElevationBehavior` class has been deprecated. "
|
||||
"Use the `CommonElevationBehavior` class instead.`"
|
||||
)
|
||||
|
||||
|
||||
class CircularElevationBehavior(CommonElevationBehavior):
|
||||
"""
|
||||
.. deprecated:: 1.1.0
|
||||
Use :class:`~CommonElevationBehavior` class instead.
|
||||
"""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
Logger.warning(
|
||||
"KivyMD: "
|
||||
"The `CircularElevationBehavior` class has been deprecated. "
|
||||
"Use the `CommonElevationBehavior` class instead.`"
|
||||
)
|
||||
|
||||
|
||||
class RoundedRectangularElevationBehavior(CommonElevationBehavior):
|
||||
"""
|
||||
.. deprecated:: 1.1.0
|
||||
Use :class:`~CommonElevationBehavior` class instead.
|
||||
"""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
Logger.warning(
|
||||
"KivyMD: "
|
||||
"The `RoundedRectangularElevationBehavior` class has been "
|
||||
"deprecated. Use the `CommonElevationBehavior` class instead.`"
|
||||
)
|
||||
|
||||
|
||||
class FakeRectangularElevationBehavior(CommonElevationBehavior):
|
||||
"""
|
||||
.. deprecated:: 1.1.0
|
||||
Use :class:`~CommonElevationBehavior` class instead.
|
||||
"""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
Logger.warning(
|
||||
"KivyMD: "
|
||||
"The `FakeRectangularElevationBehavior` class has been "
|
||||
"deprecated. Use the `CommonElevationBehavior` class instead."
|
||||
)
|
||||
|
||||
|
||||
class FakeCircularElevationBehavior(CommonElevationBehavior):
|
||||
"""
|
||||
.. deprecated:: 1.1.0
|
||||
Use :class:`~CommonElevationBehavior` class instead.
|
||||
"""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
Logger.warning(
|
||||
"KivyMD: "
|
||||
"The `FakeCircularElevationBehavior` class has been deprecated. "
|
||||
"Use the `CommonElevationBehavior` class instead."
|
||||
)
|
||||
# def on_elevation(self, instance, value) -> None:
|
||||
# self._elevation = value
|
||||
|
|
|
@ -15,7 +15,7 @@ Usage
|
|||
from kivy.lang import Builder
|
||||
|
||||
from kivymd.app import MDApp
|
||||
from kivymd.uix.behaviors import RectangularElevationBehavior
|
||||
from kivymd.uix.behaviors import CommonElevationBehavior
|
||||
from kivymd.uix.boxlayout import MDBoxLayout
|
||||
from kivymd.uix.behaviors.focus_behavior import FocusBehavior
|
||||
|
||||
|
@ -36,7 +36,7 @@ Usage
|
|||
'''
|
||||
|
||||
|
||||
class FocusWidget(MDBoxLayout, RectangularElevationBehavior, FocusBehavior):
|
||||
class FocusWidget(MDBoxLayout, CommonElevationBehavior, FocusBehavior):
|
||||
pass
|
||||
|
||||
|
||||
|
@ -65,25 +65,26 @@ Color change at focus/defocus
|
|||
|
||||
__all__ = ("FocusBehavior",)
|
||||
|
||||
from kivy.app import App
|
||||
from kivy.properties import BooleanProperty, ColorProperty
|
||||
from kivy.uix.behaviors import ButtonBehavior
|
||||
|
||||
from kivymd.uix.behaviors import HoverBehavior
|
||||
|
||||
|
||||
class FocusBehavior(HoverBehavior, ButtonBehavior):
|
||||
class FocusBehavior(HoverBehavior):
|
||||
"""
|
||||
Focus behavior class.
|
||||
|
||||
For more information, see in the :class:`~kivymd.uix.behavior.HoverBehavior`
|
||||
and :class:`~kivy.uix.button.ButtonBehavior` classes documentation.
|
||||
For more information, see in the
|
||||
:class:`~kivymd.uix.behavior.HoverBehavior` and
|
||||
:class:`~kivy.uix.button.ButtonBehavior`
|
||||
classes documentation.
|
||||
|
||||
:Events:
|
||||
:attr:`on_enter`
|
||||
Called when mouse enters the bbox of the widget AND the widget is visible
|
||||
Fired when mouse enters the bbox of the widget AND the widget is
|
||||
visible.
|
||||
:attr:`on_leave`
|
||||
Called when the mouse exits the widget AND the widget is visible
|
||||
Fired when the mouse exits the widget AND the widget is visible.
|
||||
"""
|
||||
|
||||
focus_behavior = BooleanProperty(True)
|
||||
|
@ -109,39 +110,3 @@ class FocusBehavior(HoverBehavior, ButtonBehavior):
|
|||
:attr:`unfocus_color` is a :class:`~kivy.properties.ColorProperty`
|
||||
and defaults to `None`.
|
||||
"""
|
||||
|
||||
def on_enter(self):
|
||||
"""Called when mouse enter the bbox of the widget."""
|
||||
|
||||
if (
|
||||
hasattr(self, "md_bg_color") or hasattr(self, "bg_color")
|
||||
) and self.focus_behavior:
|
||||
if hasattr(self, "theme_cls") and not self.focus_color:
|
||||
color = self.theme_cls.bg_normal
|
||||
else:
|
||||
if not self.focus_color:
|
||||
color = App.get_running_app().theme_cls.bg_normal
|
||||
else:
|
||||
color = self.focus_color
|
||||
self._set_bg_color(color)
|
||||
|
||||
def on_leave(self):
|
||||
"""Called when the mouse exit the widget."""
|
||||
|
||||
if (
|
||||
hasattr(self, "md_bg_color") or hasattr(self, "bg_color")
|
||||
) and self.focus_behavior:
|
||||
if hasattr(self, "theme_cls") and not self.unfocus_color:
|
||||
color = self.theme_cls.bg_light
|
||||
else:
|
||||
if not self.unfocus_color:
|
||||
color = App.get_running_app().theme_cls.bg_light
|
||||
else:
|
||||
color = self.unfocus_color
|
||||
self._set_bg_color(color)
|
||||
|
||||
def _set_bg_color(self, color):
|
||||
if hasattr(self, "md_bg_color"):
|
||||
self.md_bg_color = color
|
||||
elif hasattr(self, "bg_color"):
|
||||
self.bg_color = color
|
||||
|
|
|
@ -27,9 +27,13 @@ the widget.
|
|||
|
||||
.. note::
|
||||
|
||||
:class:`~HoverBehavior` will by default check to see if the current Widget is visible (i.e. not covered by a modal or popup and not a part of a Relative Layout, MDTab or Carousel that is not currently visible etc) and will only issue events if the widget is visible.
|
||||
:class:`~HoverBehavior` will by default check to see if the current Widget
|
||||
is visible (i.e. not covered by a modal or popup and not a part of a
|
||||
RelativeLayout, MDTab or Carousel that is not currently visible etc)
|
||||
and will only issue events if the widget is visible.
|
||||
|
||||
To get the legacy behavior that the events are always triggered, you can set `detect_visible` on the Widget to `False`.
|
||||
To get the legacy behavior that the events are always triggered, you can
|
||||
set `detect_visible` on the Widget to `False`.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
@ -40,13 +44,14 @@ the widget.
|
|||
from kivymd.uix.boxlayout import MDBoxLayout
|
||||
|
||||
KV = '''
|
||||
Screen
|
||||
MDScreen
|
||||
md_bg_color: self.theme_cls.backgroundColor
|
||||
|
||||
MDBoxLayout:
|
||||
id: box
|
||||
pos_hint: {'center_x': .5, 'center_y': .5}
|
||||
size_hint: .8, .8
|
||||
md_bg_color: app.theme_cls.bg_darkest
|
||||
md_bg_color: self.theme_cls.secondaryContainerColor
|
||||
'''
|
||||
|
||||
|
||||
|
@ -54,19 +59,23 @@ the widget.
|
|||
'''Custom item implementing hover behavior.'''
|
||||
|
||||
def on_enter(self, *args):
|
||||
'''The method will be called when the mouse cursor
|
||||
is within the borders of the current widget.'''
|
||||
'''
|
||||
The method will be called when the mouse cursor
|
||||
is within the borders of the current widget.
|
||||
'''
|
||||
|
||||
self.md_bg_color = (1, 1, 1, 1)
|
||||
self.md_bg_color = "white"
|
||||
|
||||
def on_leave(self, *args):
|
||||
'''The method will be called when the mouse cursor goes beyond
|
||||
the borders of the current widget.'''
|
||||
'''
|
||||
The method will be called when the mouse cursor goes beyond
|
||||
the borders of the current widget.
|
||||
'''
|
||||
|
||||
self.md_bg_color = self.theme_cls.bg_darkest
|
||||
self.md_bg_color = self.theme_cls.secondaryContainerColor
|
||||
|
||||
|
||||
class Test(MDApp):
|
||||
class Example(MDApp):
|
||||
def build(self):
|
||||
self.screen = Builder.load_string(KV)
|
||||
for i in range(5):
|
||||
|
@ -74,10 +83,9 @@ the widget.
|
|||
return self.screen
|
||||
|
||||
|
||||
Test().run()
|
||||
Example().run()
|
||||
|
||||
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/hover-behavior.gif
|
||||
:width: 250 px
|
||||
:align: center
|
||||
"""
|
||||
|
||||
|
@ -85,23 +93,25 @@ __all__ = ("HoverBehavior",)
|
|||
|
||||
from kivy.core.window import Window
|
||||
from kivy.properties import BooleanProperty, ObjectProperty
|
||||
from kivy.uix.relativelayout import RelativeLayout
|
||||
from kivy.uix.widget import Widget
|
||||
|
||||
|
||||
class HoverBehavior(object):
|
||||
class HoverBehavior:
|
||||
"""
|
||||
:Events:
|
||||
:attr:`on_enter`
|
||||
Called when mouse enters the bbox of the widget AND the widget is visible
|
||||
Fired when mouse enters the bbox of the widget and the widget is
|
||||
visible.
|
||||
:attr:`on_leave`
|
||||
Called when the mouse exits the widget AND the widget is visible
|
||||
Fired when the mouse exits the widget and the widget is visible.
|
||||
"""
|
||||
|
||||
hovering = BooleanProperty(False)
|
||||
"""
|
||||
`True`, if the mouse cursor is within the borders of the widget.
|
||||
|
||||
Note that this is set and cleared even if the widget is not visible
|
||||
Note that this is set and cleared even if the widget is not visible.
|
||||
|
||||
:attr:`hover` is a :class:`~kivy.properties.BooleanProperty`
|
||||
and defaults to `False`.
|
||||
|
@ -109,7 +119,7 @@ class HoverBehavior(object):
|
|||
|
||||
hover_visible = BooleanProperty(False)
|
||||
"""
|
||||
`True` if hovering is True AND is the current widget is visible
|
||||
`True` if hovering is `True` and is the current widget is visible.
|
||||
|
||||
:attr:`hover_visible` is a :class:`~kivy.properties.BooleanProperty`
|
||||
and defaults to `False`.
|
||||
|
@ -118,7 +128,7 @@ class HoverBehavior(object):
|
|||
enter_point = ObjectProperty(allownone=True)
|
||||
"""
|
||||
Holds the last position where the mouse pointer crossed into the Widget
|
||||
if the Widget is visible and is currently in a hovering state
|
||||
if the Widget is visible and is currently in a hovering state.
|
||||
|
||||
:attr:`enter_point` is a :class:`~kivy.properties.ObjectProperty`
|
||||
and defaults to `None`.
|
||||
|
@ -132,22 +142,24 @@ class HoverBehavior(object):
|
|||
and defaults to `True`.
|
||||
"""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.register_event_type("on_enter")
|
||||
self.register_event_type("on_leave")
|
||||
Window.bind(mouse_pos=self.on_mouse_update)
|
||||
super(HoverBehavior, self).__init__(**kwargs)
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def on_mouse_update(self, *args):
|
||||
# If the Widget currently has no parent, do nothing
|
||||
# If the Widget currently has no parent, do nothing.
|
||||
if not self.get_root_window():
|
||||
return
|
||||
pos = args[1]
|
||||
#
|
||||
# is the pointer in the same position as the widget?
|
||||
# If not - then issue an on_exit event if needed
|
||||
#
|
||||
if not self.collide_point(*self.to_widget(*pos)):
|
||||
# Is the pointer in the same position as the widget?
|
||||
# If not - then issue an on_exit event if needed.
|
||||
if not self.collide_point(
|
||||
*self.to_widget(*pos)
|
||||
if not isinstance(self, RelativeLayout)
|
||||
else (pos[0], pos[1])
|
||||
):
|
||||
self.hovering = False
|
||||
self.enter_point = None
|
||||
if self.hover_visible:
|
||||
|
@ -155,72 +167,59 @@ class HoverBehavior(object):
|
|||
self.dispatch("on_leave")
|
||||
return
|
||||
|
||||
#
|
||||
# The pointer is in the same position as the widget
|
||||
#
|
||||
|
||||
# The pointer is in the same position as the widget.
|
||||
if self.hovering:
|
||||
#
|
||||
# nothing to do here. Not - this does not handle the case where
|
||||
# a popup comes over an existing hover event.
|
||||
# This seems reasonable
|
||||
#
|
||||
# Nothing to do here. Not - this does not handle the case where
|
||||
# a popup comes over an existing hover event.
|
||||
# This seems reasonable.
|
||||
return
|
||||
|
||||
#
|
||||
# Otherwise - set the hovering attribute
|
||||
#
|
||||
self.hovering = True
|
||||
|
||||
#
|
||||
# We need to traverse the tree to see if the Widget is visible
|
||||
#
|
||||
# This is a two stage process:
|
||||
# - first go up the tree to the root Window.
|
||||
# At each stage - check that the Widget is actually visible
|
||||
# - Second - At the root Window check that there is not another branch
|
||||
# covering the Widget
|
||||
#
|
||||
|
||||
# We need to traverse the tree to see if the Widget is visible.
|
||||
# This is a two stage process - first go up the tree to the root.
|
||||
# Window. At each stage - check that the Widget is actually visible.
|
||||
# Second - at the root Window check that there is not another branch
|
||||
# covering the Widget.
|
||||
self.hover_visible = True
|
||||
|
||||
if self.detect_visible:
|
||||
widget: Widget = self
|
||||
while True:
|
||||
# Walk up the Widget tree from the target Widget
|
||||
# Walk up the Widget tree from the target Widget.
|
||||
parent = widget.parent
|
||||
try:
|
||||
# See if the mouse point collides with the parent
|
||||
# using both local and glabal coordinates to cover absoluet and relative layouts
|
||||
# using both local and global coordinates to cover absolute
|
||||
# and relative layouts.
|
||||
pinside = parent.collide_point(
|
||||
*parent.to_widget(*pos)
|
||||
) or parent.collide_point(*pos)
|
||||
except Exception:
|
||||
# The collide_point will error when you reach the root Window
|
||||
# The collide_point will error when you reach the root
|
||||
# Window.
|
||||
break
|
||||
if not pinside:
|
||||
self.hover_visible = False
|
||||
break
|
||||
# Iterate upwards
|
||||
# Iterate upwards.
|
||||
widget = parent
|
||||
|
||||
#
|
||||
# parent = root window
|
||||
# widget = first Widget on the current branch
|
||||
#
|
||||
|
||||
children = parent.children
|
||||
for child in children:
|
||||
# For each top level widget - check if is current branch
|
||||
# For each top level widget - check if is current branch.
|
||||
# If it is - then break.
|
||||
# If not then - since we start at 0 - this widget is visible
|
||||
#
|
||||
# Check to see if it should take the hover
|
||||
#
|
||||
# If not then - since we start at 0 - this widget is visible.
|
||||
# Check to see if it should take the hover.
|
||||
if child == widget:
|
||||
# this means that the current widget is visible
|
||||
# This means that the current widget is visible.
|
||||
break
|
||||
if child.collide_point(*pos):
|
||||
# this means that the current widget is covered by a modal or popup
|
||||
# This means that the current widget is covered by a modal
|
||||
# or popup.
|
||||
self.hover_visible = False
|
||||
break
|
||||
if self.hover_visible:
|
||||
|
@ -228,7 +227,7 @@ class HoverBehavior(object):
|
|||
self.dispatch("on_enter")
|
||||
|
||||
def on_enter(self):
|
||||
"""Called when mouse enters the bbox of the widget AND the widget is visible."""
|
||||
"""Fired when mouse enter the bbox of the widget."""
|
||||
|
||||
def on_leave(self):
|
||||
"""Called when the mouse exits the widget AND the widget is visible."""
|
||||
"""Fired when the mouse goes outside the widget border."""
|
||||
|
|
|
@ -15,17 +15,20 @@ as dialogs, dropdown menu, snack bars, and so on.
|
|||
|
||||
__all__ = (
|
||||
"MotionBase",
|
||||
"MotionExtendedFabButtonBehavior",
|
||||
"MotionDropDownMenuBehavior",
|
||||
"MotionDialogBehavior",
|
||||
"MotionShackBehavior",
|
||||
"MotionDatePickerBehavior",
|
||||
"MotionTimePickerBehavior",
|
||||
)
|
||||
|
||||
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
|
||||
from kivy.metrics import dp
|
||||
from kivy.properties import StringProperty, NumericProperty, ObjectProperty
|
||||
from kivymd.uix.behaviors.scale_behavior import ScaleBehavior
|
||||
|
||||
|
||||
class MotionBase:
|
||||
|
@ -166,80 +169,288 @@ class MotionDropDownMenuBehavior(MotionBase):
|
|||
self.scale_value_y = value
|
||||
|
||||
|
||||
class MotionDialogBehavior(MotionBase):
|
||||
class MotionExtendedFabButtonBehavior(MotionBase):
|
||||
"""
|
||||
Base class for dialog movement behavior.
|
||||
Base class for extended Fab button movement behavior.
|
||||
|
||||
For more information, see in the :class:`~MotionBase` class documentation.
|
||||
"""
|
||||
|
||||
show_duration = NumericProperty(0.1)
|
||||
show_transition = StringProperty("out_circ")
|
||||
"""
|
||||
The type of transition of the widget opening.
|
||||
|
||||
:attr:`show_transition` is a :class:`~kivy.properties.StringProperty`
|
||||
and defaults to `'out_circ'`.
|
||||
"""
|
||||
|
||||
shift_transition = StringProperty("out_sine")
|
||||
"""
|
||||
Text label transition.
|
||||
|
||||
:attr:`shift_transition` is a :class:`~kivy.properties.StringProperty`
|
||||
and defaults to `'out_sine'`.
|
||||
"""
|
||||
|
||||
show_duration = NumericProperty(0.3)
|
||||
"""
|
||||
Duration of widget display transition.
|
||||
|
||||
:attr:`show_duration` is a :class:`~kivy.properties.NumericProperty`
|
||||
and defaults to `0.1`.
|
||||
and defaults to `0.3`.
|
||||
"""
|
||||
|
||||
scale_x = NumericProperty(1.5)
|
||||
hide_transition = StringProperty("out_sine")
|
||||
"""
|
||||
Default X-axis scaling values.
|
||||
The type of transition of the widget closing.
|
||||
|
||||
:attr:`scale_x` is a :class:`~kivy.properties.NumericProperty`
|
||||
and defaults to `1.5`.
|
||||
:attr:`hide_transition` is a :class:`~kivy.properties.StringProperty`
|
||||
and defaults to `'linear'`.
|
||||
"""
|
||||
|
||||
scale_y = NumericProperty(1.5)
|
||||
hide_duration = NumericProperty(0.2)
|
||||
"""
|
||||
Default Y-axis scaling values.
|
||||
Duration of widget closing transition.
|
||||
|
||||
:attr:`scale_y` is a :class:`~kivy.properties.NumericProperty`
|
||||
and defaults to `1.5`.
|
||||
:attr:`hide_duration` is a :class:`~kivy.properties.NumericProperty`
|
||||
and defaults to `0.2`.
|
||||
"""
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.set_default_values()
|
||||
_x = NumericProperty(0)
|
||||
_anim_opacity = None
|
||||
|
||||
def set_default_values(self):
|
||||
"""Sets default scaled and transparency values."""
|
||||
def collapse(self, *args) -> None:
|
||||
"""Collapses the button."""
|
||||
|
||||
self.scale_value_x = self.scale_x
|
||||
self.scale_value_y = self.scale_y
|
||||
self.opacity = 0
|
||||
def collapse(*args):
|
||||
if self._label and self._icon:
|
||||
Animation(_x=0, d=self.hide_duration).start(self)
|
||||
anim = Animation(
|
||||
width=dp(56), d=self.hide_duration, t=self.hide_transition
|
||||
)
|
||||
anim.bind(on_progress=self._check_collapse_progress)
|
||||
anim.start(self)
|
||||
|
||||
Clock.schedule_once(collapse)
|
||||
|
||||
def expand(self, *args) -> None:
|
||||
"""Expands the button."""
|
||||
|
||||
def expand(*args):
|
||||
if self._label and self._icon:
|
||||
anim = Animation(
|
||||
width=self.width
|
||||
+ self._label.texture_size[0]
|
||||
+ (dp(18) if self._icon else 0),
|
||||
d=self.show_duration,
|
||||
t=self.show_transition,
|
||||
)
|
||||
anim.bind(on_progress=self._check_expand_progress)
|
||||
anim.start(self)
|
||||
Animation(
|
||||
_x=dp(12), d=self.show_duration, t=self.shift_transition
|
||||
).start(self)
|
||||
|
||||
Clock.schedule_once(expand)
|
||||
|
||||
def set_opacity_text_button(self, value: int) -> None:
|
||||
if self._label:
|
||||
self._anim_opacity = Animation(
|
||||
opacity=value,
|
||||
d=self.show_duration * 16.666666666666668 / 100
|
||||
if value
|
||||
else self.show_duration * 1.6666666666666667 / 100,
|
||||
)
|
||||
self._anim_opacity.bind(
|
||||
on_complete=lambda *x: setattr(self, "_anim_opacity", None)
|
||||
)
|
||||
self._anim_opacity.start(self._label)
|
||||
|
||||
def _check_collapse_progress(self, animation, instance, progress) -> None:
|
||||
if progress > 0.1:
|
||||
if not self._anim_opacity:
|
||||
self.set_opacity_text_button(0)
|
||||
|
||||
def _check_expand_progress(self, animation, instance, progress) -> None:
|
||||
if progress > 0.3:
|
||||
if not self._anim_opacity:
|
||||
self.set_opacity_text_button(1)
|
||||
|
||||
|
||||
class MotionDialogBehavior(ScaleBehavior, MotionBase):
|
||||
"""
|
||||
Base class for dialog movement behavior.
|
||||
|
||||
For more information, see in the
|
||||
:class:`~kivymd.uix.behaviors.scale_behavior.ScaleBehavior`
|
||||
:class:`~MotionBase`
|
||||
classes documentation.
|
||||
"""
|
||||
|
||||
show_transition = StringProperty("out_expo")
|
||||
"""
|
||||
The type of transition of the widget opening.
|
||||
|
||||
:attr:`show_transition` is a :class:`~kivy.properties.StringProperty`
|
||||
and defaults to `'out_expo'`.
|
||||
"""
|
||||
|
||||
show_button_container_transition = StringProperty("out_circ")
|
||||
"""
|
||||
The type of transition of the widget opening.
|
||||
|
||||
:attr:`show_button_container_transition` is a :class:`~kivy.properties.StringProperty`
|
||||
and defaults to `'out_circ'`.
|
||||
"""
|
||||
|
||||
hide_transition = StringProperty("out_circ")
|
||||
"""
|
||||
The type of transition of the widget opening.
|
||||
|
||||
:attr:`show_transition` is a :class:`~kivy.properties.StringProperty`
|
||||
and defaults to `'hide_transition'`.
|
||||
"""
|
||||
|
||||
show_duration = NumericProperty(0.4)
|
||||
"""
|
||||
Duration of widget display transition.
|
||||
|
||||
:attr:`show_duration` is a :class:`~kivy.properties.NumericProperty`
|
||||
and defaults to `0.2`.
|
||||
"""
|
||||
|
||||
def on_dismiss(self, *args):
|
||||
"""Called when a dialog closed."""
|
||||
"""Fired when a dialog closed."""
|
||||
|
||||
self.set_default_values()
|
||||
def remove_dialog(*args):
|
||||
Window.remove_widget(self)
|
||||
if self._scrim:
|
||||
Window.remove_widget(self._scrim)
|
||||
|
||||
def on_open(self, *args):
|
||||
"""Called when a dialog opened."""
|
||||
if self._scrim:
|
||||
Animation(alpha=0, d=self.hide_duration).start(self._scrim)
|
||||
|
||||
Animation(
|
||||
opacity=1,
|
||||
scale_value_x=1,
|
||||
scale_value_y=1,
|
||||
t=self.show_transition,
|
||||
d=self.show_duration,
|
||||
).start(self)
|
||||
y=self.ids.content_container.y,
|
||||
t=self.hide_transition,
|
||||
d=self.hide_duration,
|
||||
).start(self.ids.button_container)
|
||||
|
||||
anim = Animation(
|
||||
opacity=0,
|
||||
scale_value_y=0,
|
||||
t=self.hide_transition,
|
||||
d=self.hide_duration,
|
||||
)
|
||||
anim.bind(on_complete=remove_dialog)
|
||||
anim.start(self)
|
||||
|
||||
def on_open(self, *args):
|
||||
"""Fired when a dialog opened."""
|
||||
|
||||
def open(*args):
|
||||
self.scale_value_y = 0
|
||||
self.scale_value_center = (0, self.center[1] + self.height / 2)
|
||||
Animation(
|
||||
opacity=1,
|
||||
scale_value_y=1,
|
||||
t=self.show_transition,
|
||||
d=self.show_duration,
|
||||
).start(self)
|
||||
|
||||
Animation(
|
||||
y=dp(24),
|
||||
t=self.show_button_container_transition,
|
||||
d=self.show_duration + 0.15,
|
||||
).start(self.ids.button_container)
|
||||
|
||||
if self._scrim:
|
||||
Animation(alpha=0.4, d=self.show_duration).start(self._scrim)
|
||||
|
||||
Clock.schedule_once(open)
|
||||
|
||||
|
||||
class MotionShackBehavior(StencilBehavior, MotionBase):
|
||||
class MotionPickerBehavior(MotionDialogBehavior):
|
||||
"""
|
||||
Base class for date/time pickers movement behavior.
|
||||
|
||||
For more information, see in the
|
||||
:class:`~MotionDialogBehavior` class documentation.
|
||||
"""
|
||||
|
||||
_scrim = ObjectProperty()
|
||||
|
||||
def on_open(self, *args):
|
||||
"""Fired when a dialog opened."""
|
||||
|
||||
def open(*args):
|
||||
self.scale_value_y = 0
|
||||
self.scale_value_center = (0, self.center[1] + self.height / 2)
|
||||
Animation(
|
||||
opacity=1,
|
||||
scale_value_y=1,
|
||||
t=self.show_transition,
|
||||
d=self.show_duration,
|
||||
).start(self)
|
||||
|
||||
if self._scrim:
|
||||
Animation(alpha=0.4, d=self.show_duration).start(self._scrim)
|
||||
|
||||
Clock.schedule_once(open)
|
||||
|
||||
def on_dismiss(self, *args):
|
||||
"""Fired when a dialog closed."""
|
||||
|
||||
def remove_dialog(*args):
|
||||
Window.remove_widget(self)
|
||||
if self._scrim:
|
||||
Window.remove_widget(self._scrim)
|
||||
self.dispatch("on_dismiss")
|
||||
|
||||
if self._scrim:
|
||||
Animation(alpha=0, d=self.hide_duration).start(self._scrim)
|
||||
|
||||
anim = Animation(
|
||||
opacity=0,
|
||||
scale_value_y=0,
|
||||
t=self.hide_transition,
|
||||
d=self.hide_duration,
|
||||
)
|
||||
anim.bind(on_complete=remove_dialog)
|
||||
anim.start(self)
|
||||
|
||||
|
||||
class MotionTimePickerBehavior(MotionPickerBehavior):
|
||||
"""
|
||||
Base class for time picker movement behavior.
|
||||
|
||||
For more information, see in the
|
||||
:class:`~MotionPickerBehavior` class documentation.
|
||||
"""
|
||||
|
||||
|
||||
class MotionDatePickerBehavior(MotionPickerBehavior):
|
||||
"""
|
||||
Base class for date picker movement behavior.
|
||||
|
||||
For more information, see in the
|
||||
:class:`~MotionPickerBehavior` class documentation.
|
||||
"""
|
||||
|
||||
|
||||
class MotionShackBehavior(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.
|
||||
:class:`~MotionBase` class documentation.
|
||||
"""
|
||||
|
||||
_interval = 0
|
||||
_height = 0
|
||||
|
||||
def on_dismiss(self, *args):
|
||||
"""Called when a snackbar closed."""
|
||||
"""Fired when a snackbar closed."""
|
||||
|
||||
def remove_snackbar(*args):
|
||||
Window.parent.remove_widget(self)
|
||||
|
@ -257,7 +468,7 @@ class MotionShackBehavior(StencilBehavior, MotionBase):
|
|||
anim.start(self)
|
||||
|
||||
def on_open(self, *args):
|
||||
"""Called when a snackbar opened."""
|
||||
"""Fired when a snackbar opened."""
|
||||
|
||||
def open(*args):
|
||||
self._height = self.height
|
||||
|
@ -274,9 +485,9 @@ class MotionShackBehavior(StencilBehavior, MotionBase):
|
|||
)
|
||||
)
|
||||
anim.start(self)
|
||||
self.dispatch("on_open")
|
||||
|
||||
Clock.schedule_once(open)
|
||||
self.dispatch("on_open")
|
||||
Clock.schedule_once(open, 0.2)
|
||||
|
||||
def _wait_interval(self, interval):
|
||||
self._interval += interval
|
||||
|
|
|
@ -285,11 +285,18 @@ class CommonRipple:
|
|||
and defaults to `'ripple_func_out'`.
|
||||
"""
|
||||
|
||||
ripple_effect = BooleanProperty(True)
|
||||
"""
|
||||
Should I use the ripple effect.
|
||||
|
||||
:attr:`ripple_effect` is an :class:`~kivy.properties.BooleanProperty`
|
||||
and defaults to `True`.
|
||||
"""
|
||||
|
||||
_ripple_rad = NumericProperty()
|
||||
_doing_ripple = BooleanProperty(False)
|
||||
_finishing_ripple = BooleanProperty(False)
|
||||
_fading_out = BooleanProperty(False)
|
||||
_no_ripple_effect = BooleanProperty(False)
|
||||
_round_rad = ListProperty([0, 0, 0, 0])
|
||||
|
||||
def lay_canvas_instructions(self) -> NoReturn:
|
||||
|
@ -333,6 +340,8 @@ class CommonRipple:
|
|||
anim.start(self)
|
||||
|
||||
def anim_complete(self, *args) -> None:
|
||||
"""Fired when the "fade_out" animation complete."""
|
||||
|
||||
self._doing_ripple = False
|
||||
self._finishing_ripple = False
|
||||
self._fading_out = False
|
||||
|
@ -378,7 +387,7 @@ class CommonRipple:
|
|||
if self.ripple_color:
|
||||
pass
|
||||
elif hasattr(self, "theme_cls"):
|
||||
self.ripple_color = self.theme_cls.ripple_color
|
||||
self.ripple_color = self.theme_cls.rippleColor
|
||||
else:
|
||||
# If no theme, set Gray 300.
|
||||
self.ripple_color = [
|
||||
|
@ -429,7 +438,11 @@ class RectangularRippleBehavior(CommonRipple):
|
|||
"""
|
||||
|
||||
def lay_canvas_instructions(self) -> None:
|
||||
if self._no_ripple_effect:
|
||||
"""
|
||||
Adds graphic instructions to the canvas to implement ripple animation.
|
||||
"""
|
||||
|
||||
if not self.ripple_effect:
|
||||
return
|
||||
|
||||
with self.canvas.after if self.ripple_canvas_after else self.canvas.before:
|
||||
|
@ -493,7 +506,7 @@ class CircularRippleBehavior(CommonRipple):
|
|||
"""
|
||||
|
||||
def lay_canvas_instructions(self) -> None:
|
||||
if self._no_ripple_effect:
|
||||
if not self.ripple_effect:
|
||||
return
|
||||
|
||||
with self.canvas.after if self.ripple_canvas_after else self.canvas.before:
|
||||
|
|
|
@ -0,0 +1,537 @@
|
|||
# TODO: Add docs.
|
||||
|
||||
"""
|
||||
Behaviors/State Layer
|
||||
=====================
|
||||
|
||||
.. seealso::
|
||||
|
||||
`Material Design spec, State layers <https://m3.material.io/foundations/interaction/states/state-layers>`_
|
||||
"""
|
||||
|
||||
from kivy import platform
|
||||
from kivy.lang import Builder
|
||||
from kivy.properties import ColorProperty, NumericProperty
|
||||
|
||||
from kivymd.uix.behaviors.focus_behavior import FocusBehavior
|
||||
|
||||
|
||||
Builder.load_string(
|
||||
"""
|
||||
<StateLayerBehavior>
|
||||
canvas.after:
|
||||
Color
|
||||
rgba: self.state_layer_color
|
||||
RoundedRectangle:
|
||||
group: "State_layer_instruction"
|
||||
size: self.size
|
||||
pos: self.pos
|
||||
radius: self.radius if hasattr(self, "radius") else [0, ]
|
||||
""",
|
||||
filename="StateLayerBehavior.kv",
|
||||
)
|
||||
|
||||
# TODO: Add methods `set_text_color` and `set_icon_color`
|
||||
# (methods that set the color of text and icons in the state
|
||||
# `on_enter` and `on_leave` and `pressed`).
|
||||
|
||||
|
||||
class StateLayerBehavior(FocusBehavior):
|
||||
state_layer_color = ColorProperty([0, 0, 0, 0])
|
||||
"""
|
||||
The color of the layer state.
|
||||
|
||||
:attr:`state_layer_color` is an :class:`~kivy.properties.ColorProperty`
|
||||
and defaults to `[0, 0, 0, 0]`.
|
||||
"""
|
||||
|
||||
state_hover = NumericProperty(0.08)
|
||||
"""
|
||||
The transparency level of the layer as a percentage when hovering.
|
||||
|
||||
:attr:`state_hover` is an :class:`~kivy.properties.NumericProperty`
|
||||
and defaults to `0.08`.
|
||||
"""
|
||||
|
||||
state_press = NumericProperty(0.12)
|
||||
"""
|
||||
The transparency level of the layer as a percentage when pressed.
|
||||
|
||||
:attr:`state_press` is an :class:`~kivy.properties.NumericProperty`
|
||||
and defaults to `0.12`.
|
||||
"""
|
||||
|
||||
state_drag = NumericProperty(0.16)
|
||||
"""
|
||||
The transparency level of the layer as a percentage when dragged.
|
||||
|
||||
:attr:`state_drag` is an :class:`~kivy.properties.NumericProperty`
|
||||
and defaults to `0.16`.
|
||||
"""
|
||||
|
||||
# The transparency value of the disabled state.
|
||||
# These values are specified in the M3 specification.
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# MDIconButton
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
# Filled.
|
||||
icon_button_filled_opacity_value_disabled_container = NumericProperty(0.12)
|
||||
icon_button_filled_opacity_value_disabled_icon = NumericProperty(0.38)
|
||||
|
||||
# Tonal.
|
||||
icon_button_tonal_opacity_value_disabled_container = NumericProperty(0.12)
|
||||
icon_button_tonal_opacity_value_disabled_icon = NumericProperty(0.38)
|
||||
|
||||
# Outlined.
|
||||
icon_button_outlined_opacity_value_disabled_container = NumericProperty(
|
||||
0.12
|
||||
)
|
||||
icon_button_outlined_opacity_value_disabled_line = NumericProperty(0.12)
|
||||
icon_button_outlined_opacity_value_disabled_icon = NumericProperty(0.38)
|
||||
|
||||
# Standard.
|
||||
icon_button_standard_opacity_value_disabled_icon = NumericProperty(0.38)
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# MDFabButton
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
fab_button_opacity_value_disabled_container = NumericProperty(0.12)
|
||||
fab_button_opacity_value_disabled_icon = NumericProperty(0.38)
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# MDButton
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
# Filled.
|
||||
button_filled_opacity_value_disabled_container = NumericProperty(0.12)
|
||||
button_filled_opacity_value_disabled_icon = NumericProperty(0.38)
|
||||
button_filled_opacity_value_disabled_text = NumericProperty(0.38)
|
||||
|
||||
# Tonal.
|
||||
button_tonal_opacity_value_disabled_container = NumericProperty(0.12)
|
||||
button_tonal_opacity_value_disabled_icon = NumericProperty(0.38)
|
||||
button_tonal_opacity_value_disabled_text = NumericProperty(0.38)
|
||||
|
||||
# Outlined.
|
||||
button_outlined_opacity_value_disabled_container = NumericProperty(0.12)
|
||||
button_outlined_opacity_value_disabled_line = NumericProperty(0.12)
|
||||
button_outlined_opacity_value_disabled_icon = NumericProperty(0.38)
|
||||
button_outlined_opacity_value_disabled_text = NumericProperty(0.38)
|
||||
|
||||
# Elevated.
|
||||
button_elevated_opacity_value_disabled_container = NumericProperty(0.12)
|
||||
button_elevated_opacity_value_disabled_icon = NumericProperty(0.38)
|
||||
button_elevated_opacity_value_disabled_text = NumericProperty(0.38)
|
||||
|
||||
# Text.
|
||||
button_text_opacity_value_disabled_icon = NumericProperty(0.38)
|
||||
button_text_opacity_value_disabled_text = NumericProperty(0.38)
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# MDLabel
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
label_opacity_value_disabled_text = NumericProperty(0.38)
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# MDCard
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
card_filled_opacity_value_disabled_state_container = NumericProperty(0.38)
|
||||
card_outlined_opacity_value_disabled_state_container = NumericProperty(0.12)
|
||||
card_opacity_value_disabled_state_elevated_container = NumericProperty(0.38)
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# MDSegmentedButton
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
segmented_button_opacity_value_disabled_container = NumericProperty(0.12)
|
||||
segmented_button_opacity_value_disabled_container_active = NumericProperty(
|
||||
0.38
|
||||
)
|
||||
segmented_button_opacity_value_disabled_line = NumericProperty(0.12)
|
||||
segmented_button_opacity_value_disabled_icon = NumericProperty(0.38)
|
||||
segmented_button_opacity_value_disabled_text = NumericProperty(0.38)
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# MDChip
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
chip_opacity_value_disabled_container = NumericProperty(0.12)
|
||||
chip_opacity_value_disabled_text = NumericProperty(0.38)
|
||||
chip_opacity_value_disabled_icon = NumericProperty(0.38)
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# MDSwitch
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
switch_opacity_value_disabled_line = NumericProperty(0.12)
|
||||
switch_opacity_value_disabled_container = NumericProperty(0.12)
|
||||
switch_thumb_opacity_value_disabled_container = NumericProperty(0.38)
|
||||
switch_opacity_value_disabled_icon = NumericProperty(0.38)
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# MDCheckbox
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
checkbox_opacity_value_disabled_container = NumericProperty(0.38)
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# List
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
list_opacity_value_disabled_container = NumericProperty(0.38)
|
||||
list_opacity_value_disabled_leading_avatar = NumericProperty(0.38)
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# MDTextField
|
||||
# -------------------------------------------------------------------------
|
||||
|
||||
text_field_filled_opacity_value_disabled_state_container = NumericProperty(
|
||||
0.18
|
||||
)
|
||||
text_field_outlined_opacity_value_disabled_state_container = (
|
||||
NumericProperty(0)
|
||||
)
|
||||
text_field_opacity_value_disabled_max_length_label = NumericProperty(0.60)
|
||||
text_field_opacity_value_disabled_helper_text_label = NumericProperty(0.60)
|
||||
text_field_opacity_value_disabled_hint_text_label = NumericProperty(0.60)
|
||||
text_field_opacity_value_disabled_leading_icon = NumericProperty(0.60)
|
||||
text_field_opacity_value_disabled_trailing_icon = NumericProperty(0.60)
|
||||
text_field_opacity_value_disabled_line = NumericProperty(0.12)
|
||||
|
||||
_state = 0.0
|
||||
_bg_color = (0, 0, 0, 0)
|
||||
_is_already_disabled = False
|
||||
_shadow_softness = [0, 0]
|
||||
_elevation_level = 0
|
||||
|
||||
# def __init__(self, *args, **kwargs):
|
||||
# super().__init__(*args, **kwargs)
|
||||
|
||||
def set_properties_widget(self) -> None:
|
||||
"""Fired `on_release/on_press/on_enter/on_leave` events."""
|
||||
|
||||
if not self.disabled:
|
||||
self._restore_properties()
|
||||
self._set_state_layer_color()
|
||||
|
||||
def on_disabled(self, instance, value) -> None:
|
||||
"""Fired when the `disabled` value changes."""
|
||||
|
||||
from kivymd.uix.card import MDCard
|
||||
from kivymd.uix.button import (
|
||||
MDIconButton,
|
||||
MDButton,
|
||||
MDFabButton,
|
||||
MDExtendedFabButton,
|
||||
)
|
||||
from kivymd.uix.segmentedbutton import MDSegmentedButtonItem
|
||||
from kivymd.uix.segmentedbutton.segmentedbutton import (
|
||||
MDSegmentButtonSelectedIcon,
|
||||
)
|
||||
from kivymd.uix.selectioncontrol import MDSwitch
|
||||
from kivymd.uix.list import BaseListItem
|
||||
from kivymd.uix.textfield import MDTextField
|
||||
|
||||
if value and not self._is_already_disabled:
|
||||
self._is_already_disabled = True
|
||||
if isinstance(self, MDCard):
|
||||
self.state_layer_color = (
|
||||
{
|
||||
"filled": self.theme_cls.surfaceColor[:-1]
|
||||
+ [
|
||||
self.card_filled_opacity_value_disabled_state_container
|
||||
],
|
||||
"outlined": self.theme_cls.outlineColor[:-1]
|
||||
+ [
|
||||
self.card_outlined_opacity_value_disabled_state_container
|
||||
],
|
||||
"elevated": self.theme_cls.surfaceVariantColor[:-1]
|
||||
+ [
|
||||
self.card_opacity_value_disabled_state_elevated_container
|
||||
],
|
||||
}[self.style]
|
||||
if not self.md_bg_color_disabled
|
||||
else self.md_bg_color_disabled
|
||||
)
|
||||
elif isinstance(self, MDIconButton):
|
||||
self.state_layer_color = (
|
||||
{
|
||||
"tonal": self.theme_cls.onSurfaceColor[:-1]
|
||||
+ [
|
||||
self.icon_button_tonal_opacity_value_disabled_container
|
||||
],
|
||||
"filled": self.theme_cls.onSurfaceColor[:-1]
|
||||
+ [
|
||||
self.icon_button_filled_opacity_value_disabled_container
|
||||
],
|
||||
"outlined": self.theme_cls.onSurfaceColor[:-1]
|
||||
+ [
|
||||
self.icon_button_outlined_opacity_value_disabled_container
|
||||
],
|
||||
"standard": self.theme_cls.transparentColor,
|
||||
}[self.style]
|
||||
if not self.md_bg_color_disabled
|
||||
else self.md_bg_color_disabled
|
||||
)
|
||||
elif isinstance(self, MDButton):
|
||||
self.state_layer_color = (
|
||||
{
|
||||
"elevated": self.theme_cls.onSurfaceColor[:-1]
|
||||
+ [
|
||||
self.button_elevated_opacity_value_disabled_container
|
||||
],
|
||||
"tonal": self.theme_cls.onSurfaceColor[:-1]
|
||||
+ [self.button_tonal_opacity_value_disabled_container],
|
||||
"filled": self.theme_cls.onSurfaceColor[:-1]
|
||||
+ [self.button_filled_opacity_value_disabled_container],
|
||||
"outlined": self.theme_cls.onSurfaceColor[:-1]
|
||||
+ [
|
||||
self.button_outlined_opacity_value_disabled_container
|
||||
],
|
||||
"text": self.theme_cls.transparentColor,
|
||||
}[self.style]
|
||||
if not self.md_bg_color_disabled
|
||||
else self.md_bg_color_disabled
|
||||
)
|
||||
elif isinstance(self, (MDFabButton, MDExtendedFabButton)):
|
||||
self.state_layer_color = (
|
||||
self.theme_cls.onSurfaceColor[:-1]
|
||||
+ [self.fab_button_opacity_value_disabled_container]
|
||||
if not self.md_bg_color_disabled
|
||||
else self.md_bg_color_disabled
|
||||
)
|
||||
elif isinstance(self, MDTextField):
|
||||
if self.mode == "filled":
|
||||
self.state_layer_color = self.theme_cls.onSurfaceColor[
|
||||
:-1
|
||||
] + [
|
||||
self.text_field_filled_opacity_value_disabled_state_container
|
||||
]
|
||||
else:
|
||||
self.state_layer_color = self.theme_cls.transparentColor
|
||||
elif isinstance(self.parent, MDSegmentedButtonItem):
|
||||
self.state_layer_color = (
|
||||
self.theme_cls.onSurfaceColor[:-1]
|
||||
+ [self.segmented_button_opacity_value_disabled_container]
|
||||
if not self.parent.md_bg_color_disabled
|
||||
else self.parent.md_bg_color_disabled
|
||||
)
|
||||
elif isinstance(self, MDSwitch):
|
||||
self.state_layer_color = (
|
||||
(
|
||||
self.theme_cls.surfaceContainerHighestColor
|
||||
if not self.active
|
||||
else self.theme_cls.onSurfaceColor
|
||||
)[:-1]
|
||||
+ [self.switch_opacity_value_disabled_container]
|
||||
if not self.md_bg_color_disabled
|
||||
else self.md_bg_color_disabled
|
||||
)
|
||||
elif isinstance(self, BaseListItem):
|
||||
self.state_layer_color = (
|
||||
self.theme_cls.onSurfaceColor[:-1]
|
||||
+ [self.list_opacity_value_disabled_container]
|
||||
if not self.md_bg_color_disabled
|
||||
else self.md_bg_color_disabled
|
||||
)
|
||||
elif not value and self._is_already_disabled:
|
||||
self.state_layer_color = self.theme_cls.transparentColor
|
||||
self._is_already_disabled = False
|
||||
|
||||
def on_enter(self) -> None:
|
||||
"""Fired when mouse enter the bbox of the widget."""
|
||||
|
||||
self._state = self.state_hover
|
||||
self.set_properties_widget()
|
||||
|
||||
def on_leave(self) -> None:
|
||||
"""Fired when the mouse goes outside the widget border."""
|
||||
|
||||
self._state = 0.0
|
||||
self.set_properties_widget()
|
||||
|
||||
def _on_release(self, *args):
|
||||
"""
|
||||
Fired when the button is released
|
||||
(i.e. the touch/click that pressed the button goes away).
|
||||
"""
|
||||
|
||||
if platform in ["android", "ios"]:
|
||||
self._state = 0.0
|
||||
self.set_properties_widget()
|
||||
else:
|
||||
self.on_enter()
|
||||
|
||||
def _on_press(self, *args):
|
||||
"""Fired when the button is pressed."""
|
||||
|
||||
self._state = self.state_press
|
||||
self.set_properties_widget()
|
||||
|
||||
def _restore_properties(self):
|
||||
if self._state == self.state_hover and self.focus_behavior:
|
||||
if hasattr(self, "elevation_level"):
|
||||
self._elevation_level = self.elevation_level
|
||||
if hasattr(self, "shadow_softness"):
|
||||
self._shadow_softness = self.shadow_softness
|
||||
if hasattr(self, "md_bg_color"):
|
||||
self._bg_color = self.md_bg_color
|
||||
elif not self._state:
|
||||
if hasattr(self, "elevation_level"):
|
||||
self.elevation_level = self._elevation_level
|
||||
if hasattr(self, "shadow_softness"):
|
||||
self.shadow_softness = self._shadow_softness
|
||||
if hasattr(self, "bg_color"):
|
||||
self.bg_color = self._md_bg_color
|
||||
|
||||
# FIXME: For some widgets, the color of the state of its elements is
|
||||
# ignored. For example, for the `MDSwitch` widget, the color of the status
|
||||
# of the `Thumb` element and the color of the icon are ignored.
|
||||
def _get_target_color(self):
|
||||
from kivymd.uix.card import MDCard
|
||||
from kivymd.uix.button import (
|
||||
MDIconButton,
|
||||
MDButton,
|
||||
MDFabButton,
|
||||
MDExtendedFabButton,
|
||||
)
|
||||
from kivymd.uix.segmentedbutton.segmentedbutton import (
|
||||
MDSegmentedButtonContainer,
|
||||
)
|
||||
from kivymd.uix.chip import MDChip
|
||||
from kivymd.uix.selectioncontrol import MDSwitch, MDCheckbox
|
||||
from kivymd.uix.list import BaseListItem
|
||||
from kivymd.uix.textfield import MDTextField
|
||||
from kivymd.uix.navigationdrawer import MDNavigationDrawerItem
|
||||
|
||||
target_color = None
|
||||
|
||||
if not self.disabled:
|
||||
self._restore_properties()
|
||||
|
||||
if isinstance(self, MDTextField):
|
||||
if self.mode == "filled":
|
||||
target_color = self.theme_cls.onSurfaceColor
|
||||
else:
|
||||
target_color = self.theme_cls.transparentColor
|
||||
elif isinstance(self, (MDCard, BaseListItem)) and not isinstance(
|
||||
self, MDNavigationDrawerItem
|
||||
):
|
||||
target_color = self.theme_cls.onSurfaceColor
|
||||
elif isinstance(self, MDNavigationDrawerItem):
|
||||
target_color = self.theme_cls.onSecondaryContainerColor
|
||||
elif isinstance(self.parent, MDSegmentedButtonContainer):
|
||||
target_color = (
|
||||
self.theme_cls.onSurfaceColor
|
||||
if not self.active
|
||||
else self.theme_cls.onSecondaryContainerColor
|
||||
)
|
||||
elif isinstance(self, MDChip):
|
||||
# Here, depending on the widget state (focus/pressed...)
|
||||
# we set the target color of the widget's layer.
|
||||
# For example:
|
||||
#
|
||||
# if self._state == self.state_press:
|
||||
# target_color = [., ., ., .]
|
||||
# else:
|
||||
# ...
|
||||
if self.type == "assist":
|
||||
target_color = self.theme_cls.onSurfaceColor
|
||||
elif self.type in ["filter", "input", "suggestion"]:
|
||||
target_color = self.theme_cls.onSurfaceVariantColor
|
||||
elif isinstance(self, MDIconButton):
|
||||
if self.style == "filled":
|
||||
target_color = self.theme_cls.onPrimaryColor
|
||||
elif self.style == "tonal":
|
||||
target_color = self.theme_cls.onSecondaryContainerColor
|
||||
elif self.style in ["outlined", "standard"]:
|
||||
target_color = self.theme_cls.onSurfaceVariantColor
|
||||
elif isinstance(self, MDButton):
|
||||
target_color = (
|
||||
self.theme_cls.onPrimaryColor
|
||||
if self.style == "filled"
|
||||
else self.theme_cls.primaryColor
|
||||
)
|
||||
elif isinstance(self, MDCheckbox):
|
||||
target_color = (
|
||||
self.theme_cls.primaryColor
|
||||
if self.active
|
||||
else self.theme_cls.onSurfaceColor
|
||||
)
|
||||
elif isinstance(self, (MDFabButton, MDExtendedFabButton)):
|
||||
target_color = self.theme_cls.onPrimaryContainerColor
|
||||
elif isinstance(self, MDSwitch):
|
||||
target_color = (
|
||||
self.theme_cls.primaryColor
|
||||
if self.active
|
||||
else self.theme_cls.onSurfaceVariantColor
|
||||
)
|
||||
else:
|
||||
target_color = self.theme_cls.onSurfaceColor
|
||||
|
||||
return target_color
|
||||
|
||||
def _set_state_layer_color(self):
|
||||
from kivymd.uix.card import MDCard
|
||||
from kivymd.uix.button import (
|
||||
MDIconButton,
|
||||
MDButton,
|
||||
MDFabButton,
|
||||
MDExtendedFabButton,
|
||||
)
|
||||
from kivymd.uix.segmentedbutton.segmentedbutton import (
|
||||
MDSegmentedButtonContainer,
|
||||
)
|
||||
from kivymd.uix.chip import MDChip
|
||||
from kivymd.uix.selectioncontrol import MDSwitch, MDCheckbox
|
||||
from kivymd.uix.list import BaseListItem
|
||||
from kivymd.uix.textfield import MDTextField
|
||||
from kivymd.uix.tab.tab import MDTabsItemBase
|
||||
|
||||
target_color = self._get_target_color()
|
||||
if (
|
||||
isinstance(
|
||||
self,
|
||||
(
|
||||
MDCard,
|
||||
MDTextField,
|
||||
MDIconButton,
|
||||
MDButton,
|
||||
MDFabButton,
|
||||
MDExtendedFabButton,
|
||||
MDChip,
|
||||
MDSwitch,
|
||||
MDCheckbox,
|
||||
BaseListItem,
|
||||
MDTabsItemBase,
|
||||
),
|
||||
)
|
||||
or isinstance(self.parent, MDSegmentedButtonContainer)
|
||||
and target_color
|
||||
):
|
||||
if self._state == self.state_hover and self.focus_behavior:
|
||||
if (
|
||||
not self.focus_color
|
||||
or self.theme_cls.dynamic_color
|
||||
and self.theme_focus_color == "Primary"
|
||||
):
|
||||
if (
|
||||
isinstance(self, MDTextField)
|
||||
and self.mode == "outlined"
|
||||
):
|
||||
self.state_layer_color = target_color
|
||||
else:
|
||||
self.state_layer_color = target_color[:-1] + [
|
||||
self._state
|
||||
]
|
||||
else:
|
||||
self.state_layer_color = self.focus_color
|
||||
elif self._state == self.state_press:
|
||||
self.state_layer_color = target_color[:-1] + [self._state]
|
||||
elif not self._state:
|
||||
self.state_layer_color = target_color[:-1] + [self._state]
|
|
@ -63,7 +63,7 @@ KivyMD
|
|||
#:import images_path kivymd.images_path
|
||||
|
||||
|
||||
MDCarousel:
|
||||
Carousel:
|
||||
|
||||
StencilImage:
|
||||
size_hint: .9, .8
|
||||
|
|
|
@ -125,25 +125,16 @@ You can inherit the ``MyToggleButton`` class only from the following classes
|
|||
- :class:`~kivymd.uix.button.MDFillRoundFlatIconButton`
|
||||
"""
|
||||
|
||||
__all__ = ("MDToggleButton",)
|
||||
__all__ = ("MDToggleButtonBehavior",)
|
||||
|
||||
from kivy import Logger
|
||||
from kivy.properties import BooleanProperty, ColorProperty
|
||||
from kivy.uix.behaviors import ToggleButtonBehavior
|
||||
|
||||
from kivymd.uix.button import (
|
||||
ButtonContentsIconText,
|
||||
MDFillRoundFlatButton,
|
||||
MDFillRoundFlatIconButton,
|
||||
MDFlatButton,
|
||||
MDRaisedButton,
|
||||
MDRectangleFlatButton,
|
||||
MDRectangleFlatIconButton,
|
||||
MDRoundFlatButton,
|
||||
MDRoundFlatIconButton,
|
||||
)
|
||||
from kivymd.uix.button import MDButton, MDIconButton, MDFabButton, BaseButton
|
||||
|
||||
|
||||
class MDToggleButton(ToggleButtonBehavior):
|
||||
class MDToggleButtonBehavior(ToggleButtonBehavior):
|
||||
background_normal = ColorProperty(None)
|
||||
"""
|
||||
Color of the button in ``rgba`` format for the 'normal' state.
|
||||
|
@ -180,38 +171,29 @@ class MDToggleButton(ToggleButtonBehavior):
|
|||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
classinfo = (
|
||||
MDRaisedButton,
|
||||
MDFlatButton,
|
||||
MDRectangleFlatButton,
|
||||
MDRectangleFlatIconButton,
|
||||
MDRoundFlatButton,
|
||||
MDRoundFlatIconButton,
|
||||
MDFillRoundFlatButton,
|
||||
MDFillRoundFlatIconButton,
|
||||
)
|
||||
classinfo = (MDButton, MDIconButton, MDFabButton)
|
||||
# Do the object inherited from the "supported" buttons?
|
||||
if not issubclass(self.__class__, classinfo):
|
||||
raise ValueError(
|
||||
f"Class {self.__class__} must be inherited from one of the "
|
||||
f"classes in the list {classinfo}"
|
||||
)
|
||||
else:
|
||||
print(666, self.md_bg_color)
|
||||
# self.theme_bg_color = "Custom"
|
||||
if (
|
||||
not self.background_normal
|
||||
): # This means that if the value == [] or None will return True.
|
||||
# If the object inherits from buttons with background:
|
||||
if isinstance(
|
||||
self,
|
||||
(
|
||||
MDRaisedButton,
|
||||
MDFillRoundFlatButton,
|
||||
MDFillRoundFlatIconButton,
|
||||
),
|
||||
):
|
||||
if isinstance(self, BaseButton):
|
||||
print(111)
|
||||
self.__is_filled = True
|
||||
self.background_normal = self.theme_cls.primary_color
|
||||
self.background_normal = (
|
||||
"yellow" # self.theme_cls.primary_color
|
||||
)
|
||||
# If not background_normal must be the same as the inherited one.
|
||||
else:
|
||||
print(222)
|
||||
self.background_normal = (
|
||||
self.md_bg_color[:] if self.md_bg_color else (0, 0, 0, 0)
|
||||
)
|
||||
|
@ -228,25 +210,44 @@ class MDToggleButton(ToggleButtonBehavior):
|
|||
# self.bind(state=self._update_bg)
|
||||
self.fbind("state", self._update_bg)
|
||||
|
||||
def _update_bg(self, ins, val):
|
||||
def _update_bg(self, instance, value):
|
||||
"""Updates the color of the background."""
|
||||
|
||||
if val == "down":
|
||||
self.md_bg_color = self.background_down
|
||||
if (
|
||||
self.__is_filled is False
|
||||
): # If the background is transparent, and the button it toggled,
|
||||
# the font color must be withe [1, 1, 1, 1].
|
||||
self.text_color = self.font_color_down
|
||||
if self.theme_bg_color == "Primary":
|
||||
self.theme_bg_color = "Custom"
|
||||
if self.theme_icon_color == "Primary":
|
||||
self.theme_icon_color = "Custom"
|
||||
|
||||
if value == "down":
|
||||
if isinstance(self, MDIconButton):
|
||||
self.md_bg_color = self.theme_cls.primaryColor
|
||||
self.icon_color = self.theme_cls.onPrimaryColor
|
||||
|
||||
# if (
|
||||
# self.__is_filled is False
|
||||
# ):
|
||||
# self.text_color = self.font_color_down
|
||||
if self.group:
|
||||
self._release_group(self)
|
||||
else:
|
||||
self.md_bg_color = self.background_normal
|
||||
if (
|
||||
self.__is_filled is False
|
||||
): # If the background is transparent, the font color must be the
|
||||
# primary color.
|
||||
self.text_color = self.font_color_normal
|
||||
if isinstance(self, MDIconButton):
|
||||
self.md_bg_color = self.theme_cls.surfaceContainerHighestColor
|
||||
self.icon_color = self.theme_cls.primaryColor
|
||||
|
||||
if issubclass(self.__class__, ButtonContentsIconText):
|
||||
self.icon_color = self.text_color
|
||||
# if (
|
||||
# self.__is_filled is False
|
||||
# ):
|
||||
# self.text_color = self.font_color_normal
|
||||
|
||||
# if issubclass(self.__class__, ButtonContentsIconText):
|
||||
# self.icon_color = self.text_color
|
||||
|
||||
|
||||
class MDToggleButton(MDToggleButtonBehavior):
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
Logger.warning(
|
||||
f"KivyMD: "
|
||||
f"The `{self.__class__.__name__}` class has been deprecated. "
|
||||
f"Use the `MDToggleButtonBehavior` class instead."
|
||||
)
|
||||
|
|
|
@ -16,21 +16,32 @@ Usage
|
|||
.. code-block:: python
|
||||
|
||||
from kivy.lang import Builder
|
||||
from kivy.properties import StringProperty
|
||||
|
||||
from kivymd.app import MDApp
|
||||
from kivymd.uix.behaviors import TouchBehavior
|
||||
from kivymd.uix.button import MDRaisedButton
|
||||
from kivymd.uix.button import MDButton
|
||||
|
||||
KV = '''
|
||||
MDScreen:
|
||||
<TouchBehaviorButton>
|
||||
style: "elevated"
|
||||
|
||||
MyButton:
|
||||
text: "PRESS ME"
|
||||
MDButtonText:
|
||||
text: root.text
|
||||
|
||||
|
||||
MDScreen:
|
||||
md_bg_color: self.theme_cls.backgroundColor
|
||||
|
||||
TouchBehaviorButton:
|
||||
text: "TouchBehavior"
|
||||
pos_hint: {"center_x": .5, "center_y": .5}
|
||||
'''
|
||||
|
||||
|
||||
class MyButton(MDRaisedButton, TouchBehavior):
|
||||
class TouchBehaviorButton(MDButton, TouchBehavior):
|
||||
text = StringProperty()
|
||||
|
||||
def on_long_touch(self, *args):
|
||||
print("<on_long_touch> event")
|
||||
|
||||
|
@ -41,12 +52,12 @@ Usage
|
|||
print("<on_triple_tap> event")
|
||||
|
||||
|
||||
class MainApp(MDApp):
|
||||
class Example(MDApp):
|
||||
def build(self):
|
||||
return Builder.load_string(KV)
|
||||
|
||||
|
||||
MainApp().run()
|
||||
Example().run()
|
||||
"""
|
||||
|
||||
__all__ = ("TouchBehavior",)
|
||||
|
@ -85,16 +96,18 @@ class TouchBehavior:
|
|||
self.on_triple_tap(touch, *args)
|
||||
|
||||
def delete_clock(self, widget, touch, *args):
|
||||
"""Removes a key event from `touch.ud`."""
|
||||
|
||||
if self.collide_point(touch.x, touch.y):
|
||||
if "event" in touch.ud:
|
||||
Clock.unschedule(touch.ud["event"])
|
||||
del touch.ud["event"]
|
||||
|
||||
def on_long_touch(self, touch, *args):
|
||||
"""Called when the widget is pressed for a long time."""
|
||||
"""Fired when the widget is pressed for a long time."""
|
||||
|
||||
def on_double_tap(self, touch, *args):
|
||||
"""Called by double clicking on the widget."""
|
||||
"""Fired by double-clicking on the widget."""
|
||||
|
||||
def on_triple_tap(self, touch, *args):
|
||||
"""Called by triple clicking on the widget."""
|
||||
"""Fired by triple clicking on the widget."""
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue