test-kivy-app/kivy_venv/lib/python3.11/site-packages/kivymd/uix/tab/tab.py

1393 lines
41 KiB
Python
Raw Normal View History

2024-09-15 12:12:16 +00:00
"""
Components/Tabs
===============
.. seealso::
2024-09-15 17:57:02 +00:00
`Material Design spec, Tabs <https://m3.material.io/components/tabs/overview>`_
2024-09-15 12:12:16 +00:00
.. rubric:: Tabs organize content across different screens, data sets,
and other interactions.
2024-09-15 17:57:02 +00:00
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/tab-preview.png
2024-09-15 12:12:16 +00:00
:align: center
2024-09-15 17:57:02 +00:00
- Use tabs to group content into helpful categories
- Two types: primary and secondary
- Tabs can horizontally scroll, so a UI can have as many tabs as needed
- Place tabs next to each other as peers
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/tab-types.png
:align: center
1. Primary tabs
2. Secondary tabs
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
Usage primary tabs
------------------
Primary tabs should be used when just one set of tabs are needed.
2024-09-15 12:12:16 +00:00
.. code-block:: python
2024-09-15 17:57:02 +00:00
from kivy.lang import Builder
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
from kivymd.app import MDApp
from kivymd.uix.tab import (
MDTabsItem,
MDTabsItemIcon,
MDTabsItemText,
MDTabsBadge,
)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
KV = '''
MDScreen:
md_bg_color: self.theme_cls.backgroundColor
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
MDTabsPrimary:
id: tabs
2024-09-15 12:12:16 +00:00
pos_hint: {"center_x": .5, "center_y": .5}
2024-09-15 17:57:02 +00:00
MDDivider:
'''
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
class Example(MDApp):
def on_start(self):
for tab_icon, tab_name in {
"airplane": "Flights",
"treasure-chest": "Trips",
"compass-outline": "Explore",
}.items():
if tab_icon == "treasure-chest":
self.root.ids.tabs.add_widget(
MDTabsItem(
MDTabsItemIcon(
MDTabsBadge(
text="99",
),
icon=tab_icon,
),
MDTabsItemText(
text=tab_name,
),
)
)
else:
self.root.ids.tabs.add_widget(
MDTabsItem(
MDTabsItemIcon(
icon=tab_icon,
),
MDTabsItemText(
text=tab_name,
),
)
)
self.root.ids.tabs.switch_tab(icon="airplane")
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def build(self):
self.theme_cls.primary_palette = "Olive"
return Builder.load_string(KV)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
Example().run()
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/tab-primary-usage.png
:align: center
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
Anatomy primary tabs
--------------------
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/tab-primary-anatomy.png
:align: center
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
Usage secondary tabs
--------------------
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
Secondary tabs are necessary when a screen requires more than one level of
tabs. These tabs use a simpler style of indicator, but their function is
identical to primary tabs.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. code-block:: python
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
from kivy.lang import Builder
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
from kivymd.app import MDApp
from kivymd.uix.tab import (
MDTabsItemIcon,
MDTabsItemText,
MDTabsBadge, MDTabsItemSecondary,
)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
KV = '''
MDScreen:
md_bg_color: self.theme_cls.backgroundColor
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
MDTabsSecondary:
id: tabs
pos_hint: {"center_x": .5, "center_y": .5}
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
MDDivider:
'''
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
class Example(MDApp):
def on_start(self):
for tab_icon, tab_name in {
"airplane": "Flights",
"treasure-chest": "Trips",
"compass-outline": "Explore",
}.items():
if tab_icon == "treasure-chest":
self.root.ids.tabs.add_widget(
MDTabsItemSecondary(
MDTabsItemIcon(
icon=tab_icon,
),
MDTabsItemText(
text=tab_name,
),
MDTabsBadge(
text="5",
),
)
)
else:
self.root.ids.tabs.add_widget(
MDTabsItemSecondary(
MDTabsItemIcon(
icon=tab_icon,
),
MDTabsItemText(
text=tab_name,
),
)
)
self.root.ids.tabs.switch_tab(icon="airplane")
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def build(self):
self.theme_cls.primary_palette = "Olive"
return Builder.load_string(KV)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
Example().run()
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
Anatomy secondary tabs
----------------------
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/tab-secondary-anatomy.png
:align: center
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
Related content
---------------
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
Use tabs to group related content, not sequential content.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. code-block:: python
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
from kivy.lang import Builder
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
from kivymd.app import MDApp
from kivymd.uix.label import MDLabel
from kivymd.uix.tab import (
MDTabsItemIcon,
MDTabsItemText,
MDTabsItem,
)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
KV = '''
MDScreen:
md_bg_color: self.theme_cls.backgroundColor
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
MDTabsPrimary:
id: tabs
pos_hint: {"center_x": .5, "center_y": .5}
size_hint_x: .6
MDDivider:
MDTabsCarousel:
id: related_content_container
size_hint_y: None
height: dp(320)
'''
class Example(MDApp):
def on_start(self):
for tab_icon, tab_name in {
"airplane": "Flights",
"treasure-chest": "Trips",
"compass-outline": "Explore",
}.items():
self.root.ids.tabs.add_widget(
MDTabsItem(
MDTabsItemIcon(
icon=tab_icon,
),
MDTabsItemText(
text=tab_name,
),
)
)
self.root.ids.related_content_container.add_widget(
MDLabel(
text=tab_name,
halign="center",
)
)
self.root.ids.tabs.switch_tab(icon="airplane")
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def build(self):
self.theme_cls.primary_palette = "Olive"
return Builder.load_string(KV)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
Example().run()
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/tab-primary-related-content.gif
:align: center
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
Behaviors
=========
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
Scrollable tabs
---------------
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
When a set of tabs cannot fit on screen, use scrollable tabs. Scrollable tabs
can use longer text labels and a larger number of tabs. They are best used for
browsing on touch interfaces.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. code-block:: python
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
from kivy.lang import Builder
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
from kivymd.app import MDApp
from kivymd.uix.tab import MDTabsItemText, MDTabsItem
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
KV = '''
MDScreen:
md_bg_color: self.theme_cls.backgroundColor
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
MDTabsPrimary:
id: tabs
pos_hint: {"center_x": .5, "center_y": .5}
size_hint_x: .6
allow_stretch: False
label_only: True
MDDivider:
'''
class Example(MDApp):
def on_start(self):
for tab_name in [
"Moscow",
"Saint Petersburg",
"Novosibirsk",
"Yekaterinburg",
"Kazan",
"Nizhny Novgorod",
"Chelyabinsk",
]:
self.root.ids.tabs.add_widget(
MDTabsItem(
MDTabsItemText(
text=tab_name,
),
)
)
self.root.ids.tabs.switch_tab(text="Moscow")
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def build(self):
self.theme_cls.primary_palette = "Olive"
return Builder.load_string(KV)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
Example().run()
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/tab-primary-scrollable-behavior.gif
2024-09-15 12:12:16 +00:00
:align: center
2024-09-15 17:57:02 +00:00
Fixed tabs
==========
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
Fixed tabs display all tabs in a set simultaneously. They are best for
switching between related content quickly, such as between transportation
methods in a map. To navigate between fixed tabs, tap an individual tab, or
swipe left or right in the content area.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. code-block:: python
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
from kivy.lang import Builder
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
from kivymd.app import MDApp
from kivymd.uix.tab import MDTabsItemText, MDTabsItem
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
KV = '''
MDScreen:
md_bg_color: self.theme_cls.backgroundColor
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
MDTabsPrimary:
id: tabs
pos_hint: {"center_x": .5, "center_y": .5}
size_hint_x: .6
allow_stretch: True
label_only: True
MDDivider:
'''
class Example(MDApp):
def on_start(self):
for tab_name in [
"Moscow", "Saint Petersburg", "Novosibirsk"
]:
self.root.ids.tabs.add_widget(
MDTabsItem(
MDTabsItemText(
text=tab_name,
),
)
)
self.root.ids.tabs.switch_tab(text="Moscow")
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def build(self):
self.theme_cls.primary_palette = "Olive"
return Builder.load_string(KV)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
Example().run()
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/tab-primary-fixed-behavior.png
:align: center
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
Tap a tab
---------
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
Navigate to a tab by tapping on it.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/tab-primary-tap-a-tab-behavior.gif
:align: center
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
Swipe within the content area
-----------------------------
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
To navigate between tabs, users can swipe left or right within the content
area.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/tab-primary-swipe-within-content-area-behavior.gif
:align: center
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
Switching tab
=============
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
You can switch tabs by icon name, by tab name, and by tab objects:
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. code-block:: python
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
instance_tabs.switch_tab(icon="airplane")
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. code-block:: python
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
instance_tabs.switch_tab(text="Airplane")
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. code-block:: python
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
instance_tabs.switch_tab(
instance=instance_tabs_item # MDTabsItem
)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
API break
=========
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
1.2.0 version
-------------
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. code-block:: python
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
from kivy.lang import Builder
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
from kivymd.app import MDApp
from kivymd.uix.floatlayout import MDFloatLayout
from kivymd.uix.tab import MDTabsBase
from kivymd.icon_definitions import md_icons
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
KV = '''
MDBoxLayout:
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
MDTabs:
id: tabs
on_ref_press: app.on_ref_press(*args)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
<Tab>
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
MDIconButton:
id: icon
icon: app.icons[0]
icon_size: "48sp"
pos_hint: {"center_x": .5, "center_y": .5}
'''
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
class Tab(MDFloatLayout, MDTabsBase):
'''Class implementing content for a tab.'''
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
class Example(MDApp):
icons = list(md_icons.keys())[15:30]
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def build(self):
return Builder.load_string(KV)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def on_start(self):
for name_tab in self.icons:
self.root.ids.tabs.add_widget(
Tab(title=name_tab, icon=name_tab)
)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
Example().run()
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
2.0.0 version
-------------
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. code-block:: python
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
from kivy.lang import Builder
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
from kivymd.app import MDApp
from kivymd.icon_definitions import md_icons
from kivymd.uix.label import MDIcon
from kivymd.uix.tab import MDTabsItem, MDTabsItemIcon
from kivymd.uix.tab.tab import MDTabsItemText
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
KV = '''
MDScreen:
md_bg_color: self.theme_cls.backgroundColor
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
MDTabsPrimary:
id: tabs
allow_stretch: False
pos_hint: {"center_x": .5, "center_y": .5}
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
MDDivider:
MDTabsCarousel:
id: related_content
size_hint_y: None
height: root.height - tabs.ids.tab_scroll.height
'''
class Example(MDApp):
def on_start(self):
for name_tab in list(md_icons.keys())[15:30]:
self.root.ids.tabs.add_widget(
MDTabsItem(
MDTabsItemIcon(
icon=name_tab,
),
MDTabsItemText(
text=name_tab,
),
)
)
self.root.ids.related_content.add_widget(
MDIcon(
icon=name_tab,
pos_hint={"center_x": 0.5, "center_y": 0.5},
)
)
self.root.ids.tabs.switch_tab(icon="airplane")
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def build(self):
return Builder.load_string(KV)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
Example().run()
"""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
from __future__ import annotations
__all__ = (
"MDTabsPrimary",
"MDTabsSecondary",
"MDTabsItem",
"MDTabsItemSecondary",
"MDTabsItemIcon",
"MDTabsItemText",
"MDTabsCarousel",
"MDTabsBadge",
)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
import os
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.carousel import Carousel
from kivy.uix.widget import Widget
from kivy.utils import boundary
from kivy.animation import Animation
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.metrics import dp
from kivy.properties import (
ObjectProperty,
BooleanProperty,
ColorProperty,
NumericProperty,
AliasProperty,
StringProperty,
VariableListProperty,
)
from kivy.uix.behaviors import ButtonBehavior
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.scrollview import ScrollView
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
from kivymd import uix_path
from kivymd.theming import ThemableBehavior
from kivymd.uix.badge import MDBadge
from kivymd.uix.behaviors import (
DeclarativeBehavior,
RectangularRippleBehavior,
BackgroundColorBehavior,
)
from kivymd.uix.behaviors.state_layer_behavior import StateLayerBehavior
from kivymd.uix.label import MDLabel, MDIcon
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
with open(os.path.join(uix_path, "tab", "tab.kv"), encoding="utf-8") as kv_file:
Builder.load_string(kv_file.read())
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
###############################################################################
#
# COMMON CLASSES
#
###############################################################################
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
class MDTabsBadge(MDBadge):
"""
Implements an badge for secondary tabs.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. versionadded:: 2.0.0
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
For more information, see in the
:class:`~kivymd.uix.badge.badge.MDBadge` class documentation.
"""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
class MDTabsCarousel(Carousel):
"""
Implements a carousel for user-generated content.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
For more information, see in the
:class:`~kivy.uix.carousel.Carousel` class documentation.
"""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
lock_swiping = BooleanProperty(False)
"""
If True - disable switching tabs by swipe.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
:attr:`lock_swiping` is an :class:`~kivy.properties.BooleanProperty`
and defaults to `False`.
"""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
_tabs = ObjectProperty() # MDTabsPrimary/MDTabsSecondary object
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def on_touch_move(self, touch) -> str | bool | None:
if self.lock_swiping: # lock a swiping
return
if not self.touch_mode_change:
if self.ignore_perpendicular_swipes and self.direction in (
"top",
"bottom",
):
if abs(touch.oy - touch.y) < self.scroll_distance:
if abs(touch.ox - touch.x) > self.scroll_distance:
self._change_touch_mode()
self.touch_mode_change = True
elif self.ignore_perpendicular_swipes and self.direction in (
"right",
"left",
):
if abs(touch.ox - touch.x) < self.scroll_distance:
if abs(touch.oy - touch.y) > self.scroll_distance:
self._change_touch_mode()
self.touch_mode_change = True
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
if self._get_uid("cavoid") in touch.ud:
return
if self._touch is not touch:
super().on_touch_move(touch)
return self._get_uid() in touch.ud
if touch.grab_current is not self:
return True
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
ud = touch.ud[self._get_uid()]
direction = self.direction[0]
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
if ud["mode"] == "unknown":
if direction in "rl":
distance = abs(touch.ox - touch.x)
else:
distance = abs(touch.oy - touch.y)
if distance > self.scroll_distance:
ev = self._change_touch_mode_ev
if ev is not None:
ev.cancel()
ud["mode"] = "scroll"
else:
if direction in "rl":
self._offset += touch.dx
if direction in "tb":
self._offset += touch.dy
return True
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
class MDTabsScrollView(BackgroundColorBehavior, ScrollView):
"""
Implements a scrollable list of tabs.
This class hacked version to fix scroll_x manual setting.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
For more information, see in the
:class:`~kivymd.uix.behaviors.backgroundcolor_behavior.BackgroundColorBehavior` and
:class:`~kivy.uix.scrollview.ScrollView`
classes documentation.
"""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def goto(self, scroll_x: float | None, scroll_y: float | None) -> None:
"""Update event value along with scroll_*."""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def _update(e, x):
if e:
e.value = (e.max + e.min) * x
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
if not (scroll_x is None):
self.scroll_x = scroll_x
_update(self.effect_x, scroll_x)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
if not (scroll_y is None):
self.scroll_y = scroll_y
_update(self.effect_y, scroll_y)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
class MDTabsItemText(MDLabel):
"""
Implements an label for the :class:`~MDTabsItem` class.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
For more information, see in the
:class:`~kivymd.uix.label.label.MDLabel` class documentation.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. versionadded:: 2.0.0
"""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
_active = BooleanProperty(False)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
class MDTabsItemIcon(MDIcon):
"""
Implements an icon for the :class:`~MDTabsItem` class.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
For more information, see in the
:class:`~kivymd.uix.label.label.MDIcon` class documentation.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. versionadded:: 2.0.0
"""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
class MDTabsItemBase(
DeclarativeBehavior,
BackgroundColorBehavior,
RectangularRippleBehavior,
ButtonBehavior,
ThemableBehavior,
StateLayerBehavior,
):
"""
Implements a base item with an icon and text.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. versionadded:: 2.0.0
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
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.behaviors.ripple_behavior.RectangularRippleBehavior` and
:class:`~kivy.uix.behaviors.ButtonBehavior` and
:class:`~kivymd.theming.ThemableBehavior`
classes documentation.
"""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
active = BooleanProperty(False)
"""
Is the tab active.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
:attr:`active` is an :class:`~kivy.properties.BooleanProperty`
and defaults to `False`.
"""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
_tabs = ObjectProperty() # MDTabsPrimary/MDTabsSecondary object
_tab_content = ObjectProperty() # Carousel slide (related content) object
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def on_release(self, *args) -> None:
"""
Fired when the button is released
(i.e. the touch/click that pressed the button goes away).
"""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
if self._tab_content:
self._tabs._tabs_carousel.load_slide(self._tab_content)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
self._tabs.update_indicator(instance=self)
self._tabs.dispatch("on_tab_switch", self, self._tab_content)
self._tabs._current_tab = self
self._tabs._current_related_content = self._tab_content
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
class MDTabsItem(MDTabsItemBase, BoxLayout):
"""
Implements a item with an icon and text for :class:`~MDTabsPrimary` class.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. versionadded:: 2.0.0
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
For more information, see in the
:class:`~MDTabsItemBase` and
:class:`~kivy.uix.boxlayout.BoxLayout`
classes documentation.
"""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def add_widget(self, widget, *args, **kwargs):
if isinstance(widget, (MDTabsItemText, MDTabsItemIcon)):
if len(self.children) <= 1:
Clock.schedule_once(lambda x: self._set_width(widget))
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def _set_width(self, widget):
def set_width(*args):
self.width = widget.texture_size[0] + widget.padding_x + 2
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
if not self._tabs.allow_stretch and isinstance(widget, MDTabsItemText):
Clock.schedule_once(set_width)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
super().add_widget(widget)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
###############################################################################
#
# PRIMARY CLASSES
#
###############################################################################
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
class MDTabsPrimary(DeclarativeBehavior, ThemableBehavior, BoxLayout):
"""
Tabs primary class.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. versionchanged:: 2.0.0
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
Rename from `MDTabs` to `MDTabsPrimary` class.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
For more information, see in the
:class:`~kivymd.uix.behaviors.declarative_behavior.DeclarativeBehavior` and
:class:`~kivymd.theming.ThemableBehavior` and
:class:`~kivy.uix.boxlayout.BoxLayout`
classes documentation.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
:Events:
`on_tab_switch`
Fired when switching tabs.
"""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
md_bg_color = ColorProperty(None)
"""
The background color of the widget.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
:attr:`md_bg_color` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
label_only = BooleanProperty(False)
"""
Tabs with a label only or with an icon and a label.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. versionadded:: 2.0.0
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
:attr:`label_only` is an :class:`~kivy.properties.BooleanProperty`
and defaults to `False`.
"""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
allow_stretch = BooleanProperty(True)
"""
Whether to stretch tabs to the width of the panel.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
:attr:`allow_stretch` is an :class:`~kivy.properties.BooleanProperty`
and defaults to `True`.
"""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
lock_swiping = BooleanProperty(False)
"""
If True - disable switching tabs by swipe.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
:attr:`lock_swiping` is an :class:`~kivy.properties.BooleanProperty`
and defaults to `False`.
"""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
anim_duration = NumericProperty(0.2)
"""
Duration of the slide animation.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
:attr:`anim_duration` is an :class:`~kivy.properties.NumericProperty`
and defaults to `0.2`.
"""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
indicator_anim = BooleanProperty(True)
"""
Tab indicator animation. If you want use animation set it to ``True``.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. versionchanged:: 2.0.0
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
Rename from `tab_indicator_anim` to `indicator_anim` attribute.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
:attr:`indicator_anim` is an :class:`~kivy.properties.BooleanProperty`
and defaults to `True`.
"""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
indicator_radius = VariableListProperty([dp(2), dp(2), 0, 0], lenght=4)
"""
Radius of the tab indicator.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. versionadded:: 2.0.0
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
:attr:`indicator_radius` is an :class:`~kivy.properties.VariableListProperty`
and defaults to `[dp(2), dp(2), 0, 0]`.
"""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
indicator_height = NumericProperty("4dp")
"""
Height of the tab indicator.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. versionchanged:: 2.0.0
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
Rename from `tab_indicator_height` to `indicator_height` attribute.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
:attr:`indicator_height` is an :class:`~kivy.properties.NumericProperty`
and defaults to `'4dp'`.
"""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
indicator_duration = NumericProperty(0.5)
2024-09-15 12:12:16 +00:00
"""
2024-09-15 17:57:02 +00:00
The duration of the animation of the indicator movement when switching
tabs.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. versionadded:: 2.0.0
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
:attr:`indicator_duration` is an :class:`~kivy.properties.NumericProperty`
and defaults to `0.5`.
2024-09-15 12:12:16 +00:00
"""
2024-09-15 17:57:02 +00:00
indicator_transition = StringProperty("out_expo")
2024-09-15 12:12:16 +00:00
"""
2024-09-15 17:57:02 +00:00
The transition name of animation of the indicator movement when switching
tabs.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. versionadded:: 2.0.0
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
:attr:`indicator_transition` is an :class:`~kivy.properties.StringProperty`
and defaults to `'out_expo'.
2024-09-15 12:12:16 +00:00
"""
2024-09-15 17:57:02 +00:00
def get_last_scroll_x(self):
return self.ids.tab_scroll.scroll_x
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
last_scroll_x = AliasProperty(
get_last_scroll_x, bind=("target",), cache=True
2024-09-15 12:12:16 +00:00
)
"""
2024-09-15 17:57:02 +00:00
Is the carousel reference of the next tab/slide.
When you go from `'Tab A'` to `'Tab B'`, `'Tab B'` will be the
target tab/slide of the carousel.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
:attr:`last_scroll_x` is an :class:`~kivy.properties.AliasProperty`.
2024-09-15 12:12:16 +00:00
"""
target = ObjectProperty(None, allownone=True)
"""
It is the carousel reference of the next tab / slide.
When you go from `'Tab A'` to `'Tab B'`, `'Tab B'` will be the
target tab / slide of the carousel.
:attr:`target` is an :class:`~kivy.properties.ObjectProperty`
and default to `None`.
"""
def get_rect_instruction(self):
2024-09-15 17:57:02 +00:00
canvas_instructions = self.ids.container.canvas.before.get_group(
"md-tabs-rounded-rectangle"
2024-09-15 12:12:16 +00:00
)
return canvas_instructions[0]
indicator = AliasProperty(get_rect_instruction, cache=True)
"""
2024-09-15 17:57:02 +00:00
It is the :class:`~kivy.graphics.vertex_instructions.SmoothRoundedRectangle`
2024-09-15 12:12:16 +00:00
instruction reference of the tab indicator.
:attr:`indicator` is an :class:`~kivy.properties.AliasProperty`.
"""
2024-09-15 17:57:02 +00:00
_tabs_carousel = ObjectProperty() # MDTabsCarousel object
_current_tab = None # MDTabsItem object
_current_related_content = None # Carousel slide (related content) object
_do_releasing = True
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.register_event_type("on_tab_switch")
self.register_event_type("on_slide_progress")
Clock.schedule_once(self._check_panel_height)
Clock.schedule_once(self._set_slides_attributes)
def add_widget(self, widget, *args, **kwargs):
if isinstance(widget, MDTabsCarousel):
self._tabs_carousel = widget
widget._tabs = self
widget.bind(
_offset=self.android_animation, index=self.on_carousel_index
)
return super().add_widget(widget)
elif isinstance(widget, MDTabsItem) or (
isinstance(self, MDTabsSecondary)
and isinstance(widget, MDTabsItemSecondary)
):
widget._tabs = self
widget.bind(on_release=self.set_active_item)
self.ids.container.add_widget(widget)
else:
return super().add_widget(widget)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def do_autoscroll_tabs(self, instance: MDTabsItem, value: float) -> None:
"""
Automatically scrolls the list of tabs when swiping the carousel
slide (related content).
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. versionchanged:: 2.0.0
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
Rename from `tab_bar_autoscroll` to `do_autoscroll_tabs` method.
"""
2024-09-15 12:12:16 +00:00
bound_left = self.center_x - self.x
2024-09-15 17:57:02 +00:00
bound_right = self.ids.container.width - bound_left
dt = instance.center_x - bound_left
sx, sy = self.ids.tab_scroll.convert_distance_to_scroll(dt, 0)
2024-09-15 12:12:16 +00:00
lsx = self.last_scroll_x # ast scroll x of the tab bar
scroll_is_late = lsx < sx # determine scroll direction
2024-09-15 17:57:02 +00:00
dst = abs(lsx - sx) * value # distance to run)
2024-09-15 12:12:16 +00:00
if not dst:
return
2024-09-15 17:57:02 +00:00
if scroll_is_late and instance.center_x > bound_left:
2024-09-15 12:12:16 +00:00
x = lsx + dst
2024-09-15 17:57:02 +00:00
elif not scroll_is_late and instance.center_x < bound_right:
2024-09-15 12:12:16 +00:00
x = lsx - dst
else:
return
2024-09-15 17:57:02 +00:00
2024-09-15 12:12:16 +00:00
x = boundary(x, 0.0, 1.0)
2024-09-15 17:57:02 +00:00
self.ids.tab_scroll.goto(x, None)
2024-09-15 12:12:16 +00:00
def android_animation(
2024-09-15 17:57:02 +00:00
self, instance: MDTabsCarousel, offset: float
) -> None:
"""Fired when swiping a carousel slide (related content)."""
self.dispatch("on_slide_progress", instance, offset)
2024-09-15 12:12:16 +00:00
# Try to reproduce the android animation effect.
2024-09-15 17:57:02 +00:00
if offset != 0 and abs(offset) < instance.width:
2024-09-15 12:12:16 +00:00
forward = offset < 0
offset = abs(offset)
2024-09-15 17:57:02 +00:00
step = offset / float(instance.width)
2024-09-15 12:12:16 +00:00
skip_slide = (
2024-09-15 17:57:02 +00:00
instance.slides[instance._skip_slide]
if instance._skip_slide is not None
2024-09-15 12:12:16 +00:00
else None
)
next_slide = (
2024-09-15 17:57:02 +00:00
instance.next_slide if forward else instance.previous_slide
2024-09-15 12:12:16 +00:00
)
self.target = skip_slide if skip_slide else next_slide
if not self.target:
return
2024-09-15 17:57:02 +00:00
a = instance.current_slide.tab_item
b = self.target.tab_item
self.do_autoscroll_tabs(b, step)
item_text_object = self._get_tab_item_text_icon_object()
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
if item_text_object:
if self.__class__.__name__ == "MDTabsSecondary":
tab_text_width = a.width
else:
tab_text_width = item_text_object.texture_size[0]
if self.indicator_anim is False:
return
gap_x = abs(a.x - b.x)
if forward:
x_step = (
a.x
+ (a.width / 2 - tab_text_width / 2)
+ dp(4)
+ (gap_x * step)
)
else:
x_step = (
a.x
+ (a.width / 2 - tab_text_width / 2)
+ dp(4)
- gap_x * step
)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
w_step = tab_text_width - (
dp(8) if self.__class__.__name__ == "MDTabsPrimary" else 0
)
self.update_indicator(x_step, w_step)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def update_indicator(
self, x: float = 0.0, w: float = 0.0, instance: MDTabsItem = None
) -> None:
"""Update position and size of the indicator."""
def update_indicator(*args):
indicator_pos = (0, 0)
indicator_size = (0, 0)
if self.__class__.__name__ == "MDTabsPrimary":
item_text_object = self._get_tab_item_text_icon_object()
if item_text_object:
tab_text_width = item_text_object.texture_size[0]
indicator_pos = (
instance.x
+ (instance.width / 2 - tab_text_width / 2)
+ dp(4),
self.indicator.pos[1]
if not self._tabs_carousel
else self._tabs_carousel.height,
)
indicator_size = (
tab_text_width - dp(8),
self.indicator_height,
)
elif self.__class__.__name__ == "MDTabsSecondary":
indicator_pos = (instance.x, self.indicator.pos[1])
indicator_size = (instance.width, self.indicator_height)
Animation(
pos=indicator_pos,
size=indicator_size,
d=0 if not self.indicator_anim else self.indicator_duration,
t=self.indicator_transition,
).start(self.indicator)
if not instance:
self.indicator.pos = (x, self.indicator.pos[1])
self.indicator.size = (w, self.indicator_height)
else:
Clock.schedule_once(update_indicator)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def switch_tab(
self, instance: MDTabsItem = None, text: str = "", icon: str = ""
) -> None:
"""Switches tabs by tab object/tab text/tab icon name."""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
Clock.schedule_once(
lambda x: self._switch_tab(instance, text, icon), 0.8
)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def set_active_item(self, item: MDTabsItem) -> None:
"""Sets the active tab item."""
for widget in self.ids.container.children:
if item is widget:
# Trying to switch an already active tab.
if widget.active and item.active:
break
widget.active = not widget.active
for widget_item in item.children:
if isinstance(widget_item, MDTabsItemText):
widget_item._active = widget.active
Animation(
text_color=self.theme_cls.primaryColor
if widget.active
else self.theme_cls.onSurfaceVariantColor,
d=0.2,
).start(widget_item)
if isinstance(widget_item, MDTabsItemIcon):
widget_item._active = widget.active
Animation(
icon_color=self.theme_cls.primaryColor
if widget.active
else self.theme_cls.onSurfaceVariantColor,
d=0.2,
).start(widget_item)
else:
widget.active = False
for widget_item in widget.children:
widget_item._active = widget.active
if isinstance(widget_item, MDTabsItemText):
Animation(
text_color=self.theme_cls.onSurfaceVariantColor,
d=0.2,
).start(widget_item)
if isinstance(widget_item, MDTabsItemIcon):
Animation(
icon_color=self.theme_cls.onSurfaceVariantColor,
d=0.2,
).start(widget_item)
def get_tabs_list(self) -> list:
"""
Returns a list of :class:`~MDTabsItem` objects.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. versionchanged:: 2.0.0
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
Rename from `get_tab_list` to `get_tabs_list` method.
"""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
return self.ids.container.children
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def get_slides_list(self) -> list:
"""
Returns a list of user tab objects.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. versionchanged:: 2.0.0
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
Rename from `get_slides` to `get_slides_list` method.
"""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
if self._tabs_carousel:
return self._tabs_carousel.slides
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def get_current_tab(self) -> MDTabsItem:
"""
Returns current tab object.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. versionadded:: 1.0.0
"""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
return self._current_tab
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def get_current_related_content(self) -> Widget:
"""
Returns the carousel slide object (related content).
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. versionadded:: 2.0.0
"""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
return self._current_related_content
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def on_tab_switch(self, *args) -> None:
"""This event is launched every time the current tab is changed."""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def on_slide_progress(self, *args) -> None:
"""
This event is deployed every available frame while the tab is
scrolling.
"""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def on_carousel_index(self, instance: MDTabsCarousel, value: int) -> None:
"""
Fired when the Tab index have changed.
This event is deployed by the builtin carousel of the class.
"""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
# When the index of the carousel change, update tab indicator,
# select the current tab and reset threshold data.
if instance.current_slide and hasattr(
instance.current_slide, "tab_item"
):
Clock.schedule_once(
lambda x: instance.current_slide.tab_item.dispatch("on_release")
)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def on_size(self, instance, size) -> None:
"""Fired when the application screen size changes."""
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
width, height = size
number_tabs = len(self.ids.container.children)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
if self.allow_stretch:
for tab in self.ids.container.children:
tab.width = width / number_tabs
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
if self._tabs_carousel:
Clock.schedule_once(
lambda x: self._tabs_carousel.current_slide.tab_item.dispatch(
"on_release"
)
)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def _switch_tab(
self, instance: MDTabsItem = None, text: str = "", icon: str = ""
):
def get_match(widget_to_compare, widget_to_compare_with, value, attr):
if isinstance(widget_to_compare, widget_to_compare_with):
if getattr(widget_to_compare, attr) == value:
return True
def switch_by(by_attr, attr):
for tab_item in self.ids.container.children:
for child in tab_item.children:
if isinstance(child, MDTabsItemSecondaryContainer):
for w in child.children:
if get_match(
w,
MDTabsItemText
if by_attr == "text"
else MDTabsItemIcon,
attr,
by_attr,
):
tab_item.dispatch("on_release")
break
else:
if get_match(
child,
MDTabsItemText
if by_attr == "text"
else MDTabsItemIcon,
attr,
by_attr,
):
tab_item.dispatch("on_release")
break
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
if instance and isinstance(instance, MDTabsItem):
instance.dispatch("on_release")
elif text:
switch_by("text", text)
elif icon:
switch_by("icon", icon)
def _set_slides_attributes(self, *args):
if self._tabs_carousel:
tabs_item_list = self.ids.container.children.copy()
tabs_item_list.reverse()
for i, tab_item in enumerate(tabs_item_list):
setattr(tab_item, "_tab_content", self._tabs_carousel.slides[i])
setattr(self._tabs_carousel.slides[i], "tab_item", tab_item)
def _get_tab_item_text_icon_object(
self, get_type="text"
) -> MDTabsItemText | MDTabsItemIcon | None:
item_text_object = None
for tab_item in self.ids.container.children:
if tab_item.active:
for child in tab_item.children:
if isinstance(child, MDTabsItemSecondaryContainer):
for w in child.children:
if isinstance(
w,
MDTabsItemText
if get_type == "text"
else MDTabsItemIcon,
):
item_text_object = w
break
else:
if isinstance(
child,
MDTabsItemText
if get_type == "text"
else MDTabsItemIcon,
):
item_text_object = child
break
return item_text_object
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
def _check_panel_height(self, *args):
if self.label_only:
self.ids.tab_scroll.height = dp(48)
else:
self.ids.tab_scroll.height = dp(64)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
###############################################################################
#
# SECONDARY CLASSES
#
###############################################################################
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
class MDTabsItemSecondaryContainer(BoxLayout):
2024-09-15 12:12:16 +00:00
"""
2024-09-15 17:57:02 +00:00
Implements a container for placing widgets for the
:class:`~MDTabsItemSecondary` class.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
For more information, see in the
:class:`~kivy.uix.boxlayout.BoxLayout` class documentation.
2024-09-15 12:12:16 +00:00
"""
2024-09-15 17:57:02 +00:00
class MDTabsItemSecondary(MDTabsItemBase, AnchorLayout):
2024-09-15 12:12:16 +00:00
"""
2024-09-15 17:57:02 +00:00
Implements a item with an icon and text for :class:`~MDTabsSecondary`
class.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. versionadded:: 2.0.0
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
For more information, see in the
:class:`~MDTabsItemBase` and
:class:`~kivy.uix.anchorlayout.AnchorLayout`
classes documentation.
2024-09-15 12:12:16 +00:00
"""
2024-09-15 17:57:02 +00:00
def add_widget(self, widget, *args, **kwargs):
if isinstance(widget, (MDTabsItemText, MDTabsItemIcon, MDTabsBadge)):
Clock.schedule_once(
lambda x: self.ids.box_container.add_widget(widget)
)
else:
return super().add_widget(widget)
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
class MDTabsSecondary(MDTabsPrimary):
2024-09-15 12:12:16 +00:00
"""
2024-09-15 17:57:02 +00:00
Tabs secondary class.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
.. versionadded:: 2.0.0
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
For more information, see in the
:class:`~MDTabsPrimary` class documentation.
2024-09-15 12:12:16 +00:00
"""
2024-09-15 17:57:02 +00:00
indicator_radius = VariableListProperty(0, lenght=4)
2024-09-15 12:12:16 +00:00
"""
2024-09-15 17:57:02 +00:00
Radius of the tab indicator.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
:attr:`indicator_radius` is an :class:`~kivy.properties.VariableListProperty`
and defaults to `[0, 0, 0, 0]`.
2024-09-15 12:12:16 +00:00
"""
2024-09-15 17:57:02 +00:00
indicator_height = NumericProperty("2dp")
2024-09-15 12:12:16 +00:00
"""
2024-09-15 17:57:02 +00:00
Height of the tab indicator.
2024-09-15 12:12:16 +00:00
2024-09-15 17:57:02 +00:00
:attr:`indicator_height` is an :class:`~kivy.properties.NumericProperty`
and defaults to `'2dp'`.
2024-09-15 12:12:16 +00:00
"""
2024-09-15 17:57:02 +00:00
def _check_panel_height(self, *args):
self.ids.tab_scroll.height = dp(48)