test-kivy-app/kivy_venv/lib/python3.11/site-packages/kivymd/uix/chip/chip.py
2024-09-15 20:57:02 +03:00

1256 lines
35 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Components/Chip
===============
.. seealso::
`Material Design 3 spec, Chips <https://m3.material.io/components/chips/overview>`_
.. rubric:: Chips can show multiple interactive elements together in the same
area, such as a list of selectable movie times, or a series of email
contacts. There are four types of chips: assist, filter, input, and
suggestion.
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/chips.png
:align: center
Usage
-----
.. code-block:: kv
MDChip:
MDChipLeadingAvatar: # MDChipLeadingIcon
MDChipText:
MDChipTrailingIcon:
Anatomy
=======
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/chip-anatomy.png
:align: center
Example
-------
.. tabs::
.. tab:: Declarative KV style
.. code-block:: python
from kivy.lang import Builder
from kivymd.app import MDApp
KV = '''
MDScreen:
MDChip:
pos_hint: {"center_x": .5, "center_y": .5}
MDChipText:
text: "MDChip"
'''
class Example(MDApp):
def build(self):
self.theme_cls.theme_style = "Dark"
return Builder.load_string(KV)
Example().run()
.. tab:: Declarative Python style
.. code-block:: python
from kivymd.app import MDApp
from kivymd.uix.chip import MDChip, MDChipText
from kivymd.uix.screen import MDScreen
class Example(MDApp):
def build(self):
self.theme_cls.theme_style = "Dark"
return (
MDScreen(
MDChip(
MDChipText(
text="MDChip"
),
pos_hint={"center_x": .5, "center_y": .5},
)
)
)
Example().run()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/chip.png
:align: center
The following types of chips are available:
-------------------------------------------
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/available-type-chips.png
:align: center
- Assist_
- Filter_
- Input_
- Suggestion_
.. Assist:
Assist
------
`Assist chips <https://m3.material.io/components/chips/guidelines#5dd1928c-1476-4029-bdc5-fde66fc0dcb1>`_
represent smart or automated actions that can span multiple apps, such as
opening a calendar event from the home screen. Assist chips function as
though the user asked an assistant to complete the action. They should appear
dynamically and contextually in a UI.
An alternative to assist chips are buttons, which should appear persistently
and consistently.
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/assist-chip.png
:align: center
Example of assist
-----------------
.. code-block:: python
from kivy.lang import Builder
from kivymd.app import MDApp
KV = '''
<CommonLabel@MDLabel>
adaptive_size: True
theme_text_color: "Custom"
text_color: "#e6e9df"
<CommonAssistChip@MDChip>
# Custom attribute.
text: ""
icon: ""
# Chip attribute.
type: "assist"
md_bg_color: "#2a3127"
line_color: "grey"
elevation: 1
shadow_softness: 2
MDChipLeadingIcon:
icon: root.icon
theme_text_color: "Custom"
text_color: "#68896c"
MDChipText:
text: root.text
theme_text_color: "Custom"
text_color: "#e6e9df"
MDScreen:
FitImage:
source: "bg.png"
MDBoxLayout:
orientation: "vertical"
adaptive_size: True
pos_hint: {"center_y": .6, "center_x": .5}
CommonLabel:
text: "in 10 mins"
bold: True
pos_hint: {"center_x": .5}
CommonLabel:
text: "Therapy with Thea"
font_style: "H3"
padding_y: "12dp"
CommonLabel:
text: "Video call"
font_style: "H5"
pos_hint: {"center_x": .5}
MDBoxLayout:
adaptive_size: True
pos_hint: {"center_x": .5}
spacing: "12dp"
padding: 0, "24dp", 0, 0
CommonAssistChip:
text: "Home office"
icon: "map-marker"
CommonAssistChip:
text: "Chat"
icon: "message"
MDWidget:
'''
class Example(MDApp):
def build(self):
self.theme_cls.primary_palette = "Teal"
self.theme_cls.theme_style = "Dark"
return Builder.load_string(KV)
Example().run()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/example-assist-chip.png
:align: center
.. Filter:
Filter
------
`Filter chips <https://m3.material.io/components/chips/guidelines#8d453d50-8d8e-43aa-9ae3-87ed134d2e64>`_
use tags or descriptive words to filter content. They can be a good alternative
to toggle buttons or checkboxes.
Tapping on a filter chip activates it and appends a leading checkmark icon to
the starting edge of the chip label.
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/filter-chip.png
:align: center
Example of filtering
--------------------
.. code-block:: python
from kivy.lang import Builder
from kivy.properties import StringProperty, ListProperty
from kivymd.app import MDApp
from kivymd.uix.chip import MDChip, MDChipText
from kivymd.uix.list import MDListItem
from kivymd.icon_definitions import md_icons
from kivymd.uix.screen import MDScreen
import asynckivy
Builder.load_string(
'''
<CustomOneLineIconListItem>
MDListItemLeadingIcon:
icon: root.icon
MDListItemHeadlineText:
text: root.text
<PreviewIconsScreen>
MDBoxLayout:
orientation: "vertical"
spacing: "14dp"
padding: "20dp"
MDTextField:
id: search_field
mode: "outlined"
on_text: root.set_list_md_icons(self.text, True)
MDTextFieldLeadingIcon:
icon: "magnify"
MDTextFieldHintText:
text: "Search icon"
MDBoxLayout:
id: chip_box
spacing: "12dp"
adaptive_height: True
RecycleView:
id: rv
viewclass: "CustomOneLineIconListItem"
key_size: "height"
RecycleBoxLayout:
padding: dp(10)
default_size: None, dp(48)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: "vertical"
'''
)
class CustomOneLineIconListItem(MDListItem):
icon = StringProperty()
text = StringProperty()
class PreviewIconsScreen(MDScreen):
filter = ListProperty() # list of tags for filtering icons
def set_filter_chips(self):
'''Asynchronously creates and adds chips to the container.'''
async def set_filter_chips():
for tag in ["Outline", "Off", "On"]:
await asynckivy.sleep(0)
chip = MDChip(
MDChipText(
text=tag,
),
type="filter",
md_bg_color="#303A29",
)
chip.bind(active=lambda x, y, z=tag: self.set_filter(y, z))
self.ids.chip_box.add_widget(chip)
asynckivy.start(set_filter_chips())
def set_filter(self, active: bool, tag: str) -> None:
'''Sets a list of tags for filtering icons.'''
if active:
self.filter.append(tag)
else:
self.filter.remove(tag)
def set_list_md_icons(self, text="", search=False) -> None:
'''Builds a list of icons.'''
def add_icon_item(name_icon):
self.ids.rv.data.append(
{
"icon": name_icon,
"text": name_icon,
}
)
self.ids.rv.data = []
for name_icon in md_icons.keys():
for tag in self.filter:
if tag.lower() in name_icon:
if search:
if text in name_icon:
add_icon_item(name_icon)
else:
add_icon_item(name_icon)
class Example(MDApp):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.screen = PreviewIconsScreen()
def build(self) -> PreviewIconsScreen:
self.theme_cls.theme_style = "Dark"
return self.screen
def on_start(self) -> None:
self.screen.set_list_md_icons()
self.screen.set_filter_chips()
Example().run()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/example-filtering-icons-chip.gif
:align: center
Tap a chip to select it. Multiple chips can be selected or unselected:
.. code-block:: python
from kivy.lang import Builder
from kivymd.app import MDApp
from kivymd.uix.chip import MDChip, MDChipText
from kivymd.uix.screen import MDScreen
import asynckivy
Builder.load_string(
'''
<ChipScreen>
MDBoxLayout:
orientation: "vertical"
spacing: "14dp"
padding: "20dp"
MDLabel:
adaptive_height: True
text: "Select Type"
MDStackLayout:
id: chip_box
spacing: "12dp"
adaptive_height: True
MDWidget:
MDButton:
pos: "20dp", "20dp"
on_release: root.unchecks_chips()
MDButtonText:
text: "Uncheck chips"
'''
)
class ChipScreen(MDScreen):
async def create_chips(self):
'''Asynchronously creates and adds chips to the container.'''
for tag in ["Extra Soft", "Soft", "Medium", "Hard"]:
await asynckivy.sleep(0)
self.ids.chip_box.add_widget(
MDChip(
MDChipText(
text=tag,
),
type="filter",
md_bg_color="#303A29",
active=True,
)
)
def unchecks_chips(self) -> None:
'''Removes marks from all chips.'''
for chip in self.ids.chip_box.children:
if chip.active:
chip.active = False
class Example(MDApp):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.screen = ChipScreen()
def build(self) -> ChipScreen:
self.theme_cls.theme_style = "Dark"
return self.screen
def on_start(self) -> None:
asynckivy.start(self.screen.create_chips())
Example().run()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/example-filtering-icons-chip-2.gif
:align: center
Alternatively, a single chip can be selected.
This offers an alternative to toggle buttons, radio buttons, or single select
menus:
.. code-block:: python
from kivy.lang import Builder
from kivymd.app import MDApp
from kivymd.uix.chip import MDChip, MDChipText
from kivymd.uix.screen import MDScreen
import asynckivy
Builder.load_string(
'''
<ChipScreen>
MDBoxLayout:
orientation: "vertical"
spacing: "14dp"
padding: "20dp"
MDLabel:
adaptive_height: True
text: "Select Type"
MDStackLayout:
id: chip_box
spacing: "12dp"
adaptive_height: True
MDWidget:
'''
)
class ChipScreen(MDScreen):
async def create_chips(self):
'''Asynchronously creates and adds chips to the container.'''
for tag in ["Extra Soft", "Soft", "Medium", "Hard"]:
await asynckivy.sleep(0)
chip = MDChip(
MDChipText(
text=tag,
),
type="filter",
md_bg_color="#303A29",
)
chip.bind(active=self.uncheck_chip)
self.ids.chip_box.add_widget(chip)
def uncheck_chip(self, current_chip: MDChip, active: bool) -> None:
'''Removes a mark from an already marked chip.'''
if active:
for chip in self.ids.chip_box.children:
if current_chip is not chip:
if chip.active:
chip.active = False
class Example(MDApp):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.screen = ChipScreen()
def build(self) -> ChipScreen:
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "LightGreen"
return self.screen
def on_start(self) -> None:
asynckivy.start(self.screen.create_chips())
Example().run()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/example-filtering-single-select.gif
:align: center
.. Input:
Input
-----
`Input chips <https://m3.material.io/components/chips/guidelines#4d2d5ef5-3fcd-46e9-99f2-067747b2393f>`_
represent discrete pieces of information entered by a user, such as Gmail
contacts or filter options within a search field.
They enable user input and verify that input by converting text into chips.
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/input-chip.png
:align: center
Example of input
----------------
.. code-block:: python
from kivy.lang import Builder
from kivymd.app import MDApp
KV = '''
MDScreen:
MDChip:
pos_hint: {"center_x": .5, "center_y": .5}
type: "input"
line_color: "grey"
_no_ripple_effect: True
MDChipLeadingAvatar:
source: "data/logo/kivy-icon-128.png"
MDChipText:
text: "MDChip"
MDChipTrailingIcon:
icon: "close"
'''
class Example(MDApp):
def build(self):
self.theme_cls.theme_style = "Dark"
return Builder.load_string(KV)
Example().run()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/example-input-chip.png
:align: center
.. Suggestion:
Suggestion
----------
`Suggestion chips <https://m3.material.io/components/chips/guidelines#36d7bb16-a9bf-4cf6-a73d-8e05510d66a7>`_
help narrow a users intent by presenting dynamically generated suggestions,
such as possible responses or search filters.
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/suggestion-chip.png
:align: center
Example of suggestion
---------------------
.. code-block::
from kivy.lang import Builder
from kivymd.app import MDApp
KV = '''
MDScreen:
MDChip:
pos_hint: {"center_x": .5, "center_y": .5}
type: "suggestion"
line_color: "grey"
MDChipText:
text: "MDChip"
'''
class Example(MDApp):
def build(self):
self.theme_cls.theme_style = "Dark"
return Builder.load_string(KV)
Example().run()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/example-suggestion.png
:align: center
API break
=========
1.2.0 version
-------------
.. code-block:: python
from kivy.lang import Builder
from kivymd.app import MDApp
KV = '''
MDScreen:
MDChip:
text: "Portland"
pos_hint: {"center_x": .5, "center_y": .5}
on_release: app.on_release_chip(self)
'''
class Test(MDApp):
def build(self):
return Builder.load_string(KV)
def on_release_chip(self, instance_check):
print(instance_check)
Test().run()
2.0.0 version
-------------
.. code-block:: python
from kivy.lang import Builder
from kivymd.app import MDApp
KV = '''
MDScreen:
MDChip:
pos_hint: {"center_x": .5, "center_y": .5}
line_color: "grey"
on_release: app.on_release_chip(self)
MDChipText:
text: "MDChip"
'''
class Example(MDApp):
def build(self):
return Builder.load_string(KV)
def on_release_chip(self, instance_check):
print(instance_check)
Example().run()
"""
from __future__ import annotations
__all__ = (
"MDChip",
"MDChipLeadingAvatar",
"MDChipLeadingIcon",
"MDChipTrailingIcon",
"MDChipText",
)
import os
from kivy import Logger
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,
OptionProperty,
VariableListProperty,
)
from kivy.uix.behaviors import ButtonBehavior
from kivymd import uix_path
from kivymd.material_resources import DEVICE_TYPE
from kivymd.uix.behaviors import (
CircularRippleBehavior,
CommonElevationBehavior,
RectangularRippleBehavior,
ScaleBehavior,
TouchBehavior,
)
from kivymd.uix.behaviors.state_layer_behavior import StateLayerBehavior
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.label import MDIcon, MDLabel
with open(
os.path.join(uix_path, "chip", "chip.kv"), encoding="utf-8"
) as kv_file:
Builder.load_string(kv_file.read())
class BaseChipIcon(
CircularRippleBehavior, ScaleBehavior, ButtonBehavior, MDIcon
):
icon_color = ColorProperty(None)
"""
Button icon color in (r, g, b, a) or string format.
:attr:`icon_color` is a :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
icon_color_disabled = ColorProperty(None)
"""
The icon color in (r, g, b, a) or string format of the chip when
the chip is disabled.
.. versionadded:: 2.0.0
:attr:`icon_color_disabled` is a :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
_type = OptionProperty(
"suggestion", options=["assist", "filter", "input", "suggestion"]
)
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.ripple_scale = 1.5
Clock.schedule_once(self.adjust_icon_size)
def adjust_icon_size(self, *args) -> None:
# If the user has not changed the icon size, then we set the standard
# icon size according to the standards of material design version 3.
if (
self.font_name == "Icons"
and self.theme_cls.font_styles["Icon"]["large"]["font-size"]
== self.font_size
):
self.font_size = (
"18sp"
if not self.source and not isinstance(self, MDChipLeadingAvatar)
else "24sp"
)
if self.source and isinstance(self, MDChipLeadingAvatar):
self.icon = self.source
self._size = [dp(28), dp(28)]
self.font_size = "28sp"
self.padding_x = "6dp"
self._no_ripple_effect = True
class LabelTextContainer(MDBoxLayout):
"""Implements a container for the chip label."""
class LeadingIconContainer(MDBoxLayout):
"""Implements a container for the leading icon."""
class TrailingIconContainer(MDBoxLayout):
"""Implements a container for the trailing icon."""
class MDChipLeadingAvatar(BaseChipIcon):
"""
Implements the leading avatar for the chip.
For more information, see in the
:class:`~kivymd.uix.behaviors.ripple_behavior.CircularRippleBehavior` and
:class:`~kivymd.uix.behaviors.scale_behavior.ScaleBehavior` and
:class:`~kivy.uix.behaviors.ButtonBehavior` and
:class:`~kivymd.uix.label.label.MDIcon`
classes documentation.
"""
class MDChipLeadingIcon(BaseChipIcon):
"""
Implements the leading icon for the chip.
For more information, see in the
:class:`~kivymd.uix.behaviors.ripple_behavior.CircularRippleBehavior` and
:class:`~kivymd.uix.behaviors.scale_behavior.ScaleBehavior` and
:class:`~kivy.uix.behaviors.ButtonBehavior` and
:class:`~kivymd.uix.label.label.MDIcon`
classes documentation.
"""
class MDChipTrailingIcon(BaseChipIcon):
"""
Implements the trailing icon for the chip.
For more information, see in the
:class:`~kivymd.uix.behaviors.ripple_behavior.CircularRippleBehavior` and
:class:`~kivymd.uix.behaviors.scale_behavior.ScaleBehavior` and
:class:`~kivy.uix.behaviors.ButtonBehavior` and
:class:`~kivymd.uix.label.label.MDIcon`
classes documentation.
"""
class MDChipText(MDLabel):
"""
Implements the label for the chip.
For more information, see in the
:class:`~kivymd.uix.label.label.MDLabel` classes documentation.
"""
text_color_disabled = ColorProperty(None)
"""
The text color in (r, g, b, a) or string format of the chip when
the chip is disabled.
.. versionadded:: 2.0.0
:attr:`text_color_disabled` is a :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
_type = OptionProperty(
"suggestion", options=["assist", "filter", "input", "suggestion"]
)
class MDChip(
MDBoxLayout,
RectangularRippleBehavior,
ButtonBehavior,
CommonElevationBehavior,
TouchBehavior,
StateLayerBehavior,
):
"""
Chip class.
For more information, see in the
:class:`~kivymd.uix.boxlayout.MDBoxLayout` and
:class:`~kivymd.uix.behaviors.ripple_behavior.RectangularRippleBehavior` and
:class:`~kivy.uix.behaviors.ButtonBehavior` and
:class:`~kivymd.uix.behaviors.elevation.CommonElevationBehavior` and
:class:`~kivymd.uix.behaviors.touch_behavior.TouchBehavior`
classes documentation.
"""
radius = VariableListProperty([dp(8)], length=4)
"""
Chip radius.
:attr:`radius` is an :class:`~kivy.properties.VariableListProperty`
and defaults to `[dp(8), dp(8), dp(8), dp(8)]`.
"""
type = OptionProperty(
"suggestion", options=["assist", "filter", "input", "suggestion"]
)
"""
Type of chip.
.. versionadded:: 2.0.0
Available options are: `'assist'`, `'filter'`, `'input'`, `'suggestion'`.
:attr:`type` is an :class:`~kivy.properties.OptionProperty`
and defaults to `'suggestion'`.
"""
active = BooleanProperty(False)
"""
Whether the check is marked or not.
.. versionadded:: 1.0.0
:attr:`active` is an :class:`~kivy.properties.BooleanProperty`
and defaults to `False`.
"""
selected_color = ColorProperty(None)
"""
The background color of the chip in the marked state in (r, g, b, a)
or string format.
.. versionadded:: 2.0.0
:attr:`selected_color` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
line_color_disabled = ColorProperty(None)
"""
The color of the outline in the disabled state
.. versionadded:: 2.0.0
:attr:`line_color_disabled` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
_line_color = ColorProperty(None)
_current_md_bg_color = ColorProperty(None)
# A flag that disallow ripple animation of the chip
# at the time of clicking the chip icons.
_allow_chip_ripple = BooleanProperty(True)
# The flag signals the end of the ripple animation.
_anim_complete = BooleanProperty(False)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def on_long_touch(self, *args) -> None:
"""Fired when the widget is pressed for a long time."""
if self.type == "filter":
self.active = not self.active
def on_line_color(self, instance, value) -> None:
"""Fired when the values of :attr:`line_color` change."""
if not self.disabled:
self._line_color = value
def on_type(self, instance, value: str) -> None:
"""Fired when the values of :attr:`type` change."""
def adjust_padding(*args):
"""
According to the type of chip, it sets the margins according
to the specification of the material design version 3.
"""
self.padding = {
"input": (
"12dp"
if not self.ids.leading_icon_container.children
else (
"5dp"
if not self.ids.leading_icon_container.children[
0
].source
else "16dp"
),
0,
"4dp",
0,
),
"assist": (
"16dp"
if not self.ids.leading_icon_container.children
else "8dp",
0,
"16dp"
if not self.ids.leading_icon_container.children
else "8dp",
0,
),
"suggestion": (
"16dp"
if not self.ids.leading_icon_container.children
else "8dp",
0,
"16dp",
0,
),
"filter": (
"16dp"
if not self.ids.leading_icon_container.children
else (
"8dp"
if not self.ids.leading_icon_container.children[
0
].source
else "4dp"
),
0,
"16dp"
if not self.ids.trailing_icon_container.children
else "8dp",
0,
),
}[value]
Clock.schedule_once(adjust_padding)
def on_active(self, instance_check, active_value: bool) -> None:
"""Called when the values of :attr:`active` change."""
if active_value:
self._current_md_bg_color = self.md_bg_color
Clock.schedule_once(self.complete_anim_ripple, 0.5)
def complete_anim_ripple(self, *args) -> None:
"""Called at the end of the ripple animation."""
if self.active:
if not self.ids.leading_icon_container.children:
if self.type == "filter":
self.add_marked_icon_to_chip()
self.set_chip_bg_color(
self.selected_color
if self.selected_color
else {
"filter": self.theme_cls.surfaceContainerLowColor,
"suggestion": self.theme_cls.surfaceContainerLowColor,
"input": self.theme_cls.surfaceContainerLowColor,
"assist": self.theme_cls.surfaceContainerLowColor,
}[self.type]
if self.theme_bg_color == "Primary"
else self.md_bg_color
)
else:
if (
self.ids.leading_icon_container.children
and self.ids.leading_icon_container.children[0].icon == "check"
):
if self.type == "filter":
self.remove_marked_icon_from_chip()
self.set_chip_bg_color(self._current_md_bg_color)
def remove_marked_icon_from_chip(self) -> None:
def remove_marked_icon_from_chip(*args):
self.ids.leading_icon_container.clear_widgets()
if self.ids.leading_icon_container.children:
anim = Animation(scale_value_x=0, scale_value_y=0, d=0.2)
anim.bind(on_complete=remove_marked_icon_from_chip)
anim.start(self.ids.leading_icon_container.children[0])
Animation(
padding=[dp(16), 0, dp(16), 0],
spacing=0,
d=0.2,
).start(self)
def add_marked_icon_to_chip(self) -> None:
"""Adds and animates a check icon to the chip."""
icon_check = MDChipLeadingIcon(
icon="check",
pos_hint={"center_y": 0.5},
font_size=dp(18),
scale_value_x=0,
scale_value_y=0,
)
icon_check.bind(
on_press=self._set_allow_chip_ripple,
on_release=self._set_allow_chip_ripple,
)
self.ids.leading_icon_container.add_widget(icon_check)
# Animating the scale of the icon.
Animation(scale_value_x=1, scale_value_y=1, d=0.2).start(icon_check)
# Animating the padding of the chip.
Animation(
padding=[dp(18), 0, 0, 0],
spacing=dp(18) if self.type == "filter" else 0,
d=0.2,
).start(self)
def set_chip_bg_color(self, color: list | str) -> None:
"""Animates the background color of the chip."""
if color:
Animation(md_bg_color=color, d=0.2).start(self)
self._anim_complete = not self._anim_complete
def on_press(self, *args) -> None:
"""Fired when the button is pressed."""
if self.active:
self.active = False
self._on_press(args)
def on_release(self, *args) -> None:
"""
Fired when the button is released
(i.e. the touch/click that pressed the button goes away).
"""
self._on_release(args)
def add_widget(self, widget, *args, **kwargs):
def set_type(*args):
widget._type = self.type
def add_icon_leading_trailing(container):
if len(container.children):
type_icon = (
"'leading'"
if isinstance(
widget, (MDChipLeadingIcon, MDChipLeadingAvatar)
)
else "'trailing'"
)
Logger.warning(
f"KivyMD: "
f"Do not use more than one {type_icon} icon. "
f"This is contrary to the material design rules "
f"of version 3"
)
return
if isinstance(widget, MDChipTrailingIcon) and self.type in [
"assist",
"suggestion",
]:
Logger.warning(
f"KivyMD: "
f"According to the material design standards of version "
f"3, do not use the trailing icon for an '{self.type}' "
f"type chip."
)
return
if (
isinstance(widget, MDChipTrailingIcon)
and self.type == "filter"
and DEVICE_TYPE == "mobile"
):
Logger.warning(
"KivyMD: "
"According to the material design standards of version 3, "
"only on desktop computers and tablets, filter chips can "
"contain a finishing icon for directly removing the chip "
"or opening the options menu."
)
return
if (
isinstance(widget, (MDChipLeadingIcon, MDChipLeadingAvatar))
and self.type == "filter"
):
Logger.warning(
"KivyMD: "
"According to the material design standards of version 3, "
"it is better not to use a leading icon for a 'filter' "
"type chip."
)
if (
isinstance(widget, MDChipLeadingAvatar)
and self.type == "suggestion"
):
Logger.warning(
"KivyMD: "
"According to the material design standards of version 3, "
"it is better not to use a leading avatar for a "
"'suggestion' type chip."
)
return
widget.bind(
on_press=self._set_allow_chip_ripple,
on_release=self._set_allow_chip_ripple,
)
widget.pos_hint = {"center_y": 0.5}
self.padding = ("8dp", 0, "8dp", 0)
self.spacing = (
"8dp"
if isinstance(
widget,
(
MDChipLeadingIcon,
MDChipLeadingAvatar,
MDChipTrailingIcon,
),
)
else 0
)
container.add_widget(widget)
if isinstance(widget, MDChipText):
Clock.schedule_once(set_type)
widget.adaptive_size = True
widget.pos_hint = {"center_y": 0.5}
if self.type == "suggestion":
self.padding = ("16dp", 0, "16dp", 0)
Clock.schedule_once(
lambda x: self.ids.label_container.add_widget(widget)
)
elif isinstance(widget, (MDChipLeadingIcon, MDChipLeadingAvatar)):
Clock.schedule_once(set_type)
Clock.schedule_once(
lambda x: add_icon_leading_trailing(
self.ids.leading_icon_container
)
)
elif isinstance(widget, MDChipTrailingIcon):
Clock.schedule_once(set_type)
Clock.schedule_once(
lambda x: add_icon_leading_trailing(
self.ids.trailing_icon_container
)
)
elif isinstance(
widget,
(LabelTextContainer, LeadingIconContainer, TrailingIconContainer),
):
if isinstance(
widget, (LeadingIconContainer, TrailingIconContainer)
):
Clock.schedule_once(set_type)
return super().add_widget(widget)
def _set_allow_chip_ripple(
self, instance: MDChipLeadingIcon | MDChipTrailingIcon
) -> None:
self._allow_chip_ripple = not self._allow_chip_ripple