"""
Components/Button
=================

.. seealso::

    `Material Design spec, Buttons <https://m3.material.io/components/all-buttons>`_

.. rubric:: Buttons allow users to take actions, and make choices,
    with a single tap. When choosing the right button for an action, consider
    the level of emphasis each button type provides.

KivyMD provides the following button classes for use:

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/buttons.png
    :align: center

1. Elevated button
2. Filled button
3. Filled tonal button
4. Outlined button
5. Text button
6. Icon button
7. Segmented button
8. Floating action button (FAB)
9. Extended FAB

Common buttons
==============

.. rubric:: Buttons help people take action, such as sending an email, sharing
    a document, or liking a comment.

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/common-buttons.png
    :align: center

1. Elevated button
2. Filled button
3. Filled tonal button
4. Outlined button
5. Text button

Elevated_
Filled_
Tonal_
Outlined_
Text_

.. Elevated:

Elevated
--------

.. tabs::

    .. tab:: Declarative KV style

        .. code-block:: python

            from kivy.lang import Builder

            from kivymd.app import MDApp

            KV = '''
            MDScreen:
                md_bg_color: app.theme_cls.surfaceColor

                MDButton:
                    style: "elevated"
                    pos_hint: {"center_x": .5, "center_y": .5}

                    MDButtonIcon:
                        icon: "plus"

                    MDButtonText:
                        text: "Elevated"
            '''


            class Example(MDApp):
                def build(self):
                    self.theme_cls.primary_palette = "Green"
                    return Builder.load_string(KV)


            Example().run()

    .. tab:: Declarative python style

        .. code-block:: python

            from kivymd.app import MDApp
            from kivymd.uix.button import MDButton, MDButtonIcon, MDButtonText
            from kivymd.uix.screen import MDScreen


            class Example(MDApp):
                def build(self):
                    self.theme_cls.primary_palette = "Green"
                    return (
                        MDScreen(
                            MDButton(
                                MDButtonIcon(
                                    icon="plus",
                                ),
                                MDButtonText(
                                    text="Elevated",
                                ),
                                style="elevated",
                                pos_hint={"center_x": 0.5, "center_y": 0.5},
                            ),
                            md_bg_color=self.theme_cls.surfaceColor,
                        )
                    )


            Example().run()

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/elevated-button.gif
    :align: center

Common buttons can contain an icon or be without an icon:

.. code-block:: kv

    MDButton:
        style: "elevated"
        text: "Elevated"

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/elevated-without-icon-button.png
    :align: center

.. Filled:

Filled
------

.. code-block:: kv

    MDButton:
        style: "filled"

        MDButtonText:
            text: "Filled"

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/filled-button.gif
    :align: center

.. Tonal:

Tonal
-----

.. code-block:: kv

    MDButton:
        style: "tonal"

        MDButtonText:
            text: "Tonal"

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/tonal-button.gif
    :align: center

.. Outlined:

Outlined
--------

.. code-block:: kv

    MDButton:
        style: "outlined"

        MDButtonText:
            text: "Outlined"

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/outlined-button.gif
    :align: center

.. Text:

Text
----

.. code-block:: kv

    MDButton:
        style: "text"

        MDButtonText:
            text: "Text"

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-button.gif
    :align: center

Customization of buttons
========================

Text positioning and button size
--------------------------------

.. code-block:: kv

    MDButton:
        style: "tonal"
        theme_width: "Custom"
        height: "56dp"
        size_hint_x: .5

        MDButtonIcon:
            x: text.x - (self.width + dp(10))
            icon: "plus"

        MDButtonText:
            id: text
            text: "Tonal"
            pos_hint: {"center_x": .5, "center_y": .5}

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/positioning-size-button.png
    :align: center

Font of the button text
-----------------------

.. code-block:: kv

    MDButton:
        style: "filled"

        MDButtonIcon:
            icon: "plus"

        MDButtonText:
            text: "Filled"
            font_style: "Title"

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/font-style-button-text.png
    :align: center

.. code-block:: kv

    MDButton:
        style: "elevated"

        MDButtonText:
            text: "Elevated"
            theme_font_name: "Custom"
            font_name: "path/to/font.ttf"

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/font-name-button-text.png
    :align: center

Custom button color
-------------------

.. code-block:: kv

    MDButton:
        style: "elevated"
        theme_shadow_color: "Custom"
        shadow_color: "red"

        MDButtonIcon:
            icon: "plus"
            theme_icon_color: "Custom"
            icon_color: "green"

        MDButtonText:
            text: "Elevated"
            theme_text_color: "Custom"
            text_color: "red"

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/custom-color-button.png
    :align: center

Icon buttons
============

.. rubric:: Use icon buttons when a compact button is required, such as in a
    toolbar or image list. There are two types of icon buttons: standard and
    contained.

.. seealso::

    `Material Design spec, Icon buttons <https://m3.material.io/components/icon-buttons/overview>`_

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/icon-buttons.png
    :align: center

1. Standard icon button
2. Contained icon button (including filled, filled tonal, and outlined styles)

StandardIcon_
FilledIcon_
TonalIcon_
OutlinedIcon_

.. StandardIcon:

StandardIcon
------------

.. code-block:: kv

    MDIconButton:
        icon: "heart-outline"
        style: "standard"

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/icon-button-standard.gif
    :align: center

.. FilledIcon:

FilledIcon
----------

.. code-block:: kv

    MDIconButton:
        icon: "heart-outline"
        style: "filled"

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/icon-button-filled.gif
    :align: center

.. TonalIcon:

TonalIcon
---------

.. code-block:: kv

    MDIconButton:
        icon: "heart-outline"
        style: "tonal"

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/icon-button-tonal.gif
    :align: center

.. OutlinedIcon:

OutlinedIcon
------------

.. code-block:: kv

    MDIconButton:
        icon: "heart-outline"
        style: "outlined"

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/icon-button-outlined.gif
    :align: center

Custom icon size
----------------

.. code-block:: kv

    MDIconButton:
        icon: "heart-outline"
        style: "tonal"
        theme_font_size: "Custom"
        font_size: "48sp"
        radius: [self.height / 2, ]
        size_hint: None, None
        size: "84dp", "84dp"

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/icon-button-size.png
    :align: center

Custom button color
-------------------

.. code-block:: kv

    MDIconButton:
        icon: "heart-outline"
        style: "tonal"
        theme_bg_color: "Custom"
        md_bg_color: "brown"
        theme_icon_color: "Custom"
        icon_color: "white"

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/icon-button-color.png
    :align: center

FAB buttons
===========

.. rubric:: The FAB represents the most important action on a screen.
    It puts key actions within reach.

.. seealso::

    `Material Design spec, FAB buttons <https://m3.material.io/components/floating-action-button/overview>`_

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/fab-buttons.png
    :align: center

1. Standard FAB
2. Small FAB
3. Large FAB

There are three sizes of floating action buttons: FAB, small FAB, and large FAB:

Standard_
Small_
Large_

.. Standard:

Standard
--------

.. code-block:: kv

    MDFabButton:
        icon: "pencil-outline"
        style: "standard"

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/fab-button-standard.gif
    :align: center

.. Small:

Small
-----

.. code-block:: kv

    MDFabButton:
        icon: "pencil-outline"
        style: "small"

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/fab-button-small.png
    :align: center

.. Large:

Large
-----

.. code-block:: kv

    MDFabButton:
        icon: "pencil-outline"
        style: "large"

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/fab-button-large.gif
    :align: center

Additional color mappings
-------------------------

FABs can use other combinations of container and icon colors. The color
mappings below provide the same legibility and functionality as the default,
so the color mapping you use depends on style alone.

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/fab-color-mapping.png
    :align: center

1. Surface
2. Secondary
3. Tertiary

.. code-block:: python

    from kivy.lang import Builder

    from kivymd.app import MDApp
    from kivymd.uix.button import MDFabButton

    KV = '''
    MDScreen:
        md_bg_color: app.theme_cls.surfaceColor

        MDBoxLayout:
            id: box
            adaptive_size: True
            spacing: "32dp"
            pos_hint: {"center_x": .5, "center_y": .5}
    '''


    class Example(MDApp):
        def build(self):
            self.theme_cls.primary_palette = "Green"
            return Builder.load_string(KV)

        def on_start(self):
            styles = {
                "standard": "surface",
                "small": "secondary",
                "large": "tertiary",
            }
            for style in styles.keys():
                self.root.ids.box.add_widget(
                    MDFabButton(
                        style=style, icon="pencil-outline", color_map=styles[style]
                    )
                )


    Example().run()

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/fab-button-color-mapping.png
    :align: center

Extended FAB
============

.. rubric::  Extended floating action buttons (extended FABs) help people take
    primary actions. They're wider than FABs to accommodate a text label and
    larger target area.

.. seealso::

    `Material Design spec, FAB extended buttons <https://m3.material.io/components/extended-fab/overview>`_

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/extended-fab-button.png
    :align: center

1. Extended FAB with both icon and label text
2. Extended FAB without icon

With icon
---------

.. code-block:: python

    from kivy.lang import Builder

    from kivymd.app import MDApp

    KV = '''
    MDScreen:
        md_bg_color: app.theme_cls.surfaceColor
        on_touch_down:
            if not btn.collide_point(*args[1].pos): \\
            btn.fab_state = "expand" \\
            if btn.fab_state == "collapse" else "collapse"

            MDExtendedFabButton:
                id: btn
                pos_hint: {"center_x": .5, "center_y": .5}

                MDExtendedFabButtonIcon:
                    icon: "pencil-outline"

                MDExtendedFabButtonText:
                    text: "Compose"
    '''


    class Example(MDApp):
        def build(self):
            self.theme_cls.primary_palette = "Green"
            return Builder.load_string(KV)


    Example().run()

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/extended-fab-button-icon.gif
    :align: center

Without icon
------------

.. code-block:: kv

    MDExtendedFabButton:
        fab_state: "expand"

        MDExtendedFabButtonText:
            text: "Compose"

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/extended-fab-button-without-icon.png
    :align: center

API break
=========

1.2.0 version
-------------

.. code-block:: kv

    MDFloatingActionButton:
        icon: "plus"

.. code-block:: kv

    MDRoundFlatButton:
        text: "Outlined"

.. code-block:: kv

    MDRoundFlatIconButton:
        text: "Outlined with icon"
        icon: "plus"

.. code-block:: kv

    MDFillRoundFlatButton
        text: "Filled"

.. code-block:: kv

    MDFillRoundFlatIconButton
        text: "Filled with icon"
        icon: "plus"

2.0.0 version
-------------

.. note:: `MDFloatingActionButtonSpeedDial` type buttons were removed
    in version `2.0.0`.

.. code-block:: kv

    MDFabButton:
        icon: "plus"

.. code-block:: kv

    MDButton:
        style: "outlined"

        MDButtonText:
            text: "Outlined"

.. code-block:: kv

    MDButton:
        style: "outlined"

        MDButtonIcon:
            icon: "plus"

        MDButtonText:
            text: "Outlined with icon"

.. code-block:: kv

    MDButton:
        style: "filled"

        MDButtonText:
            text: "Filled"

.. code-block:: kv

    MDButton:
        style: "filled"

        MDButtonIcon:
            icon: "plus"

        MDButtonText:
            text: "Filled"
"""

from __future__ import annotations

__all__ = (
    "MDIconButton",
    "MDButtonText",
    "MDButtonIcon",
    "MDFabButton",
    "MDExtendedFabButton",
    "MDExtendedFabButtonIcon",
    "MDExtendedFabButtonText",
    "MDButton",
    "BaseButton",
    "BaseFabButton",
)

import os

from kivy.clock import Clock
from kivy.lang import Builder
from kivy.metrics import dp
from kivy.properties import (
    ColorProperty,
    NumericProperty,
    OptionProperty,
    VariableListProperty,
    ObjectProperty, DictProperty,
)
from kivy.uix.behaviors import ButtonBehavior
from kivy.uix.relativelayout import RelativeLayout

from kivymd.uix.label import MDIcon, MDLabel
from kivymd import uix_path
from kivymd.theming import ThemableBehavior
from kivymd.uix.behaviors import (
    CommonElevationBehavior,
    DeclarativeBehavior,
    RectangularRippleBehavior,
    BackgroundColorBehavior,
)
from kivymd.uix.behaviors.motion_behavior import MotionExtendedFabButtonBehavior
from kivymd.uix.behaviors.state_layer_behavior import StateLayerBehavior

with open(
    os.path.join(uix_path, "button", "button.kv"), encoding="utf-8"
) as kv_file:
    Builder.load_string(kv_file.read())


class BaseFabButton:
    """
    Implements the basic properties for the
    :class:`~MDExtendedFabButton` and :class:`~MDFabButton` classes.

    .. versionadded:: 2.0.0
    """

    elevation_levels = DictProperty(
        {
            0: 0,
            1: dp(4),
            2: dp(8),
            3: dp(12),
            4: dp(16),
            5: dp(18),
        }
    )
    """
    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(4), 2: dp(8), 3: dp(12), 4: dp(16), 5: dp(18)}`.
    """

    color_map = OptionProperty(
        "surface", options=("surface", "secondary", "tertiary")
    )
    """
    Additional color mappings.

    Available options are: 'surface', 'secondary', 'tertiary'.

    :attr:`color_map` is an :class:`~kivy.properties.OptionProperty`
    and defaults to `'secondary'`.
    """

    icon_color_disabled = ColorProperty(None)
    """
    The icon color in (r, g, b, a) or string format of the list item when
    the widget item is disabled.

    :attr:`icon_color_disabled` is a :class:`~kivy.properties.ColorProperty`
    and defaults to `None`.
    """

    style = OptionProperty("standard", options=("standard", "small", "large"))
    """
    Button type.

    Available options are: 'standard', 'small', 'large'.

    :attr:`style` is an :class:`~kivy.properties.OptionProperty`
    and defaults to `'standard'`.
    """

    fab_state = OptionProperty("collapse", options=("collapse", "expand"))
    """
    The state of the button.

    Available options are: 'collapse' or 'expand'.

    :attr:`fab_state` is an :class:`~kivy.properties.OptionProperty`
    and defaults to "collapse".
    """

    md_bg_color_disabled = ColorProperty(None)
    """
    The background color in (r, g, b, a) or string format of the list item when
    the list button is disabled.

    :attr:`md_bg_color_disabled` is a :class:`~kivy.properties.ColorProperty`
    and defaults to `None`.
    """

    radius = VariableListProperty(
        [
            dp(16),
        ],
        length=4,
    )
    """
    Canvas radius.

    :attr:`radius` is an :class:`~kivy.properties.VariableListProperty`
    and defaults to `[dp(16), dp(16), dp(16), dp(16)]`.
    """


class BaseButton(
    DeclarativeBehavior,
    BackgroundColorBehavior,
    RectangularRippleBehavior,
    ButtonBehavior,
    ThemableBehavior,
    StateLayerBehavior,
):
    """
    Base button class.

    For more information, see in the
    :class:`~kivymd.uix.behaviors.declarative_behavior.DeclarativeBehavior` and
    :class:`~kivymd.uix.behaviors.backgroundcolor_behavior.BackgroundColorBehavior` and
    :class:`~kivymd.uix.behaviors.ripple_behavior.RectangularRippleBehavior` and
    :class:`~kivy.uix.behaviors.ButtonBehavior` and
    :class:`~kivymd.theming.ThemableBehavior` and
    :class:`~kivymd.uix.behaviors.state_layer_behavior.StateLayerBehavior`
    classes documentation.
    """

    elevation_levels = DictProperty(
        {
            0: 0,
            1: dp(4),
            2: dp(8),
            3: dp(12),
            4: dp(16),
            5: dp(18),
        }
    )
    """
    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(4), 2: dp(8), 3: dp(12), 4: dp(16), 5: dp(18)}`.
    """

    md_bg_color_disabled = ColorProperty(None)
    """
    The background color in (r, g, b, a) or string format of the button when
    the button is disabled.

    :attr:`md_bg_color_disabled` is a :class:`~kivy.properties.ColorProperty`
    and defaults to `None`.
    """

    shadow_radius = VariableListProperty([0, 0, 0, 0])
    """
    Button shadow radius.

    :attr:`shadow_radius` is an :class:`~kivy.properties.VariableListProperty`
    and defaults to `[0, 0, 0, 0]`.
    """

    md_bg_color = ColorProperty(None)
    """
    Button background color in (r, g, b, a) or string format.

    :attr:`md_bg_color` is a :class:`~kivy.properties.ColorProperty`
    and defaults to `None`.
    """

    line_color = ColorProperty(None)
    """
    Outlined color.

    :attr:`line_color` is a :class:`~kivy.properties.ColorProperty`
    and defaults to `None`.
    """

    line_width = NumericProperty(1)
    """
    Line width for button border.

    :attr:`line_width` is a :class:`~kivy.properties.NumericProperty`
    and defaults to `1`.
    """

    def on_press(self, *args) -> None:
        """Fired when the button is pressed."""

        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)


class MDButton(BaseButton, CommonElevationBehavior, RelativeLayout):
    """
    Base class for all buttons.

    .. versionadded:: 2.2.0

    For more information, see in the
    :class:`~kivymd.uix.behaviors.elevation.CommonElevationBehavior` and
    :class:`~BaseButton` and
    :class:`~kivy.uix.relativelayout.RelativeLayout`
    classes documentation.
    """

    style = OptionProperty(
        "elevated", options=("elevated", "filled", "tonal", "outlined", "text")
    )
    """
    Button type.

    Available options are: 'filled', 'elevated', 'outlined', 'tonal', 'text'.

    :attr:`style` is an :class:`~kivy.properties.OptionProperty`
    and defaults to `'elevated'`.
    """

    radius = VariableListProperty(
        [
            dp(20),
        ]
    )
    """
    Button radius.

    :attr:`radius` is an :class:`~kivy.properties.VariableListProperty`
    and defaults to `[dp(20), dp(20), dp(20), dp(20)]`.
    """

    # kivymd.uix.button.button.MDButtonIcon object.
    _button_icon = ObjectProperty()
    # kivymd.uix.button.button.MDButtonText object.
    _button_text = ObjectProperty()

    _icon_left_pad = dp(16)
    _spacing_between_icon_text = dp(10)
    _text_right_pad = dp(24)
    _text_left_pad = dp(24)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        Clock.schedule_once(self.adjust_width, 0.2)
        Clock.schedule_once(self.adjust_pos, 0.2)

    def adjust_pos(self, *args) -> None:
        """Adjusts the pos of the button according to the content."""

        if self._button_icon and self._button_text:
            self._button_text.x = (
                self._button_icon.x
                + self._spacing_between_icon_text
                + self._icon_left_pad
                + dp(2)
            )
        elif not self._button_icon and self._button_text:
            self._button_text.x = self._text_left_pad

    def adjust_width(self, *args) -> None:
        """Adjusts the width of the button according to the content."""

        if self._button_icon and self._button_text:
            if self.theme_width == "Primary":
                self.width = (
                    self._button_icon.texture_size[0]
                    + self._button_text.texture_size[0]
                    + self._icon_left_pad
                    + self._spacing_between_icon_text
                    + self._text_right_pad
                )
        elif not self._button_icon and self._button_text:
            if self.theme_width == "Primary":
                self.width = (
                    self._button_text.texture_size[0]
                    + self._text_left_pad
                    + self._text_right_pad
                )
        elif self._button_icon and not self._button_text:
            if self.theme_width == "Primary":
                self.width = (
                    dp(48)
                    + self._button_icon.texture_size[0]
                    - self._spacing_between_icon_text
                )

    def add_widget(self, widget, *args, **kwargs):
        if isinstance(widget, MDButtonText):
            self._button_text = widget
            widget.bind(
                text=lambda x, y: Clock.schedule_once(self.adjust_width, 0.2)
            )
            widget._button = self
        elif isinstance(widget, MDButtonIcon):
            self._button_icon = widget
            widget._button = self
        if isinstance(widget, (MDButtonIcon, MDButtonText)):
            return super().add_widget(widget)

    def set_properties_widget(self) -> None:
        """Fired `on_release/on_press/on_enter/on_leave` events."""

        super().set_properties_widget()

        if (
            self._state == self.state_hover
            and self.focus_behavior
            or self._state == self.state_press
        ):
            self._elevation_level = (
                1
                if self.theme_elevation_level == "Primary"
                else self.elevation_level
            )
            self._shadow_softness = (
                0
                if self.theme_shadow_softness == "Primary"
                else self.shadow_softness
            )

            if not self.disabled:
                if self._state == self.state_hover and self.focus_behavior:
                    if self.style == "elevated":
                        self.elevation_level = 2
                        self.shadow_softness = 2
                elif self._state == self.state_press:
                    if self.style == "elevated":
                        self.elevation_level = 2
                        self.shadow_softness = 2
                elif not self._state:
                    if self.style == "elevated":
                        self.elevation_level = 1
                        self.shadow_softness = 0


class MDButtonText(MDLabel):
    """
    The class implements the text for the :class:`~MDButton` class.

    For more information, see in the
    :class:`~kivymd.uix.label.label.MDLabel` class documentation.
    """

    # kivymd.uix.button.button.MDButton object.
    _button = ObjectProperty()


class MDButtonIcon(MDIcon):
    """
    The class implements an icon for the :class:`~MDButton` class.

    For more information, see in the
    :class:`~kivymd.uix.label.label.MDIcon` class documentation.
    """

    # kivymd.uix.button.button.MDButton object.
    _button = ObjectProperty()


class MDIconButton(RectangularRippleBehavior, ButtonBehavior, MDIcon):
    """
    Base class for icon buttons.

    For more information, see in the
    :class:`~kivymd.uix.behaviors.ripple_behavior.RectangularRippleBehavior` and
    :class:`~kivy.uix.behaviors.ButtonBehavior` and
    :class:`~kivy.uix.label.label.MDIcon`
    classes documentation.
    """

    style = OptionProperty(
        "standard", options=("standard", "filled", "tonal", "outlined")
    )
    """
    Button type.

    .. versionadded:: 2.0.0

    Available options are: 'standard', 'filled', 'tonal', 'outlined'.

    :attr:`style` is an :class:`~kivy.properties.OptionProperty`
    and defaults to `'standard'`.
    """

    md_bg_color_disabled = ColorProperty(None)
    """
    The background color in (r, g, b, a) or string format of the list item when
    the list button is disabled.

    :attr:`md_bg_color_disabled` is a :class:`~kivy.properties.ColorProperty`
    and defaults to `None`.
    """

    _line_color = ColorProperty(None)

    def on_line_color(self, instance, value) -> None:
        """Fired when the values of :attr:`line_color` change."""

        if not self.disabled and self.theme_line_color == "Custom":
            self._line_color = value


class MDFabButton(
    BaseFabButton,
    CommonElevationBehavior,
    RectangularRippleBehavior,
    ButtonBehavior,
    MDIcon,
):
    """
    Base class for FAB buttons.

    For more information, see in the
    :class:`~BaseFabButton` and
    :class:`~kivymd.uix.behaviors.elevation.CommonElevationBehavior` and
    :class:`~kivymd.uix.behaviors.ripple_behavior.RectangularRippleBehavior` and
    :class:`~kivy.uix.behaviors.ButtonBehavior` and
    :class:`~kivymd.uix.label.label.MDIcon`
    classes documentation.
    """

    def on_press(self, *args) -> None:
        """Fired when the button is pressed."""

        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 set_properties_widget(self) -> None:
        """Fired `on_release/on_press/on_enter/on_leave` events."""

        super().set_properties_widget()

        if (
            self._state == self.state_hover
            and self.focus_behavior
            or self._state == self.state_press
        ):
            self._elevation_level = (
                1
                if self.theme_elevation_level == "Primary"
                else self.elevation_level
            )
            self._shadow_softness = (
                0
                if self.theme_shadow_softness == "Primary"
                else self.shadow_softness
            )

        if not self.disabled:
            if (
                self._state == self.state_hover and self.focus_behavior
            ):
                self.elevation_level = 1
                self.shadow_softness = 0
            elif self._state == self.state_press:
                self.elevation_level = 2
                self.shadow_softness = 2
            elif not self._state:
                self.elevation_level = 1
                self.shadow_softness = 0


class MDExtendedFabButtonIcon(MDIcon):
    """
    Implements an icon for the :class:`~MDExtendedFabButton` class.

    .. versionadded:: 2.0.0
    """


class MDExtendedFabButtonText(MDLabel):
    """
    Implements the text for the class :class:`~MDExtendedFabButton` class.

    .. versionadded:: 2.0.0
    """


class MDExtendedFabButton(
    DeclarativeBehavior,
    ThemableBehavior,
    MotionExtendedFabButtonBehavior,
    CommonElevationBehavior,
    StateLayerBehavior,
    BaseFabButton,
    ButtonBehavior,
    RelativeLayout,
):
    """
    Base class for Extended FAB buttons.

    .. versionadded:: 2.0.0

    For more information, see in the
    :class:`~kivymd.uix.behaviors.declarative_behavior.DeclarativeBehavior` and
    :class:`~kivymd.theming.ThemableBehavior` and
    :class:`~kivymd.uix.behaviors.motion_behavior.MotionExtendedFabButtonBehavior` and
    :class:`~kivymd.uix.behaviors.elevation.CommonElevationBehavior` and
    :class:`~kivymd.uix.behaviors.state_layer_behavior.StateLayerBehavior` and
    :class:`~BaseFabButton` and
    :class:`~kivy.uix.behaviors.ButtonBehavior` and
    :class:`~kivy.uix.relativelayout.RelativeLayout`
    classes documentation.

    :Events:
        `on_collapse`
            Fired when the button is collapsed.
        `on_expand`
            Fired when the button is expanded.
    """

    elevation_levels = DictProperty(
        {
            0: 0,
            1: dp(4),
            2: dp(8),
            3: dp(12),
            4: dp(16),
            5: dp(18),
        }
    )
    """
    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(4), 2: dp(8), 3: dp(12), 4: dp(16), 5: dp(18)}`.
    """

    _icon = ObjectProperty()
    _label = ObjectProperty()

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.register_event_type("on_collapse")
        self.register_event_type("on_expand")
        Clock.schedule_once(self._set_text_pos, 0.5)

    def add_widget(self, widget, *args, **kwargs):
        if isinstance(widget, MDExtendedFabButtonIcon):
            self._icon = widget
        elif isinstance(widget, MDExtendedFabButtonText):
            self._label = widget
            widget.opacity = 0

        return super().add_widget(widget)

    def on_collapse(self, *args):
        """Fired when the button is collapsed."""

    def on_expand(self, *args):
        """Fired when the button is expanded."""

    def on_fab_state(self, instance, state: str) -> None:
        """Fired when the :attr:`fab_state` value changes."""

        if state == "expand":
            Clock.schedule_once(self.expand)
            Clock.schedule_once(lambda x: self.dispatch("on_expand"))
        elif state == "collapse":
            Clock.schedule_once(self.collapse)
            Clock.schedule_once(lambda x: self.dispatch("on_collapse"))

    def on__x(self, instance, value) -> None:
        self._label.x = (
            self._icon.x + self._icon.texture_size[0] + dp(24) - value
        )

    def _set_text_pos(self, *args):
        if self._icon and self._label:
            self._label.x = self._icon.x + self._icon.texture_size[0] + dp(24)
        elif not self._icon and self._label:
            self._label.opacity = 1
            self.width = self._label.texture_size[0] + dp(32)
            self._label.pos_hint = {"center_x": 0.5}
