Sideband/sbapp/kivymd/uix/chip/chip.py

582 lines
15 KiB
Python
Executable File

"""
Components/Chip
===============
.. seealso::
`Material Design spec, Chips <https://material.io/components/chips>`_
.. rubric:: Chips are compact elements that represent an input, attribute, or action.
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/chips.png
:align: center
Usage
-----
.. 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()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/ordinary-chip.png
:align: center
Use with right icon
-------------------
.. code-block:: kv
MDChip:
text: "Portland"
icon_right: "close-circle-outline"
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/chip-with-right-icon.png
:align: center
Use with left icon
------------------
.. code-block:: kv
MDChip:
text: "Portland"
icon_left: "map-marker"
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/chip-with-left-icon.png
:align: center
Use with custom left icon
-------------------------
.. code-block:: kv
MDChip:
text: "Portland"
icon_left: "avatar.png"
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/chip-with-custom-left-icon.png
:align: center
Use with left and right icon
----------------------------
.. code-block:: kv
MDChip:
text: "Portland"
icon_left: "avatar.png"
icon_right: "close-circle-outline"
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/chip-with-left-right-icon.png
:align: center
Use with outline
----------------
.. code-block:: kv
MDChip:
text: "Portland"
icon_left: "avatar.png"
icon_right: "close-circle-outline"
line_color: app.theme_cls.disabled_hint_text_color
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/chip-with-outline.png
:align: center
Use with custom color
---------------------
.. code-block:: kv
MDChip:
text: "Portland"
icon_left: "avatar.png"
icon_right: "close-circle-outline"
line_color: app.theme_cls.disabled_hint_text_color
md_bg_color: 1, 0, 0, .5
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/chip-with-custom-color.png
:align: center
Use with elevation
------------------
.. code-block:: kv
MDChip:
text: "Portland"
icon_left: "avatar.png"
icon_right: "close-circle-outline"
line_color: app.theme_cls.disabled_hint_text_color
md_bg_color: 1, 0, 0, .5
elevation: 4
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/chip-with-elevation.png
:align: center
Behavior
========
Long press on the chip, it will be marked.
When you click on the marked chip, the mark will be removed:
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/chip-activate.gif
:align: center
Examples
========
Multiple choose
---------------
Selecting a single choice chip automatically deselects all other chips in the set.
.. code-block:: python
from kivy.animation import Animation
from kivy.lang import Builder
from kivymd.uix.screen import MDScreen
from kivymd.uix.chip import MDChip
from kivymd.app import MDApp
KV = '''
<MyScreen>
MDBoxLayout:
orientation: "vertical"
adaptive_size: True
spacing: "12dp"
padding: "56dp"
pos_hint: {"center_x": .5, "center_y": .5}
MDLabel:
text: "Multiple choice"
bold: True
font_style: "H5"
adaptive_size: True
MDBoxLayout:
id: chip_box
adaptive_size: True
spacing: "8dp"
MyChip:
text: "Elevator"
on_press: if self.active: root.removes_marks_all_chips()
MyChip:
text: "Washer / Dryer"
on_press: if self.active: root.removes_marks_all_chips()
MyChip:
text: "Fireplace"
on_press: if self.active: root.removes_marks_all_chips()
ScreenManager:
MyScreen:
'''
class MyChip(MDChip):
icon_check_color = (0, 0, 0, 1)
text_color = (0, 0, 0, 0.5)
_no_ripple_effect = True
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.bind(active=self.set_chip_bg_color)
self.bind(active=self.set_chip_text_color)
def set_chip_bg_color(self, instance_chip, active_value: int):
'''
Will be called every time the chip is activated/deactivated.
Sets the background color of the chip.
'''
self.md_bg_color = (
(0, 0, 0, 0.4)
if active_value
else (
self.theme_cls.bg_darkest
if self.theme_cls.theme_style == "Light"
else (
self.theme_cls.bg_light
if not self.disabled
else self.theme_cls.disabled_hint_text_color
)
)
)
def set_chip_text_color(self, instance_chip, active_value: int):
Animation(
color=(0, 0, 0, 1) if active_value else (0, 0, 0, 0.5), d=0.2
).start(self.ids.label)
class MyScreen(MDScreen):
def removes_marks_all_chips(self):
for instance_chip in self.ids.chip_box.children:
if instance_chip.active:
instance_chip.active = False
class Test(MDApp):
def build(self):
return Builder.load_string(KV)
Test().run()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/chip-multiple-choose.gif
:align: center
Only choose
-----------
Only one chip will be selected.
.. code-block:: python
KV = '''
<MyScreen>
[...]
MDBoxLayout:
id: chip_box
adaptive_size: True
spacing: "8dp"
MyChip:
text: "Elevator"
on_active: if self.active: root.removes_marks_all_chips(self)
MyChip:
text: "Washer / Dryer"
on_active: if self.active: root.removes_marks_all_chips(self)
MyChip:
text: "Fireplace"
on_active: if self.active: root.removes_marks_all_chips(self)
[...]
'''
class MyScreen(MDScreen):
def removes_marks_all_chips(self, selected_instance_chip):
for instance_chip in self.ids.chip_box.children:
if instance_chip != selected_instance_chip:
instance_chip.active = False
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/chip-only-choose.gif
:align: center
"""
__all__ = ("MDChip",)
import os
from kivy.animation import Animation
from kivy.lang import Builder
from kivy.metrics import dp
from kivy.properties import BooleanProperty, ColorProperty, StringProperty
from kivy.uix.behaviors import ButtonBehavior
from kivymd import uix_path
from kivymd.theming import ThemableBehavior
from kivymd.uix.behaviors import (
CommonElevationBehavior,
RectangularRippleBehavior,
ScaleBehavior,
TouchBehavior,
)
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.label import MDIcon
with open(
os.path.join(uix_path, "chip", "chip.kv"), encoding="utf-8"
) as kv_file:
Builder.load_string(kv_file.read())
class MDChip(
MDBoxLayout,
ThemableBehavior,
RectangularRippleBehavior,
ButtonBehavior,
CommonElevationBehavior,
TouchBehavior,
):
text = StringProperty()
"""
Chip text.
:attr:`text` is an :class:`~kivy.properties.StringProperty`
and defaults to `''`.
"""
icon_left = StringProperty()
"""
Chip left icon.
.. versionadded:: 1.0.0
:attr:`icon_left` is an :class:`~kivy.properties.StringProperty`
and defaults to `''`.
"""
icon_right = StringProperty()
"""
Chip right icon.
.. versionadded:: 1.0.0
:attr:`icon_right` is an :class:`~kivy.properties.StringProperty`
and defaults to `''`.
"""
text_color = ColorProperty(None)
"""
Chip's text color in ``rgba`` format.
:attr:`text_color` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
icon_right_color = ColorProperty(None)
"""
Chip's right icon color in ``rgba`` format.
.. versionadded:: 1.0.0
:attr:`icon_right_color` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
icon_left_color = ColorProperty(None)
"""
Chip's left icon color in ``rgba`` format.
.. versionadded:: 1.0.0
:attr:`icon_left_color` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
icon_check_color = ColorProperty(None)
"""
Chip's check icon color in ``rgba`` format.
.. versionadded:: 1.0.0
:attr:`icon_check_color` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
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`.
"""
def __init__(self, **kwargs):
super().__init__(**kwargs)
def on_long_touch(self, *args) -> None:
if self.active:
return
self.active = True if not self.active else False
def on_active(self, instance_check, active_value: bool) -> None:
if active_value:
self.do_animation_check((0, 0, 0, 0.4), 1)
else:
self.do_animation_check((0, 0, 0, 0), 0)
def do_animation_check(self, md_bg_color: list, scale_value: int) -> None:
Animation(md_bg_color=md_bg_color, t="out_sine", d=0.1).start(
self.ids.icon_left_box
)
Animation(
scale_value_x=scale_value,
scale_value_y=scale_value,
scale_value_z=scale_value,
t="out_sine",
d=0.1,
).start(self.ids.check_icon)
if not self.icon_left:
if scale_value:
self.ids.check_icon.x = -dp(4)
Animation(size=(dp(24), dp(24)), t="out_sine", d=0.1).start(
self.ids.relative_box
)
else:
self.ids.check_icon.x = 0
Animation(size=(0, 0), t="out_sine", d=0.1).start(
self.ids.relative_box
)
def on_press(self, *args):
if self.active:
self.active = False
class MDScalableCheckIcon(MDIcon, ScaleBehavior):
pos_hint = {"center_y": 0.5}
if __name__ == "__main__":
from kivymd.app import MDApp
from kivymd.uix.screen import MDScreen
KV = """
<MyScreen>
MDBoxLayout:
orientation: "vertical"
adaptive_size: True
spacing: "12dp"
padding: "56dp"
pos_hint: {"center_x": .5, "center_y": .5}
MDLabel:
text: "Multiple choose"
bold: True
font_style: "H5"
adaptive_size: True
MDBoxLayout:
id: chip_box
adaptive_size: True
spacing: "8dp"
MyChip:
text: "Elevator"
on_press: if self.active: root.removes_marks_all_chips()
MyChip:
text: "Washer / Dryer"
on_press: if self.active: root.removes_marks_all_chips()
MyChip:
text: "Fireplace"
on_press: if self.active: root.removes_marks_all_chips()
MDSeparator:
MDLabel:
text: "Only choose"
bold: True
font_style: "H5"
adaptive_size: True
MDBoxLayout:
id: chip_only_box
adaptive_size: True
spacing: "8dp"
MyChip:
text: "Elevator"
on_active: if self.active: root.removes_marks_all_chips(self, False)
MyChip:
text: "Washer / Dryer"
on_active: if self.active: root.removes_marks_all_chips(self, False)
MyChip:
text: "Fireplace"
on_active: if self.active: root.removes_marks_all_chips(self, False)
ScreenManager:
MyScreen:
"""
class MyChip(MDChip):
icon_check_color = (0, 0, 0, 1)
text_color = (0, 0, 0, 0.5)
_no_ripple_effect = True
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.bind(active=self.set_chip_bg_color)
self.bind(active=self.set_chip_text_color)
def set_chip_bg_color(self, instance_chip, active_value: int):
"""
Will be called every time the chip is activated/deactivated.
Sets the background color of the chip.
"""
self.md_bg_color = (
(0, 0, 0, 0.4)
if active_value
else (
self.theme_cls.bg_darkest
if self.theme_cls.theme_style == "Light"
else (
self.theme_cls.bg_light
if not self.disabled
else self.theme_cls.disabled_hint_text_color
)
)
)
def set_chip_text_color(self, instance_chip, active_value: int):
Animation(
color=(0, 0, 0, 1) if active_value else (0, 0, 0, 0.5), d=0.2
).start(self.ids.label)
class MyScreen(MDScreen):
def removes_marks_all_chips(
self, selected_instance_chip=None, multiple=True
):
if multiple:
for instance_chip in self.ids.chip_box.children:
if instance_chip.active:
instance_chip.active = False
else:
for instance_chip in self.ids.chip_only_box.children:
if instance_chip != selected_instance_chip:
instance_chip.active = False
class Test(MDApp):
def build(self):
return Builder.load_string(KV)
Test().run()