"""
Components/NavigationRail
=========================

.. versionadded:: 1.0.0

.. seealso::

    `Material Design spec, Navigation rail <https://m3.material.io/components/navigation-rail/specs>`_

.. rubric:: Navigation rails provide access to primary destinations in apps
    when using tablet and desktop screens.

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

Usage
-----

.. tabs::

    .. tab:: Declarative KV style

        .. code-block:: python

            from kivy.lang import Builder

            from kivymd.app import MDApp

            KV = '''
            MDBoxLayout:

                MDNavigationRail:

                    MDNavigationRailItem:
                        text: "Python"
                        icon: "language-python"

                    MDNavigationRailItem:
                        text: "JavaScript"
                        icon: "language-javascript"

                    MDNavigationRailItem:
                        text: "CPP"
                        icon: "language-cpp"

                    MDNavigationRailItem:
                        text: "Git"
                        icon: "git"

                MDScreen:
            '''


            class Example(MDApp):
                def build(self):
                    return Builder.load_string(KV)


            Example().run()

    .. tab:: Declarative python style

        .. code-block:: python

            from kivymd.app import MDApp
            from kivymd.uix.boxlayout import MDBoxLayout
            from kivymd.uix.navigationrail import MDNavigationRail, MDNavigationRailItem


            class Example(MDApp):
                def build(self):
                    self.theme_cls.theme_style = "Dark"
                    self.theme_cls.primary_palette = "Orange"
                    return (
                        MDBoxLayout(
                            MDNavigationRail(
                                MDNavigationRailItem(
                                    text="Python",
                                    icon="language-python",
                                ),
                                MDNavigationRailItem(
                                    text="JavaScript",
                                    icon="language-javascript",
                                ),
                                MDNavigationRailItem(
                                    text="CPP",
                                    icon="language-cpp",
                                ),
                                MDNavigationRailItem(
                                    text="Git",
                                    icon="git",
                                ),
                            )
                        )
                    )


            Example().run()

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

Anatomy
-------

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

1. Container
2. Label text (optional)
3. Icon
4. Active indicator
5. Badge (optional)
6. Large badge (optional)
7. Large badge label (optional)
8. Menu icon (optional)

Example
=======

.. tabs::

    .. tab:: Declarative KV and imperative python styles

        .. code-block:: python

            from kivy.clock import Clock
            from kivy.lang import Builder

            from kivymd.app import MDApp
            from kivymd.uix.behaviors import CommonElevationBehavior
            from kivymd.uix.boxlayout import MDBoxLayout
            from kivymd.uix.button import MDFillRoundFlatIconButton
            from kivymd.uix.label import MDLabel
            from kivymd.uix.screen import MDScreen

            KV = '''
            #:import FadeTransition kivy.uix.screenmanager.FadeTransition


            <ExtendedButton>
                elevation: 1
                shadow_radius: 12
                -height: "56dp"


            <DrawerClickableItem@MDNavigationDrawerItem>
                focus_color: "#e7e4c0"
                unfocus_color: "#fffcf4"


            MDScreen:

                MDNavigationLayout:

                    ScreenManager:

                        MDScreen:

                            MDBoxLayout:
                                orientation: "vertical"

                                MDBoxLayout:
                                    adaptive_height: True
                                    md_bg_color: "#fffcf4"
                                    padding: "12dp"

                                    MDLabel:
                                        text: "12:00"
                                        adaptive_height: True
                                        pos_hint: {"center_y": .5}

                                MDBoxLayout:

                                    MDNavigationRail:
                                        id: navigation_rail
                                        md_bg_color: "#fffcf4"
                                        selected_color_background: "#e7e4c0"
                                        ripple_color_item: "#e7e4c0"
                                        on_item_release: app.switch_screen(*args)

                                        MDNavigationRailMenuButton:
                                            on_release: nav_drawer.set_state("open")

                                        MDNavigationRailFabButton:
                                            md_bg_color: "#b0f0d6"

                                        MDNavigationRailItem:
                                            text: "Python"
                                            icon: "language-python"

                                        MDNavigationRailItem:
                                            text: "JavaScript"
                                            icon: "language-javascript"

                                        MDNavigationRailItem:
                                            text: "CPP"
                                            icon: "language-cpp"

                                        MDNavigationRailItem:
                                            text: "Swift"
                                            icon: "language-swift"

                                    ScreenManager:
                                        id: screen_manager
                                        transition:
                                            FadeTransition(duration=.2, clearcolor=app.theme_cls.bg_dark)

                MDNavigationDrawer:
                    id: nav_drawer
                    radius: 0, 16, 16, 0
                    md_bg_color: "#fffcf4"
                    elevation: 2
                    width: "240dp"

                    MDNavigationDrawerMenu:

                        MDBoxLayout:
                            orientation: "vertical"
                            adaptive_height: True
                            spacing: "12dp"
                            padding: 0, 0, 0, "12dp"

                            MDIconButton:
                                icon: "menu"

                            MDBoxLayout:
                                adaptive_height: True
                                padding: "12dp", 0, 0, 0

                                ExtendedButton:
                                    text: "Compose"
                                    icon: "pencil"

                        DrawerClickableItem:
                            text: "Python"
                            icon: "language-python"

                        DrawerClickableItem:
                            text: "JavaScript"
                            icon: "language-javascript"

                        DrawerClickableItem:
                            text: "CPP"
                            icon: "language-cpp"

                        DrawerClickableItem:
                            text: "Swift"
                            icon: "language-swift"
            '''


            class ExtendedButton(MDFillRoundFlatIconButton, CommonElevationBehavior):
                '''
                Implements a button of type
                `Extended FAB <https://m3.material.io/components/extended-fab/overview>`_.

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

                This type of buttons is not yet implemented in the standard widget set
                of the KivyMD library, so we will implement it ourselves in this class.
                '''

                def __init__(self, *args, **kwargs):
                    super().__init__(*args, **kwargs)
                    self.padding = "16dp"
                    Clock.schedule_once(self.set_spacing)

                def set_spacing(self, interval):
                    self.ids.box.spacing = "12dp"

                def set_radius(self, *args):
                    if self.rounded_button:
                        value = self.height / 4
                        self.radius = [value, value, value, value]
                        self._radius = value


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

                def switch_screen(
                    self, instance_navigation_rail, instance_navigation_rail_item
                ):
                    '''
                    Called when tapping on rail menu items. Switches application screens.
                    '''

                    self.root.ids.screen_manager.current = (
                        instance_navigation_rail_item.icon.split("-")[1].lower()
                    )

                def on_start(self):
                    '''Creates application screens.'''

                    navigation_rail_items = self.root.ids.navigation_rail.get_items()[:]
                    navigation_rail_items.reverse()

                    for widget in navigation_rail_items:
                        name_screen = widget.icon.split("-")[1].lower()
                        screen = MDScreen(
                            name=name_screen,
                            md_bg_color="#edd769",
                            radius=[18, 0, 0, 0],
                        )
                        box = MDBoxLayout(padding="12dp")
                        label = MDLabel(
                            text=name_screen.capitalize(),
                            font_style="H1",
                            halign="right",
                            adaptive_height=True,
                            shorten=True,
                        )
                        box.add_widget(label)
                        screen.add_widget(box)
                        self.root.ids.screen_manager.add_widget(screen)


            Example().run()

    .. tab:: Declarative python style

        .. code-block:: python

            from kivy.clock import Clock
            from kivy.metrics import dp

            from kivymd.app import MDApp
            from kivymd.uix.behaviors import CommonElevationBehavior
            from kivymd.uix.boxlayout import MDBoxLayout
            from kivymd.uix.button import MDFillRoundFlatIconButton, MDIconButton
            from kivymd.uix.label import MDLabel
            from kivymd.uix.navigationdrawer import (
                MDNavigationDrawerItem,
                MDNavigationLayout,
                MDNavigationDrawer,
                MDNavigationDrawerMenu,
            )
            from kivymd.uix.navigationrail import (
                MDNavigationRail,
                MDNavigationRailMenuButton,
                MDNavigationRailFabButton,
                MDNavigationRailItem,
            )
            from kivymd.uix.screen import MDScreen
            from kivymd.uix.screenmanager import MDScreenManager


            class DrawerClickableItem(MDNavigationDrawerItem):
                def __init__(self, *args, **kwargs):
                    super().__init__(*args, **kwargs)
                    self.focus_color = "#e7e4c0"
                    self.unfocus_color = self.theme_cls.bg_light
                    self.radius = 24


            class ExtendedButton(MDFillRoundFlatIconButton, CommonElevationBehavior):
                def __init__(self, *args, **kwargs):
                    super().__init__(*args, **kwargs)
                    self.padding = "16dp"
                    self.elevation = 1
                    self.shadow_radius = 12
                    self.height = dp(56)
                    Clock.schedule_once(self.set_spacing)

                def set_spacing(self, interval):
                    self.ids.box.spacing = "12dp"

                def set_radius(self, *args):
                    if self.rounded_button:
                        self._radius = self.radius = self.height / 4


            class Example(MDApp):
                def build(self):
                    self.theme_cls.material_style = "M3"
                    self.theme_cls.primary_palette = "Orange"
                    return MDScreen(
                        MDNavigationLayout(
                            MDScreenManager(
                                MDScreen(
                                    MDBoxLayout(
                                        MDBoxLayout(
                                            MDLabel(
                                                text="12:00",
                                                adaptive_height=True,
                                                pos_hint={"center_y": 0.5},
                                            ),
                                            adaptive_height=True,
                                            md_bg_color="#fffcf4",
                                            padding="12dp",
                                        ),
                                        MDBoxLayout(
                                            MDNavigationRail(
                                                MDNavigationRailMenuButton(
                                                    on_release=self.open_nav_drawer,
                                                ),
                                                MDNavigationRailFabButton(
                                                    md_bg_color="#b0f0d6",
                                                ),
                                                MDNavigationRailItem(
                                                    text="Python",
                                                    icon="language-python",
                                                ),
                                                MDNavigationRailItem(
                                                    text="JavaScript",
                                                    icon="language-javascript",
                                                ),
                                                MDNavigationRailItem(
                                                    text="CPP",
                                                    icon="language-cpp",
                                                ),
                                                MDNavigationRailItem(
                                                    text="Swift",
                                                    icon="language-swift",
                                                ),
                                                id="navigation_rail",
                                                md_bg_color="#fffcf4",
                                                selected_color_background="#e7e4c0",
                                                ripple_color_item="#e7e4c0",
                                            ),
                                            MDScreenManager(
                                                id="screen_manager_content",
                                            ),
                                            id="root_box",
                                        ),
                                        id="box_rail",
                                        orientation="vertical",
                                    ),
                                    id="box",
                                ),
                                id="screen",
                            ),
                            id="screen_manager",
                        ),
                        MDNavigationDrawer(
                            MDNavigationDrawerMenu(
                                MDBoxLayout(
                                    MDIconButton(
                                        icon="menu",
                                    ),
                                    MDBoxLayout(
                                        ExtendedButton(
                                            text="Compose",
                                            icon="pencil",
                                        ),
                                        adaptive_height=True,
                                        padding=["12dp", 0, 0, 0],
                                    ),
                                    orientation="vertical",
                                    adaptive_height=True,
                                    spacing="12dp",
                                    padding=("3dp", 0, 0, "12dp"),
                                ),
                                DrawerClickableItem(
                                    text="Python",
                                    icon="language-python",
                                ),
                                DrawerClickableItem(
                                    text="JavaScript",
                                    icon="language-javascript",
                                ),
                                DrawerClickableItem(
                                    text="CPP",
                                    icon="language-cpp",
                                ),
                                DrawerClickableItem(
                                    text="Swift",
                                    icon="language-swift",
                                ),
                            ),
                            id="nav_drawer",
                            radius=(0, 16, 16, 0),
                            elevation=4,
                            width="240dp",
                        ),
                    )

                def switch_screen(self, *args, screen_manager_content=None):
                    '''
                    Called when tapping on rail menu items. Switches application screens.
                    '''

                    instance_navigation_rail, instance_navigation_rail_item = args
                    screen_manager_content.current = (
                        instance_navigation_rail_item.icon.split("-")[1].lower()
                    )

                def open_nav_drawer(self, *args):
                    self.root.ids.nav_drawer.set_state("open")

                def on_start(self):
                    '''Creates application screens.'''

                    screen_manager = self.root.ids.screen_manager
                    root_box = screen_manager.ids.screen.ids.box.ids.box_rail.ids.root_box
                    navigation_rail = root_box.ids.navigation_rail
                    screen_manager_content = root_box.ids.screen_manager_content
                    navigation_rail_items = navigation_rail.get_items()[:]
                    navigation_rail_items.reverse()
                    navigation_rail.bind(
                        on_item_release=lambda *args: self.switch_screen(
                            *args, screen_manager_content=screen_manager_content
                        )
                    )

                    for widget in navigation_rail_items:
                        name_screen = widget.icon.split("-")[1].lower()
                        screen_manager_content.add_widget(
                            MDScreen(
                                MDBoxLayout(
                                    MDLabel(
                                        text=name_screen.capitalize(),
                                        font_style="H1",
                                        halign="right",
                                        adaptive_height=True,
                                        shorten=True,
                                    ),
                                    padding="12dp",
                                ),
                                name=name_screen,
                                md_bg_color="#edd769",
                                radius=[18, 0, 0, 0],
                            ),
                        )


            Example().run()

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-rail-example.gif
    :align: center

"""

__all__ = (
    "MDNavigationRail",
    "MDNavigationRailItem",
    "MDNavigationRailFabButton",
    "MDNavigationRailMenuButton",
)

import os
from typing import Union

from kivy.animation import Animation
from kivy.clock import Clock
from kivy.core.window import Window
from kivy.lang import Builder
from kivy.logger import Logger
from kivy.metrics import dp
from kivy.properties import (
    BooleanProperty,
    ColorProperty,
    ListProperty,
    NumericProperty,
    ObjectProperty,
    OptionProperty,
    StringProperty,
    VariableListProperty,
)
from kivy.uix.behaviors import ButtonBehavior

from kivymd import uix_path
from kivymd.uix.behaviors import ScaleBehavior
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.button import MDFloatingActionButton, MDIconButton
from kivymd.uix.card import MDCard
from kivymd.uix.floatlayout import MDFloatLayout
from kivymd.uix.widget import MDWidget

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


class PanelRoot(MDFloatLayout):
    """
    Contains
    :class:`~MDNavigationRailFabButton`, :class:`~MDNavigationRailMenuButton`
    buttons and a :class:`~Paneltems` container with menu items.
    """


class PanelItems(MDBoxLayout):
    """Box for menu items."""


class RippleWidget(MDWidget, ScaleBehavior):
    """
    Implements a background color for a menu item -
    (:class:`~MDNavigationRailItem`).
    """


class MDNavigationRailFabButton(MDFloatingActionButton):
    """
    Implements an optional floating action button (FAB).

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

    icon = StringProperty("pencil")
    """
    Button icon name.

    .. code-block:: kv

        MDNavigationRail:

            MDNavigationRailFabButton:
                icon: "home"

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

    :attr:`icon` is an :class:`~kivy.properties.StringProperty`
    and defaults to `'pencil'`.
    """


class MDNavigationRailMenuButton(MDIconButton):
    """
    Implements a menu button.

    For more information, see in the
    :class:`~kivymd.uix.button.MDIconButton` classes documentation.
    """

    icon = StringProperty("menu")
    """
    Button icon name.

    .. code-block:: kv

        MDNavigationRail:

            MDNavigationRailMenuButton:
                icon: "home"

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

    :attr:`icon` is an :class:`~kivy.properties.StringProperty`
    and defaults to `'menu'`.
    """


class MDNavigationRailItem(ButtonBehavior, MDBoxLayout):
    """
    Implements a menu item with an icon and text.

    For more information, see in the
    :class:`~kivy.uix.behaviors.ButtonBehavior` and
    :class:`~kivymd.uix.boxlayout.MDBoxLayout`
    classes documentation.
    """

    navigation_rail = ObjectProperty()
    """
    :class:`~MDNavigationRail` object.

    :attr:`navigation_rail` is an :class:`~kivy.properties.ObjectProperty`
    and defaults to `None`.
    """

    icon = StringProperty("checkbox-blank-circle")
    """
    Icon item.

    .. code-block:: kv

        MDNavigationRail:

            MDNavigationRailItem:
                icon: "language-python"

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

    :attr:`icon` is an :class:`~kivy.properties.StringProperty`
    and defaults to `'checkbox-blank'`.
    """

    text = StringProperty()
    """
    Text item.

    .. code-block:: kv

        MDNavigationRail:

            MDNavigationRailItem:
                text: "Python"
                icon: "language-python"

    .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-rail-item-text.png
        :align: center

    :attr:`text` is an :class:`~kivy.properties.StringProperty`
    and defaults to `''`.
    """

    badge_icon = StringProperty()
    """
    Badge icon name.

    .. code-block:: kv

        MDNavigationRail:

            MDNavigationRailItem:
                text: "Python"
                icon: "language-python"
                badge_icon: "plus"

    .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-rail-item-badge-icon.png
        :align: center

    :attr:`badge_icon` is an :class:`~kivy.properties.StringProperty`
    and defaults to `''`.
    """

    badge_icon_color = ColorProperty(None)
    """
    Badge icon color in (r, g, b, a) format.

    .. code-block:: kv

        MDNavigationRail:

            MDNavigationRailItem:
                text: "Python"
                icon: "language-python"
                badge_icon: "plus"
                badge_icon_color: 0, 0, 1, 1

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

    :attr:`badge_icon_color` is an :class:`~kivy.properties.StringProperty`
    and defaults to `None`.
    """

    badge_bg_color = ColorProperty(None)
    """
    Badge icon background color in (r, g, b, a) format.

    .. code-block:: kv

        MDNavigationRail:

            MDNavigationRailItem:
                text: "Python"
                icon: "language-python"
                badge_icon: "plus"
                badge_bg_color: "#b0f0d6"

    .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-rail-item-badge-bg-color.png
        :align: center

    :attr:`badge_bg_color` is an :class:`~kivy.properties.ColorProperty`
    and defaults to `None`.
    """

    badge_font_size = NumericProperty(0)
    """
    Badge icon font size.

    .. code-block:: kv

        MDNavigationRail:

            MDNavigationRailItem:
                text: "Python"
                icon: "language-python"
                badge_icon: "plus"
                badge_font_size: "24sp"

    .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-rail-item-badge-font-size.png
        :align: center

    :attr:`badge_font_size` is an :class:`~kivy.properties.NumericProperty`
    and defaults to `0`.
    """

    active = BooleanProperty(False)
    """
    Is the element active.

    :attr:`active` is an :class:`~kivy.properties.BooleanProperty`
    and defaults to `False`.
    """

    _selected_region_width = NumericProperty("56dp")
    _ripple_size = ListProperty([0, 0])
    _release = BooleanProperty(False)

    def on_active(
        self, instance_navigation_rail_item, value_active: bool
    ) -> None:
        """Called when the value of `active` changes."""

        self.animation_size_ripple_area(1 if value_active else 0)

    def animation_size_ripple_area(self, value: int) -> None:
        """Animates the size/fade of the ripple area."""

        Animation(
            scale_value_x=value,
            scale_value_y=value,
            scale_value_z=value,
            opacity=value,
            d=0.25,
            t=self.navigation_rail.ripple_transition,
        ).start(self.ids.ripple_widget)

    def on_press(self) -> None:
        """Called when pressed on a panel element."""

        self._release = False
        self.active = True
        self.navigation_rail.deselect_item(self)
        self.navigation_rail.dispatch("on_item_press", self)

    def on_release(self) -> None:
        """Called when released on a panel element."""

        self._release = True
        self.animation_size_ripple_area(0)
        self.navigation_rail.dispatch("on_item_release", self)


class MDNavigationRail(MDCard):
    """
    Navigation rail class.

    For more information, see in the
    :class:`~kivymd.uix.card.MDCard` class documentation.

    :Events:
        :attr:`on_item_press`
            Called on the `on_press` event of menu item -
            :class:`~MDNavigationRailItem`.

        :attr:`on_item_release`
            Called on the `on_release` event of menu item -
            :class:`~MDNavigationRailItem`.
    """

    radius = VariableListProperty(0, length=4)
    """
    Rail radius.

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

    padding = VariableListProperty([0, "36dp", 0, "36dp"], length=4)
    """
    Padding between layout box and children:
    [padding_left, padding_top, padding_right, padding_bottom].

    :attr:`padding` is a :class:`~kivy.properties.VariableListProperty`
    and defaults to `[0, '36dp', 0, '36dp']`.
    """

    anchor = OptionProperty("top", options=["top", "bottom", "center"])
    """
    The position of the panel with menu items.
    Available options are: `'top'`, `'bottom'`, `'center'`.

    .. rubric:: Top

    .. code-block:: kv

        MDNavigationRail:
            anchor: "top"

            MDNavigationRailItem:
                ...

    .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-rail-anchor-top.png
        :align: center

    .. rubric:: Center

    .. code-block:: kv

        MDNavigationRail:
            anchor: "center"

            MDNavigationRailItem:
                ...

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

    .. rubric:: Bottom

    .. code-block:: kv

        MDNavigationRail:
            anchor: "bottom"

            MDNavigationRailItem:
                ...

    .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-rail-type-bottom.png
        :align: center

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

    type = OptionProperty(
        "labeled", options=["labeled", "selected", "unselected"]
    )
    """
    Type of switching menu items.
    Available options are: `'labeled'`, `'selected'`, `'unselected'`.

    .. rubric:: Labeled

    .. code-block:: kv

        MDNavigationRail:
            type: "labeled"

            MDNavigationRailItem:
                ...

    .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-rail-type-labeled.png
        :align: center

    .. rubric:: Selected

    .. code-block:: kv

        MDNavigationRail:
            type: "selected"

            MDNavigationRailItem:
                ...

    .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-rail-type-selected.gif
        :align: center

    .. rubric:: Unselected

    .. code-block:: kv

        MDNavigationRail:
            type: "unselected"

            MDNavigationRailItem:
                ...

    .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-rail-type-unselected.gif
        :align: center

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

    text_color_item_normal = ColorProperty(None)
    """
    The text color in (r, g, b, a) or string format of the normal menu item
    (:class:`~MDNavigationRailItem`).

    .. code-block:: kv

        MDNavigationRail:
            text_color_item_normal: app.theme_cls.primary_color

            MDNavigationRailItem:
                ...

    .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-rail-text-color-item-normal.png
        :align: center

    :attr:`text_color_item_normal` is an :class:`~kivy.properties.ColorProperty`
    and defaults to `None`.
    """

    text_color_item_active = ColorProperty(None)
    """
    The text color in (r, g, b, a) or string format of the active menu item
    (:class:`~MDNavigationRailItem`).

    .. code-block:: kv

        MDNavigationRail:
            text_color_item_active: app.theme_cls.primary_color

            MDNavigationRailItem:
                ...

    .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-rail-text-color-item-active.png
        :align: center

    :attr:`text_color_item_active` is an :class:`~kivy.properties.ColorProperty`
    and defaults to `None`.
    """

    icon_color_item_normal = ColorProperty(None)
    """
    The icon color in (r, g, b, a) or string format of the normal menu item
    (:class:`~MDNavigationRailItem`).

    .. code-block:: kv

        MDNavigationRail:
            icon_color_item_normal: app.theme_cls.primary_color

            MDNavigationRailItem:
                ...

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

    :attr:`icon_color_item_normal` is an :class:`~kivy.properties.ColorProperty`
    and defaults to `None`.
    """

    icon_color_item_active = ColorProperty(None)
    """
    The icon color in (r, g, b, a) or string format of the active menu item
    (:class:`~MDNavigationRailItem`).

    .. code-block:: kv

        MDNavigationRail:
            icon_color_item_active: app.theme_cls.primary_color

            MDNavigationRailItem:
                ...

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

    :attr:`icon_color_item_active` is an :class:`~kivy.properties.ColorProperty`
    and defaults to `None`.
    """

    selected_color_background = ColorProperty(None)
    """
    Background color which will highlight the icon of the active menu item -
    :class:`~MDNavigationRailItem` - in (r, g, b, a) format.

    .. code-block:: kv

        MDNavigationRail:
            selected_color_background: "#e7e4c0"

            MDNavigationRailItem:
                ...

    .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-rail-selected-color-background.png
        :align: center

    :attr:`selected_color_background` is an :class:`~kivy.properties.ColorProperty`
    and defaults to `None`.
    """

    ripple_color_item = ColorProperty(None)
    """
    Ripple effect color of menu items (:class:`~MDNavigationRailItem`)
    in (r, g, b, a) format.

    .. code-block:: kv

        MDNavigationRail:
            ripple_color_item: "#e7e4c0"

            MDNavigationRailItem:
                ...

    .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-rail-ripple-color-item.png
        :align: center

    :attr:`ripple_color_item` is an :class:`~kivy.properties.ColorProperty`
    and defaults to `None`.
    """

    ripple_transition = StringProperty("out_cubic")
    """
    Type of animation of the ripple effect when a menu item is selected.

    :attr:`ripple_transition` is a :class:`~kivy.properties.StringProperty`
    and defaults to `'ripple_transition'`.
    """

    current_selected_item = NumericProperty(0)
    """
    Index of the menu list item (:class:`~MDNavigationRailItem`) that will be
    active by default

    .. code-block:: kv

        MDNavigationRail:
            current_selected_item: 1

            MDNavigationRailItem:
                ...

    .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-rail-current-selected-item.png
        :align: center

    :attr:`current_selected_item` is a :class:`~kivy.properties.NumericProperty`
    and defaults to `0`.
    """

    font_name = StringProperty("Roboto")
    """
    Font path for menu item (:class:`~MDNavigationRailItem`) text.

    .. code-block:: kv

        MDNavigationRail:

            MDNavigationRailItem:
                text: "Python"
                icon: "language-python"
                font_name: "nasalization-rg.ttf"

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

    :attr:`font_name` is an :class:`~kivy.properties.StringProperty`
    and defaults to `'Roboto'`.
    """

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        Clock.schedule_once(self.set_pos_menu_fab_buttons)
        Clock.schedule_once(self.set_current_selected_item)
        self.register_event_type("on_item_press")
        self.register_event_type("on_item_release")

    def on_size(self, *args):
        Clock.schedule_once(self.set_pos_menu_fab_buttons)

    def on_item_press(self, *args) -> None:
        """
        Called on the `on_press` event of menu item -
        :class:`~MDNavigationRailItem`.
        """

    def on_item_release(self, *args) -> None:
        """
        Called on the `on_release` event of menu item -
        :class:`~MDNavigationRailItem`.
        """

    def deselect_item(
        self, selected_navigation_rail_item: MDNavigationRailItem
    ) -> None:
        """
        Sets the `active` value to `False` for all menu items
        (:class:`~MDNavigationRailItem`) except the selected item.
        Called when a menu item is touched.
        """

        for navigation_rail_item in self.ids.box_items.children:
            if selected_navigation_rail_item is not navigation_rail_item:
                navigation_rail_item.active = False

    def get_items(self) -> list:
        """Returns a list of :class:`~MDNavigationRailItem` objects"""

        return self.ids.box_items.children

    def set_pos_panel_items(
        self,
        instance_fab_button: Union[None, MDNavigationRailFabButton],
        instance_menu_button: Union[None, MDNavigationRailFabButton],
    ) -> None:
        """Set :class:`~Paneltems` panel position with menu items."""

        if self.anchor == "top":
            if instance_fab_button:
                self.ids.box_items.y = instance_fab_button.y - (
                    len(self.ids.box_items.children) * dp(56)
                    + self.padding[1] * 2
                    + dp(24)
                )
            else:
                if not instance_menu_button:
                    self.ids.box_items.pos_hint = {"top": 1}
                else:
                    self.ids.box_items.y = instance_menu_button.y - (
                        len(self.ids.box_items.children) * dp(56)
                        + self.padding[1] * 2
                    )
        elif self.anchor == "center":
            self.ids.box_items.pos_hint = {"center_y": 0.5}
        elif self.anchor == "bottom":
            self.ids.box_items.y = dp(12)

    def set_current_selected_item(self, interval: Union[int, float]) -> None:
        """Sets the active menu list item (:class:`~MDNavigationRailItem`)."""

        if self.ids.box_items.children:
            items = self.ids.box_items.children[:]
            items.reverse()

            if len(items) <= self.current_selected_item:
                Logger.error(
                    f"MDNavigationRail:You have "
                    f"{len(self.ids.box_items.children)} menu items, but you "
                    f"set {self.current_selected_item} as the active item. "
                    f"The very first menu item will be set active."
                )
                index = 0
            else:
                index = self.current_selected_item

            items[index].dispatch("on_press")
            items[index].dispatch("on_release")

    def set_pos_menu_fab_buttons(self, *args) -> None:
        """
        Sets the position of the :class:`~MDNavigationRailFabButton` and
        :class:`~MDNavigationRailMenuButton` buttons on the panel.
        """

        fab_button = None  # MDNavigationRailFabButton
        menu_button = None  # MDNavigationRailMenuButton

        for widget in self.ids.box_buttons.children:
            if isinstance(widget, MDNavigationRailFabButton):
                fab_button = widget
            if isinstance(widget, MDNavigationRailMenuButton):
                menu_button = widget

        if fab_button and menu_button:

            def set_fab_button_y(interval):
                fab_button.y = self.parent.height - (
                    menu_button.height
                    + fab_button.height
                    + self.padding[1]
                    + dp(18)
                )
                self.set_pos_panel_items(fab_button, menu_button)

            Clock.schedule_once(set_fab_button_y)
        elif fab_button and not menu_button:

            def set_fab_button_y(interval):
                fab_button.y = self.parent.height - (
                    self.padding[1] + fab_button.height
                )
                self.set_pos_panel_items(fab_button, menu_button)

            Clock.schedule_once(set_fab_button_y)
        else:
            Clock.schedule_once(
                lambda x: self.set_pos_panel_items(fab_button, menu_button)
            )

    def add_widget(self, widget, *args, **kwargs):
        if isinstance(widget, MDNavigationRailFabButton):
            self.ids.box_buttons.add_widget(widget)
        elif isinstance(widget, MDNavigationRailMenuButton):
            self.ids.box_buttons.add_widget(widget)
        elif isinstance(widget, MDNavigationRailItem):
            widget.navigation_rail = self
            self.ids.box_items.add_widget(widget)
        elif isinstance(widget, (PanelRoot, PanelItems)):
            return super().add_widget(widget)