Reverted kivymd to avoid shader crash on Android

This commit is contained in:
Mark Qvist 2022-10-03 00:46:03 +02:00
parent 1595afaca3
commit bcd5c37101
97 changed files with 3446 additions and 5827 deletions

View File

@ -49,9 +49,6 @@ images_path = os.path.join(path, f"images{os.sep}")
uix_path = os.path.join(path, "uix") uix_path = os.path.join(path, "uix")
"""Path to uix directory.""" """Path to uix directory."""
glsl_path = os.path.join(path, "data", "glsl")
"""Path to glsl directory."""
_log_message = ( _log_message = (
"KivyMD:" "KivyMD:"
+ (" Release" if release else "") + (" Release" if release else "")

View File

@ -45,7 +45,7 @@ import os
from kivy.app import App from kivy.app import App
from kivy.lang import Builder from kivy.lang import Builder
from kivy.logger import Logger from kivy.logger import Logger
from kivy.properties import ObjectProperty, StringProperty from kivy.properties import ObjectProperty
from kivymd.theming import ThemeManager from kivymd.theming import ThemeManager
@ -71,16 +71,6 @@ class MDApp(App, FpsMonitoring):
information. information.
""" """
icon = StringProperty("kivymd/images/logo/kivymd-icon-512.png")
"""
See :attr:`~kivy.app.App.icon` attribute for more information.
.. versionadded:: 1.1.0
:attr:`icon` is an :class:`~kivy.properties.StringProperty`
adn default to `kivymd/images/logo/kivymd-icon-512.png`.
"""
theme_cls = ObjectProperty() theme_cls = ObjectProperty()
""" """
Instance of :class:`~ThemeManager` class. Instance of :class:`~ThemeManager` class.

View File

@ -412,7 +412,7 @@ To demonstrate the shades of the palette, you can run the following code:
self.screen = Factory.Root() self.screen = Factory.Root()
for name_tab in colors.keys(): for name_tab in colors.keys():
tab = Tab(title=name_tab) tab = Tab(text=name_tab)
self.screen.ids.android_tabs.add_widget(tab) self.screen.ids.android_tabs.add_widget(tab)
return self.screen return self.screen
@ -427,7 +427,7 @@ To demonstrate the shades of the palette, you can run the following code:
{ {
"viewclass": "ItemColor", "viewclass": "ItemColor",
"md_bg_color": colors[tab_text][value_color], "md_bg_color": colors[tab_text][value_color],
"title": value_color, "text": value_color,
} }
) )

View File

@ -1,44 +0,0 @@
/*
The shader code has been refactored for the KivyMD library.
You can find the original code of this shaders at the links:
https://www.shadertoy.com/view/WtdSDs
https://www.shadertoy.com/view/fsdyzB
Additional thanks to iq for optimizing conditional block for individual
corner radius:
https://iquilezles.org/articles/distfunctions
*/
float roundedBoxSDF(vec2 centerPosition, vec2 size, vec4 radius) {
radius.xy = (centerPosition.x > 0.0) ? radius.xy : radius.zw;
radius.x = (centerPosition.y > 0.0) ? radius.x : radius.y;
vec2 q = abs(centerPosition) - (size - shadow_softness) + radius.x;
return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - radius.x;
}
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
// Smooth the result (free antialiasing).
float edge0 = 0.0;
float smoothedAlpha = 1.0 - smoothstep(0.0, edge0, 1.0);
// Get the resultant shape.
vec4 quadColor = mix(
vec4(
shadow_color[0],
shadow_color[1],
shadow_color[2],
0.0
),
shadow_color,
smoothedAlpha
);
// Apply a drop shadow effect.
float shadowDistance = roundedBoxSDF(
fragCoord.xy - mouse.xy - (size / 2.0), size / 2.0, shadow_radius
);
float shadowAlpha = 1.0 - smoothstep(
-shadow_softness, shadow_softness, shadowDistance
);
fragColor = mix(quadColor, shadow_color, shadowAlpha - smoothedAlpha);
}

View File

@ -1,10 +0,0 @@
#ifdef GL_ES
precision highp float;
#endif
uniform vec4 resolution;
uniform vec4 mouse;
uniform vec2 size;
uniform vec4 shadow_radius;
uniform float shadow_softness;
uniform vec4 shadow_color;

View File

@ -1,10 +0,0 @@
vec2 gfc(in vec4 fc) {
vec2 canvas_pos = resolution.zw;
vec2 uv = fc.xy;
uv.y -= canvas_pos.y;
return uv;
}
void main(void) {
mainImage(gl_FragColor, gfc(gl_FragCoord));
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -0,0 +1 @@
{"quad_shadow-1.png": {"20": [2, 136, 128, 128], "21": [132, 136, 128, 128], "22": [262, 136, 128, 128], "23": [2, 6, 128, 128], "19": [132, 266, 128, 128], "18": [2, 266, 128, 128], "1": [262, 266, 128, 128], "3": [262, 6, 128, 128], "2": [132, 6, 128, 128]}, "quad_shadow-0.png": {"11": [262, 266, 128, 128], "10": [132, 266, 128, 128], "13": [132, 136, 128, 128], "12": [2, 136, 128, 128], "15": [2, 6, 128, 128], "14": [262, 136, 128, 128], "17": [262, 6, 128, 128], "16": [132, 6, 128, 128], "0": [2, 266, 128, 128]}, "quad_shadow-2.png": {"5": [132, 266, 128, 128], "4": [2, 266, 128, 128], "7": [2, 136, 128, 128], "6": [262, 266, 128, 128], "9": [262, 136, 128, 128], "8": [132, 136, 128, 128]}}

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View File

@ -0,0 +1 @@
{"rec_shadow-1.png": {"20": [2, 266, 256, 128], "21": [260, 266, 256, 128], "22": [518, 266, 256, 128], "23": [776, 266, 256, 128], "3": [260, 136, 256, 128], "2": [2, 136, 256, 128], "5": [776, 136, 256, 128], "4": [518, 136, 256, 128], "7": [260, 6, 256, 128], "6": [2, 6, 256, 128], "9": [776, 6, 256, 128], "8": [518, 6, 256, 128]}, "rec_shadow-0.png": {"11": [518, 266, 256, 128], "10": [260, 266, 256, 128], "13": [2, 136, 256, 128], "12": [776, 266, 256, 128], "15": [518, 136, 256, 128], "14": [260, 136, 256, 128], "17": [2, 6, 256, 128], "16": [776, 136, 256, 128], "19": [518, 6, 256, 128], "18": [260, 6, 256, 128], "1": [776, 6, 256, 128], "0": [2, 266, 256, 128]}}

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -0,0 +1 @@
{"rec_st_shadow-0.png": {"11": [262, 138, 128, 256], "10": [132, 138, 128, 256], "13": [522, 138, 128, 256], "12": [392, 138, 128, 256], "15": [782, 138, 128, 256], "14": [652, 138, 128, 256], "16": [912, 138, 128, 256], "0": [2, 138, 128, 256]}, "rec_st_shadow-1.png": {"20": [522, 138, 128, 256], "21": [652, 138, 128, 256], "17": [2, 138, 128, 256], "23": [912, 138, 128, 256], "19": [262, 138, 128, 256], "18": [132, 138, 128, 256], "22": [782, 138, 128, 256], "1": [392, 138, 128, 256]}, "rec_st_shadow-2.png": {"3": [132, 138, 128, 256], "2": [2, 138, 128, 256], "5": [392, 138, 128, 256], "4": [262, 138, 128, 256], "7": [652, 138, 128, 256], "6": [522, 138, 128, 256], "9": [912, 138, 128, 256], "8": [782, 138, 128, 256]}}

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -0,0 +1 @@
{"round_shadow-1.png": {"20": [2, 136, 128, 128], "21": [132, 136, 128, 128], "22": [262, 136, 128, 128], "23": [2, 6, 128, 128], "19": [132, 266, 128, 128], "18": [2, 266, 128, 128], "1": [262, 266, 128, 128], "3": [262, 6, 128, 128], "2": [132, 6, 128, 128]}, "round_shadow-0.png": {"11": [262, 266, 128, 128], "10": [132, 266, 128, 128], "13": [132, 136, 128, 128], "12": [2, 136, 128, 128], "15": [2, 6, 128, 128], "14": [262, 136, 128, 128], "17": [262, 6, 128, 128], "16": [132, 6, 128, 128], "0": [2, 266, 128, 128]}, "round_shadow-2.png": {"5": [132, 266, 128, 128], "4": [2, 266, 128, 128], "7": [2, 136, 128, 128], "6": [262, 266, 128, 128], "9": [262, 136, 128, 128], "8": [132, 136, 128, 128]}}

View File

@ -35,15 +35,8 @@ assert "Icons" in LabelBase._fonts.keys() # NOQA
images = os.listdir(kivymd.images_path) images = os.listdir(kivymd.images_path)
print(images) print(images)
assert "logo" in images
assert "alpha_layer.png" in images
assert "black.png" in images
assert "blue.png" in images
assert "red.png" in images
assert "green.png" in images
assert "yellow.png" in images
assert "folder.png" in images assert "folder.png" in images
assert "transparent.png" in images assert "rec_shadow.atlas" in images
""" """
) )
pyi_main.run( pyi_main.run(

View File

@ -1,13 +1,14 @@
def test_create_project(): def test_create_project():
import os import os
import sys
os.system( os.system(
f"python3.10 -m kivymd.tools.patterns.create_project " f"{sys.executable} -m kivymd.tools.patterns.create_project "
f"MVC " f"MVC "
f"{os.path.expanduser('~')} " f"{os.path.expanduser('~')} "
f"TestProject " f"TestProject "
f"python3.10 " f"{sys.executable} "
f"stable " f"master "
f"--name_screen TestProjectScreen " f"--name_screen TestProjectScreen "
f"--name_database restdb " f"--name_database restdb "
f"--use_hotreload yes" f"--use_hotreload yes"

View File

@ -212,8 +212,9 @@ respects, the theming stays as documented.
dictionary :attr:`kivymd.color_definition.colors`. dictionary :attr:`kivymd.color_definition.colors`.
""" """
from kivy.animation import Animation
from kivy.app import App from kivy.app import App
from kivy.atlas import Atlas
from kivy.clock import Clock from kivy.clock import Clock
from kivy.core.window import Window from kivy.core.window import Window
from kivy.event import EventDispatcher from kivy.event import EventDispatcher
@ -223,13 +224,13 @@ from kivy.properties import (
BooleanProperty, BooleanProperty,
ColorProperty, ColorProperty,
DictProperty, DictProperty,
NumericProperty,
ObjectProperty, ObjectProperty,
OptionProperty, OptionProperty,
StringProperty, StringProperty,
) )
from kivy.utils import get_color_from_hex from kivy.utils import get_color_from_hex
from kivymd import images_path
from kivymd.color_definitions import colors, hue, palette from kivymd.color_definitions import colors, hue, palette
from kivymd.font_definitions import theme_font_styles from kivymd.font_definitions import theme_font_styles
from kivymd.material_resources import DEVICE_IOS, DEVICE_TYPE from kivymd.material_resources import DEVICE_IOS, DEVICE_TYPE
@ -623,152 +624,6 @@ class ThemeManager(EventDispatcher):
and defaults to `'M2'`. and defaults to `'M2'`.
""" """
theme_style_switch_animation = BooleanProperty(False)
"""
Animate app colors when switching app color scheme ('Dark/light').
.. versionadded:: 1.1.0
.. tabs::
.. tab:: Declarative KV style
.. code-block:: python
from kivy.lang import Builder
from kivymd.app import MDApp
KV = '''
MDScreen:
MDCard:
orientation: "vertical"
padding: 0, 0, 0 , "36dp"
size_hint: .5, .5
pos_hint: {"center_x": .5, "center_y": .5}
elevation: 4
shadow_radius: 6
shadow_offset: 0, 2
MDLabel:
text: "Theme style - {}".format(app.theme_cls.theme_style)
halign: "center"
valign: "center"
bold: True
font_style: "H5"
MDRaisedButton:
text: "Set theme"
on_release: app.switch_theme_style()
pos_hint: {"center_x": .5}
'''
class Example(MDApp):
def build(self):
self.theme_cls.theme_style_switch_animation = True
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "Orange"
return Builder.load_string(KV)
def switch_theme_style(self):
self.theme_cls.primary_palette = (
"Orange" if self.theme_cls.primary_palette == "Red" else "Red"
)
self.theme_cls.theme_style = (
"Dark" if self.theme_cls.theme_style == "Light" else "Light"
)
Example().run()
.. tab:: Declarative python style
.. code-block:: python
from kivymd.app import MDApp
from kivymd.uix.button import MDRaisedButton
from kivymd.uix.card import MDCard
from kivymd.uix.label import MDLabel
from kivymd.uix.screen import MDScreen
class Example(MDApp):
def build(self):
self.theme_cls.theme_style_switch_animation = True
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "Orange"
return (
MDScreen(
MDCard(
MDLabel(
id="label",
text="Theme style - {}".format(self.theme_cls.theme_style),
halign="center",
valign="center",
bold=True,
font_style="H5",
),
MDRaisedButton(
text="Set theme",
on_release=self.switch_theme_style,
pos_hint={"center_x": 0.5},
),
id="card",
orientation="vertical",
padding=(0, 0, 0, "36dp"),
size_hint=(0.5, 0.5),
pos_hint={"center_x": 0.5, "center_y": 0.5},
elevation=4,
shadow_radius=6,
shadow_offset=(0, 2),
)
)
)
def switch_theme_style(self, *args):
self.theme_cls.primary_palette = (
"Orange" if self.theme_cls.primary_palette == "Red" else "Red"
)
self.theme_cls.theme_style = (
"Dark" if self.theme_cls.theme_style == "Light" else "Light"
)
self.root.ids.card.ids.label.text = (
"Theme style - {}".format(self.theme_cls.theme_style)
)
Example().run()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/theme-style-switch-animation.gif
:align: center
:attr:`theme_style_switch_animation` is an :class:`~kivy.properties.BooleanProperty`
and defaults to `False`.
"""
theme_style_switch_animation_duration = NumericProperty(0.2)
"""
Duration of the animation of switching the color scheme of the application
("Dark/light").
.. versionadded:: 1.1.0
.. code-block:: python
class Example(MDApp):
def build(self):
self.theme_cls.theme_style_switch_animation = True
self.theme_cls.theme_style_switch_animation_duration = 0.8
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/theme-style-switch-animation-duration.gif
:align: center
:attr:`theme_style_switch_animation_duration` is an :class:`~kivy.properties.NumericProperty`
and defaults to `0.2`.
"""
theme_style = OptionProperty("Light", options=["Light", "Dark"]) theme_style = OptionProperty("Light", options=["Light", "Dark"])
""" """
App theme style. App theme style.
@ -1329,22 +1184,14 @@ class ThemeManager(EventDispatcher):
): ):
self.set_clearcolor_by_theme_style(theme_style) self.set_clearcolor_by_theme_style(theme_style)
_set_clearcolor = False set_clearcolor = BooleanProperty(True)
def set_clearcolor_by_theme_style(self, theme_style): def set_clearcolor_by_theme_style(self, theme_style):
if self.theme_style_switch_animation and self._set_clearcolor: if not self.set_clearcolor:
Animation( return
clearcolor=get_color_from_hex( Window.clearcolor = get_color_from_hex(
self.colors[theme_style]["Background"] self.colors[theme_style]["Background"]
), )
d=self.theme_style_switch_animation_duration,
t="linear",
).start(Window)
else:
Window.clearcolor = get_color_from_hex(
self.colors[theme_style]["Background"]
)
self._set_clearcolor = True
# Font name, size (sp), always caps, letter spacing (sp). # Font name, size (sp), always caps, letter spacing (sp).
font_styles = DictProperty( font_styles = DictProperty(
@ -1551,6 +1398,10 @@ class ThemeManager(EventDispatcher):
def __init__(self, **kwargs): def __init__(self, **kwargs):
super().__init__(**kwargs) super().__init__(**kwargs)
self.rec_shadow = Atlas(f"{images_path}rec_shadow.atlas")
self.rec_st_shadow = Atlas(f"{images_path}rec_st_shadow.atlas")
self.quad_shadow = Atlas(f"{images_path}quad_shadow.atlas")
self.round_shadow = Atlas(f"{images_path}round_shadow.atlas")
Clock.schedule_once(lambda x: self.on_theme_style(0, self.theme_style)) Clock.schedule_once(lambda x: self.on_theme_style(0, self.theme_style))
self._determine_device_orientation(None, Window.size) self._determine_device_orientation(None, Window.size)
Window.bind(size=self._determine_device_orientation) Window.bind(size=self._determine_device_orientation)
@ -1636,16 +1487,6 @@ class ThemableBehavior(EventDispatcher):
""" """
def __init__(self, **kwargs): def __init__(self, **kwargs):
self.unbind_properties = [
"theme_style",
"material_style",
"device_orientation",
"primary_color",
"primary_palette",
"accent_palette",
"text_color",
]
if self.theme_cls is not None: if self.theme_cls is not None:
pass pass
else: else:
@ -1666,24 +1507,3 @@ class ThemableBehavior(EventDispatcher):
) )
self.theme_cls = App.get_running_app().theme_cls self.theme_cls = App.get_running_app().theme_cls
super().__init__(**kwargs) super().__init__(**kwargs)
# def dec_disabled(self, *args, **kwargs) -> None:
# callabacks = self.theme_cls.get_property_observers("theme_style")
# for callaback in callabacks:
# try:
# if hasattr(callaback, "proxy") and hasattr(
# callaback.proxy, "theme_cls"
# ):
# for property_name in self.unbind_properties:
# self.theme_cls.unbind(
# **{
# property_name: getattr(
# callaback.proxy, callaback.method_name
# )
# }
# )
# except ReferenceError:
# pass
# super().dec_disabled(*args, **kwargs)

View File

@ -13,18 +13,6 @@ from pathlib import Path
import kivymd import kivymd
datas = [ datas = [
# Add `.frag` files from the `kivymd/data/glsl/elevation` directory.
(
str(Path(kivymd.glsl_path).joinpath("elevation")) + os.sep,
str(
Path("kivymd").joinpath(
str(Path(kivymd.glsl_path)).split(str(Path("kivymd")) + os.sep)[
1
]
+ f"{os.sep}elevation"
)
),
),
# Add `.ttf` files from the `kivymd/fonts` directory. # Add `.ttf` files from the `kivymd/fonts` directory.
( (
kivymd.fonts_path, kivymd.fonts_path,

View File

@ -35,8 +35,8 @@
if not root.front_layer_color \ if not root.front_layer_color \
else root.front_layer_color else root.front_layer_color
radius: radius:
[root.radius_left, root.radius_right, [root.radius_left, root.radius_left,
0, 0] root.radius_right, root.radius_right]
OneLineListItem: OneLineListItem:
id: header_button id: header_button

View File

@ -202,6 +202,7 @@ from kivy.uix.boxlayout import BoxLayout
from kivymd import uix_path from kivymd import uix_path
from kivymd.theming import ThemableBehavior from kivymd.theming import ThemableBehavior
from kivymd.uix.behaviors import FakeRectangularElevationBehavior
from kivymd.uix.boxlayout import MDBoxLayout from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.card import MDCard from kivymd.uix.card import MDCard
from kivymd.uix.floatlayout import MDFloatLayout from kivymd.uix.floatlayout import MDFloatLayout
@ -527,5 +528,5 @@ class _BackLayer(BoxLayout):
pass pass
class _FrontLayer(MDCard): class _FrontLayer(MDCard, FakeRectangularElevationBehavior):
pass pass

View File

@ -35,7 +35,7 @@ Usage
MDTopAppBar: MDTopAppBar:
id: toolbar id: toolbar
title: "Example Banners" title: "Example Banners"
elevation: 4 elevation: 10
pos_hint: {'top': 1} pos_hint: {'top': 1}
MDBoxLayout: MDBoxLayout:
@ -157,6 +157,7 @@ from kivy.properties import (
from kivy.uix.widget import Widget from kivy.uix.widget import Widget
from kivymd import uix_path from kivymd import uix_path
from kivymd.uix.behaviors import FakeRectangularElevationBehavior
from kivymd.uix.boxlayout import MDBoxLayout from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.button import MDFlatButton from kivymd.uix.button import MDFlatButton
from kivymd.uix.card import MDCard from kivymd.uix.card import MDCard
@ -176,7 +177,7 @@ with open(
Builder.load_string(kv_file.read()) Builder.load_string(kv_file.read())
class MDBanner(MDCard): class MDBanner(MDCard, FakeRectangularElevationBehavior):
vertical_pad = NumericProperty(dp(68)) vertical_pad = NumericProperty(dp(68))
""" """
Indent the banner at the top of the screen. Indent the banner at the top of the screen.

View File

@ -11,20 +11,18 @@ from .backgroundcolor_behavior import (
) )
# flake8: NOQA # flake8: NOQA
from .declarative_behavior import DeclarativeBehavior from .declarative_bahavior import DeclarativeBehavior
from .elevation import ( from .elevation import (
CircularElevationBehavior, CircularElevationBehavior,
CommonElevationBehavior, CommonElevationBehavior,
FakeCircularElevationBehavior, FakeCircularElevationBehavior,
FakeRectangularElevationBehavior, FakeRectangularElevationBehavior,
ObservableShadow,
RectangularElevationBehavior, RectangularElevationBehavior,
RoundedRectangularElevationBehavior, RoundedRectangularElevationBehavior,
) )
from .magic_behavior import MagicBehavior from .magic_behavior import MagicBehavior
from .ripple_behavior import CircularRippleBehavior, RectangularRippleBehavior from .ripple_behavior import CircularRippleBehavior, RectangularRippleBehavior
from .rotate_behavior import RotateBehavior
from .scale_behavior import ScaleBehavior
from .stencil_behavior import StencilBehavior
from .touch_behavior import TouchBehavior from .touch_behavior import TouchBehavior
from .hover_behavior import HoverBehavior # isort:skip from .hover_behavior import HoverBehavior # isort:skip

View File

@ -7,9 +7,8 @@ Behaviors/Background Color
__all__ = ("BackgroundColorBehavior", "SpecificBackgroundColorBehavior") __all__ = ("BackgroundColorBehavior", "SpecificBackgroundColorBehavior")
from typing import List, Union from typing import List
from kivy.animation import Animation
from kivy.lang import Builder from kivy.lang import Builder
from kivy.properties import ( from kivy.properties import (
ColorProperty, ColorProperty,
@ -25,6 +24,8 @@ from kivy.utils import get_color_from_hex
from kivymd.color_definitions import hue, palette, text_colors from kivymd.color_definitions import hue, palette, text_colors
from kivymd.theming import ThemeManager from kivymd.theming import ThemeManager
from .elevation import CommonElevationBehavior
Builder.load_string( Builder.load_string(
""" """
#:import RelativeLayout kivy.uix.relativelayout.RelativeLayout #:import RelativeLayout kivy.uix.relativelayout.RelativeLayout
@ -37,7 +38,7 @@ Builder.load_string(
angle: self.angle angle: self.angle
origin: self._background_origin origin: self._background_origin
Color: Color:
rgba: self._md_bg_color rgba: self.md_bg_color
RoundedRectangle: RoundedRectangle:
group: "Background_instruction" group: "Background_instruction"
size: self.size size: self.size
@ -66,7 +67,7 @@ Builder.load_string(
) )
class BackgroundColorBehavior: class BackgroundColorBehavior(CommonElevationBehavior):
background = StringProperty() background = StringProperty()
""" """
Background image path. Background image path.
@ -152,26 +153,15 @@ class BackgroundColorBehavior:
_background_x = NumericProperty(0) _background_x = NumericProperty(0)
_background_y = NumericProperty(0) _background_y = NumericProperty(0)
_background_origin = ReferenceListProperty(_background_x, _background_y) _background_origin = ReferenceListProperty(
_md_bg_color = ColorProperty([0, 0, 0, 0]) _background_x,
_background_y,
)
def __init__(self, **kwarg): def __init__(self, **kwarg):
super().__init__(**kwarg) super().__init__(**kwarg)
self.bind(pos=self.update_background_origin) self.bind(pos=self.update_background_origin)
def on_md_bg_color(self, instance_md_widget, color: Union[list, str]):
if (
hasattr(self, "theme_cls")
and self.theme_cls.theme_style_switch_animation
):
Animation(
_md_bg_color=color,
d=self.theme_cls.theme_style_switch_animation_duration,
t="linear",
).start(self)
else:
self._md_bg_color = color
def update_background_origin( def update_background_origin(
self, instance_md_widget, pos: List[float] self, instance_md_widget, pos: List[float]
) -> None: ) -> None:
@ -216,14 +206,12 @@ class SpecificBackgroundColorBehavior(BackgroundColorBehavior):
super().__init__(**kwargs) super().__init__(**kwargs)
if hasattr(self, "theme_cls"): if hasattr(self, "theme_cls"):
self.theme_cls.bind( self.theme_cls.bind(
primary_palette=self._update_specific_text_color, primary_palette=self._update_specific_text_color
accent_palette=self._update_specific_text_color,
theme_style=self._update_specific_text_color,
) )
self.bind( self.theme_cls.bind(accent_palette=self._update_specific_text_color)
background_hue=self._update_specific_text_color, self.theme_cls.bind(theme_style=self._update_specific_text_color)
background_palette=self._update_specific_text_color, self.bind(background_hue=self._update_specific_text_color)
) self.bind(background_palette=self._update_specific_text_color)
self._update_specific_text_color(None, None) self._update_specific_text_color(None, None)
def _update_specific_text_color( def _update_specific_text_color(
@ -246,17 +234,5 @@ class SpecificBackgroundColorBehavior(BackgroundColorBehavior):
secondary_color[3] = 0.54 secondary_color[3] = 0.54
else: else:
secondary_color[3] = 0.7 secondary_color[3] = 0.7
self.specific_text_color = color
if ( self.specific_secondary_text_color = secondary_color
hasattr(self, "theme_cls")
and self.theme_cls.theme_style_switch_animation
):
Animation(
specific_text_color=color,
specific_secondary_text_color=secondary_color,
d=self.theme_cls.theme_style_switch_animation_duration,
t="linear",
).start(self)
else:
self.specific_text_color = color
self.specific_secondary_text_color = secondary_color

File diff suppressed because it is too large Load Diff

View File

@ -111,7 +111,7 @@ from kivy.properties import (
from kivy.uix.behaviors import ToggleButtonBehavior from kivy.uix.behaviors import ToggleButtonBehavior
class CommonRipple: class CommonRipple(object):
"""Base class for ripple effect.""" """Base class for ripple effect."""
ripple_rad_default = NumericProperty(1) ripple_rad_default = NumericProperty(1)

View File

@ -1,133 +0,0 @@
"""
Behaviors/Rotate
================
.. versionadded:: 1.1.0
Base class for controlling the rotate of the widget.
.. note:: See `kivy.graphics.Rotate
<https://kivy.org/doc/stable/api-kivy.graphics.html#kivy.graphics.Rotate>`_
for more information.
Kivy
----
.. code-block:: python
from kivy.animation import Animation
from kivy.lang import Builder
from kivy.app import App
from kivy.properties import NumericProperty
from kivy.uix.button import Button
KV = '''
Screen:
RotateButton:
size_hint: .5, .5
pos_hint: {"center_x": .5, "center_y": .5}
on_release: app.change_rotate(self)
canvas.before:
PushMatrix
Rotate:
angle: self.rotate_value_angle
axis: 0, 0, 1
origin: self.center
canvas.after:
PopMatrix
'''
class RotateButton(Button):
rotate_value_angle = NumericProperty(0)
class Test(App):
def build(self):
return Builder.load_string(KV)
def change_rotate(self, instance_button: Button) -> None:
Animation(rotate_value_angle=45, d=0.3).start(instance_button)
Test().run()
KivyMD
------
.. code-block:: python
from kivy.animation import Animation
from kivy.lang import Builder
from kivy.uix.behaviors import ButtonBehavior
from kivymd.app import MDApp
from kivymd.uix.behaviors import RotateBehavior
from kivymd.uix.boxlayout import MDBoxLayout
KV = '''
MDScreen:
RotateBox:
size_hint: .5, .5
pos_hint: {"center_x": .5, "center_y": .5}
on_release: app.change_rotate(self)
md_bg_color: "red"
'''
class RotateBox(ButtonBehavior, RotateBehavior, MDBoxLayout):
pass
class Test(MDApp):
def build(self):
return Builder.load_string(KV)
def change_rotate(self, instance_button: RotateBox) -> None:
Animation(rotate_value_angle=45, d=0.3).start(instance_button)
Test().run()
"""
__all__ = ("RotateBehavior",)
from kivy.lang import Builder
from kivy.properties import ListProperty, NumericProperty
Builder.load_string(
"""
<RotateBehavior>
canvas.before:
PushMatrix
Rotate:
angle: self.rotate_value_angle
axis: tuple(self.rotate_value_axis)
origin: self.center
canvas.after:
PopMatrix
"""
)
class RotateBehavior:
"""Base class for controlling the rotate of the widget."""
rotate_value_angle = NumericProperty(0)
"""
Property for getting/setting the angle of the rotation.
:attr:`rotate_value_angle` is an :class:`~kivy.properties.NumericProperty`
and defaults to `0`.
"""
rotate_value_axis = ListProperty((0, 0, 1))
"""
Property for getting/setting the axis of the rotation.
:attr:`rotate_value_axis` is an :class:`~kivy.properties.ListProperty`
and defaults to `(0, 0, 1)`.
"""

View File

@ -1,156 +0,0 @@
"""
Behaviors/Scale
===============
.. versionadded:: 1.1.0
Base class for controlling the scale of the widget.
.. note:: See `kivy.graphics.Rotate
<https://kivy.org/doc/stable/api-kivy.graphics.html#kivy.graphics.Scale>`_
for more information.
Kivy
----
.. code-block:: python
from kivy.animation import Animation
from kivy.lang import Builder
from kivy.properties import NumericProperty
from kivy.uix.button import Button
from kivy.app import App
KV = '''
Screen:
ScaleButton:
size_hint: .5, .5
pos_hint: {"center_x": .5, "center_y": .5}
on_release: app.change_scale(self)
canvas.before:
PushMatrix
Scale:
x: self.scale_value_x
y: self.scale_value_y
z: self.scale_value_x
origin: self.center
canvas.after:
PopMatrix
'''
class ScaleButton(Button):
scale_value_x = NumericProperty(1)
scale_value_y = NumericProperty(1)
scale_value_z = NumericProperty(1)
class Test(App):
def build(self):
return Builder.load_string(KV)
def change_scale(self, instance_button: Button) -> None:
Animation(
scale_value_x=0.5,
scale_value_y=0.5,
scale_value_z=0.5,
d=0.3,
).start(instance_button)
Test().run()
KivyMD
------
.. code-block:: python
from kivy.animation import Animation
from kivy.lang import Builder
from kivy.uix.behaviors import ButtonBehavior
from kivymd.app import MDApp
from kivymd.uix.behaviors import ScaleBehavior
from kivymd.uix.boxlayout import MDBoxLayout
KV = '''
MDScreen:
ScaleBox:
size_hint: .5, .5
pos_hint: {"center_x": .5, "center_y": .5}
on_release: app.change_scale(self)
md_bg_color: "red"
'''
class ScaleBox(ButtonBehavior, ScaleBehavior, MDBoxLayout):
pass
class Test(MDApp):
def build(self):
return Builder.load_string(KV)
def change_scale(self, instance_button: ScaleBox) -> None:
Animation(
scale_value_x=0.5,
scale_value_y=0.5,
scale_value_z=0.5,
d=0.3,
).start(instance_button)
Test().run()
"""
__all__ = ("ScaleBehavior",)
from kivy.lang import Builder
from kivy.properties import NumericProperty
Builder.load_string(
"""
<ScaleBehavior>
canvas.before:
PushMatrix
Scale:
x: self.scale_value_x
y: self.scale_value_y
z: self.scale_value_x
origin: self.center
canvas.after:
PopMatrix
"""
)
class ScaleBehavior:
"""Base class for controlling the scale of the widget."""
scale_value_x = NumericProperty(1)
"""
X-axis value.
:attr:`scale_value_x` is an :class:`~kivy.properties.NumericProperty`
and defaults to `1`.
"""
scale_value_y = NumericProperty(1)
"""
Y-axis value.
:attr:`scale_value_y` is an :class:`~kivy.properties.NumericProperty`
and defaults to `1`.
"""
scale_value_z = NumericProperty(1)
"""
Z-axis value.
:attr:`scale_value_z` is an :class:`~kivy.properties.NumericProperty`
and defaults to `1`.
"""

View File

@ -1,134 +0,0 @@
"""
Behaviors/Stencil
=================
.. versionadded:: 1.1.0
Base class for controlling the stencil instructions of the widget.
.. note:: See `Stencil instructions
<https://kivy.org/doc/stable/api-kivy.graphics.stencil_instructions.html>`_
for more information.
Kivy
----
.. code-block:: python
from kivy.lang import Builder
from kivy.app import App
KV = '''
Carousel:
Button:
size_hint: .9, .8
pos_hint: {"center_x": .5, "center_y": .5}
canvas.before:
StencilPush
RoundedRectangle:
pos: root.pos
size: root.size
StencilUse
canvas.after:
StencilUnUse
RoundedRectangle:
pos: root.pos
size: root.size
StencilPop
'''
class Test(App):
def build(self):
return Builder.load_string(KV)
Test().run()
KivyMD
------
.. code-block:: python
from kivy.lang import Builder
from kivymd.app import MDApp
from kivymd.uix.behaviors import StencilBehavior
from kivymd.uix.fitimage import FitImage
KV = '''
#:import os os
#:import images_path kivymd.images_path
MDCarousel:
StencilImage:
size_hint: .9, .8
pos_hint: {"center_x": .5, "center_y": .5}
source: os.path.join(images_path, "logo", "kivymd-icon-512.png")
'''
class StencilImage(FitImage, StencilBehavior):
pass
class Test(MDApp):
def build(self):
return Builder.load_string(KV)
Test().run()
"""
__all__ = ("StencilBehavior",)
from kivy.lang import Builder
from kivy.properties import VariableListProperty
Builder.load_string(
"""
<StencilBehavior>
canvas.before:
StencilPush
RoundedRectangle:
pos: root.pos
size: root.size
# FIXME: Sometimes the radius has the value [], which get a
# `GraphicException: Invalid radius value, must be list of tuples/numerics` error
radius: root.radius if root.radius else [0, 0, 0, 0]
StencilUse
canvas.after:
StencilUnUse
RoundedRectangle:
pos: root.pos
size: root.size
# FIXME: Sometimes the radius has the value [], which get a
# `GraphicException: Invalid radius value, must be list of tuples/numerics` error
radius: root.radius if root.radius else [0, 0, 0, 0]
StencilPop
"""
)
class StencilBehavior:
"""Base class for controlling the stencil instructions of the widget."""
radius = VariableListProperty([0], length=4)
"""
Canvas radius.
.. versionadded:: 1.0.0
.. code-block:: python
# Top left corner slice.
MDWidget:
radius: [25, 0, 0, 0]
:attr:`radius` is an :class:`~kivy.properties.VariableListProperty`
and defaults to `[0, 0, 0, 0]`.
"""

View File

@ -14,104 +14,61 @@ example:
pass pass
.. tabs:: .. code-block:: python
.. tab:: Declarative KV style from kivy.lang import Builder
.. code-block:: python from kivymd.app import MDApp
from kivymd.uix.behaviors.toggle_behavior import MDToggleButton
from kivymd.uix.button import MDRectangleFlatButton
from kivy.lang import Builder KV = '''
Screen:
from kivymd.app import MDApp MDBoxLayout:
from kivymd.uix.behaviors.toggle_behavior import MDToggleButton adaptive_size: True
from kivymd.uix.button import MDFlatButton pos_hint: {"center_x": .5, "center_y": .5}
KV = ''' MyToggleButton:
MDScreen: text: "Show ads"
group: "x"
MDBoxLayout: MyToggleButton:
adaptive_size: True text: "Do not show ads"
spacing: "12dp" group: "x"
pos_hint: {"center_x": .5, "center_y": .5}
MyToggleButton: MyToggleButton:
text: "Show ads" text: "Does not matter"
group: "x" group: "x"
'''
MyToggleButton:
text: "Do not show ads"
group: "x"
MyToggleButton:
text: "Does not matter"
group: "x"
'''
class MyToggleButton(MDFlatButton, MDToggleButton): class MyToggleButton(MDRectangleFlatButton, MDToggleButton):
def __init__(self, *args, **kwargs): def __init__(self, **kwargs):
super().__init__(*args, **kwargs) super().__init__(**kwargs)
self.background_down = self.theme_cls.primary_color self.background_down = self.theme_cls.primary_light
class Test(MDApp): class Test(MDApp):
def build(self): def build(self):
self.theme_cls.theme_style = "Dark" return Builder.load_string(KV)
self.theme_cls.primary_palette = "Orange"
return Builder.load_string(KV)
Test().run() Test().run()
.. tab:: Declarative python style
.. code-block:: python
from kivymd.app import MDApp
from kivymd.uix.behaviors.toggle_behavior import MDToggleButton
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.button import MDFlatButton
from kivymd.uix.screen import MDScreen
class MyToggleButton(MDFlatButton, MDToggleButton):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.background_down = self.theme_cls.primary_color
class Test(MDApp):
def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "Orange"
return (
MDScreen(
MDBoxLayout(
MyToggleButton(
text="Show ads",
group="x",
),
MyToggleButton(
text="Do not show ads",
group="x",
),
MyToggleButton(
text="Does not matter",
group="x",
),
adaptive_size=True,
spacing="12dp",
pos_hint={"center_x": .5, "center_y": .5},
),
)
)
Test().run()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/toggle-button-1.gif .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/toggle-button-1.gif
:align: center :align: center
.. code-block:: python
class MyToggleButton(MDFillRoundFlatButton, MDToggleButton):
def __init__(self, **kwargs):
self.background_down = MDApp.get_running_app().theme_cls.primary_dark
super().__init__(**kwargs)
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/toggle-button-2.gif
:align: center
You can inherit the ``MyToggleButton`` class only from the following classes You can inherit the ``MyToggleButton`` class only from the following classes
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
@ -131,7 +88,6 @@ from kivy.properties import BooleanProperty, ColorProperty
from kivy.uix.behaviors import ToggleButtonBehavior from kivy.uix.behaviors import ToggleButtonBehavior
from kivymd.uix.button import ( from kivymd.uix.button import (
ButtonContentsIconText,
MDFillRoundFlatButton, MDFillRoundFlatButton,
MDFillRoundFlatIconButton, MDFillRoundFlatIconButton,
MDFlatButton, MDFlatButton,
@ -193,8 +149,7 @@ class MDToggleButton(ToggleButtonBehavior):
# Do the object inherited from the "supported" buttons? # Do the object inherited from the "supported" buttons?
if not issubclass(self.__class__, classinfo): if not issubclass(self.__class__, classinfo):
raise ValueError( raise ValueError(
f"Class {self.__class__} must be inherited from one of the " f"Class {self.__class__} must be inherited from one of the classes in the list {classinfo}"
f"classes in the list {classinfo}"
) )
if ( if (
not self.background_normal not self.background_normal
@ -210,12 +165,10 @@ class MDToggleButton(ToggleButtonBehavior):
): ):
self.__is_filled = True self.__is_filled = True
self.background_normal = self.theme_cls.primary_color self.background_normal = self.theme_cls.primary_color
# If not background_normal must be the same as the inherited one. # If not the background_normal must be the same as the inherited one:
else: else:
self.background_normal = ( self.background_normal = self.md_bg_color[:]
self.md_bg_color[:] if self.md_bg_color else (0, 0, 0, 0) # If no background_down is setted:
)
# If no background_down is setter.
if ( if (
not self.background_down not self.background_down
): # This means that if the value == [] or None will return True. ): # This means that if the value == [] or None will return True.
@ -247,6 +200,3 @@ class MDToggleButton(ToggleButtonBehavior):
): # If the background is transparent, the font color must be the ): # If the background is transparent, the font color must be the
# primary color. # primary color.
self.text_color = self.font_color_normal self.text_color = self.font_color_normal
if issubclass(self.__class__, ButtonContentsIconText):
self.icon_color = self.text_color

View File

@ -1,3 +1,4 @@
#:import sm kivy.uix.screenmanager
#:import STANDARD_INCREMENT kivymd.material_resources.STANDARD_INCREMENT #:import STANDARD_INCREMENT kivymd.material_resources.STANDARD_INCREMENT
@ -6,9 +7,9 @@
height: height:
STANDARD_INCREMENT if app.theme_cls.material_style == "M2" else "80dp" STANDARD_INCREMENT if app.theme_cls.material_style == "M2" else "80dp"
ScreenManager: MDScreenManager:
id: tab_manager id: tab_manager
transition: root.transition(duration=root.transition_duration) transition: sm.FadeTransition(duration=.2)
on_current: on_current:
root.dispatch( \ root.dispatch( \
"on_switch_tabs", \ "on_switch_tabs", \
@ -95,7 +96,7 @@
radius: [16,] radius: [16,]
size: root._selected_region_width, dp(32) size: root._selected_region_width, dp(32)
pos: pos:
self.center_x - root._selected_region_width / 2, \ self.center_x - self.width - dp(8), \
self.center_y - (dp(16)) self.center_y - (dp(16))
MDLabel: MDLabel:

View File

@ -62,120 +62,59 @@ For ease of understanding, this code works like this:
Example Example
------- -------
.. tabs:: .. code-block:: python
.. tab:: Declarative KV style from kivy.lang import Builder
.. code-block:: python from kivymd.app import MDApp
from kivy.lang import Builder
from kivymd.app import MDApp
class Test(MDApp): class Test(MDApp):
def build(self): def build(self):
self.theme_cls.material_style = "M3" self.theme_cls.material_style = "M3"
self.theme_cls.theme_style = "Dark" return Builder.load_string(
return Builder.load_string( '''
''' MDScreen:
MDScreen:
MDBottomNavigation: MDBottomNavigation:
#panel_color: "#eeeaea" panel_color: "#eeeaea"
selected_color_background: "orange" selected_color_background: "#97ecf8"
text_color_active: "lightgrey" text_color_active: 0, 0, 0, 1
MDBottomNavigationItem: MDBottomNavigationItem:
name: 'screen 1' name: 'screen 1'
text: 'Mail' text: 'Mail'
icon: 'gmail' icon: 'gmail'
badge_icon: "numeric-10" badge_icon: "numeric-10"
MDLabel: MDLabel:
text: 'Mail' text: 'Mail'
halign: 'center' halign: 'center'
MDBottomNavigationItem: MDBottomNavigationItem:
name: 'screen 2' name: 'screen 2'
text: 'Twitter' text: 'Discord'
icon: 'twitter' icon: 'discord'
badge_icon: "numeric-5" badge_icon: "numeric-5"
MDLabel: MDLabel:
text: 'Twitter' text: 'Discord'
halign: 'center' halign: 'center'
MDBottomNavigationItem: MDBottomNavigationItem:
name: 'screen 3' name: 'screen 3'
text: 'LinkedIN' text: 'LinkedIN'
icon: 'linkedin' icon: 'linkedin'
MDLabel: MDLabel:
text: 'LinkedIN' text: 'LinkedIN'
halign: 'center' halign: 'center'
''' '''
) )
Test().run() Test().run()
.. tab:: Declarative python style
.. code-block:: python
from kivymd.app import MDApp
from kivymd.uix.bottomnavigation import MDBottomNavigation, MDBottomNavigationItem
from kivymd.uix.label import MDLabel
from kivymd.uix.screen import MDScreen
class Test(MDApp):
def build(self):
self.theme_cls.material_style = "M3"
self.theme_cls.theme_style = "Dark"
return (
MDScreen(
MDBottomNavigation(
MDBottomNavigationItem(
MDLabel(
text='Mail',
halign='center',
),
name='screen 1',
text='Mail',
icon='gmail',
badge_icon="numeric-10",
),
MDBottomNavigationItem(
MDLabel(
text='Twitter',
halign='center',
),
name='screen 1',
text='Twitter',
icon='twitter',
badge_icon="numeric-10",
),
MDBottomNavigationItem(
MDLabel(
text='LinkedIN',
halign='center',
),
name='screen 1',
text='LinkedIN',
icon='linkedin',
badge_icon="numeric-10",
),
selected_color_background="orange",
text_color_active="lightgrey",
)
)
)
Test().run()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bottom-navigation.gif .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/bottom-navigation.gif
:align: center :align: center
@ -253,13 +192,16 @@ from kivy.properties import (
) )
from kivy.uix.behaviors import ButtonBehavior from kivy.uix.behaviors import ButtonBehavior
from kivy.uix.boxlayout import BoxLayout from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import FadeTransition, ScreenManagerException from kivy.uix.screenmanager import ScreenManagerException
from kivymd import uix_path from kivymd import uix_path
from kivymd.material_resources import STANDARD_INCREMENT from kivymd.material_resources import STANDARD_INCREMENT
from kivymd.theming import ThemableBehavior, ThemeManager from kivymd.theming import ThemableBehavior, ThemeManager
from kivymd.uix.anchorlayout import MDAnchorLayout from kivymd.uix.anchorlayout import MDAnchorLayout
from kivymd.uix.behaviors import CommonElevationBehavior, DeclarativeBehavior from kivymd.uix.behaviors import (
DeclarativeBehavior,
FakeRectangularElevationBehavior,
)
from kivymd.uix.behaviors.backgroundcolor_behavior import ( from kivymd.uix.behaviors.backgroundcolor_behavior import (
SpecificBackgroundColorBehavior, SpecificBackgroundColorBehavior,
) )
@ -471,28 +413,6 @@ class MDBottomNavigationItem(MDTab):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
def animate_header(
self, bottom_navigation_object, bottom_navigation_header_object
) -> None:
if bottom_navigation_object.use_text:
Animation(_label_font_size=sp(12), d=0.1).start(
bottom_navigation_object.previous_tab.header
)
Animation(
_selected_region_width=0,
t="in_out_sine",
d=0,
).start(bottom_navigation_header_object)
Animation(
_text_color_normal=bottom_navigation_header_object.text_color_normal
if bottom_navigation_object.previous_tab.header.text_color_normal
!= [1, 1, 1, 1]
else self.theme_cls.disabled_hint_text_color,
d=0.1,
).start(bottom_navigation_object.previous_tab.header)
bottom_navigation_object.previous_tab.header.active = False
self.header.active = True
def on_tab_press(self, *args) -> None: def on_tab_press(self, *args) -> None:
"""Called when clicking on a panel item.""" """Called when clicking on a panel item."""
@ -500,13 +420,28 @@ class MDBottomNavigationItem(MDTab):
bottom_navigation_header_object = ( bottom_navigation_header_object = (
bottom_navigation_object.previous_tab.header bottom_navigation_object.previous_tab.header
) )
bottom_navigation_object.ids.tab_manager.current = self.name
if bottom_navigation_object.previous_tab is not self: if bottom_navigation_object.previous_tab is not self:
self.animate_header( if bottom_navigation_object.use_text:
bottom_navigation_object, bottom_navigation_header_object Animation(_label_font_size=sp(12), d=0.1).start(
) bottom_navigation_object.previous_tab.header
)
super().on_tab_press(*args) Animation(
_selected_region_width=0,
t="in_out_sine",
d=0,
).start(bottom_navigation_header_object)
Animation(
_text_color_normal=bottom_navigation_header_object.text_color_normal
if bottom_navigation_object.previous_tab.header.text_color_normal
!= [1, 1, 1, 1]
else self.theme_cls.disabled_hint_text_color,
d=0.1,
).start(bottom_navigation_object.previous_tab.header)
bottom_navigation_object.previous_tab.header.active = False
self.header.active = True
bottom_navigation_object.previous_tab = self
def on_disabled( def on_disabled(
self, instance_bottom_navigation_item, disabled_value: bool self, instance_bottom_navigation_item, disabled_value: bool
@ -563,26 +498,6 @@ class MDBottomNavigation(DeclarativeBehavior, TabbedPanelBase):
.. versionadded:: 1.0.0 .. versionadded:: 1.0.0
""" """
transition = ObjectProperty(FadeTransition)
"""
Transition animation of bottom navigation screen manager.
.. versionadded:: 1.1.0
:attr:`transition` is an :class:`~kivy.properties.ObjectProperty`
and defaults to `FadeTransition`.
"""
transition_duration = NumericProperty(0.2)
"""
Duration animation of bottom navigation screen manager.
.. versionadded:: 1.1.0
:attr:`transition_duration` is an :class:`~kivy.properties.NumericProperty`
and defaults to `0.2`.
"""
text_color_normal = ColorProperty([1, 1, 1, 1]) text_color_normal = ColorProperty([1, 1, 1, 1])
""" """
Text color of the label when it is not selected. Text color of the label when it is not selected.
@ -857,6 +772,8 @@ class MDBottomNavigation(DeclarativeBehavior, TabbedPanelBase):
class MDBottomNavigationBar( class MDBottomNavigationBar(
ThemableBehavior, CommonElevationBehavior, MDFloatLayout ThemableBehavior,
FakeRectangularElevationBehavior,
MDFloatLayout,
): ):
pass pass

View File

@ -34,7 +34,7 @@ Usage :class:`~MDListBottomSheet`
MDTopAppBar: MDTopAppBar:
title: "Example BottomSheet" title: "Example BottomSheet"
pos_hint: {"top": 1} pos_hint: {"top": 1}
elevation: 4 elevation: 10
MDRaisedButton: MDRaisedButton:
text: "Open list bottom sheet" text: "Open list bottom sheet"
@ -94,7 +94,7 @@ which will be used as an icon to the left of the item:
MDTopAppBar: MDTopAppBar:
title: 'Example BottomSheet' title: 'Example BottomSheet'
pos_hint: {"top": 1} pos_hint: {"top": 1}
elevation: 4 elevation: 10
MDRaisedButton: MDRaisedButton:
text: "Open grid bottom sheet" text: "Open grid bottom sheet"
@ -180,7 +180,7 @@ which will be used as an icon to the left of the item:
MDTopAppBar: MDTopAppBar:
title: 'Example BottomSheet' title: 'Example BottomSheet'
pos_hint: {"top": 1} pos_hint: {"top": 1}
elevation: 4 elevation: 10
MDRaisedButton: MDRaisedButton:
text: "Open custom bottom sheet" text: "Open custom bottom sheet"

View File

@ -93,8 +93,6 @@ from kivymd.uix.behaviors import DeclarativeBehavior
class MDBoxLayout(DeclarativeBehavior, BoxLayout, MDAdaptiveWidget): class MDBoxLayout(DeclarativeBehavior, BoxLayout, MDAdaptiveWidget):
""" """
Box layout class. Box layout class. For more information, see in the
For more information, see in the
:class:`~kivy.uix.boxlayout.BoxLayout` class documentation. :class:`~kivy.uix.boxlayout.BoxLayout` class documentation.
""" """

View File

@ -1,7 +1,6 @@
# NOQA F401 # NOQA F401
from .button import ( from .button import (
BaseButton, BaseButton,
ButtonContentsIconText,
MDFillRoundFlatButton, MDFillRoundFlatButton,
MDFillRoundFlatIconButton, MDFillRoundFlatIconButton,
MDFlatButton, MDFlatButton,

View File

@ -3,9 +3,9 @@
Clear Clear
Color: Color:
rgba: rgba:
self._md_bg_color \ (self._md_bg_color or [0.0, 0.0, 0.0, 0.0]) \
if not self.disabled else \ if not self.disabled else \
self._md_bg_color_disabled (self._md_bg_color_disabled or [0.0, 0.0, 0.0, 0.0])
RoundedRectangle: RoundedRectangle:
size: self.size size: self.size
pos: self.pos pos: self.pos
@ -13,17 +13,19 @@
radius: [root._radius, ] radius: [root._radius, ]
Color: Color:
rgba: rgba:
root._line_color \ root._line_color or [0.0, 0.0, 0.0, 0.0] \
if not root.disabled else \ if not root.disabled else \
(root._line_color_disabled or self._disabled_color) ( \
root._line_color_disabled \
or self._disabled_color \
or [0.0, 0.0, 0.0, 0.0] \
)
Line: Line:
width: root.line_width width: root.line_width
rounded_rectangle: rounded_rectangle:
( \ (self.x, self.y, self.width, self.height, \
self.x, self.y, self.width, self.height, \
root._radius, root._radius, root._radius, root._radius, \ root._radius, root._radius, root._radius, root._radius, \
self.height \ self.height)
)
size_hint: None, None size_hint: None, None
anchor_x: root.halign anchor_x: root.halign
@ -31,28 +33,21 @@
_round_rad: [self._radius] * 4 _round_rad: [self._radius] * 4
<ButtonContentsText> <ButtonContentsText>
lbl_txt: lbl_txt lbl_txt: lbl_txt
width: width:
max( \ max(root._min_width, \
root._min_width, \ root.padding[0] + lbl_txt.texture_size[0] + root.padding[2])
root.padding[0] + lbl_txt.texture_size[0] + root.padding[2] \
)
size_hint_min_x: size_hint_min_x:
max( \ max(root._min_width, \
root._min_width, \ root.padding[0] + lbl_txt.texture_size[0] + root.padding[2])
root.padding[0] + lbl_txt.texture_size[0] + root.padding[2] \
)
height: height:
max( \ max(root._min_height, \
root._min_height, \ root.padding[1] + lbl_txt.texture_size[1] + root.padding[3])
root.padding[1] + lbl_txt.texture_size[1] + root.padding[3] \
)
size_hint_min_y: size_hint_min_y:
max( \ max(root._min_height, \
root._min_height, \ root.padding[1] + lbl_txt.texture_size[1] + root.padding[3])
root.padding[1] + lbl_txt.texture_size[1] + root.padding[3] \
)
MDLabel: MDLabel:
id: lbl_txt id: lbl_txt
@ -89,10 +84,7 @@
# This is only a temporary fix and does not fix the cause of the error. # This is only a temporary fix and does not fix the cause of the error.
(root._icon_color if root._icon_color else root.theme_cls.text_color) \ (root._icon_color if root._icon_color else root.theme_cls.text_color) \
if not root.disabled else \ if not root.disabled else \
root.theme_cls.disabled_hint_text_color \ root.theme_cls.disabled_hint_text_color
if not root.disabled_color else \
root.disabled_color
on_icon: on_icon:
if self.icon not in md_icons.keys(): self.size_hint = (1, 1) if self.icon not in md_icons.keys(): self.size_hint = (1, 1)
theme_text_color: root._theme_icon_color theme_text_color: root._theme_icon_color
@ -139,7 +131,7 @@
id: box id: box
adaptive_size: True adaptive_size: True
padding: 0 padding: 0
spacing: "8dp" spacing: "4dp"
MDIcon: MDIcon:
id: lbl_ic id: lbl_ic
@ -201,21 +193,48 @@
radius: [self.height / 2] radius: [self.height / 2]
<MDFloatingRootButton> <BaseFloatingRootButton>
theme_text_color: "Custom" theme_text_color: "Custom"
md_bg_color: self.theme_cls.primary_color md_bg_color: self.theme_cls.primary_color
<MDFloatingLabel>
padding_x: "8dp"
padding_y: "8dp"
adaptive_size: True
theme_text_color: "Custom"
canvas.before: canvas.before:
PushMatrix
Rotate:
angle: self._angle
axis: (0, 0, 1)
origin: self.center
canvas.after:
PopMatrix
# FIXME: Use :class:`~kivymd.uix.boxlayout.MDBoxLayout` instead
# :class:`~kivy.uix.boxlayout.BoxLayout`.
<BaseFloatingLabel>
size_hint: None, None
padding: "8dp", "4dp", "8dp", "4dp"
height: label.texture_size[1] + self.padding[1] * 2
width: label.texture_size[0] + self.padding[0] * 2
elevation: 10
# TODO: Use `md_bg_color` and `radius` instead `canvasю
canvas:
Color: Color:
rgba: self.bg_color rgba:
self.theme_cls.primary_color \
if not root.bg_color else \
root.bg_color
RoundedRectangle: RoundedRectangle:
size: self.size
pos: self.pos pos: self.pos
radius: self.radius size: self.size
radius: [5]
Label:
id: label
markup: True
text: root.text
size_hint: None, None
size: self.texture_size
color:
root.theme_cls.text_color \
if not root.text_color else \
root.text_color

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,17 @@
md_bg_color: app.theme_cls.divider_color md_bg_color: app.theme_cls.divider_color
<MDCard>
canvas.before:
Color:
rgba: self.md_bg_color
RoundedRectangle:
size: self.size
pos: self.pos
radius: root.radius
source: root.background
<MDSeparator> <MDSeparator>
md_bg_color: md_bg_color:
self.theme_cls.divider_color \ self.theme_cls.divider_color \

View File

@ -26,6 +26,26 @@ Components/Card
MDCard MDCard
------ ------
.. warning:: Starting from the KivyMD 1.1.0 library version, it is necessary
to manually inherit the card class from one of the ``Elevation`` classes
from ``kivymd/uix/behaviors/elevation.py`` module to draw the card shadow.
.. code-block:: python
from kivymd.uix.behaviors import RoundedRectangularElevationBehavior
from kivymd.uix.card import MDCard
class MD3Card(MDCard, RoundedRectangularElevationBehavior):
'''Implements a material design v3 card.'''
It actually allows for better control over the providers that implement the
rendering of the shadows.
.. note:: You can read more information about the classes that implement the
rendering of shadows on this
`documentation page <https://kivymd.readthedocs.io/en/latest/behaviors/elevation/>`_.
An example of the implementation of a card in the style of material design version 3 An example of the implementation of a card in the style of material design version 3
------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------
@ -39,6 +59,7 @@ An example of the implementation of a card in the style of material design versi
from kivy.properties import StringProperty from kivy.properties import StringProperty
from kivymd.app import MDApp from kivymd.app import MDApp
from kivymd.uix.behaviors import RoundedRectangularElevationBehavior
from kivymd.uix.card import MDCard from kivymd.uix.card import MDCard
KV = ''' KV = '''
@ -72,7 +93,7 @@ An example of the implementation of a card in the style of material design versi
''' '''
class MD3Card(MDCard): class MD3Card(MDCard, RoundedRectangularElevationBehavior):
'''Implements a material design v3 card.''' '''Implements a material design v3 card.'''
text = StringProperty() text = StringProperty()
@ -105,6 +126,7 @@ An example of the implementation of a card in the style of material design versi
.. code-block:: python .. code-block:: python
from kivymd.app import MDApp from kivymd.app import MDApp
from kivymd.uix.behaviors import RoundedRectangularElevationBehavior
from kivymd.uix.boxlayout import MDBoxLayout from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.button import MDIconButton from kivymd.uix.button import MDIconButton
from kivymd.uix.card import MDCard from kivymd.uix.card import MDCard
@ -113,7 +135,7 @@ An example of the implementation of a card in the style of material design versi
from kivymd.uix.screen import MDScreen from kivymd.uix.screen import MDScreen
class MD3Card(MDCard): class MD3Card(MDCard, RoundedRectangularElevationBehavior):
'''Implements a material design v3 card.''' '''Implements a material design v3 card.'''
@ -148,6 +170,7 @@ An example of the implementation of a card in the style of material design versi
adaptive_size=True, adaptive_size=True,
color="grey", color="grey",
pos=("12dp", "12dp"), pos=("12dp", "12dp"),
bold=True,
), ),
), ),
line_color=(0.2, 0.2, 0.2, 0.8), line_color=(0.2, 0.2, 0.2, 0.8),
@ -232,9 +255,10 @@ End full code
MDBoxLayout: MDBoxLayout:
orientation: "vertical" orientation: "vertical"
spacing: "10dp"
MDTopAppBar: MDTopAppBar:
elevation: 4 elevation: 10
title: "MDCardSwipe" title: "MDCardSwipe"
MDScrollView: MDScrollView:
@ -262,7 +286,7 @@ End full code
'''Creates a list of cards.''' '''Creates a list of cards.'''
for i in range(20): for i in range(20):
self.root.ids.md_list.add_widget( self.screen.ids.md_list.add_widget(
SwipeToDeleteItem(text=f"One-line item {i}") SwipeToDeleteItem(text=f"One-line item {i}")
) )
@ -292,7 +316,7 @@ End full code
MDScreen( MDScreen(
MDBoxLayout( MDBoxLayout(
MDTopAppBar( MDTopAppBar(
elevation=4, elevation=10,
title="MDCardSwipe", title="MDCardSwipe",
), ),
MDScrollView( MDScrollView(
@ -304,6 +328,7 @@ End full code
), ),
id="box", id="box",
orientation="vertical", orientation="vertical",
spacing="10dp",
), ),
) )
) )
@ -401,7 +426,7 @@ You can use this event to remove items from a list:
.. code-block:: python .. code-block:: python
def on_swipe_complete(self, instance): def on_swipe_complete(self, instance):
self.root.ids.md_list.remove_widget(instance) self.screen.ids.md_list.remove_widget(instance)
.. tab:: Decralative python styles .. tab:: Decralative python styles
@ -471,9 +496,10 @@ End full code
MDBoxLayout: MDBoxLayout:
orientation: "vertical" orientation: "vertical"
spacing: "10dp"
MDTopAppBar: MDTopAppBar:
elevation: 4 elevation: 10
title: "MDCardSwipe" title: "MDCardSwipe"
MDScrollView: MDScrollView:
@ -534,7 +560,7 @@ End full code
MDScreen( MDScreen(
MDBoxLayout( MDBoxLayout(
MDTopAppBar( MDTopAppBar(
elevation=4, elevation=10,
title="MDCardSwipe", title="MDCardSwipe",
), ),
MDScrollView( MDScrollView(
@ -546,6 +572,7 @@ End full code
), ),
id="box", id="box",
orientation="vertical", orientation="vertical",
spacing="10dp",
), ),
) )
) )
@ -603,21 +630,26 @@ Focus behavior
from kivy.lang import Builder from kivy.lang import Builder
from kivymd.app import MDApp from kivymd.app import MDApp
from kivymd.uix.behaviors import FakeRectangularElevationBehavior
from kivymd.uix.card import MDCard
KV = ''' KV = '''
MDScreen: MDScreen:
MDCard: ElevationCard:
size_hint: .7, .4 size_hint: .7, .4
focus_behavior: True focus_behavior: True
pos_hint: {"center_x": .5, "center_y": .5} pos_hint: {"center_x": .5, "center_y": .5}
md_bg_color: "darkgrey" md_bg_color: "darkgrey"
unfocus_color: "darkgrey" unfocus_color: "darkgrey"
focus_color: "grey" focus_color: "grey"
elevation: 6
''' '''
class ElevationCard(MDCard, FakeRectangularElevationBehavior):
pass
class Example(MDApp): class Example(MDApp):
def build(self): def build(self):
self.theme_cls.theme_style = "Dark" self.theme_cls.theme_style = "Dark"
@ -631,23 +663,27 @@ Focus behavior
.. code-block:: python .. code-block:: python
from kivymd.app import MDApp from kivymd.app import MDApp
from kivymd.uix.behaviors import FakeRectangularElevationBehavior
from kivymd.uix.card import MDCard from kivymd.uix.card import MDCard
from kivymd.uix.screen import MDScreen from kivymd.uix.screen import MDScreen
class ElevationCard(MDCard, FakeRectangularElevationBehavior):
pass
class Example(MDApp): class Example(MDApp):
def build(self): def build(self):
self.theme_cls.theme_style = "Dark" self.theme_cls.theme_style = "Dark"
return ( return (
MDScreen( MDScreen(
MDCard( ElevationCard(
size_hint=(0.7, 0.4), size_hint=(0.7, 0.4),
focus_behavior=True, focus_behavior=True,
pos_hint={"center_x": 0.5, "center_y": 0.5}, pos_hint={"center_x": 0.5, "center_y": 0.5},
md_bg_color="darkgrey", md_bg_color="darkgrey",
unfocus_color="darkgrey", unfocus_color="darkgrey",
focus_color="grey", focus_color="grey",
elevation=6,
), ),
) )
) )
@ -655,6 +691,7 @@ Focus behavior
Example().run() Example().run()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/card-focus.gif .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/card-focus.gif
:align: center :align: center
@ -695,14 +732,12 @@ from kivy.properties import (
VariableListProperty, VariableListProperty,
) )
from kivy.uix.boxlayout import BoxLayout from kivy.uix.boxlayout import BoxLayout
from kivy.utils import get_color_from_hex
from kivymd import uix_path from kivymd import uix_path
from kivymd.color_definitions import colors from kivymd.color_definitions import colors
from kivymd.theming import ThemableBehavior from kivymd.theming import ThemableBehavior
from kivymd.uix.behaviors import ( from kivymd.uix.behaviors import (
BackgroundColorBehavior, BackgroundColorBehavior,
CommonElevationBehavior,
DeclarativeBehavior, DeclarativeBehavior,
RectangularRippleBehavior, RectangularRippleBehavior,
) )
@ -746,7 +781,6 @@ class MDCard(
ThemableBehavior, ThemableBehavior,
BackgroundColorBehavior, BackgroundColorBehavior,
RectangularRippleBehavior, RectangularRippleBehavior,
CommonElevationBehavior,
FocusBehavior, FocusBehavior,
BoxLayout, BoxLayout,
): ):
@ -766,6 +800,14 @@ class MDCard(
and defaults to `False`. and defaults to `False`.
""" """
elevation = NumericProperty(None, allownone=True)
"""
Elevation value.
:attr:`elevation` is an :class:`~kivy.properties.NumericProperty`
and defaults to 1.
"""
radius = VariableListProperty([dp(6), dp(6), dp(6), dp(6)]) radius = VariableListProperty([dp(6), dp(6), dp(6), dp(6)])
""" """
Card radius by default. Card radius by default.
@ -789,16 +831,15 @@ class MDCard(
""" """
_bg_color_map = ( _bg_color_map = (
get_color_from_hex(colors["Light"]["CardsDialogs"]), colors["Light"]["CardsDialogs"],
get_color_from_hex(colors["Dark"]["CardsDialogs"]), colors["Dark"]["CardsDialogs"],
[1.0, 1.0, 1.0, 0.0], [1.0, 1.0, 1.0, 0.0],
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.theme_cls.bind( self.theme_cls.bind(theme_style=self.update_md_bg_color)
material_style=self.set_style, theme_style=self.update_md_bg_color self.theme_cls.bind(material_style=self.set_style)
)
Clock.schedule_once(self.set_style) Clock.schedule_once(self.set_style)
Clock.schedule_once( Clock.schedule_once(
lambda x: self.on_ripple_behavior(0, self.ripple_behavior) lambda x: self.on_ripple_behavior(0, self.ripple_behavior)
@ -807,9 +848,7 @@ class MDCard(
def update_md_bg_color(self, instance_card, theme_style: str) -> None: def update_md_bg_color(self, instance_card, theme_style: str) -> None:
if self.md_bg_color in self._bg_color_map: if self.md_bg_color in self._bg_color_map:
self.md_bg_color = get_color_from_hex( self.md_bg_color = colors[theme_style]["CardsDialogs"]
colors[theme_style]["CardsDialogs"]
)
def set_style(self, *args) -> None: def set_style(self, *args) -> None:
self.set_radius() self.set_radius()
@ -826,7 +865,7 @@ class MDCard(
if self.style == "outlined" or self.style == "filled": if self.style == "outlined" or self.style == "filled":
self.elevation = 0 self.elevation = 0
elif self.style == "elevated": elif self.style == "elevated":
self.elevation = 2 self.elevation = 1
def set_radius(self) -> None: def set_radius(self) -> None:
if ( if (

View File

@ -132,7 +132,7 @@ Use with elevation
icon_right: "close-circle-outline" icon_right: "close-circle-outline"
line_color: app.theme_cls.disabled_hint_text_color line_color: app.theme_cls.disabled_hint_text_color
md_bg_color: 1, 0, 0, .5 md_bg_color: 1, 0, 0, .5
elevation: 4 elevation: 12
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/chip-with-elevation.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/chip-with-elevation.png
:align: center :align: center
@ -304,6 +304,7 @@ __all__ = ("MDChip",)
import os import os
from kivy import Logger
from kivy.animation import Animation from kivy.animation import Animation
from kivy.lang import Builder from kivy.lang import Builder
from kivy.metrics import dp from kivy.metrics import dp
@ -313,13 +314,14 @@ from kivy.uix.behaviors import ButtonBehavior
from kivymd import uix_path from kivymd import uix_path
from kivymd.theming import ThemableBehavior from kivymd.theming import ThemableBehavior
from kivymd.uix.behaviors import ( from kivymd.uix.behaviors import (
CommonElevationBehavior, FakeRectangularElevationBehavior,
RectangularRippleBehavior, RectangularRippleBehavior,
ScaleBehavior,
TouchBehavior, TouchBehavior,
) )
from kivymd.uix.boxlayout import MDBoxLayout from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.label import MDIcon from kivymd.uix.label import MDIcon
from kivymd.uix.stacklayout import MDStackLayout
from kivymd.uix.templates import ScaleWidget
with open( with open(
os.path.join(uix_path, "chip", "chip.kv"), encoding="utf-8" os.path.join(uix_path, "chip", "chip.kv"), encoding="utf-8"
@ -328,12 +330,12 @@ with open(
class MDChip( class MDChip(
MDBoxLayout,
ThemableBehavior, ThemableBehavior,
RectangularRippleBehavior, RectangularRippleBehavior,
ButtonBehavior, FakeRectangularElevationBehavior,
CommonElevationBehavior,
TouchBehavior, TouchBehavior,
ButtonBehavior,
MDBoxLayout,
): ):
text = StringProperty() text = StringProperty()
""" """
@ -454,7 +456,7 @@ class MDChip(
self.active = False self.active = False
class MDScalableCheckIcon(MDIcon, ScaleBehavior): class MDScalableCheckIcon(MDIcon, ScaleWidget):
pos_hint = {"center_y": 0.5} pos_hint = {"center_y": 0.5}

View File

@ -1,4 +1,5 @@
#:import DEVICE_TYPE kivymd.material_resources.DEVICE_TYPE #:import DEVICE_TYPE kivymd.material_resources.DEVICE_TYPE
#:import FakeRectangularElevationBehavior kivymd.uix.behaviors.FakeRectangularElevationBehavior
<CellRow> <CellRow>
@ -65,7 +66,7 @@
size_hint_y: None size_hint_y: None
height: self.minimum_height height: self.minimum_height
spacing: "4dp" spacing: "4dp"
tooltip_text: root.tooltip if root.tooltip else root.text tooltip_text: root.text
BoxLayout: BoxLayout:
id: box id: box
@ -174,11 +175,7 @@
font_size: "14sp" font_size: "14sp"
on_release: root.table_data.open_pagination_menu() on_release: root.table_data.open_pagination_menu()
text: text:
"{}".format( \ f"{root.table_data.rows_num if root.table_data.rows_num < len(root.table_data.row_data) else len(root.table_data.row_data)}"
root.table_data.rows_num \
if root.table_data.rows_num < len(root.table_data.row_data) else \
len(root.table_data.row_data) \
)
Widget: Widget:
size_hint_x: None size_hint_x: None
@ -195,11 +192,9 @@
if root.theme_cls.theme_style == "Dark" else \ if root.theme_cls.theme_style == "Dark" else \
(0, 0, 0, 1) (0, 0, 0, 1)
text: text:
"1-{} of {}".format( \ f"1-" \
root.table_data.rows_num \ f"{root.table_data.rows_num if root.table_data.rows_num > len(root.table_data.row_data) else len(root.table_data.row_data)} " \
if root.table_data.rows_num > len(root.table_data.row_data) else \ f"of {len(root.table_data.row_data)}"
len(root.table_data.row_data), len(root.table_data.row_data) \
)
MDIconButton: MDIconButton:
id: button_back id: button_back
@ -222,7 +217,7 @@
on_release: root.table_data.set_next_row_data_parts("forward") on_release: root.table_data.set_next_row_data_parts("forward")
<TableContainer@MDCard> <TableContainer@MDCard+FakeRectangularElevationBehavior>
<MDDataTable> <MDDataTable>

View File

@ -11,6 +11,19 @@ Components/DataTables
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-previous.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-previous.png
:align: center :align: center
Warnings
---------
.. warning:: Data tables are still far from perfect. The class is in constant
change, because of optimizations and bug fixes. If you find a bug or have
an improvement you want to share, take some time and share your discoveries
with us over the main git repo.
Any help is well appreciated.
.. warning:: In versions prior to `Kivy 2.1.0-dev0` exists an error in which is
the table has only one row in the current page, the table will only render
one column instead of the whole row.
.. note:: `MDDataTable` allows developers to sort the data provided by column. .. note:: `MDDataTable` allows developers to sort the data provided by column.
This happens thanks to the use of an external function that you can bind This happens thanks to the use of an external function that you can bind
while you're defining the table columns. Be aware that the sorting function while you're defining the table columns. Be aware that the sorting function
@ -146,15 +159,6 @@ class CellHeader(MDTooltip, BoxLayout):
and defaults to `''`. and defaults to `''`.
""" """
tooltip = StringProperty()
"""
Tooltip containing descriptive text for the column.
If the tooltip is not provided, column `text` shall be used instead.
:attr:`tooltip` is a :class:`~kivy.properties.StringProperty`
and defaults to `''`.
"""
# TODO: Added example. # TODO: Added example.
sort_action = ObjectProperty() sort_action = ObjectProperty()
""" """
@ -336,19 +340,11 @@ class TableHeader(ThemableBehavior, ScrollView):
CellHeader( CellHeader(
text=col_heading[0], text=col_heading[0],
sort_action=col_heading[2], sort_action=col_heading[2],
tooltip=col_heading[3],
width=self.cols_minimum[i], width=self.cols_minimum[i],
table_data=self.table_data, table_data=self.table_data,
is_sorted=(col_heading[0] == self.sorted_on), is_sorted=(col_heading[0] == self.sorted_on),
sorted_order=self.sorted_order, sorted_order=self.sorted_order,
) )
if len(col_heading) == 4
else CellHeader(
text=col_heading[0],
sort_action=col_heading[2],
width=self.cols_minimum[i],
table_data=self.table_data,
)
if len(col_heading) == 3 if len(col_heading) == 3
else CellHeader( else CellHeader(
text=col_heading[0], text=col_heading[0],
@ -360,9 +356,6 @@ class TableHeader(ThemableBehavior, ScrollView):
else: else:
# Sets the text in the first cell. # Sets the text in the first cell.
self.ids.first_cell.text = col_heading[0] self.ids.first_cell.text = col_heading[0]
self.ids.first_cell.tooltip = (
col_heading[3] if len(col_heading) == 4 else ""
)
self.ids.first_cell.ids.separator.height = 0 self.ids.first_cell.ids.separator.height = 0
self.ids.first_cell.width = self.cols_minimum[i] self.ids.first_cell.width = self.cols_minimum[i]
@ -772,9 +765,6 @@ class TablePagination(ThemableBehavior, MDBoxLayout):
class MDDataTable(ThemableBehavior, AnchorLayout): class MDDataTable(ThemableBehavior, AnchorLayout):
""" """
See :class:`~kivy.uix.anchorlayout.AnchorLayout` class documentation for
more information.
:Events: :Events:
:attr:`on_row_press` :attr:`on_row_press`
Called when a table row is clicked. Called when a table row is clicked.
@ -785,6 +775,7 @@ class MDDataTable(ThemableBehavior, AnchorLayout):
.. code-block:: python .. code-block:: python
from kivy.metrics import dp from kivy.metrics import dp
from kivymd.app import MDApp from kivymd.app import MDApp
@ -923,82 +914,38 @@ class MDDataTable(ThemableBehavior, AnchorLayout):
""" """
Data for header columns. Data for header columns.
.. tabs:: .. code-block:: python
.. tab:: Imperative python style from kivy.metrics import dp
.. code-block:: python from kivymd.app import MDApp
from kivymd.uix.datatables import MDDataTable
from kivy.metrics import dp from kivy.uix.anchorlayout import AnchorLayout
from kivymd.app import MDApp
from kivymd.uix.datatables import MDDataTable
from kivy.uix.anchorlayout import AnchorLayout
class Example(MDApp): class Example(MDApp):
def build(self): def build(self):
self.theme_cls.theme_style = "Dark" layout = AnchorLayout()
self.theme_cls.primary_palette = "Orange" self.data_tables = MDDataTable(
size_hint=(0.7, 0.6),
layout = AnchorLayout() use_pagination=True,
self.data_tables = MDDataTable( check=True,
size_hint=(0.7, 0.6), # name column, width column, sorting function column(optional)
use_pagination=True, column_data=[
check=True, ("No.", dp(30)),
# name column, width column, sorting function column(optional), custom tooltip ("Status", dp(30)),
column_data=[ ("Signal Name", dp(60)),
("No.", dp(30), None, "Custom tooltip"), ("Severity", dp(30)),
("Status", dp(30)), ("Stage", dp(30)),
("Signal Name", dp(60)), ("Schedule", dp(30), lambda *args: print("Sorted using Schedule")),
("Severity", dp(30)), ("Team Lead", dp(30)),
("Stage", dp(30)), ],
("Schedule", dp(30), lambda *args: print("Sorted using Schedule")), )
("Team Lead", dp(30)), layout.add_widget(self.data_tables)
], return layout
)
layout.add_widget(self.data_tables)
return layout
Example().run() Example().run()
.. tab:: Declarative python style
.. code-block:: python
from kivy.metrics import dp
from kivymd.app import MDApp
from kivymd.uix.anchorlayout import MDAnchorLayout
from kivymd.uix.datatables import MDDataTable
class Example(MDApp):
def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "Orange"
return MDAnchorLayout(
MDDataTable(
size_hint=(0.7, 0.6),
use_pagination=True,
check=True,
# name column, width column, sorting function column(optional)
column_data=[
("No.", dp(30)),
("Status", dp(30)),
("Signal Name", dp(60)),
("Severity", dp(30)),
("Stage", dp(30)),
("Schedule", dp(30),
lambda *args: print("Sorted using Schedule")),
("Team Lead", dp(30)),
],
)
)
Example().run()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-column-data.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-column-data.png
:align: center :align: center
@ -1113,9 +1060,6 @@ class MDDataTable(ThemableBehavior, AnchorLayout):
class Example(MDApp): class Example(MDApp):
def build(self): def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "Orange"
layout = AnchorLayout() layout = AnchorLayout()
data_tables = MDDataTable( data_tables = MDDataTable(
size_hint=(0.9, 0.6), size_hint=(0.9, 0.6),
@ -1243,7 +1187,7 @@ class MDDataTable(ThemableBehavior, AnchorLayout):
""" """
Use or not use checkboxes for rows. Use or not use checkboxes for rows.
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-check.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-check.gif
:align: center :align: center
:attr:`check` is an :class:`~kivy.properties.BooleanProperty` :attr:`check` is an :class:`~kivy.properties.BooleanProperty`
@ -1265,9 +1209,6 @@ class MDDataTable(ThemableBehavior, AnchorLayout):
class Example(MDApp): class Example(MDApp):
def build(self): def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "Orange"
layout = AnchorLayout() layout = AnchorLayout()
data_tables = MDDataTable( data_tables = MDDataTable(
size_hint=(0.9, 0.6), size_hint=(0.9, 0.6),
@ -1297,19 +1238,19 @@ class MDDataTable(ThemableBehavior, AnchorLayout):
and defaults to `False`. and defaults to `False`.
""" """
elevation = NumericProperty(4) elevation = NumericProperty(8)
""" """
Table elevation. Table elevation.
:attr:`elevation` is an :class:`~kivy.properties.NumericProperty` :attr:`elevation` is an :class:`~kivy.properties.NumericProperty`
and defaults to `4`. and defaults to `8`.
""" """
rows_num = NumericProperty(5) rows_num = NumericProperty(5)
""" """
The number of rows displayed on one page of the table. The number of rows displayed on one page of the table.
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-use-pagination-rows-num.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-use-pagination.gif
:align: center :align: center
:attr:`rows_num` is an :class:`~kivy.properties.NumericProperty` :attr:`rows_num` is an :class:`~kivy.properties.NumericProperty`
@ -1325,7 +1266,7 @@ class MDDataTable(ThemableBehavior, AnchorLayout):
.. rubric:: Center .. rubric:: Center
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-menu-pos-top.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-menu-pos-center.png
:align: center :align: center
.. rubric:: Auto .. rubric:: Auto
@ -1341,6 +1282,11 @@ class MDDataTable(ThemableBehavior, AnchorLayout):
""" """
Menu height for selecting the number of displayed rows. Menu height for selecting the number of displayed rows.
.. rubric:: 140dp
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-menu-height-140.png
:align: center
.. rubric:: 240dp .. rubric:: 240dp
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-menu-height-240.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-menu-height-240.png
@ -1352,7 +1298,7 @@ class MDDataTable(ThemableBehavior, AnchorLayout):
background_color = ColorProperty([0, 0, 0, 0]) background_color = ColorProperty([0, 0, 0, 0])
""" """
Background color in the format (r, g, b, a) or string format. Background color in the format (r, g, b, a).
See :attr:`~kivy.uix.modalview.ModalView.background_color`. See :attr:`~kivy.uix.modalview.ModalView.background_color`.
Use markup strings Use markup strings
@ -1369,9 +1315,6 @@ class MDDataTable(ThemableBehavior, AnchorLayout):
class Example(MDApp): class Example(MDApp):
def build(self): def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "Orange"
layout = AnchorLayout() layout = AnchorLayout()
data_tables = MDDataTable( data_tables = MDDataTable(
size_hint=(0.9, 0.6), size_hint=(0.9, 0.6),
@ -1411,8 +1354,7 @@ class MDDataTable(ThemableBehavior, AnchorLayout):
background_color_header = ColorProperty(None) background_color_header = ColorProperty(None)
""" """
Background color in the format (r, g, b, a) or string format for Background color for :class:`~TableHeader` class.
:class:`~TableHeader` class.
.. versionadded:: 1.0.0 .. versionadded:: 1.0.0
@ -1432,8 +1374,7 @@ class MDDataTable(ThemableBehavior, AnchorLayout):
background_color_cell = ColorProperty(None) background_color_cell = ColorProperty(None)
""" """
Background color in the format (r, g, b, a) or string format for Background color for :class:`~CellRow` class.
:class:`~CellRow` class.
.. versionadded:: 1.0.0 .. versionadded:: 1.0.0
@ -1454,8 +1395,7 @@ class MDDataTable(ThemableBehavior, AnchorLayout):
background_color_selected_cell = ColorProperty(None) background_color_selected_cell = ColorProperty(None)
""" """
Background selected color in the format (r, g, b, a) or string format for Background selected color for :class:`~CellRow` class.
:class:`~CellRow` class.
.. versionadded:: 1.0.0 .. versionadded:: 1.0.0
@ -1468,7 +1408,7 @@ class MDDataTable(ThemableBehavior, AnchorLayout):
background_color_selected_cell="e4514f", background_color_selected_cell="e4514f",
) )
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-background-color-selected-cell.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/data-tables-background-color-selected-cell.gif
:align: center :align: center
:attr:`background_color_selected_cell` is a :class:`~kivy.properties.ColorProperty` and :attr:`background_color_selected_cell` is a :class:`~kivy.properties.ColorProperty` and
@ -1563,9 +1503,6 @@ class MDDataTable(ThemableBehavior, AnchorLayout):
data_tables = None data_tables = None
def build(self): def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "Orange"
layout = MDFloatLayout() # root layout layout = MDFloatLayout() # root layout
# Creating control buttons. # Creating control buttons.
button_box = MDBoxLayout( button_box = MDBoxLayout(
@ -1667,9 +1604,6 @@ class MDDataTable(ThemableBehavior, AnchorLayout):
data_tables = None data_tables = None
def build(self): def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "Orange"
layout = MDFloatLayout() layout = MDFloatLayout()
layout.add_widget( layout.add_widget(
MDRaisedButton( MDRaisedButton(

View File

@ -18,11 +18,7 @@
PopMatrix PopMatrix
<DialogContainer@MDCard> <DialogContainer@MDCard+FakeRectangularElevationBehavior>
shadow_color: 0.0, 0.0, 0.0, 0.0
elevation: 0
shadow_softness: 0
shadow_offset: 0, 0
<MDDialog> <MDDialog>
@ -32,6 +28,7 @@
orientation: "vertical" orientation: "vertical"
size_hint_y: None size_hint_y: None
height: self.minimum_height height: self.minimum_height
elevation: 24
padding: "24dp", "24dp", "8dp", "8dp" padding: "24dp", "24dp", "8dp", "8dp"
radius: root.radius radius: root.radius
md_bg_color: md_bg_color:

View File

@ -38,8 +38,6 @@ Usage
dialog = None dialog = None
def build(self): def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "Orange"
return Builder.load_string(KV) return Builder.load_string(KV)
def show_alert_dialog(self): def show_alert_dialog(self):
@ -89,7 +87,6 @@ from kivy.uix.modalview import ModalView
from kivymd import uix_path from kivymd import uix_path
from kivymd.material_resources import DEVICE_TYPE from kivymd.material_resources import DEVICE_TYPE
from kivymd.theming import ThemableBehavior from kivymd.theming import ThemableBehavior
from kivymd.uix.behaviors import CommonElevationBehavior
from kivymd.uix.button import BaseButton from kivymd.uix.button import BaseButton
from kivymd.uix.card import MDSeparator from kivymd.uix.card import MDSeparator
from kivymd.uix.list import BaseListItem from kivymd.uix.list import BaseListItem
@ -100,40 +97,7 @@ with open(
Builder.load_string(kv_file.read()) Builder.load_string(kv_file.read())
class BaseDialog(ThemableBehavior, ModalView, CommonElevationBehavior): class BaseDialog(ThemableBehavior, ModalView):
elevation = NumericProperty(3)
"""
See :attr:`kivymd.uix.behaviors.elevation.CommonElevationBehavior.elevation`
attribute for more information.
.. versionadded:: 1.1.0
:attr:`elevation` is an :class:`~kivy.properties.NumericProperty`
and defaults to `3`.
"""
shadow_softness = NumericProperty(24)
"""
See :attr:`kivymd.uix.behaviors.elevation.CommonElevationBehavior.shadow_softness`
attribute for more information.
.. versionadded:: 1.1.0
:attr:`shadow_softness` is an :class:`~kivy.properties.NumericProperty`
and defaults to `24`.
"""
shadow_offset = ListProperty((0, 4))
"""
See :attr:`kivymd.uix.behaviors.elevation.CommonElevationBehavior.shadow_offset`
attribute for more information.
.. versionadded:: 1.1.0
:attr:`shadow_offset` is an :class:`~kivy.properties.ListProperty`
and defaults to `[0, 4]`.
"""
radius = ListProperty([dp(7), dp(7), dp(7), dp(7)]) radius = ListProperty([dp(7), dp(7), dp(7), dp(7)])
""" """
Dialog corners rounding value. Dialog corners rounding value.
@ -286,22 +250,21 @@ class MDDialog(BaseDialog):
class Example(MDApp): class Example(MDApp):
dialog = None dialog = None
def build(self): def build(self):
self.theme_cls.theme_style = "Dark" return Builder.load_string(KV)
self.theme_cls.primary_palette = "Orange"
return Builder.load_string(KV)
def show_simple_dialog(self): def show_simple_dialog(self):
if not self.dialog: if not self.dialog:
self.dialog = MDDialog( self.dialog = MDDialog(
title="Set backup account", title="Set backup account",
type="simple", type="simple",
items=[ items=[
Item(text="user01@gmail.com", source="kivymd/images/logo/kivymd-icon-128.png"), Item(text="user01@gmail.com", source="user-1.png"),
Item(text="user02@gmail.com", source="data/logo/kivy-icon-128.png"), Item(text="user02@gmail.com", source="user-2.png"),
], Item(text="Add account", source="add-icon.png"),
) ],
self.dialog.open() )
self.dialog.open()
Example().run() Example().run()
@ -354,8 +317,6 @@ class MDDialog(BaseDialog):
dialog = None dialog = None
def build(self): def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "Orange"
return Builder.load_string(KV) return Builder.load_string(KV)
def show_confirmation_dialog(self): def show_confirmation_dialog(self):
@ -424,140 +385,71 @@ class MDDialog(BaseDialog):
""" """
Custom content class. Custom content class.
.. tabs:: .. code-block:: python
.. tab:: Declarative KV style from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
.. code-block:: python from kivymd.app import MDApp
from kivymd.uix.button import MDFlatButton
from kivymd.uix.dialog import MDDialog
from kivy.lang import Builder KV = '''
from kivy.uix.boxlayout import BoxLayout <Content>
orientation: "vertical"
spacing: "12dp"
size_hint_y: None
height: "120dp"
from kivymd.app import MDApp MDTextField:
from kivymd.uix.button import MDFlatButton hint_text: "City"
from kivymd.uix.dialog import MDDialog
KV = ''' MDTextField:
<Content> hint_text: "Street"
orientation: "vertical"
spacing: "12dp"
size_hint_y: None
height: "120dp"
MDTextField:
hint_text: "City"
MDTextField:
hint_text: "Street"
MDFloatLayout: MDFloatLayout:
MDFlatButton: MDFlatButton:
text: "ALERT DIALOG" text: "ALERT DIALOG"
pos_hint: {'center_x': .5, 'center_y': .5} pos_hint: {'center_x': .5, 'center_y': .5}
on_release: app.show_confirmation_dialog() on_release: app.show_confirmation_dialog()
''' '''
class Content(BoxLayout): class Content(BoxLayout):
pass pass
class Example(MDApp): class Example(MDApp):
dialog = None dialog = None
def build(self): def build(self):
self.theme_cls.theme_style = "Dark" return Builder.load_string(KV)
self.theme_cls.primary_palette = "Orange"
return Builder.load_string(KV)
def show_confirmation_dialog(self): def show_confirmation_dialog(self):
if not self.dialog: if not self.dialog:
self.dialog = MDDialog( self.dialog = MDDialog(
title="Address:", title="Address:",
type="custom", type="custom",
content_cls=Content(), content_cls=Content(),
buttons=[ buttons=[
MDFlatButton( MDFlatButton(
text="CANCEL", text="CANCEL",
theme_text_color="Custom", theme_text_color="Custom",
text_color=self.theme_cls.primary_color, text_color=self.theme_cls.primary_color,
), ),
MDFlatButton( MDFlatButton(
text="OK", text="OK",
theme_text_color="Custom", theme_text_color="Custom",
text_color=self.theme_cls.primary_color, text_color=self.theme_cls.primary_color,
), ),
], ],
) )
self.dialog.open() self.dialog.open()
Example().run() Example().run()
.. tab:: Declarative Python style
.. code-block:: python
from kivymd.app import MDApp
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.button import MDFlatButton
from kivymd.uix.dialog import MDDialog
from kivymd.uix.floatlayout import MDFloatLayout
from kivymd.uix.textfield import MDTextField
class Example(MDApp):
dialog = None
def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "Orange"
return (
MDFloatLayout(
MDFlatButton(
text="ALERT DIALOG",
pos_hint={'center_x': 0.5, 'center_y': 0.5},
on_release=self.show_confirmation_dialog,
)
)
)
def show_confirmation_dialog(self, *args):
if not self.dialog:
self.dialog = MDDialog(
title="Address:",
type="custom",
content_cls=MDBoxLayout(
MDTextField(
hint_text="City",
),
MDTextField(
hint_text="Street",
),
orientation="vertical",
spacing="12dp",
size_hint_y=None,
height="120dp",
),
buttons=[
MDFlatButton(
text="CANCEL",
theme_text_color="Custom",
text_color=self.theme_cls.primary_color,
),
MDFlatButton(
text="OK",
theme_text_color="Custom",
text_color=self.theme_cls.primary_color,
),
],
)
self.dialog.open()
Example().run()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dialog-custom.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dialog-custom.png
:align: center :align: center
@ -568,7 +460,7 @@ class MDDialog(BaseDialog):
md_bg_color = ColorProperty(None) md_bg_color = ColorProperty(None)
""" """
Background color in the (r, g, b, a) or string format. Background color in the format (r, g, b, a).
:attr:`md_bg_color` is an :class:`~kivy.properties.ColorProperty` :attr:`md_bg_color` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`. and defaults to `None`.

View File

@ -1,7 +1,7 @@
<_Triangle>: <_Triangle>:
canvas: canvas:
Color: Color:
rgba: app.theme_cls.text_color rgba: root.theme_cls.text_color
Triangle: Triangle:
points: points:
[ \ [ \
@ -13,8 +13,7 @@
<MDDropDownItem> <MDDropDownItem>
orientation: "vertical" orientation: "vertical"
size_hint: None, None adaptive_size: True
size: self.minimum_size
spacing: "5dp" spacing: "5dp"
padding: "5dp", "5dp", "5dp", 0 padding: "5dp", "5dp", "5dp", 0

View File

@ -15,13 +15,13 @@ Usage
from kivymd.app import MDApp from kivymd.app import MDApp
KV = ''' KV = '''
MDScreen Screen
MDDropDownItem: MDDropDownItem:
id: drop_item id: drop_item
pos_hint: {'center_x': .5, 'center_y': .5} pos_hint: {'center_x': .5, 'center_y': .5}
text: 'Item' text: 'Item'
on_release: print("Press item") on_release: self.set_item("New Item")
''' '''
@ -48,12 +48,12 @@ import os
from kivy.lang import Builder from kivy.lang import Builder
from kivy.properties import NumericProperty, StringProperty from kivy.properties import NumericProperty, StringProperty
from kivy.uix.behaviors import ButtonBehavior from kivy.uix.behaviors import ButtonBehavior
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.widget import Widget from kivy.uix.widget import Widget
from kivymd import uix_path from kivymd import uix_path
from kivymd.theming import ThemableBehavior from kivymd.theming import ThemableBehavior
from kivymd.uix.behaviors import DeclarativeBehavior from kivymd.uix.behaviors import FakeRectangularElevationBehavior
from kivymd.uix.boxlayout import MDBoxLayout
with open( with open(
os.path.join(uix_path, "dropdownitem", "dropdownitem.kv"), encoding="utf-8" os.path.join(uix_path, "dropdownitem", "dropdownitem.kv"), encoding="utf-8"
@ -61,12 +61,15 @@ with open(
Builder.load_string(kv_file.read()) Builder.load_string(kv_file.read())
class _Triangle(Widget): class _Triangle(ThemableBehavior, Widget):
pass pass
class MDDropDownItem( class MDDropDownItem(
DeclarativeBehavior, ThemableBehavior, ButtonBehavior, BoxLayout ThemableBehavior,
FakeRectangularElevationBehavior,
ButtonBehavior,
MDBoxLayout,
): ):
text = StringProperty() text = StringProperty()
""" """

View File

@ -6,29 +6,28 @@
background_normal: "" background_normal: ""
background_down: "" background_down: ""
dir_or_file_name: "" dir_or_file_name: ""
icon_color: 0, 0, 0, 0
_selected: False _selected: False
events_callback: lambda x: None events_callback: lambda x: None
orientation: "vertical" orientation: "vertical"
ModifiedOneLineIconListItem: ModifiedOneLineIconListItem:
text: root.dir_or_file_name text: root.dir_or_file_name
on_release: root.events_callback(root.path, root)
bg_color: bg_color:
self.theme_cls.bg_darkest \ self.theme_cls.bg_darkest \
if root._selected else \ if root._selected else self.theme_cls.bg_normal
self.theme_cls.bg_normal on_release: root.events_callback(root.path, root)
IconLeftWidget: IconLeftWidget:
icon: root.icon icon: root.icon
theme_icon_color: "Custom" theme_text_color: "Custom"
icon_color: root.icon_color text_color: self.theme_cls.primary_color
MDSeparator: MDSeparator:
<LabelContent@MDLabel> <LabelContent@MDLabel>
adaptive_height: True size_hint_y: None
height: self.texture_size[1]
shorten: True shorten: True
shorten_from: "center" shorten_from: "center"
halign: "center" halign: "center"
@ -62,6 +61,23 @@
text: root.name text: root.name
<FloatButton>
anchor_x: "right"
anchor_y: "bottom"
size_hint_y: None
height: dp(56)
padding: dp(10)
MDFloatingActionButton:
size_hint: None, None
size:dp(56), dp(56)
icon: root.icon
opposite_colors: True
elevation: 8
on_release: root.callback()
md_bg_color: root.md_bg_color
<MDFileManager> <MDFileManager>
md_bg_color: root.theme_cls.bg_normal md_bg_color: root.theme_cls.bg_normal
@ -74,11 +90,7 @@
title: root.current_path title: root.current_path
right_action_items: [["close-box", lambda x: root.exit_manager(1)]] right_action_items: [["close-box", lambda x: root.exit_manager(1)]]
left_action_items: [["chevron-left", lambda x: root.back()]] left_action_items: [["chevron-left", lambda x: root.back()]]
elevation: 3 elevation: 10
md_bg_color:
app.theme_cls.primary_color \
if not root.background_color_toolbar else \
root.background_color_toolbar
RecycleView: RecycleView:
id: rv id: rv

View File

@ -9,7 +9,7 @@ Usage
.. code-block:: python .. code-block:: python
path = os.path.expanduser("~") # path to the directory that will be opened in the file manager path = '/' # path to the directory that will be opened in the file manager
file_manager = MDFileManager( file_manager = MDFileManager(
exit_manager=self.exit_manager, # function called when the user reaches directory tree root exit_manager=self.exit_manager, # function called when the user reaches directory tree root
select_path=self.select_path, # function called when selecting a file/directory select_path=self.select_path, # function called when selecting a file/directory
@ -19,7 +19,7 @@ Usage
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/file-manager.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/file-manager.png
:align: center :align: center
.. warning:: Be careful! To use the `'/'` path on Android devices, you need .. warning:: Be careful! To use the `/` path on Android devices, you need
special permissions. Therefore, you are likely to get an error. special permissions. Therefore, you are likely to get an error.
Or with ``preview`` mode: Or with ``preview`` mode:
@ -32,7 +32,7 @@ Or with ``preview`` mode:
preview=True, preview=True,
) )
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/file-manager-preview.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/file-manager-previous.png
:align: center :align: center
.. warning:: The `preview` mode is intended only for viewing images and will .. warning:: The `preview` mode is intended only for viewing images and will
@ -43,8 +43,6 @@ Example
.. code-block:: python .. code-block:: python
import os
from kivy.core.window import Window from kivy.core.window import Window
from kivy.lang import Builder from kivy.lang import Builder
@ -55,19 +53,19 @@ Example
KV = ''' KV = '''
MDBoxLayout: MDBoxLayout:
orientation: "vertical" orientation: 'vertical'
MDTopAppBar: MDTopAppBar:
title: "MDFileManager" title: "MDFileManager"
left_action_items: [["menu", lambda x: None]] left_action_items: [['menu', lambda x: None]]
elevation: 3 elevation: 10
MDFloatLayout: MDFloatLayout:
MDRoundFlatIconButton: MDRoundFlatIconButton:
text: "Open manager" text: "Open manager"
icon: "folder" icon: "folder"
pos_hint: {"center_x": .5, "center_y": .5} pos_hint: {'center_x': .5, 'center_y': .6}
on_release: app.file_manager_open() on_release: app.file_manager_open()
''' '''
@ -78,23 +76,23 @@ Example
Window.bind(on_keyboard=self.events) Window.bind(on_keyboard=self.events)
self.manager_open = False self.manager_open = False
self.file_manager = MDFileManager( self.file_manager = MDFileManager(
exit_manager=self.exit_manager, select_path=self.select_path exit_manager=self.exit_manager,
select_path=self.select_path,
preview=True,
) )
def build(self): def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "Orange"
return Builder.load_string(KV) return Builder.load_string(KV)
def file_manager_open(self): def file_manager_open(self):
self.file_manager.show(os.path.expanduser("~")) # output manager to the screen self.file_manager.show('/') # output manager to the screen
self.manager_open = True self.manager_open = True
def select_path(self, path: str): def select_path(self, path):
''' '''It will be called when you click on the file name
It will be called when you click on the file name
or the catalog selection button. or the catalog selection button.
:type path: str;
:param path: path to the selected directory or file; :param path: path to the selected directory or file;
''' '''
@ -128,9 +126,6 @@ Not tested on `iOS`.
def file_manager_open(self): def file_manager_open(self):
self.file_manager.show_disks() self.file_manager.show_disks()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/file-manager-show-disks.png
:align: center
""" """
__all__ = ("MDFileManager",) __all__ = ("MDFileManager",)
@ -141,7 +136,6 @@ import re
from typing import List, Tuple, Union from typing import List, Tuple, Union
from kivy import platform from kivy import platform
from kivy.clock import Clock
from kivy.factory import Factory from kivy.factory import Factory
from kivy.lang import Builder from kivy.lang import Builder
from kivy.metrics import dp from kivy.metrics import dp
@ -154,6 +148,7 @@ from kivy.properties import (
OptionProperty, OptionProperty,
StringProperty, StringProperty,
) )
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.behaviors import ButtonBehavior from kivy.uix.behaviors import ButtonBehavior
from kivy.uix.modalview import ModalView from kivy.uix.modalview import ModalView
@ -161,7 +156,6 @@ from kivymd import images_path, uix_path
from kivymd.theming import ThemableBehavior from kivymd.theming import ThemableBehavior
from kivymd.uix.behaviors import CircularRippleBehavior from kivymd.uix.behaviors import CircularRippleBehavior
from kivymd.uix.boxlayout import MDBoxLayout from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.button import MDFloatingActionButton
from kivymd.uix.fitimage import FitImage from kivymd.uix.fitimage import FitImage
from kivymd.uix.list import BaseListItem from kivymd.uix.list import BaseListItem
from kivymd.uix.relativelayout import MDRelativeLayout from kivymd.uix.relativelayout import MDRelativeLayout
@ -173,7 +167,9 @@ with open(
class BodyManager(MDBoxLayout): class BodyManager(MDBoxLayout):
"""Base class for folders and files icons.""" """
Base class for folders and files icons.
"""
class BodyManagerWithPreview(MDBoxLayout): class BodyManagerWithPreview(MDBoxLayout):
@ -186,146 +182,47 @@ class IconButton(CircularRippleBehavior, ButtonBehavior, FitImage):
"""Folder icons/thumbnails images in ``preview`` mode.""" """Folder icons/thumbnails images in ``preview`` mode."""
class FloatButton(ThemableBehavior, AnchorLayout):
callback = ObjectProperty()
md_bg_color = ColorProperty([1, 1, 1, 1])
icon = StringProperty()
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.theme_cls.bind(primary_palette=self.set_md_bg_color)
def set_md_bg_color(self, *args):
self.md_bg_color = self.theme_cls.primary_color
class ModifiedOneLineIconListItem(BaseListItem): class ModifiedOneLineIconListItem(BaseListItem):
_txt_left_pad = NumericProperty("72dp") _txt_left_pad = NumericProperty("72dp")
_txt_top_pad = NumericProperty("16dp") _txt_top_pad = NumericProperty("16dp")
_txt_bot_pad = NumericProperty("15dp") _txt_bot_pad = NumericProperty("15dp")
_num_lines = 1 _num_lines = 1
def __init__(self, *args, **kwargs): def __init__(self, **kwargs):
super().__init__(*args, **kwargs) super().__init__(**kwargs)
self.height = dp(48) self.height = dp(48)
class MDFileManager(MDRelativeLayout, ThemableBehavior): class MDFileManager(ThemableBehavior, MDRelativeLayout):
icon = StringProperty("check")
""" """
Implements a modal dialog with a file manager. The icon that will be used on the directory selection button.
For more information, see in the
:class:`~kivymd.uix.relativelayout.MDRelativeLayout` class documentation.
:Events:
`on_pre_open`:
Called before the MDFileManager is opened.
`on_open`:
Called when the MDFileManager is opened.
`on_pre_dismiss`:
Called before the MDFileManager is closed.
`on_dismiss`:
Called when the MDFileManager is closed.
"""
icon = StringProperty("check", deprecated=True)
"""
Icon that will be used on the directory selection button.
.. deprecated:: 1.1.0
Use :attr:`icon_selection_button` instead.
:attr:`icon` is an :class:`~kivy.properties.StringProperty` :attr:`icon` is an :class:`~kivy.properties.StringProperty`
and defaults to `check`. and defaults to `check`.
""" """
icon_selection_button = StringProperty("check")
"""
Icon that will be used on the directory selection button.
.. versionadded:: 1.1.0
.. code-block:: python
MDFileManager(
...
icon_selection_button="pencil",
)
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/file-manager-icon-selection-button.png
:align: center
:attr:`icon_selection_button` is an :class:`~kivy.properties.StringProperty`
and defaults to `check`.
"""
background_color_selection_button = ColorProperty(None)
"""
Background color of the current directory/path selection button.
.. versionadded:: 1.1.0
.. code-block:: python
MDFileManager(
...
background_color_selection_button="brown",
)
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/file-manager-background-color-selection-button.png
:align: center
:attr:`background_color_selection_button` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
background_color_toolbar = ColorProperty(None)
"""
Background color of the file manager toolbar.
.. versionadded:: 1.1.0
.. code-block:: python
MDFileManager(
...
background_color_toolbar="brown",
)
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/file-manager-background-color-toolbar.png
:align: center
:attr:`background_color_toolbar` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
icon_folder = StringProperty(f"{images_path}folder.png") icon_folder = StringProperty(f"{images_path}folder.png")
""" """
Icon that will be used for folder icons when using ``preview = True``. The icon that will be used for folder icons when using ``preview = True``.
.. code-block:: python
MDFileManager(
...
preview=True,
icon_folder="path/to/icon.png",
)
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/file-manager-icon-folder.png
:align: center
:attr:`icon` is an :class:`~kivy.properties.StringProperty` :attr:`icon` is an :class:`~kivy.properties.StringProperty`
and defaults to `check`. and defaults to `check`.
""" """
icon_color = ColorProperty(None)
"""
Color of the folder icon when the :attr:`preview` property is set to False.
.. versionadded:: 1.1.0
.. code-block:: python
MDFileManager(
...
preview=False,
icon_color="brown",
)
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/file-manager-icon-color.png
:align: center
:attr:`icon_color` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
exit_manager = ObjectProperty(lambda x: None) exit_manager = ObjectProperty(lambda x: None)
""" """
Function called when the user reaches directory tree root. Function called when the user reaches directory tree root.
@ -362,12 +259,12 @@ class MDFileManager(MDRelativeLayout, ThemableBehavior):
and defaults to `all`. and defaults to `all`.
""" """
current_path = StringProperty(os.path.expanduser("~")) current_path = StringProperty(os.getcwd())
""" """
Current directory. Current directory.
:attr:`current_path` is an :class:`~kivy.properties.StringProperty` :attr:`current_path` is an :class:`~kivy.properties.StringProperty`
and defaults to `os.path.expanduser("~")`. and defaults to `/`.
""" """
use_access = BooleanProperty(True) use_access = BooleanProperty(True)
@ -398,9 +295,9 @@ class MDFileManager(MDRelativeLayout, ThemableBehavior):
"name", options=["nothing", "name", "date", "size", "type"] "name", options=["nothing", "name", "date", "size", "type"]
) )
""" """
It can take the values 'nothing' 'name' 'date' 'size' 'type' - sorts files It can take the values 'nothing' 'name' 'date' 'size' 'type' - sorts files by option
by option. By default, sort by name. Available options are: By default, sort by name.
`'nothing'`, `'name'`, `'date'`, `'size'`, `'type'`. Available options are: `'nothing'`, `'name'`, `'date'`, `'size'`, `'type'`.
:attr:`sort_by` is an :class:`~kivy.properties.OptionProperty` :attr:`sort_by` is an :class:`~kivy.properties.OptionProperty`
and defaults to `name`. and defaults to `name`.
@ -428,33 +325,29 @@ class MDFileManager(MDRelativeLayout, ThemableBehavior):
""" """
Contains the list of files that are currently selected. Contains the list of files that are currently selected.
:attr:`selection` is a read-only :class:`~kivy.properties.ListProperty` :attr:`selection` is a read-only :class:`~kivy.properties.ListProperty` and
and defaults to `[]`. defaults to `[]`.
"""
selection_button = ObjectProperty()
"""
The instance of the directory/path selection button.
.. versionadded:: 1.1.0
:attr:`selection_button` is a read-only :class:`~kivy.properties.ObjectProperty`
and defaults to `None`.
""" """
_window_manager = None _window_manager = None
_window_manager_open = False _window_manager_open = False
def __init__(self, *args, **kwargs): def __init__(self, **kwargs):
super().__init__(*args, **kwargs) super().__init__(**kwargs)
self.register_event_type("on_pre_open")
self.register_event_type("on_open")
self.register_event_type("on_pre_dismiss")
self.register_event_type("on_dismiss")
toolbar_label = self.ids.toolbar.children[1].children[0] toolbar_label = self.ids.toolbar.children[1].children[0]
toolbar_label.font_style = "Subtitle1" toolbar_label.font_style = "Subtitle1"
Clock.schedule_once(self._create_selection_button) if (
self.selector == "any"
or self.selector == "multi"
or self.selector == "folder"
):
self.add_widget(
FloatButton(
callback=self.select_directory_on_press_button,
md_bg_color=self.theme_cls.primary_color,
icon=self.icon,
)
)
if self.preview: if self.preview:
self.ext = [".png", ".jpg", ".jpeg"] self.ext = [".png", ".jpg", ".jpeg"]
@ -507,7 +400,15 @@ class MDFileManager(MDRelativeLayout, ThemableBehavior):
} }
) )
self.ids.rv.data = manager_list self.ids.rv.data = manager_list
self._show()
if not self._window_manager:
self._window_manager = ModalView(
size_hint=self.size_hint, auto_dismiss=False
)
self._window_manager.add_widget(self)
if not self._window_manager_open:
self._window_manager.open()
self._window_manager_open = True
def show(self, path: str) -> None: def show(self, path: str) -> None:
""" """
@ -573,9 +474,6 @@ class MDFileManager(MDRelativeLayout, ThemableBehavior):
"icon": icon, "icon": icon,
"dir_or_file_name": name, "dir_or_file_name": name,
"events_callback": self.select_dir_or_file, "events_callback": self.select_dir_or_file,
"icon_color": self.theme_cls.primary_color
if not self.icon_color
else self.icon_color,
"_selected": False, "_selected": False,
} }
) )
@ -590,14 +488,19 @@ class MDFileManager(MDRelativeLayout, ThemableBehavior):
"icon": "file-outline", "icon": "file-outline",
"dir_or_file_name": os.path.split(name)[1], "dir_or_file_name": os.path.split(name)[1],
"events_callback": self.select_dir_or_file, "events_callback": self.select_dir_or_file,
"icon_color": self.theme_cls.primary_color
if not self.icon_color
else self.icon_color,
"_selected": False, "_selected": False,
} }
) )
self.ids.rv.data = manager_list self.ids.rv.data = manager_list
self._show()
if not self._window_manager:
self._window_manager = ModalView(
size_hint=self.size_hint, auto_dismiss=False
)
self._window_manager.add_widget(self)
if not self._window_manager_open:
self._window_manager.open()
self._window_manager_open = True
def get_access_string(self, path: str) -> str: def get_access_string(self, path: str) -> str:
access_string = "" access_string = ""
@ -654,9 +557,7 @@ class MDFileManager(MDRelativeLayout, ThemableBehavior):
def close(self) -> None: def close(self) -> None:
"""Closes the file manager window.""" """Closes the file manager window."""
self.dispatch("on_pre_dismiss")
self._window_manager.dismiss() self._window_manager.dismiss()
self.dispatch("on_dismiss")
self._window_manager_open = False self._window_manager_open = False
def select_dir_or_file( def select_dir_or_file(
@ -708,84 +609,6 @@ class MDFileManager(MDRelativeLayout, ThemableBehavior):
if self.selector == "folder" or self.selector == "any": if self.selector == "folder" or self.selector == "any":
self.select_path(self.current_path) self.select_path(self.current_path)
def on_icon(self, instance_file_manager, icon_name: str) -> None:
"""Called when the :attr:`icon` property is changed."""
self.icon_selection_button = icon_name
def on_background_color_toolbar(
self, instance_file_manager, color: Union[str, list]
) -> None:
"""
Called when the :attr:`background_color_toolbar` property is changed.
"""
def on_background_color_toolbar(*args):
self.ids.toolbar.md_bg_color = color
Clock.schedule_once(on_background_color_toolbar)
def on_pre_open(self, *args):
"""
Default pre-open event handler.
.. versionadded:: 1.1.0
"""
def on_open(self, *args):
"""
Default open event handler.
.. versionadded:: 1.1.0
"""
def on_pre_dismiss(self, *args):
"""
Default pre-dismiss event handler.
.. versionadded:: 1.1.0
"""
def on_dismiss(self, *args):
"""
Default dismiss event handler.
.. versionadded:: 1.1.0
"""
def _show(self):
if not self._window_manager:
self._window_manager = ModalView(
size_hint=self.size_hint, auto_dismiss=False
)
self.size_hint = (1, 1)
self._window_manager.add_widget(self)
if not self._window_manager_open:
self._window_manager.open()
self._window_manager_open = True
self.dispatch("on_pre_open")
self.dispatch("on_open")
def _create_selection_button(self, *args):
if (
self.selector == "any"
or self.selector == "multi"
or self.selector == "folder"
):
self.selection_button = MDFloatingActionButton(
on_release=self.select_directory_on_press_button,
md_bg_color=self.theme_cls.primary_color
if not self.background_color_selection_button
else self.background_color_selection_button,
icon=self.icon_selection_button,
pos_hint={"right": 0.99},
y=dp(12),
elevation=0,
)
self.add_widget(self.selection_button)
def __sort_files(self, files): def __sort_files(self, files):
def sort_by_name(files): def sort_by_name(files):
files.sort(key=locale.strxfrm) files.sort(key=locale.strxfrm)

View File

@ -132,11 +132,11 @@ from kivy.properties import BooleanProperty, ObjectProperty
from kivy.uix.image import AsyncImage from kivy.uix.image import AsyncImage
from kivy.uix.widget import Widget from kivy.uix.widget import Widget
from kivymd.uix.behaviors import StencilBehavior
from kivymd.uix.boxlayout import MDBoxLayout from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.templates import StencilWidget
class FitImage(MDBoxLayout, StencilBehavior): class FitImage(MDBoxLayout, StencilWidget):
source = ObjectProperty() source = ObjectProperty()
""" """
Filename/source of your image. Filename/source of your image.

View File

@ -90,7 +90,4 @@ from kivymd.uix.behaviors import DeclarativeBehavior
class MDGridLayout(DeclarativeBehavior, GridLayout, MDAdaptiveWidget): class MDGridLayout(DeclarativeBehavior, GridLayout, MDAdaptiveWidget):
""" pass
Grid layout class. For more information, see in the
:class:`~kivy.uix.gridlayout.GridLayout` class documentation.
"""

View File

@ -63,7 +63,7 @@ Base example
x: 24 x: 24
FitImage: FitImage:
source: "kivymd/images/logo/kivymd-icon-512.png" source: "https://github.com/kivymd/internal/raw/main/logo/kivymd_logo_blue.png"
size_hint: None, None size_hint: None, None
size: hero_from.size size: hero_from.size
@ -72,7 +72,7 @@ Base example
pos_hint: {"center_x": .5} pos_hint: {"center_x": .5}
y: "36dp" y: "36dp"
on_release: on_release:
root.current_heroes = ["hero"] root.current_hero = "hero"
root.current = "screen B" root.current = "screen B"
MDScreen: MDScreen:
@ -82,7 +82,6 @@ Base example
MDHeroTo: MDHeroTo:
id: hero_to id: hero_to
tag: "hero"
size_hint: None, None size_hint: None, None
size: "220dp", "220dp" size: "220dp", "220dp"
pos_hint: {"center_x": .5, "center_y": .5} pos_hint: {"center_x": .5, "center_y": .5}
@ -92,7 +91,7 @@ Base example
pos_hint: {"center_x": .5} pos_hint: {"center_x": .5}
y: "36dp" y: "36dp"
on_release: on_release:
root.current_heroes = ["hero"] root.current_hero = "hero"
root.current = "screen A" root.current = "screen A"
''' '''
@ -114,7 +113,6 @@ Note that the child of the :class:`~MDHeroFrom` widget must have the size of the
MDHeroFrom: MDHeroFrom:
id: hero_from id: hero_from
tag: "hero"
FitImage: FitImage:
size_hint: None, None size_hint: None, None
@ -129,7 +127,7 @@ container in which the hero is located:
MDRaisedButton: MDRaisedButton:
text: "Move Hero To Screen B" text: "Move Hero To Screen B"
on_release: on_release:
root.current_heroes = ["hero"] root.current_hero = "hero"
root.current = "screen 2" root.current = "screen 2"
If you need to switch to a screen that does not contain heroes, set the If you need to switch to a screen that does not contain heroes, set the
@ -140,7 +138,7 @@ If you need to switch to a screen that does not contain heroes, set the
MDRaisedButton: MDRaisedButton:
text: "Go To Another Screen" text: "Go To Another Screen"
on_release: on_release:
root.current_heroes = [] root.current_hero = ""
root.current = "another screen" root.current = "another screen"
Example Example
@ -168,7 +166,7 @@ Example
x: 24 x: 24
FitImage: FitImage:
source: "kivymd/images/logo/kivymd-icon-512.png" source: "https://github.com/kivymd/internal/raw/main/logo/kivymd_logo_blue.png"
size_hint: None, None size_hint: None, None
size: hero_from.size size: hero_from.size
@ -177,7 +175,7 @@ Example
pos_hint: {"center_x": .5} pos_hint: {"center_x": .5}
y: "36dp" y: "36dp"
on_release: on_release:
root.current_heroes = ["hero"] root.current_hero = "hero"
root.current = "screen B" root.current = "screen B"
MDScreen: MDScreen:
@ -187,7 +185,6 @@ Example
MDHeroTo: MDHeroTo:
id: hero_to id: hero_to
tag: "hero"
size_hint: None, None size_hint: None, None
size: "220dp", "220dp" size: "220dp", "220dp"
pos_hint: {"center_x": .5, "center_y": .5} pos_hint: {"center_x": .5, "center_y": .5}
@ -197,7 +194,7 @@ Example
pos_hint: {"center_x": .5} pos_hint: {"center_x": .5}
y: "52dp" y: "52dp"
on_release: on_release:
root.current_heroes = [] root.current_hero = ""
root.current = "screen C" root.current = "screen C"
MDRaisedButton: MDRaisedButton:
@ -205,7 +202,7 @@ Example
pos_hint: {"center_x": .5} pos_hint: {"center_x": .5}
y: "8dp" y: "8dp"
on_release: on_release:
root.current_heroes = ["hero"] root.current_hero = "hero"
root.current = "screen A" root.current = "screen A"
MDScreen: MDScreen:
@ -286,7 +283,7 @@ background color of the hero during the flight between the screens:
pos_hint: {"center_x": .5} pos_hint: {"center_x": .5}
y: "36dp" y: "36dp"
on_release: on_release:
root.current_heroes = ["hero"] root.current_hero = "hero"
root.current = "screen B" root.current = "screen B"
MDScreen: MDScreen:
@ -296,7 +293,6 @@ background color of the hero during the flight between the screens:
MDHeroTo: MDHeroTo:
id: hero_to id: hero_to
tag: "hero"
size_hint: None, None size_hint: None, None
size: "220dp", "220dp" size: "220dp", "220dp"
pos_hint: {"center_x": .5, "center_y": .5} pos_hint: {"center_x": .5, "center_y": .5}
@ -306,7 +302,7 @@ background color of the hero during the flight between the screens:
pos_hint: {"center_x": .5} pos_hint: {"center_x": .5}
y: "36dp" y: "36dp"
on_release: on_release:
root.current_heroes = ["hero"] root.current_hero = "hero"
root.current = "screen A" root.current = "screen A"
''' '''
@ -374,7 +370,7 @@ Usage with ScrollView
radius: 24 radius: 24
box_radius: 0, 0, 24, 24 box_radius: 0, 0, 24, 24
box_color: 0, 0, 0, .5 box_color: 0, 0, 0, .5
source: "kivymd/images/logo/kivymd-icon-512.png" source: "image.jpg"
size_hint: None, None size_hint: None, None
size: root.size size: root.size
mipmap: True mipmap: True
@ -403,7 +399,7 @@ Usage with ScrollView
MDScreen: MDScreen:
name: "screen B" name: "screen B"
heroes_to: [hero_to] hero_to: hero_to
MDHeroTo: MDHeroTo:
id: hero_to id: hero_to
@ -416,7 +412,7 @@ Usage with ScrollView
pos_hint: {"center_x": .5} pos_hint: {"center_x": .5}
y: "36dp" y: "36dp"
on_release: on_release:
root.current_heroes = [hero_to.tag] root.current_hero = "hero"
root.current = "screen A" root.current = "screen A"
''' '''
@ -445,8 +441,7 @@ Usage with ScrollView
def on_release(self): def on_release(self):
def switch_screen(*args): def switch_screen(*args):
self.manager.current_heroes = [self.tag] self.manager.current_hero = self.tag
self.manager.ids.hero_to.tag = self.tag
self.manager.current = "screen B" self.manager.current = "screen B"
Clock.schedule_once(switch_screen, 0.2) Clock.schedule_once(switch_screen, 0.2)
@ -470,93 +465,6 @@ Usage with ScrollView
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/hero-usage-with-scrollview.gif .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/hero-usage-with-scrollview.gif
:align: center :align: center
Using multiple heroes at the same time
--------------------------------------
.. code-block:: python
from kivy.lang import Builder
from kivymd.app import MDApp
KV = '''
MDScreenManager:
MDScreen:
name: "screen A"
md_bg_color: "lightblue"
MDHeroFrom:
id: hero_kivymd
tag: "kivymd"
size_hint: None, None
size: "200dp", "200dp"
pos_hint: {"top": .98}
x: 24
FitImage:
source: "kivymd/images/logo/kivymd-icon-512.png"
size_hint: None, None
size: hero_kivymd.size
MDHeroFrom:
id: hero_kivy
tag: "kivy"
size_hint: None, None
size: "200dp", "200dp"
pos_hint: {"top": .98}
x: 324
FitImage:
source: "data/logo/kivy-icon-512.png"
size_hint: None, None
size: hero_kivy.size
MDRaisedButton:
text: "Move Hero To Screen B"
pos_hint: {"center_x": .5}
y: "36dp"
on_release:
root.current_heroes = ["kivymd", "kivy"]
root.current = "screen B"
MDScreen:
name: "screen B"
heroes_to: hero_to_kivymd, hero_to_kivy
md_bg_color: "cadetblue"
MDHeroTo:
id: hero_to_kivy
tag: "kivy"
size_hint: None, None
pos_hint: {"center_x": .5, "center_y": .5}
MDHeroTo:
id: hero_to_kivymd
tag: "kivymd"
size_hint: None, None
pos_hint: {"right": 1, "top": 1}
MDRaisedButton:
text: "Move Hero To Screen A"
pos_hint: {"center_x": .5}
y: "36dp"
on_release:
root.current_heroes = ["kivy", "kivymd"]
root.current = "screen A"
'''
class Test(MDApp):
def build(self):
return Builder.load_string(KV)
Test().run()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/hero-multiple-heroes.gif
:align: center
""" """
from kivy.properties import StringProperty from kivy.properties import StringProperty
@ -568,9 +476,6 @@ class MDHeroFrom(MDBoxLayout):
""" """
The container from which the hero begins his flight. The container from which the hero begins his flight.
For more information, see in the
:class:`~kivymd.uix.boxlayout.MDBoxLayout` class documentation.
:Events: :Events:
`on_transform_in` `on_transform_in`
when the hero flies from screen **A** to screen **B**. when the hero flies from screen **A** to screen **B**.
@ -582,7 +487,7 @@ class MDHeroFrom(MDBoxLayout):
""" """
Tag ID for heroes. Tag ID for heroes.
:attr:`tag` is an :class:`~kivy.properties.StringProperty` :attr:`shift_right` is an :class:`~kivy.properties.StringProperty`
and defaults to `''`. and defaults to `''`.
""" """
@ -599,17 +504,4 @@ class MDHeroFrom(MDBoxLayout):
class MDHeroTo(MDBoxLayout): class MDHeroTo(MDBoxLayout):
""" """The container in which the hero comes."""
The container in which the hero comes.
For more information, see in the
:class:`~kivymd.uix.boxlayout.MDBoxLayout` class documentation.
"""
tag = StringProperty(allownone=True)
"""
Tag ID for heroes.
:attr:`tag` is an :class:`~kivy.properties.StringProperty`
and defaults to `''`.
"""

View File

@ -65,13 +65,12 @@ Implementation
:align: center :align: center
""" """
__all__ = [ __all__ = "MDSmartTile"
"MDSmartTile",
]
import os import os
from kivy.lang import Builder from kivy.lang import Builder
from kivy.logger import Logger
from kivy.properties import ( from kivy.properties import (
BooleanProperty, BooleanProperty,
ColorProperty, ColorProperty,

View File

@ -17,14 +17,8 @@
rgba: (1, 1, 1, 1) if self.source else (0, 0, 0, 0) rgba: (1, 1, 1, 1) if self.source else (0, 0, 0, 0)
Rectangle: Rectangle:
source: self.source if self.source else None source: self.source if self.source else None
pos: pos: self.pos
self.pos \ size: self.size
if not self.source else \
(self.x - self._size[0] / 2, self.y)
size:
self._size \
if self.source else \
self.size
font_style: "Icon" font_style: "Icon"
text: u"{}".format(md_icons[root.icon]) if root.icon in md_icons else "blank" text: u"{}".format(md_icons[root.icon]) if root.icon in md_icons else "blank"

View File

@ -222,18 +222,14 @@ __all__ = ("MDLabel", "MDIcon")
import os import os
from typing import Union from typing import Union
from kivy.animation import Animation
from kivy.clock import Clock from kivy.clock import Clock
from kivy.graphics import Color, Rectangle
from kivy.lang import Builder from kivy.lang import Builder
from kivy.metrics import sp from kivy.metrics import sp
from kivy.properties import ( from kivy.properties import (
AliasProperty, AliasProperty,
BooleanProperty, BooleanProperty,
ColorProperty, ColorProperty,
ListProperty,
NumericProperty, NumericProperty,
ObjectProperty,
OptionProperty, OptionProperty,
StringProperty, StringProperty,
) )
@ -326,7 +322,6 @@ class MDLabel(DeclarativeBehavior, ThemableBehavior, Label, MDAdaptiveWidget):
parent_background = ColorProperty(None) parent_background = ColorProperty(None)
can_capitalize = BooleanProperty(True) can_capitalize = BooleanProperty(True)
canvas_bg = ObjectProperty()
def __init__(self, **kwargs): def __init__(self, **kwargs):
super().__init__(**kwargs) super().__init__(**kwargs)
@ -354,7 +349,6 @@ class MDLabel(DeclarativeBehavior, ThemableBehavior, Label, MDAdaptiveWidget):
font_info = self.theme_cls.font_styles[self.font_style] font_info = self.theme_cls.font_styles[self.font_style]
self.font_name = font_info[0] self.font_name = font_info[0]
self.font_size = sp(font_info[1]) self.font_size = sp(font_info[1])
if font_info[2] and self.can_capitalize: if font_info[2] and self.can_capitalize:
self._capitalizing = True self._capitalizing = True
else: else:
@ -380,68 +374,29 @@ class MDLabel(DeclarativeBehavior, ThemableBehavior, Label, MDAdaptiveWidget):
# generic None value it's not yet been set # generic None value it's not yet been set
self._text_color_str = "" self._text_color_str = ""
if theme_text_color == "Custom" and self.text_color: if theme_text_color == "Custom" and self.text_color:
color = self.text_color self.color = self.text_color
elif ( elif (
theme_text_color == "ContrastParentBackground" theme_text_color == "ContrastParentBackground"
and self.parent_background and self.parent_background
): ):
color = get_contrast_text_color(self.parent_background) self.color = get_contrast_text_color(self.parent_background)
else: else:
color = [0, 0, 0, 1] self.color = [0, 0, 0, 1]
if self.theme_cls.theme_style_switch_animation: def on_text_color(self, instance_label, color: list) -> None:
Animation(
color=color,
d=self.theme_cls.theme_style_switch_animation_duration,
t="linear",
).start(self)
else:
self.color = color
def on_text_color(self, instance_label, color: Union[list, str]) -> None:
if self.theme_text_color == "Custom": if self.theme_text_color == "Custom":
if self.theme_cls.theme_style_switch_animation: self.color = self.text_color
Animation(
color=self.text_color,
d=self.theme_cls.theme_style_switch_animation_duration,
t="linear",
).start(self)
else:
self.color = self.text_color
def on_opposite_colors(self, *args) -> None: def on_opposite_colors(self, *args) -> None:
self.on_theme_text_color(self, self.theme_text_color) self.on_theme_text_color(self, self.theme_text_color)
def on_md_bg_color(self, instance_label, color: Union[list, str]) -> None:
self.canvas.remove_group("Background_instruction")
with self.canvas.before:
Color(rgba=color)
self.canvas_bg = Rectangle(pos=self.pos, size=self.size)
self.bind(pos=self.update_canvas_bg_pos)
def on_size(self, instance_label, size: list) -> None:
if self.canvas_bg:
self.canvas_bg.size = size
def update_canvas_bg_pos(self, instance_label, pos: list) -> None:
if self.canvas_bg:
self.canvas_bg.pos = pos
def _do_update_theme_color(self, *args): def _do_update_theme_color(self, *args):
if self._text_color_str: if self._text_color_str:
self.color = getattr(self.theme_cls, self._text_color_str)
if not self.disabled: if not self.disabled:
color = getattr(self.theme_cls, self._text_color_str) self.color = getattr(self.theme_cls, self._text_color_str)
else: else:
color = getattr(self.theme_cls, "disabled_hint_text_color") self.color = getattr(self.theme_cls, "disabled_hint_text_color")
if self.theme_cls.theme_style_switch_animation:
Animation(
color=color,
d=self.theme_cls.theme_style_switch_animation_duration,
t="linear",
).start(self)
else:
self.color = color
class MDIcon(MDFloatLayout, MDLabel): class MDIcon(MDFloatLayout, MDLabel):
@ -501,16 +456,11 @@ class MDIcon(MDFloatLayout, MDLabel):
and defaults to `None`. and defaults to `None`.
""" """
_size = ListProperty((0, 0)) def __init__(self, **kwargs):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
Clock.schedule_once(self.adjust_size)
def adjust_size(self, *args) -> None:
from kivymd.uix.selectioncontrol import MDCheckbox from kivymd.uix.selectioncontrol import MDCheckbox
super().__init__(**kwargs)
if not isinstance(self, MDCheckbox): if not isinstance(self, MDCheckbox):
self.size_hint = (None, None) self.size_hint = (None, None)
self._size = self.texture_size[1], self.texture_size[1] self.size = self.texture_size
self.adaptive_size = True self.adaptive_size = True

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
#:import STANDARD_INCREMENT kivymd.material_resources.STANDARD_INCREMENT #:import STD_INC kivymd.material_resources.STANDARD_INCREMENT
<RightContent> <RightContent>
@ -14,7 +14,7 @@
<MDMenu> <MDMenu>
size_hint: None, None size_hint: None, None
width: root.width_mult * STANDARD_INCREMENT width: root.width_mult * STD_INC
bar_width: 0 bar_width: 0
key_viewclass: "viewclass" key_viewclass: "viewclass"
key_size: "height" key_size: "height"
@ -28,7 +28,7 @@
orientation: "vertical" orientation: "vertical"
<MenuContainer@MDCard> <MenuContainer@MDCard+FakeRectangularElevationBehavior>
<MDDropdownMenu> <MDDropdownMenu>

View File

@ -781,7 +781,7 @@ class MDDropdownMenu(ThemableBehavior, FloatLayout):
and defaults to `'[dp(7)]'`. and defaults to `'[dp(7)]'`.
""" """
elevation = NumericProperty(4) elevation = NumericProperty(10)
""" """
Elevation value of menu dialog. Elevation value of menu dialog.
@ -790,7 +790,7 @@ class MDDropdownMenu(ThemableBehavior, FloatLayout):
.. code-block:: python .. code-block:: python
self.menu = MDDropdownMenu( self.menu = MDDropdownMenu(
elevation=4, elevation=16,
..., ...,
) )
@ -798,7 +798,7 @@ class MDDropdownMenu(ThemableBehavior, FloatLayout):
:align: center :align: center
:attr:`elevation` is an :class:`~kivy.properties.NumericProperty` :attr:`elevation` is an :class:`~kivy.properties.NumericProperty`
and defaults to `4`. and defaults to `10`.
""" """
_start_coords = [] _start_coords = []

View File

@ -61,7 +61,7 @@ A simple example
MDTopAppBar: MDTopAppBar:
title: "Navigation Drawer" title: "Navigation Drawer"
elevation: 4 elevation: 10
pos_hint: {"top": 1} pos_hint: {"top": 1}
md_bg_color: "#e7e4c0" md_bg_color: "#e7e4c0"
specific_text_color: "#4a4939" specific_text_color: "#4a4939"
@ -115,7 +115,7 @@ A simple example
MDScreen( MDScreen(
MDTopAppBar( MDTopAppBar(
title="Navigation Drawer", title="Navigation Drawer",
elevation=4, elevation=10,
pos_hint={"top": 1}, pos_hint={"top": 1},
md_bg_color="#e7e4c0", md_bg_color="#e7e4c0",
specific_text_color="#4a4939", specific_text_color="#4a4939",
@ -188,7 +188,7 @@ Standard content for the navigation bar
MDTopAppBar: MDTopAppBar:
title: "Navigation Drawer" title: "Navigation Drawer"
elevation: 4 elevation: 10
pos_hint: {"top": 1} pos_hint: {"top": 1}
md_bg_color: "#e7e4c0" md_bg_color: "#e7e4c0"
specific_text_color: "#4a4939" specific_text_color: "#4a4939"
@ -296,7 +296,7 @@ Standard content for the navigation bar
MDScreen( MDScreen(
MDTopAppBar( MDTopAppBar(
title="Navigation Drawer", title="Navigation Drawer",
elevation=4, elevation=10,
pos_hint={"top": 1}, pos_hint={"top": 1},
md_bg_color="#e7e4c0", md_bg_color="#e7e4c0",
specific_text_color="#4a4939", specific_text_color="#4a4939",
@ -396,7 +396,7 @@ Switching screens in the ``ScreenManager`` and using the common ``MDTopAppBar``
MDTopAppBar: MDTopAppBar:
pos_hint: {"top": 1} pos_hint: {"top": 1}
elevation: 4 elevation: 10
title: "MDNavigationDrawer" title: "MDNavigationDrawer"
left_action_items: [["menu", lambda x: nav_drawer.set_state("open")]] left_action_items: [["menu", lambda x: nav_drawer.set_state("open")]]
@ -465,7 +465,7 @@ Switching screens in the ``ScreenManager`` and using the common ``MDTopAppBar``
MDScreen( MDScreen(
MDTopAppBar( MDTopAppBar(
pos_hint={"top": 1}, pos_hint={"top": 1},
elevation=4, elevation=10,
title="MDNavigationDrawer", title="MDNavigationDrawer",
left_action_items=[["menu", lambda x: self.nav_drawer_open()]], left_action_items=[["menu", lambda x: self.nav_drawer_open()]],
), ),
@ -551,9 +551,14 @@ from kivy.properties import (
StringProperty, StringProperty,
VariableListProperty, VariableListProperty,
) )
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import ScreenManager from kivy.uix.screenmanager import ScreenManager
from kivymd import uix_path from kivymd import uix_path
from kivymd.uix.behaviors import (
DeclarativeBehavior,
FakeRectangularElevationBehavior,
)
from kivymd.uix.behaviors.focus_behavior import FocusBehavior from kivymd.uix.behaviors.focus_behavior import FocusBehavior
from kivymd.uix.boxlayout import MDBoxLayout from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.card import MDCard from kivymd.uix.card import MDCard
@ -1024,7 +1029,7 @@ class MDNavigationDrawerMenu(MDScrollView):
widget.text_color = widget._text_color widget.text_color = widget._text_color
class MDNavigationDrawer(MDCard): class MDNavigationDrawer(MDCard, FakeRectangularElevationBehavior):
type = OptionProperty("modal", options=("standard", "modal")) type = OptionProperty("modal", options=("standard", "modal"))
""" """
Type of drawer. Modal type will be on top of screen. Standard type will be Type of drawer. Modal type will be on top of screen. Standard type will be

View File

@ -29,86 +29,45 @@ Usage
MDNavigationRailItem: MDNavigationRailItem:
.. tabs:: .. code-block:: python
.. tab:: Declarative KV style from kivy.lang import Builder
.. code-block:: python from kivymd.app import MDApp
from kivy.lang import Builder KV = '''
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): MDBoxLayout:
def build(self):
return Builder.load_string(KV) 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:
'''
Example().run() class Example(MDApp):
def build(self):
.. tab:: Declarative python style return Builder.load_string(KV)
.. code-block:: python
from kivymd.app import MDApp
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.navigationrail import MDNavigationRail, MDNavigationRailItem
class Example(MDApp): Example().run()
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 .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-rail-usage.png
:align: center :align: center
@ -116,412 +75,202 @@ Usage
Example Example
======= =======
.. tabs:: .. code-block:: python
.. tab:: Declarative KV and imperative python styles from kivy.clock import Clock
from kivy.lang import Builder
.. code-block:: python from kivymd.app import MDApp
from kivymd.uix.behaviors import RoundedRectangularElevationBehavior
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.button import MDFillRoundFlatIconButton
from kivymd.uix.label import MDLabel
from kivymd.uix.screen import MDScreen
from kivy.clock import Clock KV = '''
from kivy.lang import Builder #:import FadeTransition kivy.uix.screenmanager.FadeTransition
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> <ExtendedButton>
elevation: 3.5 elevation: 3
shadow_radius: 12 -height: "56dp"
shadow_softness: 4
-height: "56dp"
<DrawerClickableItem@MDNavigationDrawerItem> <DrawerClickableItem@MDNavigationDrawerItem>
focus_color: "#e7e4c0" focus_color: "#e7e4c0"
unfocus_color: "#fffcf4" unfocus_color: "#fffcf4"
MDScreen: MDScreen:
MDNavigationLayout: MDNavigationLayout:
ScreenManager: ScreenManager:
MDScreen: MDScreen:
MDBoxLayout: MDBoxLayout:
orientation: "vertical" 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: 4
width: "240dp"
MDNavigationDrawerMenu:
MDBoxLayout: MDBoxLayout:
orientation: "vertical"
adaptive_height: True adaptive_height: True
spacing: "12dp" md_bg_color: "#fffcf4"
padding: "3dp", 0, 0, "12dp" padding: "12dp"
MDIconButton: MDLabel:
icon: "menu" text: "12:00"
adaptive_height: True
pos_hint: {"center_y": .5}
ExtendedButton: MDBoxLayout:
text: "Compose"
icon: "pencil"
DrawerClickableItem: MDNavigationRail:
text: "Python" id: navigation_rail
icon: "language-python" md_bg_color: "#fffcf4"
selected_color_background: "#e7e4c0"
ripple_color_item: "#e7e4c0"
on_item_release: app.switch_screen(*args)
DrawerClickableItem: MDNavigationRailMenuButton:
text: "JavaScript" on_release: nav_drawer.set_state("open")
icon: "language-javascript"
DrawerClickableItem: MDNavigationRailFabButton:
text: "CPP" md_bg_color: "#b0f0d6"
icon: "language-cpp"
DrawerClickableItem: MDNavigationRailItem:
text: "Swift" text: "Python"
icon: "language-swift" 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: 12
width: "240dp"
MDNavigationDrawerMenu:
MDBoxLayout:
orientation: "vertical"
adaptive_height: True
spacing: "12dp"
padding: 0, 0, 0, "12dp"
MDIconButton:
icon: "menu"
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(
RoundedRectangularElevationBehavior, MDFillRoundFlatIconButton
):
'''
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, **kwargs):
super().__init__(**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:
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 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 = (
class ExtendedButton(MDFillRoundFlatIconButton, CommonElevationBehavior): instance_navigation_rail_item.icon.split("-")[1].lower()
'''
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:
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 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, def on_start(self):
MDNavigationRailMenuButton, '''Creates application screens.'''
MDNavigationRailFabButton,
MDNavigationRailItem, navigation_rail_items = self.root.ids.navigation_rail.get_items()[:]
) navigation_rail_items.reverse()
from kivymd.uix.screen import MDScreen
from kivymd.uix.screenmanager import MDScreenManager 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)
class DrawerClickableItem(MDNavigationDrawerItem): Example().run()
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 = 3.5
self.shadow_radius = 12
self.shadow_softness = 4
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",
),
ExtendedButton(
text="Compose",
icon="pencil",
),
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 .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/navigation-rail-example.gif
:align: center :align: center
@ -557,11 +306,12 @@ from kivy.uix.behaviors import ButtonBehavior
from kivymd import uix_path from kivymd import uix_path
from kivymd.theming import ThemableBehavior from kivymd.theming import ThemableBehavior
from kivymd.uix.behaviors import ScaleBehavior from kivymd.uix.behaviors import FakeRectangularElevationBehavior
from kivymd.uix.boxlayout import MDBoxLayout from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.button import MDFloatingActionButton, MDIconButton from kivymd.uix.button import MDFloatingActionButton, MDIconButton
from kivymd.uix.card import MDCard from kivymd.uix.card import MDCard
from kivymd.uix.floatlayout import MDFloatLayout from kivymd.uix.floatlayout import MDFloatLayout
from kivymd.uix.templates import ScaleWidget
from kivymd.uix.widget import MDWidget from kivymd.uix.widget import MDWidget
with open( with open(
@ -583,7 +333,7 @@ class PanelItems(MDBoxLayout):
"""Box for menu items.""" """Box for menu items."""
class RippleWidget(MDWidget, ScaleBehavior): class RippleWidget(MDWidget, ScaleWidget):
""" """
Implements a background color for a menu item - Implements a background color for a menu item -
(:class:`~MDNavigationRailItem`). (:class:`~MDNavigationRailItem`).
@ -812,7 +562,7 @@ class MDNavigationRailItem(ThemableBehavior, ButtonBehavior, MDBoxLayout):
self.navigation_rail.dispatch("on_item_release", self) self.navigation_rail.dispatch("on_item_release", self)
class MDNavigationRail(MDCard): class MDNavigationRail(MDCard, FakeRectangularElevationBehavior):
""" """
:Events: :Events:
:attr:`on_item_press` :attr:`on_item_press`

View File

@ -11,110 +11,65 @@ Components/DatePicker
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/picker-previous.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/picker-previous.png
:align: center :align: center
.. warning:: The widget is under testing. Therefore, we would be grateful if
you would let us know about the bugs found.
.. rubric:: Usage .. rubric:: Usage
.. tabs:: .. code-block:: python
.. tab:: Declarative KV style from kivy.lang import Builder
.. code-block:: python from kivymd.app import MDApp
from kivymd.uix.pickers import MDDatePicker
from kivy.lang import Builder KV = '''
MDFloatLayout:
from kivymd.app import MDApp MDTopAppBar:
from kivymd.uix.pickers import MDDatePicker title: "MDDatePicker"
pos_hint: {"top": 1}
elevation: 10
KV = ''' MDRaisedButton:
MDFloatLayout: text: "Open date picker"
pos_hint: {'center_x': .5, 'center_y': .5}
on_release: app.show_date_picker()
'''
MDRaisedButton:
text: "Open date picker" class Test(MDApp):
pos_hint: {'center_x': .5, 'center_y': .5} def build(self):
on_release: app.show_date_picker() return Builder.load_string(KV)
def on_save(self, instance, value, date_range):
'''
Events called when the "OK" dialog box button is clicked.
:type instance: <kivymd.uix.picker.MDDatePicker object>;
:param value: selected date;
:type value: <class 'datetime.date'>;
:param date_range: list of 'datetime.date' objects in the selected range;
:type date_range: <class 'list'>;
''' '''
print(instance, value, date_range)
class Test(MDApp): def on_cancel(self, instance, value):
def build(self): '''Events called when the "CANCEL" dialog box button is clicked.'''
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "Orange"
return Builder.load_string(KV)
def on_save(self, instance, value, date_range): def show_date_picker(self):
''' date_dialog = MDDatePicker()
Events called when the "OK" dialog box button is clicked. date_dialog.bind(on_save=self.on_save, on_cancel=self.on_cancel)
date_dialog.open()
:type instance: <kivymd.uix.picker.MDDatePicker object>;
:param value: selected date;
:type value: <class 'datetime.date'>;
:param date_range: list of 'datetime.date' objects in the selected range;
:type date_range: <class 'list'>;
'''
print(instance, value, date_range)
def on_cancel(self, instance, value):
'''Events called when the "CANCEL" dialog box button is clicked.'''
def show_date_picker(self):
date_dialog = MDDatePicker()
date_dialog.bind(on_save=self.on_save, on_cancel=self.on_cancel)
date_dialog.open()
Test().run() Test().run()
.. tab:: Declarative python style
.. code-block:: python
from kivymd.app import MDApp
from kivymd.uix.button import MDRaisedButton
from kivymd.uix.pickers import MDDatePicker
from kivymd.uix.screen import MDScreen
class Test(MDApp): .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/MDDatePicker.gif
def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "Orange"
return (
MDScreen(
MDRaisedButton(
text="Open data picker",
pos_hint={'center_x': .5, 'center_y': .5},
on_release=self.show_date_picker,
)
)
)
def on_save(self, instance, value, date_range):
'''
Events called when the "OK" dialog box button is clicked.
:type instance: <kivymd.uix.picker.MDDatePicker object>;
:param value: selected date;
:type value: <class 'datetime.date'>;
:param date_range: list of 'datetime.date' objects in the selected range;
:type date_range: <class 'list'>;
'''
print(instance, value, date_range)
def on_cancel(self, instance, value):
'''Events called when the "CANCEL" dialog box button is clicked.'''
def show_date_picker(self, *args):
date_dialog = MDDatePicker()
date_dialog.bind(on_save=self.on_save, on_cancel=self.on_cancel)
date_dialog.open()
Test().run()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/MDDatePicker.png
:align: center :align: center
Open date dialog with the specified date Open date dialog with the specified date
@ -126,7 +81,7 @@ Open date dialog with the specified date
date_dialog = MDDatePicker(year=1983, month=4, day=12) date_dialog = MDDatePicker(year=1983, month=4, day=12)
date_dialog.open() date_dialog.open()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/specified-date.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/previous-date.png
:align: center :align: center
Interval date Interval date
@ -139,16 +94,12 @@ that are not included in this range will have the status `disabled`.
def show_date_picker(self): def show_date_picker(self):
date_dialog = MDDatePicker( date_dialog = MDDatePicker(
min_date=datetime.date.today(), min_date=datetime.date(2021, 2, 15),
max_date=datetime.date( max_date=datetime.date(2021, 3, 27),
datetime.date.today().year,
datetime.date.today().month,
datetime.date.today().day + 2,
),
) )
date_dialog.open() date_dialog.open()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/range-date.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/range-date.gif
:align: center :align: center
The range of available dates can be changed in the picker dialog: The range of available dates can be changed in the picker dialog:
@ -171,7 +122,7 @@ You can set the range of years using the :attr:`~kivymd.uix.picker.MDDatePicker.
.. code-block:: python .. code-block:: python
def show_date_picker(self): def show_date_picker(self):
date_dialog = MDDatePicker(min_year=2022, max_year=2030) date_dialog = MDDatePicker(min_year=2021, max_year=2030)
date_dialog.open() date_dialog.open()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/min-max-year-date.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/min-max-year-date.png
@ -190,8 +141,6 @@ Set and select a date range
:align: center :align: center
""" """
from __future__ import annotations
__all__ = ("MDDatePicker", "BaseDialogPicker", "DatePickerInputField") __all__ = ("MDDatePicker", "BaseDialogPicker", "DatePickerInputField")
import calendar import calendar
@ -203,6 +152,7 @@ from typing import Union
from kivy import Logger from kivy import Logger
from kivy.animation import Animation from kivy.animation import Animation
from kivy.clock import Clock
from kivy.lang import Builder from kivy.lang import Builder
from kivy.metrics import dp from kivy.metrics import dp
from kivy.properties import ( from kivy.properties import (
@ -225,7 +175,7 @@ from kivymd.theming import ThemableBehavior, ThemeManager
from kivymd.toast import toast from kivymd.toast import toast
from kivymd.uix.behaviors import ( from kivymd.uix.behaviors import (
CircularRippleBehavior, CircularRippleBehavior,
CommonElevationBehavior, FakeRectangularElevationBehavior,
SpecificBackgroundColorBehavior, SpecificBackgroundColorBehavior,
) )
from kivymd.uix.boxlayout import MDBoxLayout from kivymd.uix.boxlayout import MDBoxLayout
@ -244,7 +194,7 @@ with open(
class BaseDialogPicker( class BaseDialogPicker(
BaseDialog, BaseDialog,
CommonElevationBehavior, FakeRectangularElevationBehavior,
SpecificBackgroundColorBehavior, SpecificBackgroundColorBehavior,
): ):
""" """
@ -305,11 +255,11 @@ class BaseDialogPicker(
primary_color = ColorProperty(None) primary_color = ColorProperty(None)
""" """
Background color of toolbar in (r, g, b, a) or string format. Background color of toolbar in (r, g, b, a) format.
.. code-block:: python .. code-block:: python
MDDatePicker(primary_color="brown") MDDatePicker(primary_color=get_color_from_hex("#72225b"))
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/primary-color-date.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/primary-color-date.png
:align: center :align: center
@ -320,13 +270,13 @@ class BaseDialogPicker(
accent_color = ColorProperty(None) accent_color = ColorProperty(None)
""" """
Background color of calendar/clock face in (r, g, b, a) or string format. Background color of calendar/clock face in (r, g, b, a) format.
.. code-block:: python .. code-block:: python
MDDatePicker( MDDatePicker(
primary_color="brown", primary_color=get_color_from_hex("#72225b"),
accent_color="darkred", accent_color=get_color_from_hex("#5d1a4a"),
) )
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/accent-color-date.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/accent-color-date.png
@ -338,15 +288,14 @@ class BaseDialogPicker(
selector_color = ColorProperty(None) selector_color = ColorProperty(None)
""" """
Background color of the selected day of the month or hour in (r, g, b, a) Background color of the selected day of the month or hour in (r, g, b, a) format.
or string format.
.. code-block:: python .. code-block:: python
MDDatePicker( MDDatePicker(
primary_color="brown", primary_color=get_color_from_hex("#72225b"),
accent_color="darkred", accent_color=get_color_from_hex("#5d1a4a"),
selector_color="red", selector_color=get_color_from_hex("#e93f39"),
) )
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/selector-color-date.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/selector-color-date.png
@ -358,15 +307,15 @@ class BaseDialogPicker(
text_toolbar_color = ColorProperty(None) text_toolbar_color = ColorProperty(None)
""" """
Color of labels for text on a toolbar in (r, g, b, a) or string format. Color of labels for text on a toolbar in (r, g, b, a) format.
.. code-block:: python .. code-block:: python
MDDatePicker( MDDatePicker(
primary_color="brown", primary_color=get_color_from_hex("#72225b"),
accent_color="darkred", accent_color=get_color_from_hex("#5d1a4a"),
selector_color="red", selector_color=get_color_from_hex("#e93f39"),
text_toolbar_color="lightgrey", text_toolbar_color=get_color_from_hex("#cccccc"),
) )
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-toolbar-color-date.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-toolbar-color-date.png
@ -378,16 +327,16 @@ class BaseDialogPicker(
text_color = ColorProperty(None) text_color = ColorProperty(None)
""" """
Color of text labels in calendar/clock face in (r, g, b, a) or string format. Color of text labels in calendar/clock face in (r, g, b, a) format.
.. code-block:: python .. code-block:: python
MDDatePicker( MDDatePicker(
primary_color="brown", primary_color=get_color_from_hex("#72225b"),
accent_color="darkred", accent_color=get_color_from_hex("#5d1a4a"),
selector_color="red", selector_color=get_color_from_hex("#e93f39"),
text_toolbar_color="lightgrey", text_toolbar_color=get_color_from_hex("#cccccc"),
text_color="orange", text_color=("#ffffff"),
) )
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-color-date.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-color-date.png
@ -399,18 +348,17 @@ class BaseDialogPicker(
text_current_color = ColorProperty(None) text_current_color = ColorProperty(None)
""" """
Color of the text of the current day of the month/hour in (r, g, b, a) Color of the text of the current day of the month/hour in (r, g, b, a) format.
or string format.
.. code-block:: python .. code-block:: python
MDDatePicker( MDDatePicker(
primary_color="brown", primary_color=get_color_from_hex("#72225b"),
accent_color="darkred", accent_color=get_color_from_hex("#5d1a4a"),
selector_color="red", selector_color=get_color_from_hex("#e93f39"),
text_toolbar_color="lightgrey", text_toolbar_color=get_color_from_hex("#cccccc"),
text_color="orange", text_color=("#ffffff"),
text_current_color="white", text_current_color=get_color_from_hex("#e93f39"),
) )
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-current-color-date.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-current-color-date.png
@ -427,13 +375,13 @@ class BaseDialogPicker(
.. code-block:: python .. code-block:: python
MDDatePicker( MDDatePicker(
primary_color="brown", primary_color=get_color_from_hex("#72225b"),
accent_color="darkred", accent_color=get_color_from_hex("#5d1a4a"),
selector_color="red", selector_color=get_color_from_hex("#e93f39"),
text_toolbar_color="lightgrey", text_toolbar_color=get_color_from_hex("#cccccc"),
text_color="orange", text_color=("#ffffff"),
text_current_color="white", text_current_color=get_color_from_hex("#e93f39"),
text_button_color="lightgrey", text_button_color=(1, 1, 1, .5),
) )
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-button-color-date.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-button-color-date.png
@ -443,124 +391,52 @@ class BaseDialogPicker(
and defaults to `None`. and defaults to `None`.
""" """
input_field_background_color_normal = ColorProperty(None) input_field_background_color = ColorProperty(None)
""" """
Background color normal of input fields in (r, g, b, a) or string format. Background color of input fields in (r, g, b, a) format.
.. versionadded:: 1.1.0
.. code-block:: python .. code-block:: python
MDDatePicker( MDDatePicker(
primary_color="brown", primary_color=get_color_from_hex("#72225b"),
accent_color="darkred", accent_color=get_color_from_hex("#5d1a4a"),
selector_color="red", selector_color=get_color_from_hex("#e93f39"),
text_toolbar_color="lightgrey", text_toolbar_color=get_color_from_hex("#cccccc"),
text_color="orange", text_color=("#ffffff"),
text_current_color="white", text_current_color=get_color_from_hex("#e93f39"),
text_button_color="lightgrey", input_field_background_color=(1, 1, 1, 0.2),
input_field_background_color_normal="coral",
) )
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/input-field-background-color-date.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/input-field-background-color-date.png
:align: center :align: center
:attr:`input_field_background_color_normal` is an :class:`~kivy.properties.ColorProperty` :attr:`input_field_background_color` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`. and defaults to `None`.
""" """
input_field_background_color_focus = ColorProperty(None)
"""
Background color normal of input fields in (r, g, b, a) or string format.
.. versionadded:: 1.1.0
.. code-block:: python
MDDatePicker(
primary_color="brown",
accent_color="darkred",
selector_color="red",
text_toolbar_color="lightgrey",
text_color="orange",
text_current_color="white",
text_button_color="lightgrey",
input_field_background_color_normal="coral",
input_field_background_color_focus="red",
)
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/input-field-background-color-focus-date.png
:align: center
:attr:`input_field_background_color_focus` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
input_field_background_color = ColorProperty(None)
"""
.. deprecated:: 1.1.0
Use :attr:`input_field_background_color_normal` instead.
"""
input_field_text_color = ColorProperty(None) input_field_text_color = ColorProperty(None)
""" """
.. deprecated:: 1.1.0 Text color of input fields in (r, g, b, a) format.
Use :attr:`input_field_text_color_normal` instead.
"""
input_field_text_color_normal = ColorProperty(None) Background color of input fields.
"""
Text color normal of input fields in (r, g, b, a) or string format.
.. versionadded:: 1.1.0
.. code-block:: python .. code-block:: python
MDDatePicker( MDDatePicker(
primary_color="brown", primary_color=get_color_from_hex("#72225b"),
accent_color="darkred", accent_color=get_color_from_hex("#5d1a4a"),
selector_color="red", selector_color=get_color_from_hex("#e93f39"),
text_toolbar_color="lightgrey", text_toolbar_color=get_color_from_hex("#cccccc"),
text_color="orange", text_color=("#ffffff"),
text_current_color="white", text_current_color=get_color_from_hex("#e93f39"),
text_button_color="lightgrey", input_field_background_color=(1, 1, 1, 0.2),
input_field_background_color_normal="brown", input_field_text_color=(1, 1, 1, 1),
input_field_background_color_focus="red",
input_field_text_color_normal="white",
) )
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/input-field-text-color-normal-date.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/input-field-background-color-date.png
:align: center :align: center
:attr:`input_field_text_color_normal` is an :class:`~kivy.properties.ColorProperty` :attr:`input_field_text_color` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
input_field_text_color_focus = ColorProperty(None)
"""
Text color focus of input fields in (r, g, b, a) or string format.
.. versionadded:: 1.1.0
.. code-block:: python
MDDatePicker(
primary_color="brown",
accent_color="darkred",
selector_color="red",
text_toolbar_color="lightgrey",
text_color="orange",
text_current_color="white",
text_button_color="lightgrey",
input_field_background_color_normal="brown",
input_field_background_color_focus="red",
input_field_text_color_normal="white",
)
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/input-field-text-color-normal-date.png
:align: center
:attr:`input_field_text_color_focus` is an :class:`~kivy.properties.ColorProperty`
and defaults to `None`. and defaults to `None`.
""" """
@ -571,18 +447,16 @@ class BaseDialogPicker(
.. code-block:: python .. code-block:: python
MDDatePicker( MDDatePicker(
primary_color="brown", primary_color=get_color_from_hex("#72225b"),
accent_color="darkred", accent_color=get_color_from_hex("#5d1a4a"),
selector_color="red", selector_color=get_color_from_hex("#e93f39"),
text_toolbar_color="lightgrey", text_toolbar_color=get_color_from_hex("#cccccc"),
text_color="orange", text_color=("#ffffff"),
text_current_color="white", text_current_color=get_color_from_hex("#e93f39"),
text_button_color="lightgrey", input_field_background_color=(1, 1, 1, 0.2),
input_field_background_color_normal="brown", input_field_text_color=(1, 1, 1, 1),
input_field_background_color_focus="red", font_name="Weather.ttf",
input_field_text_color_normal="white",
input_field_text_color_focus="lightgrey",
font_name="nasalization.ttf",
) )
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/font-name-date.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/font-name-date.png
@ -597,20 +471,6 @@ class BaseDialogPicker(
self.register_event_type("on_save") self.register_event_type("on_save")
self.register_event_type("on_cancel") self.register_event_type("on_cancel")
def on_input_field_background_color(
self, instance, value: str | list | tuple
) -> None:
"""For supported of current API."""
self.input_field_background_color_normal = value
def on_input_field_text_color(
self, instance, value: str | list | tuple
) -> None:
"""For supported of current API."""
self.input_field_text_color_normal = value
def on_save(self, *args) -> None: def on_save(self, *args) -> None:
"""Events called when the "OK" dialog box button is clicked.""" """Events called when the "OK" dialog box button is clicked."""
@ -746,13 +606,6 @@ class DatePickerDaySelectableItem(
self.owner.set_selected_widget(self) self.owner.set_selected_widget(self)
def on_touch_down(self, touch):
# If year_layout is active don't dispatch on_touch_down events,
# so date items don't consume touch.
if not self.owner.ids._year_layout.disabled:
return
super().on_touch_down(touch)
class DatePickerYearSelectableItem(RecycleDataViewBehavior, MDLabel): class DatePickerYearSelectableItem(RecycleDataViewBehavior, MDLabel):
"""Implements an item for a pick list of the year.""" """Implements an item for a pick list of the year."""
@ -808,7 +661,7 @@ class DatePickerYearSelectableItem(RecycleDataViewBehavior, MDLabel):
class MDDatePicker(BaseDialogPicker): class MDDatePicker(BaseDialogPicker):
text_weekday_color = ColorProperty(None) text_weekday_color = ColorProperty(None)
""" """
Text color of weekday names in (r, g, b, a) or string format. Text color of weekday names in (r, g, b, a) format.
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-date-picker-text-weekday-color.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-date-picker-text-weekday-color.png
:align: center :align: center
@ -1347,39 +1200,19 @@ class MDDatePicker(BaseDialogPicker):
"""Creates and returns a text field object used to enter dates.""" """Creates and returns a text field object used to enter dates."""
if issubclass(self.input_field_cls, MDTextField): if issubclass(self.input_field_cls, MDTextField):
text_color_focus = (
self.input_field_text_color_focus
if self.input_field_text_color_focus
else self.theme_cls.primary_color
)
text_color_normal = (
self.input_field_text_color_normal
if self.input_field_text_color_normal
else self.theme_cls.disabled_hint_text_color
)
fill_color_focus = (
self.input_field_background_color_focus
if self.input_field_background_color_focus
else self.theme_cls.bg_dark
)
fill_color_normal = (
self.input_field_background_color_normal
if self.input_field_background_color_normal
else self.theme_cls.bg_darkest
)
field = self.input_field_cls( field = self.input_field_cls(
owner=self, owner=self,
helper_text=self.helper_text, helper_text=self.helper_text,
fill_color_normal=fill_color_normal, line_color_normal=self.theme_cls.divider_color,
fill_color_focus=fill_color_focus,
hint_text_color_normal=text_color_normal,
hint_text_color_focus=text_color_focus,
text_color_normal=text_color_normal,
text_color_focus=text_color_focus,
line_color_focus=text_color_focus,
line_color_normal=text_color_normal,
) )
field.color_mode = "custom"
field.line_color_focus = (
self.theme_cls.primary_color
if not self.input_field_text_color
else self.input_field_text_color
)
field.current_hint_text_color = field.line_color_focus
field._current_hint_text_color = field.line_color_focus
return field return field
else: else:
raise TypeError( raise TypeError(

View File

@ -16,73 +16,35 @@ Components/TimePicker
.. rubric:: Usage .. rubric:: Usage
.. tabs:: .. code-block::
.. tab:: Declarative KV style from kivy.lang import Builder
.. code-block:: python from kivymd.app import MDApp
from kivymd.uix.pickers import MDTimePicker
from kivy.lang import Builder KV = '''
MDFloatLayout:
from kivymd.app import MDApp MDRaisedButton:
from kivymd.uix.pickers import MDTimePicker text: "Open time picker"
pos_hint: {'center_x': .5, 'center_y': .5}
KV = ''' on_release: app.show_time_picker()
MDFloatLayout: '''
MDRaisedButton:
text: "Open time picker"
pos_hint: {'center_x': .5, 'center_y': .5}
on_release: app.show_time_picker()
'''
class Test(MDApp): class Test(MDApp):
def build(self): def build(self):
self.theme_cls.theme_style = "Dark" return Builder.load_string(KV)
self.theme_cls.primary_palette = "Orange"
return Builder.load_string(KV)
def show_time_picker(self): def show_time_picker(self):
'''Open time picker dialog.''' '''Open time picker dialog.'''
time_dialog = MDTimePicker() time_dialog = MDTimePicker()
time_dialog.open() time_dialog.open()
Test().run() Test().run()
.. tab:: Declarative python style
.. code-block:: python
from kivymd.app import MDApp
from kivymd.uix.button import MDRaisedButton
from kivymd.uix.pickers import MDTimePicker
from kivymd.uix.screen import MDScreen
class Test(MDApp):
def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "Orange"
return (
MDScreen(
MDRaisedButton(
text="Open time picker",
pos_hint={'center_x': .5, 'center_y': .5},
on_release=self.show_time_picker,
)
)
)
def show_time_picker(self, *args):
'''Open time picker dialog.'''
MDTimePicker().open()
Test().run()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/MDTimePicker.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/MDTimePicker.png
:align: center :align: center
@ -129,14 +91,14 @@ Use the :attr:`~MDTimePicker.set_time` method of the
.. code-block:: python .. code-block:: python
MDTimePicker( time_dialog = MDTimePicker(
primary_color="brown", primary_color=get_color_from_hex("#72225b"),
accent_color="red", accent_color=get_color_from_hex("#5d1a4a"),
text_button_color="white", text_button_color=(1, 1, 1, 1),
).open() )
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/time-picker-customization.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/time-picker-customization.png
:align: center :align: center
""" """
__all__ = ("MDTimePicker",) __all__ = ("MDTimePicker",)
@ -232,8 +194,8 @@ class TimeInputTextField(MDTextField):
hour_regx = "^[0-9]$|^0[1-9]$|^1[0-2]$" hour_regx = "^[0-9]$|^0[1-9]$|^1[0-2]$"
minute_regx = "^[0-9]$|^0[0-9]$|^[1-5][0-9]$" minute_regx = "^[0-9]$|^0[0-9]$|^[1-5][0-9]$"
def __init__(self, *args, **kwargs): def __init__(self, **kwargs):
super().__init__(*args, **kwargs) super().__init__(**kwargs)
Clock.schedule_once(self.set_text) Clock.schedule_once(self.set_text)
self.register_event_type("on_select") self.register_event_type("on_select")
self.bind(text_color_focus=self.setter("hint_text_color_normal")) self.bind(text_color_focus=self.setter("hint_text_color_normal"))
@ -255,20 +217,17 @@ class TimeInputTextField(MDTextField):
to somehow make them aligned. to somehow make them aligned.
""" """
def set_text(*args): if not self.text:
if not self.text: self.text = " "
self.text = " "
self._refresh_text(self.text) self._refresh_text(self.text)
max_size = max(self._lines_rects, key=lambda r: r.size[0]).size max_size = max(self._lines_rects, key=lambda r: r.size[0]).size
dx = (self.width - max_size[0]) / 2.0 dx = (self.width - max_size[0]) / 2.0
dy = (self.height - max_size[1]) / 2.0 dy = (self.height - max_size[1]) / 2.0
self.padding = [dx, dy, dx, dy] self.padding = [dx, dy, dx, dy]
if len(self.text) > 1: if len(self.text) > 1:
self.text = self.text.replace(" ", "") self.text = self.text.replace(" ", "")
Clock.schedule_once(set_text)
def on_focus(self, *args) -> None: def on_focus(self, *args) -> None:
super().on_focus(*args) super().on_focus(*args)

View File

@ -36,7 +36,7 @@ Example
title: app.title title: app.title
md_bg_color: app.theme_cls.primary_color md_bg_color: app.theme_cls.primary_color
background_palette: 'Primary' background_palette: 'Primary'
elevation: 4 elevation: 10
left_action_items: [['menu', lambda x: x]] left_action_items: [['menu', lambda x: x]]
MDScrollViewRefreshLayout: MDScrollViewRefreshLayout:

View File

@ -29,7 +29,7 @@ MDScreen
md_bg_color: app.theme_cls.primary_color md_bg_color: app.theme_cls.primary_color
""" """
from kivy.properties import ListProperty, ObjectProperty from kivy.properties import ObjectProperty
from kivy.uix.screenmanager import Screen from kivy.uix.screenmanager import Screen
from kivymd.uix import MDAdaptiveWidget from kivymd.uix import MDAdaptiveWidget
@ -44,34 +44,20 @@ class MDScreen(DeclarativeBehavior, Screen, MDAdaptiveWidget):
see in the :class:`~kivy.uix.screenmanager.Screen` class documentation. see in the :class:`~kivy.uix.screenmanager.Screen` class documentation.
""" """
hero_to = ObjectProperty(deprecated=True) hero_to = ObjectProperty()
""" """
Must be a :class:`~kivymd.uix.hero.MDHeroTo` class. Must be a :class:`~kivymd.uix.hero.MDHeroTo` class.
See the documentation of the See the documentation of the
`MDHeroTo <https://kivymd.readthedocs.io/en/latest/components/hero/>`_ `MDHeroTo <https://kivymd.readthedocs.io/en/latest/components/hero/>`_
widget for more detailed information. widget for more detailed information.
.. deprecated:: 1.0.0 .. versionchanged:: 1.0.0
Use attr:`heroes_to` attribute instead.
:attr:`hero_to` is an :class:`~kivy.properties.ObjectProperty` :attr:`hero_to` is an :class:`~kivy.properties.ObjectProperty`
and defaults to `None`. and defaults to `None`.
""" """
heroes_to = ListProperty() def on_hero_to(self, screen, widget) -> None:
"""
Must be a list of :class:`~kivymd.uix.hero.MDHeroTo` class.
.. versionadded:: 1.0.0
:attr:`heroes_to` is an :class:`~kivy.properties.LiatProperty`
and defaults to `[]`.
"""
def on_hero_to(self, screen, widget: MDHeroTo) -> None:
"""Called when the value of the :attr:`hero_to` attribute changes."""
if not isinstance(widget, MDHeroTo) or not issubclass( if not isinstance(widget, MDHeroTo) or not issubclass(
widget.__class__, MDHeroTo widget.__class__, MDHeroTo
): ):
@ -79,4 +65,3 @@ class MDScreen(DeclarativeBehavior, Screen, MDAdaptiveWidget):
f"The `{widget}` widget must be an `kivymd.uix.hero.MDHeroTo` " f"The `{widget}` widget must be an `kivymd.uix.hero.MDHeroTo` "
f"class or inherited from this class" f"class or inherited from this class"
) )
self.heroes_to = [widget]

View File

@ -10,7 +10,6 @@ If you want to use Hero animations you need to use
:class:`~kivy.uix.screenmanager.ScreenManager` class. :class:`~kivy.uix.screenmanager.ScreenManager` class.
""" """
from kivy import Logger
from kivy.clock import Clock from kivy.clock import Clock
from kivy.properties import ListProperty, StringProperty from kivy.properties import ListProperty, StringProperty
from kivy.uix.screenmanager import ScreenManager from kivy.uix.screenmanager import ScreenManager
@ -22,22 +21,17 @@ from kivymd.uix.hero import MDHeroFrom
class MDScreenManager(DeclarativeBehavior, ScreenManager): class MDScreenManager(DeclarativeBehavior, ScreenManager):
""" """
Screen manager. This is the main class that will control your Screen manager. This is the main class that will control your
:class:`~kivymd.uix.screen.MDScreen` stack and memory. :class:`~kivymd.uix.screen.MDScreen` stack and memory. For more
For more
information, see in the :class:`~kivy.uix.screenmanager.ScreenManager` information, see in the :class:`~kivy.uix.screenmanager.ScreenManager`
class documentation. class documentation.
""" """
current_hero = StringProperty(None, deprecated=True) current_hero = StringProperty(None)
""" """
The name of the current tag for the :class:`~kivymd.uix.hero.MDHeroFrom` The name of the current tag for the :class:`~kivymd.uix.hero.MDHeroFrom`
and :class:`~kivymd.uix.hero.MDHeroTo` objects that will be animated when and :class:`~kivymd.uix.hero.MDHeroTo` objects that will be animated when
animating the transition between screens. animating the transition between screens.
.. deprecated:: 1.1.0
Use :attr:`current_heroes` attribute instead.
See the `Hero <https://kivymd.readthedocs.io/en/latest/components/hero/>`_ See the `Hero <https://kivymd.readthedocs.io/en/latest/components/hero/>`_
module documentation for more information about creating and using Hero module documentation for more information about creating and using Hero
animations. animations.
@ -46,17 +40,6 @@ class MDScreenManager(DeclarativeBehavior, ScreenManager):
and defaults to `None`. and defaults to `None`.
""" """
current_heroes = ListProperty()
"""
A list of names (tags) of heroes that need to be animated when moving
to the next screen.
.. versionadded:: 1.1.0
:attr:`current_heroes` is an :class:`~kivy.properties.ListProperty`
and defaults to `[]`.
"""
# Collection of `MDHeroFrom` objects on all screens of the current # Collection of `MDHeroFrom` objects on all screens of the current
# screen manager. # screen manager.
_heroes_data = ListProperty() _heroes_data = ListProperty()
@ -75,48 +58,28 @@ class MDScreenManager(DeclarativeBehavior, ScreenManager):
self.transition = MDSlideTransition() self.transition = MDSlideTransition()
def get_hero_from_widget(self) -> list: def get_hero_from_widget(self) -> None:
""" """
Get a list of :class:`~kivymd.uix.hero.MDHeroFrom` objects according Get an :class:`~kivymd.uix.hero.MDHeroTo` object with the
to the tag names specified in the :attr:`~current_heroes` list. :attr:`~current_hero` tag.
""" """
hero_from_widget = [] hero_from_widget = None
for name_hero in self.current_heroes: for hero_widget in self._heroes_data:
for hero_widget in self._heroes_data: if isinstance(hero_widget, MDHeroFrom) or issubclass(
if isinstance(hero_widget, MDHeroFrom) or issubclass( hero_widget.__class__, MDHeroFrom
hero_widget.__class__, MDHeroFrom ):
): if hero_widget.tag == self.current_hero:
if hero_widget.tag == name_hero: hero_from_widget = hero_widget
hero_from_widget.append(hero_widget) break
return hero_from_widget return hero_from_widget
def on_current_hero(self, instance, value: str) -> None:
"""
Called when the value of the :attr:`current_hero` attribute changes.
"""
Logger.warning(
"KivyMD: "
"`kivymd/uix/screenmanager.MDScreenManager.current_hero` "
"attribute is deprecated. "
"Use `kivymd/uix/screenmanager.MDScreenManager.current_heroes` "
"attribute instead."
)
if value:
self.current_heroes = [value]
else:
self.current_heroes = []
def add_widget(self, widget, *args, **kwargs): def add_widget(self, widget, *args, **kwargs):
super().add_widget(widget, *args, **kwargs) super().add_widget(widget, *args, **kwargs)
Clock.schedule_once(lambda x: self._create_heroes_data(widget)) Clock.schedule_once(lambda x: self._create_heroes_data(widget))
# TODO: Add a method to delete an object from the arrt:`_heroes_data`
# collection when deleting an object using the `remove_widget` method.
def _create_heroes_data(self, widget): def _create_heroes_data(self, widget):
def find_hero_widget(child_widget): def find_hero_widget(child_widget):
widget_hero = None widget_hero = None

View File

@ -15,11 +15,8 @@
pos_hint: {"center_y": .5} pos_hint: {"center_y": .5}
x: root._segment_switch_x x: root._segment_switch_x
md_bg_color: root.segment_color md_bg_color: root.segment_color
elevation: 2 elevation: 6
_radius: root.radius[0] - 4 _radius: root.radius[0] - 4
width:
segment_panel.width / segment_panel.children_number \
- segment_panel.spacing
SegmentPanel: SegmentPanel:
id: segment_panel id: segment_panel

View File

@ -10,77 +10,58 @@ Components/SegmentedControl
Usage Usage
===== =====
.. tabs:: .. code-block:: python
.. tab:: Declarative KV style from kivy.lang import Builder
.. code-block:: python from kivymd.app import MDApp
from kivy.lang import Builder
from kivymd.app import MDApp
KV = ''' KV = '''
MDScreen: MDScreen:
MDSegmentedControl: MDSegmentedControl:
pos_hint: {"center_x": .5, "center_y": .5} pos_hint: {"center_x": .5, "center_y": .5}
MDSegmentedControlItem: MDSegmentedControlItem:
text: "Male" text: "Male"
MDSegmentedControlItem: MDSegmentedControlItem:
text: "Female" text: "Female"
MDSegmentedControlItem: MDSegmentedControlItem:
text: "All" text: "All"
''' '''
class Example(MDApp): class Test(MDApp):
def build(self): def build(self):
self.theme_cls.theme_style = "Dark" return Builder.load_string(KV)
self.theme_cls.primary_palette = "Orange"
return Builder.load_string(KV)
Example().run() Test().run()
.. tab:: Declarative python style Or only in python code:
.. code-block:: python .. code-block:: python
from kivymd.app import MDApp from kivymd.app import MDApp
from kivymd.uix.screen import MDScreen from kivymd.uix.screen import MDScreen
from kivymd.uix.segmentedcontrol import ( from kivymd.uix.segmentedcontrol import MDSegmentedControl, MDSegmentedControlItem
MDSegmentedControl, MDSegmentedControlItem
)
class Example(MDApp): class Test(MDApp):
def build(self): def build(self):
self.theme_cls.theme_style = "Dark" screen = MDScreen()
self.theme_cls.primary_palette = "Orange" segment_control = MDSegmentedControl(pos_hint={"center_x": .5, "center_y": .5})
return ( segment_control.add_widget(MDSegmentedControlItem(text="Male"))
MDScreen( segment_control.add_widget(MDSegmentedControlItem(text="Female"))
MDSegmentedControl( segment_control.add_widget(MDSegmentedControlItem(text="All"))
MDSegmentedControlItem( screen.add_widget(segment_control)
text="Male" return screen
),
MDSegmentedControlItem(
text="Female"
),
MDSegmentedControlItem(
text="All"
),
pos_hint={"center_x": 0.5, "center_y": 0.5}
)
)
)
Example().run() Test().run()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-segmented-control-usage.gif .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-segmented-control-usage.gif
:align: center :align: center
@ -136,22 +117,12 @@ with open(
class MDSegmentedControlItem(MDLabel): class MDSegmentedControlItem(MDLabel):
""" """Implements a label to place on the :class:`~SegmentPanel` panel."""
Implements a label to place on the :class:`~SegmentPanel` panel.
See :class:`~kivymd.uix.label.MDLabel` class documentation for more
information.
"""
# TODO: Add an attribute for the color of the active segment label. # TODO: Add an attribute for the color of the active segment label.
class MDSegmentedControl(MDRelativeLayout, ThemableBehavior): class MDSegmentedControl(MDRelativeLayout, ThemableBehavior):
""" """
Implements a segmented control panel.
Relative layout class. For more information, see in the
:class:`~kivy.uix.relativelayout.RelativeLayout` class documentation.
:Events: :Events:
`on_active` `on_active`
Called when the segment is activated. Called when the segment is activated.
@ -164,7 +135,7 @@ class MDSegmentedControl(MDRelativeLayout, ThemableBehavior):
.. code-block:: kv .. code-block:: kv
MDSegmentedControl: MDSegmentedControl:
md_bg_color: "brown" md_bg_color: "#451938"
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-segmented-control-md-bg-color.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-segmented-control-md-bg-color.png
:align: center :align: center
@ -180,8 +151,8 @@ class MDSegmentedControl(MDRelativeLayout, ThemableBehavior):
.. code-block:: kv .. code-block:: kv
MDSegmentedControl: MDSegmentedControl:
md_bg_color: "brown" md_bg_color: "#451938"
segment_color: "red" segment_color: "#e4514f"
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-segmented-control-segment-color.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-segmented-control-segment-color.png
:align: center :align: center
@ -189,8 +160,8 @@ class MDSegmentedControl(MDRelativeLayout, ThemableBehavior):
.. code-block:: kv .. code-block:: kv
MDSegmentedControl: MDSegmentedControl:
md_bg_color: "brown" md_bg_color: "#451938"
segment_color: "red" segment_color: "#e4514f"
MDSegmentedControlItem: MDSegmentedControlItem:
text: "[color=fff]Male[/color]" text: "[color=fff]Male[/color]"
@ -225,9 +196,9 @@ class MDSegmentedControl(MDRelativeLayout, ThemableBehavior):
.. code-block:: kv .. code-block:: kv
MDSegmentedControl: MDSegmentedControl:
md_bg_color: "brown" md_bg_color: "#451938"
segment_color: "red" segment_color: "#e4514f"
separator_color: "white" separator_color: 1, 1, 1, 1
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-segmented-control-separator-color.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/md-segmented-control-separator-color.png
:align: center :align: center
@ -284,6 +255,9 @@ class MDSegmentedControl(MDRelativeLayout, ThemableBehavior):
Clock.schedule_once(self.set_default_colors) Clock.schedule_once(self.set_default_colors)
Clock.schedule_once(self._remove_last_separator) Clock.schedule_once(self._remove_last_separator)
# FIXME: Sometimes this interval is not enough to get the width
# of the segment label textures.
Clock.schedule_once(self._set_width_segment_switch, 2.2)
def set_default_colors(self, *args) -> None: def set_default_colors(self, *args) -> None:
""" """
@ -339,10 +313,6 @@ class MDSegmentedControl(MDRelativeLayout, ThemableBehavior):
self.ids.segment_panel.add_widget(widget) self.ids.segment_panel.add_widget(widget)
separator = MDSeparator(orientation="vertical") separator = MDSeparator(orientation="vertical")
self.ids.segment_panel.add_widget(separator) self.ids.segment_panel.add_widget(separator)
if not self.ids.segment_panel._started:
self.ids.segment_panel._started = True
else:
self.ids.segment_panel.children_number += 1
Clock.schedule_once( Clock.schedule_once(
lambda x: self.update_separator_color(separator) lambda x: self.update_separator_color(separator)
) )
@ -356,6 +326,15 @@ class MDSegmentedControl(MDRelativeLayout, ThemableBehavior):
self.current_active_segment = widget self.current_active_segment = widget
self.dispatch("on_active", widget) self.dispatch("on_active", widget)
def _set_width_segment_switch(self, *args):
"""
Sets the width of the switch. I think this is not done quite correctly.
"""
self.ids.segment_switch.width = self.ids.segment_panel.children[
0
].width + dp(12)
def _remove_last_separator(self, *args): def _remove_last_separator(self, *args):
self.ids.segment_panel.remove_widget(self.ids.segment_panel.children[0]) self.ids.segment_panel.remove_widget(self.ids.segment_panel.children[0])
@ -371,7 +350,3 @@ class SegmentPanel(MDBoxLayout):
Implements a panel for placing items - :class:`~MDSegmentedControlItem` Implements a panel for placing items - :class:`~MDSegmentedControlItem`
for the :class:`~MDSegmentedControl` class. for the :class:`~MDSegmentedControl` class.
""" """
children_number = NumericProperty(1)
_started = BooleanProperty(defaultvalue=False)

View File

@ -101,7 +101,7 @@
size_hint: None, None size_hint: None, None
size: dp(24), dp(24) size: dp(24), dp(24)
elevation: elevation:
(2.5 if root.active else 1) \ (8 if root.active else 5) \
if app.theme_cls.material_style != "M3" else \ if app.theme_cls.material_style != "M3" else \
0 0
pos: pos:

View File

@ -192,10 +192,15 @@ from kivy.properties import (
) )
from kivy.uix.behaviors import ToggleButtonBehavior from kivy.uix.behaviors import ToggleButtonBehavior
from kivy.uix.floatlayout import FloatLayout from kivy.uix.floatlayout import FloatLayout
from kivy.utils import get_color_from_hex
from kivymd import uix_path from kivymd import uix_path
from kivymd.color_definitions import colors
from kivymd.theming import ThemableBehavior from kivymd.theming import ThemableBehavior
from kivymd.uix.behaviors import CircularRippleBehavior, CommonElevationBehavior from kivymd.uix.behaviors import (
CircularRippleBehavior,
FakeCircularElevationBehavior,
)
from kivymd.uix.floatlayout import MDFloatLayout from kivymd.uix.floatlayout import MDFloatLayout
from kivymd.uix.label import MDIcon from kivymd.uix.label import MDIcon
@ -356,10 +361,8 @@ class MDCheckbox(CircularRippleBehavior, ToggleButtonBehavior, MDIcon):
disabled=self.update_color, disabled=self.update_color,
state=self.update_color, state=self.update_color,
) )
self.theme_cls.bind( self.theme_cls.bind(primary_color=self.update_primary_color)
theme_style=self.update_primary_color, self.theme_cls.bind(theme_style=self.update_primary_color)
primary_color=self.update_primary_color,
)
self.update_icon() self.update_icon()
self.update_color() self.update_color()
@ -420,7 +423,7 @@ class ThumbIcon(MDIcon):
class Thumb( class Thumb(
CommonElevationBehavior, FakeCircularElevationBehavior,
CircularRippleBehavior, CircularRippleBehavior,
MDFloatLayout, MDFloatLayout,
): ):

View File

@ -3,7 +3,7 @@
#:import colors kivymd.color_definitions.colors #:import colors kivymd.color_definitions.colors
<HintBoxContainer@MDCard> <HintBoxContainer@MDCard+FakeRectangularElevationBehavior>
<MDSlider> <MDSlider>
@ -131,20 +131,16 @@
) \ ) \
) \ ) \
) )
elevation: 0 if root._is_off else (3 if root.active else 1) elevation: 0 if root._is_off else (4 if root.active else 2)
HintBoxContainer: HintBoxContainer:
id: hint_box id: hint_box
size_hint: None, None size_hint: None, None
md_bg_color: root.hint_bg_color if root.hint_bg_color else [0, 0, 0, 0] md_bg_color: root.hint_bg_color
elevation: 1.5 elevation: 0
opacity: 1 if root.active else 0 opacity: 1 if root.active else 0
radius: root.hint_radius radius: root.hint_radius
padding: "6dp", "6dp", "6dp", "8dp" padding: "6dp", "6dp", "6dp", "8dp"
shadow_color:
([0, 0, 0, 0.6] if root.hint_bg_color else [0, 0, 0, 0]) \
if root.active else \
[0, 0, 0, 0]
size: size:
lbl_value.width + self.padding[0] * 2, \ lbl_value.width + self.padding[0] * 2, \
lbl_value.height + self.padding[0] lbl_value.height + self.padding[0]

View File

@ -82,7 +82,7 @@ class MDSlider(ThemableBehavior, Slider):
and defaults to `True`. and defaults to `True`.
""" """
hint_bg_color = ColorProperty(None) hint_bg_color = ColorProperty([0, 0, 0, 0])
""" """
Hint rectangle color in (r.g.b.a) format. Hint rectangle color in (r.g.b.a) format.

View File

@ -38,8 +38,8 @@ Example
from kivy.lang.builder import Builder from kivy.lang.builder import Builder
from kivymd.app import MDApp
from kivymd.uix.card import MDCard from kivymd.uix.card import MDCard
from kivymd.uix.behaviors import RoundedRectangularElevationBehavior
KV = ''' KV = '''
<CardItem> <CardItem>
@ -47,6 +47,7 @@ Example
height: "86dp" height: "86dp"
padding: "4dp" padding: "4dp"
radius: 12 radius: 12
elevation: 4
FitImage: FitImage:
source: "avatar.jpg" source: "avatar.jpg"
@ -94,10 +95,8 @@ Example
''' '''
class CardItem(MDCard): class CardItem(MDCard, RoundedRectangularElevationBehavior):
def __init__(self, *args, **kwargs): pass
super().__init__(*args, **kwargs)
self.elevation = 3
class Example(MDApp): class Example(MDApp):
@ -193,6 +192,7 @@ class MDSliverAppbar(MDBoxLayout, ThemableBehavior):
from kivymd.uix.card import MDCard from kivymd.uix.card import MDCard
from kivymd.uix.toolbar import MDTopAppBar from kivymd.uix.toolbar import MDTopAppBar
from kivymd.uix.behaviors import RoundedRectangularElevationBehavior
KV = ''' KV = '''
#:import SliverToolbar __main__.SliverToolbar #:import SliverToolbar __main__.SliverToolbar
@ -203,6 +203,7 @@ class MDSliverAppbar(MDBoxLayout, ThemableBehavior):
height: "86dp" height: "86dp"
padding: "4dp" padding: "4dp"
radius: 12 radius: 12
elevation: 4
FitImage: FitImage:
source: "avatar.jpg" source: "avatar.jpg"
@ -251,16 +252,13 @@ class MDSliverAppbar(MDBoxLayout, ThemableBehavior):
''' '''
class CardItem(MDCard): class CardItem(MDCard, RoundedRectangularElevationBehavior):
def __init__(self, *args, **kwargs): pass
super().__init__(*args, **kwargs)
self.elevation = 3
class SliverToolbar(MDTopAppBar): class SliverToolbar(MDTopAppBar):
def __init__(self, **kwargs): def __init__(self, **kwargs):
super().__init__(**kwargs) super().__init__(**kwargs)
self.shadow_color = (0, 0, 0, 0)
self.type_height = "medium" self.type_height = "medium"
self.headline_text = "Headline medium" self.headline_text = "Headline medium"
self.left_action_items = [["arrow-left", lambda x: x]] self.left_action_items = [["arrow-left", lambda x: x]]
@ -424,7 +422,6 @@ class MDSliverAppbar(MDBoxLayout, ThemableBehavior):
# Adding a custom MDTopAppBar object. # Adding a custom MDTopAppBar object.
if issubclass(instance_toolbar_cls.__class__, MDTopAppBar): if issubclass(instance_toolbar_cls.__class__, MDTopAppBar):
instance_toolbar_cls.pos_hint = {"top": 1} instance_toolbar_cls.pos_hint = {"top": 1}
instance_toolbar_cls.elevation = 0
self.ids.float_box.add_widget(instance_toolbar_cls) self.ids.float_box.add_widget(instance_toolbar_cls)
else: else:
raise MDSliverAppbarException( raise MDSliverAppbarException(

View File

@ -8,7 +8,7 @@
padding: "10dp", "10dp", "10dp", "10dp" padding: "10dp", "10dp", "10dp", "10dp"
md_bg_color: "323232" if not root.bg_color else root.bg_color md_bg_color: "323232" if not root.bg_color else root.bg_color
radius: root.radius radius: root.radius
elevation: 4 if root.padding else 0 elevation: 11 if root.padding else 0
canvas: canvas:
Color: Color:

View File

@ -284,6 +284,7 @@ from kivy.properties import (
) )
from kivymd import uix_path from kivymd import uix_path
from kivymd.uix.behaviors import FakeRectangularElevationBehavior
from kivymd.uix.button import BaseButton from kivymd.uix.button import BaseButton
from kivymd.uix.card import MDCard from kivymd.uix.card import MDCard
@ -293,7 +294,7 @@ with open(
Builder.load_string(kv_file.read()) Builder.load_string(kv_file.read())
class BaseSnackbar(MDCard): class BaseSnackbar(MDCard, FakeRectangularElevationBehavior):
""" """
:Events: :Events:
:attr:`on_open` :attr:`on_open`

View File

@ -38,7 +38,7 @@ Example
MDTopAppBar: MDTopAppBar:
id: toolbar id: toolbar
title: "MDSwiper" title: "MDSwiper"
elevation: 4 elevation: 10
pos_hint: {"top": 1} pos_hint: {"top": 1}
MDSwiper: MDSwiper:
@ -142,7 +142,7 @@ Example
MDTopAppBar: MDTopAppBar:
id: toolbar id: toolbar
title: "MDSwiper" title: "MDSwiper"
elevation: 4 elevation: 10
pos_hint: {"top": 1} pos_hint: {"top": 1}
MDSwiper: MDSwiper:
@ -203,6 +203,7 @@ from kivy.animation import Animation
from kivy.clock import Clock from kivy.clock import Clock
from kivy.core.window import Window from kivy.core.window import Window
from kivy.effects.dampedscroll import DampedScrollEffect from kivy.effects.dampedscroll import DampedScrollEffect
from kivy.event import EventDispatcher
from kivy.lang.builder import Builder from kivy.lang.builder import Builder
from kivy.properties import ( from kivy.properties import (
BooleanProperty, BooleanProperty,
@ -211,6 +212,7 @@ from kivy.properties import (
StringProperty, StringProperty,
) )
from kivy.uix.anchorlayout import AnchorLayout from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.utils import platform from kivy.utils import platform
from kivymd import uix_path from kivymd import uix_path
@ -292,7 +294,7 @@ class MDSwiperItem(MDBoxLayout):
anim.start(self) anim.start(self)
class MDSwiper(MDScrollView): class MDSwiper(MDScrollView, EventDispatcher):
items_spacing = NumericProperty("20dp") items_spacing = NumericProperty("20dp")
""" """
The space between each :class:`MDSwiperItem`. The space between each :class:`MDSwiperItem`.

View File

@ -79,10 +79,6 @@
layout: layout layout: layout
size_hint: 1, None size_hint: 1, None
elevation: root.elevation elevation: root.elevation
radius: root.radius
shadow_offset: root.shadow_offset
shadow_color: root.shadow_color
shadow_softness: root.shadow_softness
height: root.tab_bar_height height: root.tab_bar_height
md_bg_color: md_bg_color:
self.theme_cls.primary_color \ self.theme_cls.primary_color \

View File

@ -944,6 +944,7 @@ from kivy.properties import (
from kivy.uix.anchorlayout import AnchorLayout from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.behaviors import ToggleButtonBehavior from kivy.uix.behaviors import ToggleButtonBehavior
from kivy.uix.scrollview import ScrollView from kivy.uix.scrollview import ScrollView
from kivy.uix.widget import Widget
from kivy.utils import boundary from kivy.utils import boundary
from kivymd import uix_path from kivymd import uix_path
@ -952,11 +953,11 @@ from kivymd.icon_definitions import md_icons
from kivymd.theming import ThemableBehavior, ThemeManager from kivymd.theming import ThemableBehavior, ThemeManager
from kivymd.uix.behaviors import ( from kivymd.uix.behaviors import (
DeclarativeBehavior, DeclarativeBehavior,
FakeRectangularElevationBehavior,
RectangularRippleBehavior, RectangularRippleBehavior,
SpecificBackgroundColorBehavior, SpecificBackgroundColorBehavior,
) )
from kivymd.uix.boxlayout import MDBoxLayout from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.card import MDCard
from kivymd.uix.carousel import MDCarousel from kivymd.uix.carousel import MDCarousel
from kivymd.uix.label import MDLabel from kivymd.uix.label import MDLabel
@ -1023,7 +1024,7 @@ class MDTabsLabel(ToggleButtonBehavior, RectangularRippleBehavior, MDLabel):
Clock.schedule_once(self.tab_bar._label_request_indicator_update, 0) Clock.schedule_once(self.tab_bar._label_request_indicator_update, 0)
class MDTabsBase: class MDTabsBase(Widget):
""" """
This class allow you to create a tab. This class allow you to create a tab.
You must create a new class that inherits from MDTabsBase. You must create a new class that inherits from MDTabsBase.
@ -1129,9 +1130,9 @@ class MDTabsBase:
This property will affect the Tab's Title Label widget. This property will affect the Tab's Title Label widget.
""" """
def __init__(self, *args, **kwargs): def __init__(self, **kwargs):
self.tab_label = MDTabsLabel(tab=self) self.tab_label = MDTabsLabel(tab=self)
super().__init__(*args, **kwargs) super().__init__(**kwargs)
self.bind( self.bind(
icon=self._update_text, icon=self._update_text,
title=self._update_text, title=self._update_text,
@ -1272,7 +1273,9 @@ class MDTabsScrollView(ScrollView):
_update(self.effect_y, scroll_y) _update(self.effect_y, scroll_y)
class MDTabsBar(MDCard): class MDTabsBar(
ThemableBehavior, FakeRectangularElevationBehavior, MDBoxLayout
):
""" """
This class is just a boxlayout that contains the scroll view for tabs. This class is just a boxlayout that contains the scroll view for tabs.
It is also responsible for resizing the tab shortcut when necessary. It is also responsible for resizing the tab shortcut when necessary.
@ -1548,43 +1551,13 @@ class MDTabs(
and defaults to `None`. and defaults to `None`.
""" """
shadow_softness = NumericProperty(12)
"""
See :attr:`kivymd.uix.behaviors.CommonElevationBehavior.shadow_softness`
attribute.
.. versionadded:: 1.1.0
:attr:`shadow_softness` is an :class:`~kivy.properties.NumericProperty`
and defaults to `12`.
"""
shadow_color = ColorProperty([0, 0, 0, 0.6])
"""
See :attr:`kivymd.uix.behaviors.CommonElevationBehavior.shadow_color`
attribute.
.. versionadded:: 1.1.0
:attr:`shadow_color` is an :class:`~kivy.properties.ColorProperty`
and defaults to `[0, 0, 0, 0.6]`.
"""
shadow_offset = ListProperty((0, 0))
"""
See :attr:`kivymd.uix.behaviors.CommonElevationBehavior.shadow_offset`
attribute.
.. versionadded:: 1.1.0
:attr:`shadow_offset` is an :class:`~kivy.properties.ListProperty`
and defaults to `[0, 0]`.
"""
elevation = NumericProperty(0) elevation = NumericProperty(0)
""" """
See :attr:`kivymd.uix.behaviors.CommonElevationBehavior.elevation` Tab value elevation.
attribute.
.. seealso::
`Behaviors/Elevation <https://kivymd.readthedocs.io/en/latest/behaviors/elevation/index.html>`_
:attr:`elevation` is an :class:`~kivy.properties.NumericProperty` :attr:`elevation` is an :class:`~kivy.properties.NumericProperty`
and defaults to `0`. and defaults to `0`.

View File

@ -487,8 +487,6 @@ class MDTapTargetView(ThemableBehavior, EventDispatcher):
_outer_radius = NumericProperty(0) _outer_radius = NumericProperty(0)
_target_radius = NumericProperty(0) _target_radius = NumericProperty(0)
__elevation = 0
def __init__(self, **kwargs): def __init__(self, **kwargs):
self.ripple_max_dist = dp(90) self.ripple_max_dist = dp(90)
self.on_outer_radius(self, self.outer_radius) self.on_outer_radius(self, self.outer_radius)
@ -516,89 +514,6 @@ class MDTapTargetView(ThemableBehavior, EventDispatcher):
if not self.outer_circle_color: if not self.outer_circle_color:
self.outer_circle_color = self.theme_cls.primary_color[:-1] self.outer_circle_color = self.theme_cls.primary_color[:-1]
def start(self, *args):
"""Starts widget opening animation."""
self._initialize()
self._animate_outer()
self.state = "open"
self.core_title_text.opacity = 1
self.core_description_text.opacity = 1
self.dispatch("on_open")
elevation = getattr(self.widget, "elevation", None)
if elevation:
self.__elevation = elevation
self.widget.elevation = 0
def stop(self, *args):
"""Starts widget close animation."""
# It needs a better implementation.
if self.anim_ripple is not None:
self.anim_ripple.unbind(on_complete=self._repeat_ripple)
self.core_title_text.opacity = 0
self.core_description_text.opacity = 0
anim = Animation(
d=0.15,
t="in_cubic",
**dict(
zip(
["_outer_radius", "_target_radius", "target_ripple_radius"],
[0, 0, 0],
)
),
)
anim.bind(on_complete=self._after_stop)
anim.start(self.widget)
def on_open(self, *args):
"""Called at the time of the start of the widget opening animation."""
def on_close(self, *args):
"""Called at the time of the start of the widget closed animation."""
def on_draw_shadow(self, instance, value):
Logger.warning(
"The shadow adding method will be implemented in future versions"
)
def on_description_text(self, instance, value):
self.core_description_text.text = value
def on_description_text_size(self, instance, value):
self.core_description_text.font_size = value
def on_description_text_bold(self, instance, value):
self.core_description_text.bold = value
def on_title_text(self, instance, value):
self.core_title_text.text = value
def on_title_text_size(self, instance, value):
self.core_title_text.font_size = value
def on_title_text_bold(self, instance, value):
self.core_title_text.bold = value
def on_outer_radius(self, instance, value):
self._outer_radius = self.outer_radius * 2
def on_target_radius(self, instance, value):
self._target_radius = self.target_radius * 2
def on_target_touch(self):
if self.stop_on_target_touch:
self.stop()
def on_outer_touch(self):
if self.stop_on_outer_touch:
self.stop()
def on_outside_click(self):
if self.cancelable:
self.stop()
def _initialize(self): def _initialize(self):
setattr(self.widget, "_outer_radius", 0) setattr(self.widget, "_outer_radius", 0)
setattr(self.widget, "_target_radius", 0) setattr(self.widget, "_target_radius", 0)
@ -612,7 +527,7 @@ class MDTapTargetView(ThemableBehavior, EventDispatcher):
def _draw_canvas(self): def _draw_canvas(self):
_pos = self._ttv_pos() _pos = self._ttv_pos()
self.widget.canvas.before.remove_group("ttv_group") self.widget.canvas.before.clear()
with self.widget.canvas.before: with self.widget.canvas.before:
# Outer circle. # Outer circle.
@ -673,14 +588,34 @@ class MDTapTargetView(ThemableBehavior, EventDispatcher):
group="ttv_group", group="ttv_group",
) )
def stop(self, *args):
"""Starts widget close animation."""
# It needs a better implementation.
if self.anim_ripple is not None:
self.anim_ripple.unbind(on_complete=self._repeat_ripple)
self.core_title_text.opacity = 0
self.core_description_text.opacity = 0
anim = Animation(
d=0.15,
t="in_cubic",
**dict(
zip(
["_outer_radius", "_target_radius", "target_ripple_radius"],
[0, 0, 0],
)
),
)
anim.bind(on_complete=self._after_stop)
anim.start(self.widget)
def _after_stop(self, *args): def _after_stop(self, *args):
self.widget.canvas.before.remove_group("ttv_group") self.widget.canvas.before.remove_group("ttv_group")
args[0].stop_all(self.widget) args[0].stop_all(self.widget)
elev = getattr(self.widget, "elevation", None)
elevation = getattr(self.widget, "elevation", None) if elev:
if elevation: self._fix_elev()
self.widget.elevation = self.__elevation
self.dispatch("on_close") self.dispatch("on_close")
# Don't forget to unbind the function or it'll mess # Don't forget to unbind the function or it'll mess
@ -704,6 +639,16 @@ class MDTapTargetView(ThemableBehavior, EventDispatcher):
) )
Color(a=1) Color(a=1)
def start(self, *args):
"""Starts widget opening animation."""
self._initialize()
self._animate_outer()
self.state = "open"
self.core_title_text.opacity = 1
self.core_description_text.opacity = 1
self.dispatch("on_open")
def _animate_outer(self): def _animate_outer(self):
anim = Animation( anim = Animation(
d=0.2, d=0.2,
@ -739,6 +684,53 @@ class MDTapTargetView(ThemableBehavior, EventDispatcher):
setattr(self.widget, "target_ripple_alpha", 1) setattr(self.widget, "target_ripple_alpha", 1)
self._animate_ripple() self._animate_ripple()
def on_open(self, *args):
"""Called at the time of the start of the widget opening animation."""
def on_close(self, *args):
"""Called at the time of the start of the widget closed animation."""
def on_draw_shadow(self, instance, value):
Logger.warning(
"The shadow adding method will be implemented in future versions"
)
def on_description_text(self, instance, value):
self.core_description_text.text = value
def on_description_text_size(self, instance, value):
self.core_description_text.font_size = value
def on_description_text_bold(self, instance, value):
self.core_description_text.bold = value
def on_title_text(self, instance, value):
self.core_title_text.text = value
def on_title_text_size(self, instance, value):
self.core_title_text.font_size = value
def on_title_text_bold(self, instance, value):
self.core_title_text.bold = value
def on_outer_radius(self, instance, value):
self._outer_radius = self.outer_radius * 2
def on_target_radius(self, instance, value):
self._target_radius = self.target_radius * 2
def on_target_touch(self):
if self.stop_on_target_touch:
self.stop()
def on_outer_touch(self):
if self.stop_on_outer_touch:
self.stop()
def on_outside_click(self):
if self.cancelable:
self.stop()
def _some_func(self, wid, touch): def _some_func(self, wid, touch):
""" """
This function decides which one to dispatch based on the touch This function decides which one to dispatch based on the touch

View File

@ -0,0 +1,9 @@
<RotateWidget>
canvas.before:
PushMatrix
Rotate:
angle: self.rotate_value_angle
axis: tuple(self.rotate_value_axis)
origin: self.center
canvas.after:
PopMatrix

View File

@ -2,31 +2,127 @@
Templates/RotateWidget Templates/RotateWidget
====================== ======================
.. deprecated:: 1.0.0 .. versionadded:: 1.0.0
.. note:: `RotateWidget` class has been deprecated. Please use Base class for controlling the rotate of the widget.
`RotateBahavior <https://kivymd.readthedocs.io/en/latest/behaviors/rotate/>`_
class instead. .. note:: See `kivy.graphics.Rotate
<https://kivy.org/doc/stable/api-kivy.graphics.html#kivy.graphics.Rotate>`_
for more information.
Kivy
----
.. code-block:: python
from kivy.animation import Animation
from kivy.lang import Builder
from kivy.app import App
from kivy.properties import NumericProperty
from kivy.uix.button import Button
KV = '''
Screen:
RotateButton:
size_hint: .5, .5
pos_hint: {"center_x": .5, "center_y": .5}
on_release: app.change_rotate(self)
canvas.before:
PushMatrix
Rotate:
angle: self.rotate_value_angle
axis: 0, 0, 1
origin: self.center
canvas.after:
PopMatrix
'''
class RotateButton(Button):
rotate_value_angle = NumericProperty(0)
class Test(App):
def build(self):
return Builder.load_string(KV)
def change_rotate(self, instance_button: Button) -> None:
Animation(rotate_value_angle=45, d=0.3).start(instance_button)
Test().run()
KivyMD
------
.. code-block:: python
from kivy.animation import Animation
from kivy.lang import Builder
from kivymd.app import MDApp
from kivymd.uix.button import MDRaisedButton
from kivymd.uix.templates import RotateWidget
KV = '''
MDScreen:
RotateButton:
size_hint: .5, .5
pos_hint: {"center_x": .5, "center_y": .5}
on_release: app.change_rotate(self)
elevation:0
'''
class RotateButton(MDRaisedButton, RotateWidget):
pass
class Test(MDApp):
def build(self):
return Builder.load_string(KV)
def change_rotate(self, instance_button: MDRaisedButton) -> None:
Animation(rotate_value_angle=45, d=0.3).start(instance_button)
Test().run()
""" """
__all__ = ("RotateWidget",) __all__ = ("RotateWidget",)
from kivy import Logger import os
from kivymd.uix.behaviors import RotateBehavior from kivy.lang import Builder
from kivy.properties import ListProperty, NumericProperty
from kivymd import uix_path
with open(
os.path.join(uix_path, "templates", "rotatewidget", "rotatewidget.kv"),
encoding="utf-8",
) as kv_file:
Builder.load_string(kv_file.read())
class RotateWidget(RotateBehavior): class RotateWidget:
"""Base class for controlling the rotate of the widget."""
rotate_value_angle = NumericProperty(0)
""" """
.. deprecated:: 1.1.0 Property for getting/setting the angle of the rotation.
Use :class:`~kivymd.uix.behaviors.rotate_behavior.RotateBehavior`
class instead. :attr:`rotate_value_angle` is an :class:`~kivy.properties.NumericProperty`
and defaults to `0`.
""" """
def __init__(self, **kwargs): rotate_value_axis = ListProperty((0, 0, 1))
super().__init__(**kwargs) """
Logger.warning( Property for getting/setting the axis of the rotation.
"KivyMD: "
"The `RotateWidget` class has been deprecated. " :attr:`rotate_value_axis` is an :class:`~kivy.properties.NumericProperty`
"Use the `RotateBehavior` class instead." and defaults to `(0, 0, 1)`.
) """

View File

@ -0,0 +1,10 @@
<ScaleWidget>
canvas.before:
PushMatrix
Scale:
x: self.scale_value_x
y: self.scale_value_y
z: self.scale_value_x
origin: self.center
canvas.after:
PopMatrix

View File

@ -2,33 +2,149 @@
Templates/ScaleWidget Templates/ScaleWidget
===================== =====================
.. deprecated:: 1.1.0 .. versionadded:: 1.0.0
Base class for controlling the scale of the widget. Base class for controlling the scale of the widget.
.. note:: `ScaleWidget` class has been deprecated. Please use .. note:: See `kivy.graphics.Scale
`ScaleBehavior <https://kivymd.readthedocs.io/en/latest/behaviors/scale/>`_ <https://kivy.org/doc/stable/api-kivy.graphics.html#kivy.graphics.Scale>`_
class instead. for more information.
Kivy
----
.. code-block:: python
from kivy.animation import Animation
from kivy.lang import Builder
from kivy.properties import NumericProperty
from kivy.uix.button import Button
from kivy.app import App
KV = '''
Screen:
ScaleButton:
size_hint: .5, .5
pos_hint: {"center_x": .5, "center_y": .5}
on_release: app.change_scale(self)
canvas.before:
PushMatrix
Scale:
x: self.scale_value_x
y: self.scale_value_y
z: self.scale_value_x
origin: self.center
canvas.after:
PopMatrix
'''
class ScaleButton(Button):
scale_value_x = NumericProperty(1)
scale_value_y = NumericProperty(1)
scale_value_z = NumericProperty(1)
class Test(App):
def build(self):
return Builder.load_string(KV)
def change_scale(self, instance_button: Button) -> None:
Animation(
scale_value_x=0.5,
scale_value_y=0.5,
scale_value_z=0.5,
d=0.3,
).start(instance_button)
Test().run()
KivyMD
------
.. code-block:: python
from kivy.animation import Animation
from kivy.lang import Builder
from kivymd.app import MDApp
from kivymd.uix.button import MDRaisedButton
from kivymd.uix.templates import ScaleWidget
KV = '''
MDScreen:
ScaleButton:
size_hint: .5, .5
pos_hint: {"center_x": .5, "center_y": .5}
on_release: app.change_scale(self)
elevation:0
'''
class ScaleButton(MDRaisedButton, ScaleWidget):
pass
class Test(MDApp):
def build(self):
return Builder.load_string(KV)
def change_scale(self, instance_button: MDRaisedButton) -> None:
Animation(
scale_value_x=0.5,
scale_value_y=0.5,
scale_value_z=0.5,
d=0.3,
).start(instance_button)
Test().run()
""" """
__all__ = ("ScaleWidget",) __all__ = ("ScaleWidget",)
from kivy import Logger import os
from kivymd.uix.behaviors import ScaleBehavior from kivy.lang import Builder
from kivy.properties import NumericProperty
from kivymd import uix_path
with open(
os.path.join(uix_path, "templates", "scalewidget", "scalewidget.kv"),
encoding="utf-8",
) as kv_file:
Builder.load_string(kv_file.read())
class ScaleWidget(ScaleBehavior): class ScaleWidget:
"""Base class for controlling the scale of the widget."""
scale_value_x = NumericProperty(1)
""" """
.. deprecated:: 1.1.0 X-axis value.
Use :class:`~kivymd.uix.behaviors.scale_behavior.ScaleBehavior`
class instead. :attr:`scale_value_x` is an :class:`~kivy.properties.NumericProperty`
and defaults to `1`.
""" """
def __init__(self, **kwargs): scale_value_y = NumericProperty(1)
super().__init__(**kwargs) """
Logger.warning( Y-axis value.
"KivyMD: "
"The `ScaleWidget` class has been deprecated. " :attr:`scale_value_y` is an :class:`~kivy.properties.NumericProperty`
"Use the `ScaleBehavior` class instead." and defaults to `1`.
) """
scale_value_z = NumericProperty(1)
"""
Z-axis value.
:attr:`scale_value_z` is an :class:`~kivy.properties.NumericProperty`
and defaults to `1`.
"""

View File

@ -0,0 +1,19 @@
<StencilWidget>
canvas.before:
StencilPush
RoundedRectangle:
pos: root.pos
size: root.size
# FIXME: Sometimes the radius has the value [], which get a
# `GraphicException: Invalid radius value, must be list of tuples/numerics` error
radius: root.radius if root.radius else [0, 0, 0, 0]
StencilUse
canvas.after:
StencilUnUse
RoundedRectangle:
pos: root.pos
size: root.size
# FIXME: Sometimes the radius has the value [], which get a
# `GraphicException: Invalid radius value, must be list of tuples/numerics` error
radius: root.radius if root.radius else [0, 0, 0, 0]
StencilPop

View File

@ -2,33 +2,115 @@
Templates/StencilWidget Templates/StencilWidget
======================= =======================
.. deprecated:: 1.1.0 .. versionadded:: 1.0.0
Base class for controlling the stencil instructions of the widget. Base class for controlling the stencil instructions of the widget.
.. note:: `StencilWidget` class has been deprecated. Please use .. note:: See `Stencil instructions
`StencilBehavior <https://kivymd.readthedocs.io/en/latest/behaviors/stencil/>`_ <https://kivy.org/doc/stable/api-kivy.graphics.stencil_instructions.html>`_
class instead. for more information.
Kivy
----
.. code-block:: python
from kivy.lang import Builder
from kivy.app import App
KV = '''
Carousel:
Button:
size_hint: .9, .8
pos_hint: {"center_x": .5, "center_y": .5}
canvas.before:
StencilPush
RoundedRectangle:
pos: root.pos
size: root.size
StencilUse
canvas.after:
StencilUnUse
RoundedRectangle:
pos: root.pos
size: root.size
StencilPop
'''
class Test(App):
def build(self):
return Builder.load_string(KV)
Test().run()
KivyMD
------
.. code-block:: python
from kivy.lang import Builder
from kivymd.app import MDApp
from kivymd.uix.templates import StencilWidget
from kivymd.uix.fitimage import FitImage
KV = '''
MDCarousel:
StencilImage:
size_hint: .9, .8
pos_hint: {"center_x": .5, "center_y": .5}
source: "image.png"
'''
class StencilImage(FitImage, StencilWidget):
pass
class Test(MDApp):
def build(self):
return Builder.load_string(KV)
Test().run()
""" """
__all__ = ("StencilWidget",) __all__ = ("StencilWidget",)
from kivy import Logger import os
from kivymd.uix.behaviors import StencilBehavior from kivy.lang import Builder
from kivy.properties import VariableListProperty
from kivymd import uix_path
with open(
os.path.join(uix_path, "templates", "stencilwidget", "stencilwidget.kv"),
encoding="utf-8",
) as kv_file:
Builder.load_string(kv_file.read())
class StencilWidget(StencilBehavior): class StencilWidget:
""" """Base class for controlling the stencil instructions of the widget"""
.. deprecated:: 1.1.0
Use :class:`~kivymd.uix.behaviors.scale_behavior.StencilBehavior` radius = VariableListProperty([0], length=4)
class instead.
""" """
Canvas radius.
def __init__(self, **kwargs): .. versionadded:: 1.0.0
super().__init__(**kwargs)
Logger.warning( .. code-block:: python
"KivyMD: "
"The `StencilWidget` class has been deprecated. " # Top left corner slice.
"Use the `StencilBehavior` class instead." MDWidget:
) radius: [25, 0, 0, 0]
:attr:`radius` is an :class:`~kivy.properties.VariableListProperty`
and defaults to `[0, 0, 0, 0]`.
"""

View File

@ -1,7 +1,4 @@
<MDTextField> <MDTextField>
input_filter: self.field_filter
do_backspace: self.do_backspace
canvas.before: canvas.before:
Clear Clear

View File

@ -14,6 +14,7 @@ Components/TextField
`KivyMD` provides the following field classes for use: `KivyMD` provides the following field classes for use:
- MDTextField_ - MDTextField_
- MDTextFieldRound_
- MDTextFieldRect_ - MDTextFieldRect_
.. Note:: :class:`~MDTextField` inherited from .. Note:: :class:`~MDTextField` inherited from
@ -78,15 +79,15 @@ parameter to `True`:
from kivymd.app import MDApp from kivymd.app import MDApp
KV = ''' KV = '''
MDScreen: BoxLayout:
padding: "10dp"
MDTextField: MDTextField:
id: text_field_error id: text_field_error
hint_text: "Helper text on error (press 'Enter')" hint_text: "Helper text on error (press 'Enter')"
helper_text: "There will always be a mistake" helper_text: "There will always be a mistake"
helper_text_mode: "on_error" helper_text_mode: "on_error"
pos_hint: {"center_x": .5, "center_y": .5} pos_hint: {"center_y": .5}
size_hint_x: .5
''' '''
@ -96,8 +97,6 @@ parameter to `True`:
self.screen = Builder.load_string(KV) self.screen = Builder.load_string(KV)
def build(self): def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "Orange"
self.screen.ids.text_field_error.bind( self.screen.ids.text_field_error.bind(
on_text_validate=self.set_error_message, on_text_validate=self.set_error_message,
on_focus=self.set_error_message, on_focus=self.set_error_message,
@ -120,7 +119,6 @@ Helper text mode `'on_error'` (with required)
MDTextField: MDTextField:
hint_text: "required = True" hint_text: "required = True"
text: "required = True"
required: True required: True
helper_text_mode: "on_error" helper_text_mode: "on_error"
helper_text: "Enter text" helper_text: "Enter text"
@ -188,7 +186,7 @@ Round mode
max_text_length: 15 max_text_length: 15
helper_text: "Massage" helper_text: "Massage"
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-round-mode.gif .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-round-mode.png
:align: center :align: center
.. MDTextFieldRect: .. MDTextFieldRect:
@ -205,7 +203,6 @@ MDTextFieldRect
MDTextFieldRect: MDTextFieldRect:
size_hint: 1, None size_hint: 1, None
height: "30dp" height: "30dp"
background_color: app.theme_cls.bg_normal
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-rect.gif .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-rect.gif
:align: center :align: center
@ -281,17 +278,18 @@ __all__ = ("MDTextField", "MDTextFieldRect")
import os import os
import re import re
from datetime import date
from typing import Union from typing import Union
from kivy.animation import Animation from kivy.animation import Animation
from kivy.clock import Clock from kivy.clock import Clock
from kivy.lang import Builder from kivy.lang import Builder
from kivy.logger import Logger
from kivy.metrics import dp, sp from kivy.metrics import dp, sp
from kivy.properties import ( from kivy.properties import (
AliasProperty, AliasProperty,
BooleanProperty, BooleanProperty,
ColorProperty, ColorProperty,
DictProperty,
ListProperty, ListProperty,
NumericProperty, NumericProperty,
ObjectProperty, ObjectProperty,
@ -313,220 +311,6 @@ with open(
Builder.load_string(kv_file.read()) Builder.load_string(kv_file.read())
# TODO: Add a class to work with the phone number mask.
class AutoFormatTelephoneNumber:
"""
Implements automatic formatting of the text entered in the text field
according to the mask, for example '+38 (###) ### ## ##'.
"""
def __init__(self):
self._backspace = False
def isnumeric(self, value):
try:
int(value)
return True
except ValueError:
return False
def do_backspace(self, *args):
if self.validator and self.validator == "phone":
self._backspace = True
text = self.text
text = text[:-1]
self.text = text
self._backspace = False
def field_filter(self, value, boolean):
if self.validator and self.validator == "phone":
if len(self.text) == 14:
return
if self.isnumeric(value):
return value
return value
def format(self, value):
if value != "" and not value.isspace() and not self._backspace:
if len(value) <= 1 and self.focus:
self.text = value
self._check_cursor()
elif len(value) == 4:
start = self.text[:-1]
end = self.text[-1]
self.text = "%s) %s" % (start, end)
self._check_cursor()
elif len(value) == 8:
self.text += "-"
self._check_cursor()
elif len(value) in [12, 16]:
start = self.text[:-1]
end = self.text[-1]
self.text = "%s-%s" % (start, end)
self._check_cursor()
def _check_cursor(self):
def set_pos_cursor(pos_corsor, interval=0.5):
self.cursor = (pos_corsor, 0)
if self.focus:
Clock.schedule_once(lambda x: set_pos_cursor(len(self.text)), 0.1)
class Validator:
"""Container class for various validation methods."""
datetime_date = ObjectProperty()
"""
The last valid date as a <class 'datetime.date'> object.
:attr:`datetime_date` is an :class:`~kivy.properties.ObjectProperty`
and defaults to `None`.
"""
date_interval = ListProperty([None, None])
"""
The date interval that is valid for input.
Can be entered as <class 'datetime.date'> objects or a string format.
Both values or just one value can be entered.
In string format, must follow the current date_format.
Example: Given date_format -> "mm/dd/yyyy"
Input examples -> "12/31/1900", "12/31/2100" or "12/31/1900", None.
:attr:`date_interval` is an :class:`~kivy.properties.ListProperty`
and defaults to `[None, None]`.
"""
date_format = OptionProperty(
None,
options=[
"dd/mm/yyyy",
"mm/dd/yyyy",
"yyyy/mm/dd",
],
)
"""
Format of date strings that will be entered.
Available options are: `'dd/mm/yyyy'`, `'mm/dd/yyyy'`, `'yyyy/mm/dd'`.
:attr:`date_format` is an :class:`~kivy.properties.OptionProperty`
and defaults to `None`.
"""
def is_email_valid(self, text: str) -> bool:
if not re.match(r"[^@]+@[^@]+\.[^@]+", text):
return True
return False
def is_time_valid(self, text: str) -> bool:
if re.match(r"^(2[0-3]|[01]?[0-9]):([0-5]?[0-9])$", text) or re.match(
r"^(2[0-3]|[01]?[0-9]):([0-5]?[0-9]):([0-5]?[0-9])$", text
):
return False
return True
def is_date_valid(self, text: str) -> bool:
if not self.date_format:
raise Exception("TextInput date_format was not defined.")
# Regex strings.
dd = "[0][1-9]|[1-2][0-9]|[3][0-1]"
mm = "[0][1-9]|[1][0-2]"
yyyy = "[0-9][0-9][0-9][0-9]"
fmt = self.date_format.split("/")
largs = locals()
# Access the local variables dict in the correct format based on
# date_format split. Example: "mm/dd/yyyy" -> ["mm", "dd", "yyyy"]
# largs[fmt[0]] would be largs["mm"] so the month regex string.
if re.match(
f"^({largs[fmt[0]]})/({largs[fmt[1]]})/({largs[fmt[2]]})$", text
):
input_split = text.split("/")
largs[fmt[0]] = input_split[0]
largs[fmt[1]] = input_split[1]
largs[fmt[2]] = input_split[2]
# Organize input into correct slots and try to convert
# to datetime object. This way February exceptions are
# tested. Also tests with the date_interval are simpler
# using datetime objects.
try:
datetime = date(
int(largs["yyyy"]), int(largs["mm"]), int(largs["dd"])
)
except ValueError:
return True
if self.date_interval:
if (
self.date_interval[0]
and not self.date_interval[0] <= datetime
or self.date_interval[1]
and not datetime <= self.date_interval[1]
):
return True
self.datetime_date = datetime
return False
return True
def on_date_interval(self, *args) -> None:
"""Default event handler for date_interval input."""
def on_date_interval():
if not self.date_format:
raise Exception("TextInput date_format was not defined.")
fmt = self.date_format.split("/")
largs = {}
# Convert string inputs into datetime.date objects and store
# them back into self.date_interval.
try:
if self.date_interval[0] and not isinstance(
self.date_interval[0], date
):
split = self.date_interval[0].split("/")
largs[fmt[0]] = split[0]
largs[fmt[1]] = split[1]
largs[fmt[2]] = split[2]
self.date_interval[0] = date(
int(largs["yyyy"]), int(largs["mm"]), int(largs["dd"])
)
if self.date_interval[1] and not isinstance(
self.date_interval[1], date
):
split = self.date_interval[1].split("/")
largs[fmt[0]] = split[0]
largs[fmt[1]] = split[1]
largs[fmt[2]] = split[2]
self.date_interval[1] = date(
int(largs["yyyy"]), int(largs["mm"]), int(largs["dd"])
)
except Exception:
raise Exception(
r"TextInput date_interval was defined incorrectly, it must "
r"be composed of <class 'datetime.date'> objects or strings"
r" following current date_format."
)
# Test if the interval is valid.
if isinstance(self.date_interval[0], date) and isinstance(
self.date_interval[1], date
):
if self.date_interval[0] >= self.date_interval[1]:
raise Exception(
"TextInput date_interval last date must be greater"
" than the first date or set to None."
)
Clock.schedule_once(lambda x: on_date_interval())
class MDTextFieldRect(ThemableBehavior, TextInput): class MDTextFieldRect(ThemableBehavior, TextInput):
line_anim = BooleanProperty(True) line_anim = BooleanProperty(True)
""" """
@ -599,13 +383,7 @@ class TextfieldLabel(ThemableBehavior, Label):
self.font_size = sp(self.theme_cls.font_styles[self.font_style][1]) self.font_size = sp(self.theme_cls.font_styles[self.font_style][1])
class MDTextField( class MDTextField(DeclarativeBehavior, ThemableBehavior, TextInput):
DeclarativeBehavior,
ThemableBehavior,
TextInput,
Validator,
AutoFormatTelephoneNumber,
):
helper_text = StringProperty() helper_text = StringProperty()
""" """
Text for ``helper_text`` mode. Text for ``helper_text`` mode.
@ -652,185 +430,17 @@ class MDTextField(
and defaults to `'line'`. and defaults to `'line'`.
""" """
phone_mask = StringProperty("")
validator = OptionProperty(None, options=["date", "email", "time", "phone"])
"""
The type of text field for entering Email, time, etc.
Automatically sets the type of the text field as "error" if the user input
does not match any of the set validation types.
Available options are: `'date'`, `'email'`, `'time'`.
When using `'date'`, :attr:`date_format` must be defined.
.. versionadded:: 1.1.0
.. code-block:: python
MDTextField:
hint_text: "Email"
helper_text: "user@gmail.com"
validator: "email"
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-validator.png
:align: center
.. tabs::
.. tab:: Declarative KV style
.. code-block:: python
from kivy.lang import Builder
from kivymd.app import MDApp
KV = '''
MDScreen:
MDBoxLayout:
orientation: "vertical"
spacing: "20dp"
adaptive_height: True
size_hint_x: .8
pos_hint: {"center_x": .5, "center_y": .5}
MDTextField:
hint_text: "Date dd/mm/yyyy without limits"
helper_text: "Enter a valid dd/mm/yyyy date"
validator: "date"
date_format: "dd/mm/yyyy"
MDTextField:
hint_text: "Date mm/dd/yyyy without limits"
helper_text: "Enter a valid mm/dd/yyyy date"
validator: "date"
date_format: "mm/dd/yyyy"
MDTextField:
hint_text: "Date yyyy/mm/dd without limits"
helper_text: "Enter a valid yyyy/mm/dd date"
validator: "date"
date_format: "yyyy/mm/dd"
MDTextField:
hint_text: "Date dd/mm/yyyy in [01/01/1900, 01/01/2100] interval"
helper_text: "Enter a valid dd/mm/yyyy date"
validator: "date"
date_format: "dd/mm/yyyy"
date_interval: "01/01/1900", "01/01/2100"
MDTextField:
hint_text: "Date dd/mm/yyyy in [01/01/1900, None] interval"
helper_text: "Enter a valid dd/mm/yyyy date"
validator: "date"
date_format: "dd/mm/yyyy"
date_interval: "01/01/1900", None
MDTextField:
hint_text: "Date dd/mm/yyyy in [None, 01/01/2100] interval"
helper_text: "Enter a valid dd/mm/yyyy date"
validator: "date"
date_format: "dd/mm/yyyy"
date_interval: None, "01/01/2100"
'''
class Test(MDApp):
def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "Orange"
return Builder.load_string(KV)
Test().run()
.. tab:: Declarative python style
.. code-block:: python
from kivymd.app import MDApp
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.screen import MDScreen
from kivymd.uix.textfield import MDTextField
class Test(MDApp):
def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "Orange"
return (
MDScreen(
MDBoxLayout(
MDTextField(
hint_text="Date dd/mm/yyyy without limits",
helper_text="Enter a valid dd/mm/yyyy date",
validator="date",
date_format="dd/mm/yyyy",
),
MDTextField(
hint_text="Date mm/dd/yyyy without limits",
helper_text="Enter a valid mm/dd/yyyy date",
validator="date",
date_format="mm/dd/yyyy",
),
MDTextField(
hint_text="Date yyyy/mm/dd without limits",
helper_text="Enter a valid yyyy/mm/dd date",
validator="date",
date_format="yyyy/mm/dd",
),
MDTextField(
hint_text="Date dd/mm/yyyy in [01/01/1900, 01/01/2100] interval",
helper_text="Enter a valid dd/mm/yyyy date",
validator="date",
date_format="dd/mm/yyyy",
date_interval=["01/01/1900", "01/01/2100"],
),
MDTextField(
hint_text="Date dd/mm/yyyy in [01/01/1900, None] interval",
helper_text="Enter a valid dd/mm/yyyy date",
validator="date",
date_format="dd/mm/yyyy",
date_interval=["01/01/1900", None],
),
MDTextField(
hint_text="Date dd/mm/yyyy in [None, 01/01/2100] interval",
helper_text="Enter a valid dd/mm/yyyy date",
validator="date",
date_format="dd/mm/yyyy",
date_interval=[None, "01/01/2100"],
),
orientation="vertical",
spacing="20dp",
adaptive_height=True,
size_hint_x=0.8,
pos_hint={"center_x": 0.5, "center_y": 0.5},
)
)
)
Test().run()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-validator-date.png
:align: center
:attr:`validator` is an :class:`~kivy.properties.OptionProperty`
and defaults to `None`.
"""
line_color_normal = ColorProperty([0, 0, 0, 0]) line_color_normal = ColorProperty([0, 0, 0, 0])
""" """
Line color normal (static underline line) in (r, g, b, a) or string format. Line color normal (static underline line) in ``rgba`` format.
.. code-block:: kv .. code-block:: kv
MDTextField: MDTextField:
hint_text: "line_color_normal" hint_text: "line_color_normal"
line_color_normal: "red" line_color_normal: 1, 0, 1, 1
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-line-color-normal.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-line-color-normal.gif
:align: center :align: center
:attr:`line_color_normal` is an :class:`~kivy.properties.ColorProperty` :attr:`line_color_normal` is an :class:`~kivy.properties.ColorProperty`
@ -839,13 +449,13 @@ class MDTextField(
line_color_focus = ColorProperty([0, 0, 0, 0]) line_color_focus = ColorProperty([0, 0, 0, 0])
""" """
Line color focus (active underline line) in (r, g, b, a) or string format. Line color focus (active underline line) in ``rgba`` format.
.. code-block:: kv .. code-block:: kv
MDTextField: MDTextField:
hint_text: "line_color_focus" hint_text: "line_color_focus"
line_color_focus: "red" line_color_focus: 0, 1, 0, 1
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-line-color-focus.gif .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-line-color-focus.gif
:align: center :align: center
@ -864,7 +474,7 @@ class MDTextField(
error_color = ColorProperty([0, 0, 0, 0]) error_color = ColorProperty([0, 0, 0, 0])
""" """
Error color in (r, g, b, a) or string format for ``required = True``. Error color in ``rgba`` format for ``required = True``.
:attr:`error_color` is an :class:`~kivy.properties.ColorProperty` :attr:`error_color` is an :class:`~kivy.properties.ColorProperty`
and defaults to `[0, 0, 0, 0]`. and defaults to `[0, 0, 0, 0]`.
@ -872,18 +482,7 @@ class MDTextField(
fill_color_normal = ColorProperty([0, 0, 0, 0]) fill_color_normal = ColorProperty([0, 0, 0, 0])
""" """
Fill background color in (r, g, b, a) or string format in 'fill' mode when] Fill background color in 'fill' mode when text field is out of focus.
text field is out of focus.
.. code=block:: kv
MDTextField:
hint_text: "Fill mode"
mode: "fill"
fill_color_normal: "brown"
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-fill-color-normal.png
:align: center
:attr:`fill_color_normal` is an :class:`~kivy.properties.ColorProperty` :attr:`fill_color_normal` is an :class:`~kivy.properties.ColorProperty`
and defaults to `[0, 0, 0, 0]`. and defaults to `[0, 0, 0, 0]`.
@ -891,18 +490,7 @@ class MDTextField(
fill_color_focus = ColorProperty([0, 0, 0, 0]) fill_color_focus = ColorProperty([0, 0, 0, 0])
""" """
Fill background color in (r, g, b, a) or string format in 'fill' mode when Fill background color in 'fill' mode when the text field has focus.
the text field has focus.
.. code=block:: kv
MDTextField:
hint_text: "Fill mode"
mode: "fill"
fill_color_focus: "brown"
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-fill-color-focus.gif
:align: center
:attr:`fill_color_focus` is an :class:`~kivy.properties.ColorProperty` :attr:`fill_color_focus` is an :class:`~kivy.properties.ColorProperty`
and defaults to `[0, 0, 0, 0]`. and defaults to `[0, 0, 0, 0]`.
@ -926,8 +514,7 @@ class MDTextField(
hint_text_color_normal = ColorProperty([0, 0, 0, 0]) hint_text_color_normal = ColorProperty([0, 0, 0, 0])
""" """
Hint text color in (r, g, b, a) or string format when text field is out Hint text color when text field is out of focus.
of focus.
.. versionadded:: 1.0.0 .. versionadded:: 1.0.0
@ -935,9 +522,9 @@ class MDTextField(
MDTextField: MDTextField:
hint_text: "hint_text_color_normal" hint_text: "hint_text_color_normal"
hint_text_color_normal: "red" hint_text_color_normal: 0, 1, 0, 1
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-hint-text-color-normal.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-hint-text-color-normal.gif
:align: center :align: center
:attr:`hint_text_color_normal` is an :class:`~kivy.properties.ColorProperty` :attr:`hint_text_color_normal` is an :class:`~kivy.properties.ColorProperty`
@ -946,8 +533,7 @@ class MDTextField(
hint_text_color_focus = ColorProperty([0, 0, 0, 0]) hint_text_color_focus = ColorProperty([0, 0, 0, 0])
""" """
Hint text color in (r, g, b, a) or string format when the text field has Hint text color when the text field has focus.
focus.
.. versionadded:: 1.0.0 .. versionadded:: 1.0.0
@ -955,7 +541,7 @@ class MDTextField(
MDTextField: MDTextField:
hint_text: "hint_text_color_focus" hint_text: "hint_text_color_focus"
hint_text_color_focus: "red" hint_text_color_focus: 0, 1, 0, 1
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-hint-text-color-focus.gif .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-hint-text-color-focus.gif
:align: center :align: center
@ -966,8 +552,7 @@ class MDTextField(
helper_text_color_normal = ColorProperty([0, 0, 0, 0]) helper_text_color_normal = ColorProperty([0, 0, 0, 0])
""" """
Helper text color in (r, g, b, a) or string format when text field is out Helper text color when text field is out of focus.
of focus.
.. versionadded:: 1.0.0 .. versionadded:: 1.0.0
@ -976,7 +561,7 @@ class MDTextField(
MDTextField: MDTextField:
helper_text: "helper_text_color_normal" helper_text: "helper_text_color_normal"
helper_text_mode: "persistent" helper_text_mode: "persistent"
helper_text_color_normal: "red" helper_text_color_normal: 0, 1, 0, 1
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-helper-text-color-normal.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-helper-text-color-normal.png
:align: center :align: center
@ -987,8 +572,7 @@ class MDTextField(
helper_text_color_focus = ColorProperty([0, 0, 0, 0]) helper_text_color_focus = ColorProperty([0, 0, 0, 0])
""" """
Helper text color in (r, g, b, a) or string format when the text field has Helper text color when the text field has focus.
focus.
.. versionadded:: 1.0.0 .. versionadded:: 1.0.0
@ -997,7 +581,7 @@ class MDTextField(
MDTextField: MDTextField:
helper_text: "helper_text_color_focus" helper_text: "helper_text_color_focus"
helper_text_mode: "persistent" helper_text_mode: "persistent"
helper_text_color_focus: "red" helper_text_color_focus: 0, 1, 0, 1
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-helper-text-color-focus.gif .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-helper-text-color-focus.gif
:align: center :align: center
@ -1008,8 +592,7 @@ class MDTextField(
icon_right_color_normal = ColorProperty([0, 0, 0, 0]) icon_right_color_normal = ColorProperty([0, 0, 0, 0])
""" """
Color in (r, g, b, a) or string format of right icon when text field is out Color of right icon when text field is out of focus.
of focus.
.. versionadded:: 1.0.0 .. versionadded:: 1.0.0
@ -1018,9 +601,9 @@ class MDTextField(
MDTextField: MDTextField:
icon_right: "language-python" icon_right: "language-python"
hint_text: "icon_right_color_normal" hint_text: "icon_right_color_normal"
icon_right_color_normal: "red" icon_right_color_normal: 0, 1, 0, 1
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-icon-right-color-normal.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-icon-right-color-normal.gif
:align: center :align: center
:attr:`icon_right_color_normal` is an :class:`~kivy.properties.ColorProperty` :attr:`icon_right_color_normal` is an :class:`~kivy.properties.ColorProperty`
@ -1029,8 +612,7 @@ class MDTextField(
icon_right_color_focus = ColorProperty([0, 0, 0, 0]) icon_right_color_focus = ColorProperty([0, 0, 0, 0])
""" """
Color in (r, g, b, a) or string format of right icon when the text field Color of right icon when the text field has focus.
has focus.
.. versionadded:: 1.0.0 .. versionadded:: 1.0.0
@ -1039,7 +621,7 @@ class MDTextField(
MDTextField: MDTextField:
icon_right: "language-python" icon_right: "language-python"
hint_text: "icon_right_color_focus" hint_text: "icon_right_color_focus"
icon_right_color_focus: "red" icon_right_color_focus: 0, 1, 0, 1
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-icon-right-color-focus.gif .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-icon-right-color-focus.gif
:align: center :align: center
@ -1050,30 +632,47 @@ class MDTextField(
icon_left_color_normal = ColorProperty([0, 0, 0, 0]) icon_left_color_normal = ColorProperty([0, 0, 0, 0])
""" """
Color in (r, g, b, a) or string format of right icon when text field is out Color of right icon when text field is out of focus.
of focus.
.. versionadded:: 1.0.0 .. versionadded:: 1.0.0
.. code-block:: kv
MDTextField:
icon_right: "language-python"
hint_text: "icon_right_color_normal"
icon_left_color_normal: 0, 1, 0, 1
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-icon-right-color-normal.gif
:align: center
:attr:`icon_left_color_normal` is an :class:`~kivy.properties.ColorProperty` :attr:`icon_left_color_normal` is an :class:`~kivy.properties.ColorProperty`
and defaults to `[0, 0, 0, 0]`. and defaults to `[0, 0, 0, 0]`.
""" """
icon_left_color_focus = ColorProperty([0, 0, 0, 0]) icon_left_color_focus = ColorProperty([0, 0, 0, 0])
""" """
Color in (r, g, b, a) or string format of right icon when the text field Color of right icon when the text field has focus.
has focus.
.. versionadded:: 1.0.0 .. versionadded:: 1.0.0
.. code-block:: kv
MDTextField:
icon_right: "language-python"
hint_text: "icon_right_color_focus"
icon_right_color_focus: 0, 1, 0, 1
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-icon-right-color-focus.gif
:align: center
:attr:`icon_left_color_focus` is an :class:`~kivy.properties.ColorProperty` :attr:`icon_left_color_focus` is an :class:`~kivy.properties.ColorProperty`
and defaults to `[0, 0, 0, 0]`. and defaults to `[0, 0, 0, 0]`.
""" """
max_length_text_color = ColorProperty([0, 0, 0, 0]) max_length_text_color = ColorProperty([0, 0, 0, 0])
""" """
Text color in (r, g, b, a) or string format of the maximum length of Text color of the maximum length of characters to be input.
characters to be input.
.. versionadded:: 1.0.0 .. versionadded:: 1.0.0
@ -1081,10 +680,10 @@ class MDTextField(
MDTextField: MDTextField:
hint_text: "max_length_text_color" hint_text: "max_length_text_color"
max_length_text_color: "red" max_length_text_color: 0, 1, 0, 1
max_text_length: 5 max_text_length: 5
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-max-length-text-color.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-max-length-text-color.gif
:align: center :align: center
:attr:`max_length_text_color` is an :class:`~kivy.properties.ColorProperty` :attr:`max_length_text_color` is an :class:`~kivy.properties.ColorProperty`
@ -1119,7 +718,7 @@ class MDTextField(
text_color_normal = ColorProperty([0, 0, 0, 0]) text_color_normal = ColorProperty([0, 0, 0, 0])
""" """
Text color in (r, g, b, a) or string format when text field is out of focus. Text color in ``rgba`` format when text field is out of focus.
.. versionadded:: 1.0.0 .. versionadded:: 1.0.0
@ -1127,9 +726,9 @@ class MDTextField(
MDTextField: MDTextField:
hint_text: "text_color_normal" hint_text: "text_color_normal"
text_color_normal: "red" text_color_normal: 0, 1, 0, 1
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-text-color-normal.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-text-color-normal.gif
:align: center :align: center
:attr:`text_color_normal` is an :class:`~kivy.properties.ColorProperty` :attr:`text_color_normal` is an :class:`~kivy.properties.ColorProperty`
@ -1138,7 +737,7 @@ class MDTextField(
text_color_focus = ColorProperty([0, 0, 0, 0]) text_color_focus = ColorProperty([0, 0, 0, 0])
""" """
Text color in (r, g, b, a) or string format when text field has focus. Text color in ``rgba`` format when text field has focus.
.. versionadded:: 1.0.0 .. versionadded:: 1.0.0
@ -1146,7 +745,7 @@ class MDTextField(
MDTextField: MDTextField:
hint_text: "text_color_focus" hint_text: "text_color_focus"
text_color_focus: "red" text_color_focus: 0, 1, 0, 1
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-text-color-focus.gif .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-text-color-focus.gif
:align: center :align: center
@ -1280,8 +879,8 @@ class MDTextField(
text=self.set_text, text=self.set_text,
) )
self.theme_cls.bind( self.theme_cls.bind(
primary_color=self.set_default_colors, primary_color=lambda x, y: self.set_default_colors(0, True),
theme_style=self.set_default_colors, theme_style=lambda x, y: self.set_default_colors(0, True),
) )
Clock.schedule_once(self.check_text) Clock.schedule_once(self.check_text)
@ -1331,17 +930,9 @@ class MDTextField(
) )
if self.error_color == [0, 0, 0, 0] or updated: if self.error_color == [0, 0, 0, 0] or updated:
self.error_color = ( self.error_color = self.theme_cls.error_color
self.theme_cls.error_color
if self.error_color == [0, 0, 0, 0]
else self.error_color
)
if self.max_length_text_color == [0, 0, 0, 0] or updated: if self.max_length_text_color == [0, 0, 0, 0] or updated:
self.max_length_text_color = ( self.max_length_text_color = self.theme_cls.disabled_hint_text_color
self.theme_cls.disabled_hint_text_color
if self.max_length_text_color == [0, 0, 0, 0]
else self.max_length_text_color
)
self._hint_text_color = self.hint_text_color_normal self._hint_text_color = self.hint_text_color_normal
self._text_color_normal = self.text_color_normal self._text_color_normal = self.text_color_normal
@ -1510,11 +1101,8 @@ class MDTextField(
self.text = re.sub("\n", " ", text) if not self.multiline else text self.text = re.sub("\n", " ", text) if not self.multiline else text
self.set_max_text_length() self.set_max_text_length()
if self.validator and self.validator == "phone":
pass
# self.format(self.text)
if (self.text and self.max_length_text_color) or self._get_has_error(): if self.text and self.max_length_text_color and self._get_has_error():
self.error = True self.error = True
if ( if (
self.text self.text
@ -1713,34 +1301,22 @@ class MDTextField(
if value_height >= self.max_height and self.max_height: if value_height >= self.max_height and self.max_height:
self.height = self.max_height self.height = self.max_height
def on_text_color_normal( def on_text_color_normal(self, instance_text_field, color: list):
self, instance_text_field, color: Union[list, str]
):
self._text_color_normal = color self._text_color_normal = color
def on_hint_text_color_normal( def on_hint_text_color_normal(self, instance_text_field, color: list):
self, instance_text_field, color: Union[list, str]
):
self._hint_text_color = color self._hint_text_color = color
def on_helper_text_color_normal( def on_helper_text_color_normal(self, instance_text_field, color: list):
self, instance_text_field, color: Union[list, str]
):
self._helper_text_color = color self._helper_text_color = color
def on_icon_right_color_normal( def on_icon_right_color_normal(self, instance_text_field, color: list):
self, instance_text_field, color: Union[list, str]
):
self._icon_right_color = color self._icon_right_color = color
def on_line_color_normal( def on_line_color_normal(self, instance_text_field, color: list):
self, instance_text_field, color: Union[list, str]
):
self._line_color_normal = color self._line_color_normal = color
def on_max_length_text_color( def on_max_length_text_color(self, instance_text_field, color: list):
self, instance_text_field, color: Union[list, str]
):
self._max_length_text_color = color self._max_length_text_color = color
def _set_color(self, attr_name: str, color: str, updated: bool) -> None: def _set_color(self, attr_name: str, color: str, updated: bool) -> None:
@ -1777,13 +1353,6 @@ class MDTextField(
the :attr:`~MDTextField.required` parameter is set to `True`. the :attr:`~MDTextField.required` parameter is set to `True`.
""" """
if self.validator and self.validator != "phone":
has_error = {
"date": self.is_date_valid,
"email": self.is_email_valid,
"time": self.is_time_valid,
}[self.validator](self.text)
return has_error
if self.max_text_length and len(self.text) > self.max_text_length: if self.max_text_length and len(self.text) > self.max_text_length:
has_error = True has_error = True
else: else:
@ -1798,12 +1367,9 @@ class MDTextField(
if __name__ == "__main__": if __name__ == "__main__":
from kivy.core.window import Window
from kivy.lang import Builder from kivy.lang import Builder
from kivy.uix.textinput import TextInput from kivy.uix.textinput import TextInput
Window.size = (800, 750)
from kivymd.app import MDApp from kivymd.app import MDApp
KV = """ KV = """
@ -1819,53 +1385,41 @@ MDScreen:
MDTextField: MDTextField:
hint_text: "Label" hint_text: "Label"
helper_text: "Error message" helper_text: "Error massage"
mode: "rectangle" mode: "rectangle"
max_text_length: 5 max_text_length: 5
MDTextField: MDTextField:
icon_left: "git" icon_left: "git"
hint_text: "Label" hint_text: "Label"
helper_text: "Error message" helper_text: "Error massage"
mode: "rectangle" mode: "rectangle"
MDTextField: MDTextField:
icon_left: "git" icon_left: "git"
hint_text: "Label" hint_text: "Label"
helper_text: "Error message" helper_text: "Error massage"
mode: "fill" mode: "fill"
MDTextField: MDTextField:
hint_text: "Label" hint_text: "Label"
helper_text: "Error message" helper_text: "Error massage"
mode: "fill" mode: "fill"
MDTextField: MDTextField:
hint_text: "Label" hint_text: "Label"
helper_text: "Error message" helper_text: "Error massage"
MDTextField: MDTextField:
icon_left: "git" icon_left: "git"
hint_text: "Label" hint_text: "Label"
helper_text: "Error message" helper_text: "Error massage"
MDTextField: MDTextField:
hint_text: "Round mode" hint_text: "Round mode"
mode: "round" mode: "round"
max_text_length: 15 max_text_length: 15
helper_text: "Message" helper_text: "Massage"
MDTextField:
hint_text: "Date dd/mm/yyyy in [01/01/1900, 01/01/2100] interval"
helper_text: "Enter a valid dd/mm/yyyy date"
validator: "date"
date_format: "dd/mm/yyyy"
date_interval: "01/01/1900", "01/01/2100"
MDTextField:
hint_text: "Email"
helper_text: "user@gmail.com"
validator: "email"
MDFlatButton: MDFlatButton:
text: "SET TEXT" text: "SET TEXT"
@ -1875,8 +1429,6 @@ MDScreen:
class Test(MDApp): class Test(MDApp):
def build(self): def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "Orange"
return Builder.load_string(KV) return Builder.load_string(KV)
def set_text(self): def set_text(self):

View File

@ -121,8 +121,8 @@ Shadow elevation control
.. code-block:: kv .. code-block:: kv
MDTopAppBar: MDTopAppBar:
title: "Elevation 4" title: "Elevation 10"
elevation: 4 elevation: 10
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/toolbar-7.png .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/toolbar-7.png
:align: center :align: center
@ -327,7 +327,7 @@ Material design 3 style
:align: center :align: center
""" """
__all__ = ("MDTopAppBar", "MDBottomAppBar", "ActionTopAppBarButton") __all__ = ("MDTopAppBar", "MDBottomAppBar")
import os import os
from math import cos, radians, sin from math import cos, radians, sin
@ -337,8 +337,10 @@ from kivy.animation import Animation
from kivy.clock import Clock from kivy.clock import Clock
from kivy.core.window import Window from kivy.core.window import Window
from kivy.lang import Builder from kivy.lang import Builder
from kivy.logger import Logger
from kivy.metrics import dp from kivy.metrics import dp
from kivy.properties import ( from kivy.properties import (
AliasProperty,
BooleanProperty, BooleanProperty,
ColorProperty, ColorProperty,
ListProperty, ListProperty,
@ -354,15 +356,15 @@ from kivymd import uix_path
from kivymd.color_definitions import text_colors from kivymd.color_definitions import text_colors
from kivymd.theming import ThemableBehavior from kivymd.theming import ThemableBehavior
from kivymd.uix.behaviors import ( from kivymd.uix.behaviors import (
CommonElevationBehavior,
DeclarativeBehavior, DeclarativeBehavior,
ScaleBehavior, FakeRectangularElevationBehavior,
SpecificBackgroundColorBehavior, SpecificBackgroundColorBehavior,
) )
from kivymd.uix.button import MDFloatingActionButton, MDIconButton from kivymd.uix.button import MDFloatingActionButton, MDIconButton
from kivymd.uix.controllers import WindowController from kivymd.uix.controllers import WindowController
from kivymd.uix.list import OneLineIconListItem from kivymd.uix.list import OneLineIconListItem
from kivymd.uix.menu import MDDropdownMenu from kivymd.uix.menu import MDDropdownMenu
from kivymd.uix.templates import ScaleWidget
from kivymd.uix.tooltip import MDTooltip from kivymd.uix.tooltip import MDTooltip
from kivymd.utils.set_bars_colors import set_bars_colors from kivymd.utils.set_bars_colors import set_bars_colors
@ -372,7 +374,7 @@ with open(
Builder.load_string(kv_file.read()) Builder.load_string(kv_file.read())
class ActionBottomAppBarButton(MDFloatingActionButton, ScaleBehavior): class ActionBottomAppBarButton(MDFloatingActionButton, ScaleWidget):
""" """
Implements a floating action button (FAB) for a toolbar with type 'bottom'. Implements a floating action button (FAB) for a toolbar with type 'bottom'.
""" """
@ -407,11 +409,11 @@ class OverFlowMenuItem(OneLineIconListItem):
class NotchedBox( class NotchedBox(
ThemableBehavior, ThemableBehavior,
CommonElevationBehavior, FakeRectangularElevationBehavior,
SpecificBackgroundColorBehavior, SpecificBackgroundColorBehavior,
BoxLayout, BoxLayout,
): ):
elevation = NumericProperty(4) elevation = NumericProperty(6)
notch_radius = NumericProperty() notch_radius = NumericProperty()
notch_center_x = NumericProperty("100dp") notch_center_x = NumericProperty("100dp")
@ -959,10 +961,8 @@ class MDTopAppBar(DeclarativeBehavior, NotchedBox, WindowController):
self.icon_color = self.theme_cls.primary_color self.icon_color = self.theme_cls.primary_color
self.bind(specific_text_color=self.update_action_bar_text_colors) self.bind(specific_text_color=self.update_action_bar_text_colors)
self.theme_cls.bind( self.theme_cls.bind(material_style=self.update_bar_height)
material_style=self.update_bar_height, self.theme_cls.bind(primary_palette=self.update_md_bg_color)
primary_palette=self.update_md_bg_color,
)
Clock.schedule_once( Clock.schedule_once(
lambda x: self.on_left_action_items(0, self.left_action_items) lambda x: self.on_left_action_items(0, self.left_action_items)
@ -1103,7 +1103,6 @@ class MDTopAppBar(DeclarativeBehavior, NotchedBox, WindowController):
+ self.theme_cls.standard_increment / 2 + self.theme_cls.standard_increment / 2
+ self._shift + self._shift
) )
self.shadow_offset = [0, 30]
self.on_mode(None, self.mode) self.on_mode(None, self.mode)
def on_type_height(self, instance_toolbar, height_type_value: str) -> None: def on_type_height(self, instance_toolbar, height_type_value: str) -> None:

View File

@ -314,7 +314,7 @@ class MDTooltip(ThemableBehavior, HoverBehavior, TouchBehavior):
Clock.schedule_once(self.animation_tooltip_dismiss) Clock.schedule_once(self.animation_tooltip_dismiss)
def on_show(self) -> None: def on_show(self) -> None:
"""Default display event handler.""" """Default dismiss event handler."""
def on_dismiss(self) -> None: def on_dismiss(self) -> None:
""" """

View File

@ -35,9 +35,7 @@ __all__ = (
"MDTransitionBase", "MDTransitionBase",
) )
from kivy import Logger
from kivy.animation import Animation, AnimationTransition from kivy.animation import Animation, AnimationTransition
from kivy.properties import DictProperty
from kivy.uix.screenmanager import ( from kivy.uix.screenmanager import (
ScreenManagerException, ScreenManagerException,
SlideTransition, SlideTransition,
@ -45,41 +43,13 @@ from kivy.uix.screenmanager import (
TransitionBase, TransitionBase,
) )
from kivymd.uix.hero import MDHeroFrom, MDHeroTo
from kivymd.uix.screenmanager import MDScreenManager from kivymd.uix.screenmanager import MDScreenManager
class MDTransitionBase(TransitionBase): class MDTransitionBase(TransitionBase):
"""
TransitionBase is used to animate 2 screens within the
:class:`~kivymd.uix.screenmanager.MDScreenManager`.
For more
information, see in the :class:`~kivy.uix.screenmanager.TransitionBase`
class documentation.
"""
_direction = "in" _direction = "in"
# Collection of child widgets of all 'MDHeroFrom' widgets that are hero_widget = None
# on the screen, for example: hero_from_widget = None # kivymd.uix.hero.MDHeroFrom object
#
# MDScreen:
#
# MDHeroFrom:
# tag: "kivymd"
#
# FitImage:
#
# MDHeroFrom:
# tag: "kivy"
#
# FitImage:
#
# {
# 'kivy': <kivymd.uix.fitimage.fitimage.FitImage object>,
# 'kivymd': <kivymd.uix.fitimage.fitimage.FitImage object>,
# }
_hero_from_widget_children = DictProperty()
def start(self, instance_screen_manager: MDScreenManager) -> None: def start(self, instance_screen_manager: MDScreenManager) -> None:
super().start(instance_screen_manager) super().start(instance_screen_manager)
@ -89,160 +59,67 @@ class MDTransitionBase(TransitionBase):
]() ]()
def animated_hero_in(self) -> None: def animated_hero_in(self) -> None:
"""Animates the flight of heroes from screen **A** to screen **B**.""" if self.manager._heroes_data and self.manager.current_hero:
self.hero_from_widget = self.manager.get_hero_from_widget()
self._check_widget_properties()
self.hero_widget = self.hero_from_widget.children[0]
self.hero_from_widget.remove_widget(self.hero_widget)
if self.manager._heroes_data and self.manager.current_heroes: self.hero_widget.pos = self.screen_out.to_widget(
for hero_from_widget in self.manager.get_hero_from_widget(): *self.hero_from_widget.to_window(*self.hero_from_widget.pos)
for heroes_tag in self.manager.current_heroes: )
if heroes_tag == hero_from_widget.tag: self.hero_widget.size = self.hero_from_widget.size
self._check_widget_properties(hero_from_widget) self.manager.get_root_window().add_widget(self.hero_widget)
# Get child widget of the 'MDHeroFrom' container. Animation(
hero_widget = hero_from_widget.children[0] size=self.screen_in.hero_to.size,
self._hero_from_widget_children[ d=self.duration,
hero_from_widget.tag pos=self.screen_in.hero_to.pos,
] = hero_widget ).start(self.hero_widget)
self.hero_from_widget.dispatch(
# Removing the child widget from the 'MDHeroFrom' "on_transform_in", self.hero_widget, self.duration
# container. )
hero_from_widget.remove_widget(hero_widget)
# We set the size, position of the child widget of the
# 'MDHeroFrom' container and add this widget to the
# root window.
hero_widget.pos = self.screen_out.to_widget(
*hero_from_widget.to_window(*hero_from_widget.pos)
)
hero_widget.size = hero_from_widget.size
self.manager.get_root_window().add_widget(hero_widget)
# Animating widgets added to the root window.
if self.screen_in.heroes_to:
for hero_to_widget in self.screen_in.heroes_to:
self._check_hero_to_widget_tag(
hero_to_widget, hero_from_widget
)
if hero_to_widget.tag == heroes_tag:
Animation(
size=hero_to_widget.size,
d=self.duration,
pos=hero_to_widget.pos,
).start(hero_widget)
hero_from_widget.dispatch(
"on_transform_in",
hero_widget,
self.duration,
)
def animated_hero_out(self) -> None: def animated_hero_out(self) -> None:
"""Animates the flight of heroes from screen **B** to screen **A**.""" if self.manager._heroes_data and self.manager.current_hero:
self.screen_out.hero_to.remove_widget(self.hero_widget)
self.manager.get_root_window().add_widget(self.hero_widget)
if ( self.hero_from_widget.dispatch(
self.manager._heroes_data "on_transform_out", self.hero_widget, self.duration
and self.manager.current_heroes )
and self.screen_out.heroes_to Animation(
): pos=self.screen_in.to_widget(
*self.hero_from_widget.to_window(*self.hero_from_widget.pos)
for heroes_tag in self.manager.current_heroes: ),
for hero_to_widget in self.screen_out.heroes_to: size=self.hero_from_widget.size,
if hero_to_widget.tag == heroes_tag: d=self.duration,
hero_from_children = self._hero_from_widget_children[ ).start(self.hero_widget)
heroes_tag
]
hero_to_widget.remove_widget(hero_from_children)
self.manager.get_root_window().add_widget(
hero_from_children
)
for (
hero_from_widget
) in self.manager.get_hero_from_widget():
hero_from_widget.dispatch(
"on_transform_out",
self._hero_from_widget_children[
hero_from_widget.tag
],
self.duration,
)
Animation(
pos=self.screen_in.to_widget(
*hero_from_widget.to_window(
*hero_from_widget.pos
)
),
size=hero_from_widget.size,
d=self.duration,
).start(
self._hero_from_widget_children[
hero_from_widget.tag
]
)
def on_complete(self) -> None: def on_complete(self) -> None:
"""
Override method.
See :attr:`kivy.uix.screenmanager.TransitionBase.on_complete'.
"""
super().on_complete() super().on_complete()
if self.manager._heroes_data and self.manager.current_heroes:
for hero_from_widget in self.manager.get_hero_from_widget():
for heroes_tag in self.manager.current_heroes:
if heroes_tag == hero_from_widget.tag:
hero_from_children = self._hero_from_widget_children[
heroes_tag
]
self.manager.get_root_window().remove_widget(
hero_from_children
)
# Adding a child widget from the 'MDHeraFrom' container
# to the 'MDHeroTo' container.
if self._direction == "in":
for hero_to_widget in self.screen_in.heroes_to:
if hero_to_widget.tag == heroes_tag:
hero_to_widget.add_widget(
hero_from_children
)
# Restores the child widget for the 'MDHeraFrom'
# container.
elif self._direction == "out":
hero_from_widget.add_widget(hero_from_children)
if self._direction == "out": if self._direction == "out":
self._direction = "in" self._direction = "in"
if self.manager._heroes_data and self.manager.current_hero:
self.manager.get_root_window().remove_widget(self.hero_widget)
self.hero_from_widget.add_widget(self.hero_widget)
else: else:
self._direction = "out" self._direction = "out"
if self.manager._heroes_data and self.manager.current_hero:
self.manager.get_root_window().remove_widget(self.hero_widget)
self.screen_in.hero_to.add_widget(self.hero_widget)
# Checks the attributes for the 'self.screen_in' screen. def _check_widget_properties(self):
# Called from the animated_hero_in method. if not self.screen_in.hero_to:
def _check_widget_properties(self, hero_from_widget: MDHeroFrom):
if not self.screen_in.heroes_to:
raise Exception( raise Exception(
f"The `heroes_to` attribute is not specified for screen " f"The `hero_to` attribute is not specified for screen {self.screen_in}"
f"{self.screen_in}"
) )
# The 'MDHeroFrom' widget allows you to place only one widget in if len(self.hero_from_widget.children) > 1:
# itself.
if len(hero_from_widget.children) > 1:
raise Exception( raise Exception(
f"{hero_from_widget.__class__} accept only one widget" f"{self.hero_from_widget.__class__} accept only one widget"
) )
# For new API support.
def _check_hero_to_widget_tag(
self, hero_to_widget: MDHeroTo, hero_from_widget: MDHeroFrom
) -> None:
if not hero_to_widget.tag:
Logger.warning(
"KivyMD: "
f"Set the tag '{hero_from_widget.tag}' "
f"for the {hero_to_widget} widget to the same "
f"as for the {hero_from_widget} widget"
)
hero_to_widget.tag = hero_from_widget.tag
class MDSwapTransition(SwapTransition, MDTransitionBase): class MDSwapTransition(SwapTransition, MDTransitionBase):
pass pass

View File

@ -36,13 +36,11 @@ MDWidget
__all__ = ("MDWidget",) __all__ = ("MDWidget",)
from kivy.uix.widget import Widget
from kivymd.uix import MDAdaptiveWidget from kivymd.uix import MDAdaptiveWidget
from kivymd.uix.behaviors import DeclarativeBehavior from kivymd.uix.behaviors import DeclarativeBehavior
class MDWidget(DeclarativeBehavior, MDAdaptiveWidget, Widget): class MDWidget(DeclarativeBehavior, MDAdaptiveWidget):
""" """
See :class:`~kivy.uix.Widget` class documentation for more information. See :class:`~kivy.uix.Widget` class documentation for more information.