working condition
This commit is contained in:
parent
417e54da96
commit
511e0b0379
517 changed files with 29187 additions and 32696 deletions
|
@ -1,3 +1,10 @@
|
|||
from .colorpicker import MDColorPicker # NOQA F401
|
||||
from .datepicker import MDDatePicker # NOQA F401
|
||||
from .timepicker import MDTimePicker # NOQA F401
|
||||
from .datepicker import (
|
||||
MDModalDatePicker,
|
||||
MDDockedDatePicker,
|
||||
MDModalInputDatePicker,
|
||||
) # NOQA F401
|
||||
from .timepicker import (
|
||||
MDTimePickerDialVertical,
|
||||
MDTimePickerDialHorizontal,
|
||||
MDTimePickerInput,
|
||||
) # NOQA F401
|
||||
|
|
Binary file not shown.
|
@ -1 +0,0 @@
|
|||
from .colorpicker import MDColorPicker # NOQA F401
|
Binary file not shown.
Binary file not shown.
|
@ -1,299 +0,0 @@
|
|||
#:import STANDARD_INCREMENT kivymd.material_resources.STANDARD_INCREMENT
|
||||
#:import images_path kivymd.images_path
|
||||
#:import colors kivymd.color_definitions.colors
|
||||
#:import Window kivy.core.window.Window
|
||||
|
||||
|
||||
<SelectAlphaChannelWidget>
|
||||
orientation: "vertical"
|
||||
adaptive_height: True
|
||||
spacing: "12dp"
|
||||
padding: 0, 0, 0, "8dp"
|
||||
|
||||
FitImage:
|
||||
size_hint_y: None
|
||||
height: "36dp"
|
||||
source: f"{images_path}/alpha_layer.png"
|
||||
radius: [8,]
|
||||
|
||||
canvas.after:
|
||||
Color:
|
||||
rgba:
|
||||
root._rgb[:-1] + [root._opacity_value_selected_color]
|
||||
RoundedRectangle:
|
||||
pos: self.pos
|
||||
size: self.size
|
||||
radius: [8,]
|
||||
|
||||
MDSlider:
|
||||
id: slider
|
||||
size_hint_y: None
|
||||
height: "12dp"
|
||||
hint: False
|
||||
max: 1
|
||||
value: root._opacity_value_selected_color
|
||||
on_value:
|
||||
root._opacity_value_selected_color = self.value
|
||||
if root.color_picker: \
|
||||
root.color_picker._opacity_value_selected_color = self.value
|
||||
|
||||
|
||||
<SliderItem@MDBoxLayout>
|
||||
spacing: "12dp"
|
||||
color_slider: "Red"
|
||||
max: 255
|
||||
adaptive_height: True
|
||||
|
||||
MDSlider:
|
||||
id: slider
|
||||
size_hint_y: None
|
||||
height: "36dp"
|
||||
color: colors[root.color_slider]["500"]
|
||||
max: root.max
|
||||
value: 1 if root.max == 1 else 0
|
||||
on_value:
|
||||
root.parent.dispatch("on_slide_value", root.parent.get_color())
|
||||
|
||||
MDLabel:
|
||||
adaptive_size: True
|
||||
-text_size: None, None
|
||||
pos_hint: {"center_y": .5}
|
||||
text:
|
||||
str(int(slider.value)) \
|
||||
if root.max != 1 \
|
||||
else str(round(slider.value, 1))
|
||||
|
||||
|
||||
<SliderTab>
|
||||
orientation: "vertical"
|
||||
padding: "12dp", "24dp", "12dp", 0
|
||||
spacing: "24dp"
|
||||
|
||||
SliderItem:
|
||||
id: slider_red
|
||||
color_slider: "Red"
|
||||
|
||||
SliderItem:
|
||||
id: slider_green
|
||||
color_slider: "Green"
|
||||
|
||||
SliderItem:
|
||||
id: slider_blue
|
||||
color_slider: "Blue"
|
||||
|
||||
Widget:
|
||||
|
||||
SelectAlphaChannelWidget:
|
||||
id: select_alpha_channel_widget
|
||||
color_picker: root.color_picker
|
||||
|
||||
|
||||
<GradientTab>
|
||||
orientation: "vertical"
|
||||
padding: "12dp", "12dp", "12dp", 0
|
||||
spacing: "8dp"
|
||||
|
||||
MDBoxLayout:
|
||||
id: color_selection_box
|
||||
spacing: "12dp"
|
||||
|
||||
Widget:
|
||||
id: gradient_widget
|
||||
|
||||
MDBoxLayout:
|
||||
orientation: "vertical"
|
||||
size_hint_x: None
|
||||
width: "24dp"
|
||||
|
||||
canvas.before:
|
||||
StencilPush
|
||||
RoundedRectangle:
|
||||
size: self.size
|
||||
pos: self.pos
|
||||
radius: root.color_picker.radius_color_scale
|
||||
StencilUse
|
||||
|
||||
canvas.after:
|
||||
StencilUnUse
|
||||
RoundedRectangle:
|
||||
size: self.size
|
||||
pos: self.pos
|
||||
radius: root.color_picker.radius_color_scale
|
||||
StencilPop
|
||||
|
||||
Image:
|
||||
source: f"{images_path}/blue.png"
|
||||
allow_stretch: True
|
||||
keep_ratio: False
|
||||
on_touch_down:
|
||||
if self.collide_point(*args[1].pos): \
|
||||
root.updated_canvas(self, args[1])
|
||||
|
||||
Image:
|
||||
source: f"{images_path}/green.png"
|
||||
allow_stretch: True
|
||||
keep_ratio: False
|
||||
on_touch_down:
|
||||
if self.collide_point(*args[1].pos): \
|
||||
root.updated_canvas(self, args[1])
|
||||
|
||||
Image:
|
||||
source: f"{images_path}/yellow.png"
|
||||
allow_stretch: True
|
||||
keep_ratio: False
|
||||
on_touch_down:
|
||||
if self.collide_point(*args[1].pos): \
|
||||
root.updated_canvas(self, args[1])
|
||||
|
||||
Image:
|
||||
source: f"{images_path}/red.png"
|
||||
allow_stretch: True
|
||||
keep_ratio: False
|
||||
on_touch_down:
|
||||
if self.collide_point(*args[1].pos): \
|
||||
root.updated_canvas(self, args[1])
|
||||
|
||||
Image:
|
||||
source: f"{images_path}/black.png"
|
||||
allow_stretch: True
|
||||
keep_ratio: False
|
||||
on_touch_down:
|
||||
if self.collide_point(*args[1].pos): \
|
||||
root.updated_canvas(self, args[1])
|
||||
|
||||
SelectAlphaChannelWidget:
|
||||
id: select_alpha_channel_widget
|
||||
color_picker: root.color_picker
|
||||
|
||||
|
||||
<TabColorList>
|
||||
rv: rv
|
||||
|
||||
RecycleView:
|
||||
id: rv
|
||||
key_viewclass: "viewclass"
|
||||
key_size: "height"
|
||||
|
||||
RecycleBoxLayout:
|
||||
orientation: "vertical"
|
||||
size_hint_y: None
|
||||
height: self.minimum_height
|
||||
padding: "8dp"
|
||||
spacing: "8dp"
|
||||
default_size_hint: 1, None
|
||||
default_size: None, dp(48)
|
||||
|
||||
|
||||
<ColorListItem>
|
||||
size_hint_y: None
|
||||
padding: "12dp"
|
||||
md_bg_color: root.color
|
||||
radius: [8,]
|
||||
|
||||
MDLabel:
|
||||
text: root.hue_code
|
||||
theme_text_color: "Custom"
|
||||
text_color: root.text_color
|
||||
halign: "center"
|
||||
|
||||
|
||||
<MDColorPicker>
|
||||
# These are the sums of the widths of the `TypeColorButton` buttons in the
|
||||
# `type_color_button_box` box.
|
||||
size_hint_min_x: dp(264)
|
||||
|
||||
MDBoxLayout:
|
||||
orientation: "vertical"
|
||||
|
||||
MDBoxLayout:
|
||||
id: header
|
||||
orientation: "vertical"
|
||||
padding: 0, "8dp", 0, 0
|
||||
spacing: "8dp"
|
||||
radius: root.radius[:2] + [0, 0]
|
||||
size_hint_y: None
|
||||
height: STANDARD_INCREMENT
|
||||
md_bg_color:
|
||||
app.theme_cls.primary_color \
|
||||
if not root.default_color \
|
||||
else root.default_color
|
||||
|
||||
MDLabel:
|
||||
id: lbl_color_value
|
||||
halign: "center"
|
||||
shorten: True
|
||||
bold: True
|
||||
markup: True
|
||||
|
||||
MDBoxLayout:
|
||||
id: type_color_button_box
|
||||
adaptive_height: True
|
||||
|
||||
TypeColorButton:
|
||||
text: "HEX"
|
||||
group: "x"
|
||||
size_hint_x: 1
|
||||
on_release: root.type_color = self.text
|
||||
|
||||
TypeColorButton:
|
||||
text: "RGB"
|
||||
group: "x"
|
||||
size_hint_x: 1
|
||||
on_release: root.type_color = self.text
|
||||
|
||||
TypeColorButton:
|
||||
text: "RGBA"
|
||||
group: "x"
|
||||
size_hint_x: 1
|
||||
on_release: root.type_color = self.text
|
||||
|
||||
MDBottomNavigation:
|
||||
id: bottom_navigation
|
||||
use_text: False
|
||||
on_switch_tabs: root.dispatch("on_switch_tabs", *args)
|
||||
|
||||
MDBottomNavigationItem:
|
||||
id: bottom_navigation_gradient
|
||||
name: "bottom navigation gradient"
|
||||
icon: "gradient-vertical"
|
||||
|
||||
MDBottomNavigationItem:
|
||||
id: view_headline
|
||||
name: "view headline"
|
||||
icon: "view-headline"
|
||||
|
||||
ColorListTab:
|
||||
id: color_list_tabs
|
||||
text_color_normal: 0, 0, 0, 1
|
||||
on_tab_switch: self.generates_list_colors(*args)
|
||||
color_picker: root
|
||||
|
||||
MDBottomNavigationItem:
|
||||
id: tune
|
||||
name: "tune"
|
||||
icon: "tune"
|
||||
|
||||
SliderTab:
|
||||
color_picker: root
|
||||
on_slide_value:
|
||||
root.dispatch("on_select_color", args[1])
|
||||
|
||||
MDBoxLayout:
|
||||
size_hint_y: None
|
||||
height: "48dp"
|
||||
md_bg_color: app.theme_cls.bg_dark
|
||||
radius: [0, 0] + root.radius[2:]
|
||||
|
||||
MDFlatButton:
|
||||
text: root.text_button_ok
|
||||
size_hint: 1, 1
|
||||
on_release:
|
||||
root.dispatch( \
|
||||
"on_release", \
|
||||
root.type_color, \
|
||||
root._get_selected_color(root.selected_color))
|
||||
|
||||
MDFlatButton:
|
||||
text: root.text_button_cancel
|
||||
size_hint: 1, 1
|
||||
on_release: root.dismiss()
|
|
@ -1,657 +0,0 @@
|
|||
"""
|
||||
Components/ColorPicker
|
||||
======================
|
||||
|
||||
.. versionadded:: 1.0.0
|
||||
|
||||
.. rubric:: Create, share, and apply color palettes to your UI, as well as measure the accessibility level of any color combination..
|
||||
|
||||
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/color-picker-preview.png
|
||||
:align: center
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from typing import Union
|
||||
|
||||
from kivy.lang import Builder
|
||||
|
||||
from kivymd.app import MDApp
|
||||
from kivymd.uix.pickers import MDColorPicker
|
||||
|
||||
KV = '''
|
||||
MDScreen:
|
||||
|
||||
MDTopAppBar:
|
||||
id: toolbar
|
||||
title: "MDTopAppBar"
|
||||
pos_hint: {"top": 1}
|
||||
|
||||
MDRaisedButton:
|
||||
text: "OPEN PICKER"
|
||||
pos_hint: {"center_x": .5, "center_y": .5}
|
||||
md_bg_color: toolbar.md_bg_color
|
||||
on_release: app.open_color_picker()
|
||||
'''
|
||||
|
||||
|
||||
class MyApp(MDApp):
|
||||
def build(self):
|
||||
return Builder.load_string(KV)
|
||||
|
||||
def open_color_picker(self):
|
||||
color_picker = MDColorPicker(size_hint=(0.45, 0.85))
|
||||
color_picker.open()
|
||||
color_picker.bind(
|
||||
on_select_color=self.on_select_color,
|
||||
on_release=self.get_selected_color,
|
||||
)
|
||||
|
||||
def update_color(self, color: list) -> None:
|
||||
self.root.ids.toolbar.md_bg_color = color
|
||||
|
||||
def get_selected_color(
|
||||
self,
|
||||
instance_color_picker: MDColorPicker,
|
||||
type_color: str,
|
||||
selected_color: Union[list, str],
|
||||
):
|
||||
'''Return selected color.'''
|
||||
|
||||
print(f"Selected color is {selected_color}")
|
||||
self.update_color(selected_color[:-1] + [1])
|
||||
|
||||
def on_select_color(self, instance_gradient_tab, color: list) -> None:
|
||||
'''Called when a gradient image is clicked.'''
|
||||
|
||||
|
||||
MyApp().run()
|
||||
|
||||
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/color-picker-usage.png
|
||||
:align: center
|
||||
"""
|
||||
|
||||
import os
|
||||
import struct
|
||||
from io import BytesIO
|
||||
from typing import List, Union
|
||||
|
||||
from kivy.clock import Clock
|
||||
from kivy.core.image import Image as CoreImage
|
||||
from kivy.graphics import RoundedRectangle
|
||||
from kivy.lang import Builder
|
||||
from kivy.metrics import dp
|
||||
from kivy.properties import (
|
||||
ColorProperty,
|
||||
ListProperty,
|
||||
NumericProperty,
|
||||
ObjectProperty,
|
||||
OptionProperty,
|
||||
StringProperty,
|
||||
VariableListProperty,
|
||||
)
|
||||
from kivy.uix.behaviors import ButtonBehavior
|
||||
from kivy.utils import get_color_from_hex, get_hex_from_color
|
||||
from PIL import Image as PilImage
|
||||
from PIL import ImageDraw
|
||||
|
||||
from kivymd import uix_path
|
||||
from kivymd.color_definitions import colors as _colors
|
||||
from kivymd.color_definitions import text_colors
|
||||
from kivymd.uix.behaviors import RectangularRippleBehavior
|
||||
from kivymd.uix.behaviors.toggle_behavior import MDToggleButton
|
||||
from kivymd.uix.boxlayout import MDBoxLayout
|
||||
from kivymd.uix.button import MDRaisedButton
|
||||
from kivymd.uix.dialog import BaseDialog
|
||||
from kivymd.uix.tab import MDTabs, MDTabsBase, MDTabsLabel
|
||||
|
||||
__all__ = ("MDColorPicker",)
|
||||
|
||||
with open(
|
||||
os.path.join(uix_path, "pickers", "colorpicker", "colorpicker.kv"),
|
||||
encoding="utf-8",
|
||||
) as kv_file:
|
||||
Builder.load_string(kv_file.read())
|
||||
|
||||
|
||||
class TypeColorButton(MDRaisedButton, MDToggleButton):
|
||||
"""
|
||||
The class implements the button to switch the color type -
|
||||
'RGBA', 'HEX', 'RGB'.
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.theme_text_color = "Custom"
|
||||
self.text_color = (0, 0, 0, 1)
|
||||
self.elevation = 0
|
||||
|
||||
|
||||
class SelectAlphaChannelWidget(MDBoxLayout):
|
||||
"""
|
||||
The class implements the widget with the current color and slider to set
|
||||
the value of the transparency of the selected color.
|
||||
"""
|
||||
|
||||
# :class:`~kivymd.uix.colorpicker.MDColorPicker` class.
|
||||
color_picker = ObjectProperty()
|
||||
|
||||
# The `RGB` value for the transparency preview widget of the selected
|
||||
# color.
|
||||
_rgb = ColorProperty([0, 0, 0, 0])
|
||||
# The opacity value for the transparency preview widget of the selected
|
||||
# color.
|
||||
_opacity_value_selected_color = NumericProperty(1)
|
||||
|
||||
def on_color_picker(
|
||||
self, instance_select_alpha_channel_widget, instance_color_picker
|
||||
) -> None:
|
||||
instance_color_picker.bind(_rgb=self.set_scale_rgb)
|
||||
|
||||
def set_scale_rgb(
|
||||
self,
|
||||
instance_color_picker,
|
||||
color: Union[List[int], List[float]],
|
||||
) -> None:
|
||||
if color[0] > 1:
|
||||
self._rgb = [x / 255.0 for x in color]
|
||||
else:
|
||||
self._rgb = color
|
||||
|
||||
|
||||
class SliderTab(MDBoxLayout):
|
||||
"""
|
||||
The class has implemented `RGB` value sliders and a scale for setting the
|
||||
transparency value of the selected color. This is the third tab on the
|
||||
bottom navigation panel.
|
||||
"""
|
||||
|
||||
# :class:`~kivymd.uix.colorpicker.MDColorPicker` class.
|
||||
color_picker = ObjectProperty()
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.register_event_type("on_slide_value")
|
||||
|
||||
def get_color(self) -> List[float]:
|
||||
return [
|
||||
self.ids.slider_red.ids.slider.value / 255,
|
||||
self.ids.slider_green.ids.slider.value / 255,
|
||||
self.ids.slider_blue.ids.slider.value / 255,
|
||||
self.color_picker._opacity_value_selected_color,
|
||||
]
|
||||
|
||||
def on_slide_value(self, *args) -> None:
|
||||
"""Basic event handler for changing the slider value."""
|
||||
|
||||
|
||||
class GradientTab(MDBoxLayout):
|
||||
"""
|
||||
The class implements a tab with a gradient, a color selection scale and
|
||||
a scale for setting the transparency value of the selected color.
|
||||
This is the first tab on the bottom navigation panel.
|
||||
"""
|
||||
|
||||
# :class:`~kivymd.uix.colorpicker.MDColorPicker` class.
|
||||
color_picker = ObjectProperty()
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.rectangle = None
|
||||
self.texture = None
|
||||
Clock.schedule_once(lambda x: self.create_gradient_texture())
|
||||
Clock.schedule_once(self.create_canvas_with_gradient_texture)
|
||||
|
||||
def create_gradient_texture(
|
||||
self, r_g_b=None, interval: Union[int, float] = 0
|
||||
) -> None:
|
||||
"""
|
||||
Creates a gradient value buffer and texture object.
|
||||
Called when clicking on the gradient bar to the right.
|
||||
"""
|
||||
|
||||
# TODO: Perhaps there is a better way to create a gradient.
|
||||
# The implementation using the PIL package is most likely not the most
|
||||
# better. In any case, performance tests should be carried out.
|
||||
gradient_widget_width = int(self.ids.gradient_widget.width)
|
||||
gradient_widget_height = int(self.ids.gradient_widget.height - dp(100))
|
||||
img = PilImage.new(
|
||||
"RGBA", (gradient_widget_width, gradient_widget_height), "#FFFFFF"
|
||||
)
|
||||
draw = ImageDraw.Draw(img)
|
||||
|
||||
if not self.color_picker.default_color:
|
||||
r, g, b = (
|
||||
r_g_b
|
||||
if r_g_b
|
||||
else self.color_picker.get_rgb(self.theme_cls.primary_color)
|
||||
)
|
||||
else:
|
||||
r, g, b = [
|
||||
int(value * 255)
|
||||
for value in self.color_picker.default_color[:-1]
|
||||
]
|
||||
self.color_picker._rgb = [r, g, b]
|
||||
(
|
||||
r_adjacent_color_constant,
|
||||
g_adjacent_color_constant,
|
||||
b_adjacent_color_constant,
|
||||
) = (
|
||||
self.color_picker.adjacent_color_constants
|
||||
if r_g_b != (0, 0, 0)
|
||||
else (0.40, 0.40, 0.40) # if the selected color is black
|
||||
)
|
||||
|
||||
for i in range(gradient_widget_width):
|
||||
r, g, b = (
|
||||
r + r_adjacent_color_constant,
|
||||
g + g_adjacent_color_constant,
|
||||
b + b_adjacent_color_constant,
|
||||
)
|
||||
draw.line(
|
||||
(i, 0, i, gradient_widget_width), fill=(int(r), int(g), int(b))
|
||||
)
|
||||
|
||||
data = BytesIO()
|
||||
img.save(data, format="png")
|
||||
data.seek(0)
|
||||
self.texture = CoreImage(BytesIO(data.read()), ext="png").texture
|
||||
|
||||
def create_canvas_with_gradient_texture(
|
||||
self, interval: Union[int, float]
|
||||
) -> None:
|
||||
"""Creates a canvas with a gradient texture."""
|
||||
|
||||
with self.ids.color_selection_box.canvas:
|
||||
self.rectangle = RoundedRectangle(
|
||||
texture=self.texture,
|
||||
pos=self.ids.gradient_widget.pos,
|
||||
size=self.ids.gradient_widget.size,
|
||||
radius=self.color_picker.radius,
|
||||
group="gradient",
|
||||
)
|
||||
self.bind(
|
||||
size=lambda instance, size: Clock.schedule_once(
|
||||
lambda dt: self._update_canvas(instance, size)
|
||||
)
|
||||
)
|
||||
|
||||
def get_rgba_color_from_touch_region(self, widget, touch) -> List[int]:
|
||||
"""
|
||||
Returns the color of the pixel in the gradient that was clicked.
|
||||
"""
|
||||
|
||||
pixel = widget.texture.get_region(*touch.pos, 1, 1)
|
||||
rgba = struct.unpack("4B", pixel.pixels)
|
||||
return rgba
|
||||
|
||||
def updated_canvas(self, widget, touch, color=None) -> None:
|
||||
"""
|
||||
Called when clicking on the gradient bar to the right.
|
||||
Updates the color of the gradient texture.
|
||||
"""
|
||||
|
||||
if self.color_picker.default_color:
|
||||
self.color_picker.default_color = None
|
||||
|
||||
self.ids.color_selection_box.canvas.remove_group("gradient")
|
||||
if not color:
|
||||
# (0-255, 0-255, 0-255, 0-255)
|
||||
color = self.get_rgba_color_from_touch_region(widget, touch)
|
||||
self.create_gradient_texture(color[:-1])
|
||||
self.color_picker.dispatch(
|
||||
"on_select_color", [x / 255.0 for x in color]
|
||||
)
|
||||
else:
|
||||
self.create_gradient_texture(color)
|
||||
self.create_canvas_with_gradient_texture(0)
|
||||
|
||||
def on_touch_down(self, touch):
|
||||
"""Handles the ``self.ids.gradient_widget`` touch event."""
|
||||
|
||||
if self.ids.gradient_widget.collide_point(*touch.pos):
|
||||
color = self.get_rgba_color_from_touch_region(self, touch)
|
||||
self.color_picker.dispatch(
|
||||
"on_select_color", [x / 255.0 for x in color]
|
||||
)
|
||||
return super().on_touch_down(touch)
|
||||
|
||||
def _update_canvas(self, instance_gradient_widget, size: list) -> None:
|
||||
self.rectangle.size = self.ids.gradient_widget.size
|
||||
self.rectangle.pos = self.ids.gradient_widget.pos
|
||||
|
||||
|
||||
class TabColorList(MDBoxLayout, MDTabsBase):
|
||||
"""Implements a tab for :class:`~ColorListTab` class."""
|
||||
|
||||
|
||||
class ColorListTab(MDTabs):
|
||||
"""
|
||||
The class implements a tab with tabs with a list of colors.
|
||||
This is the second tab on the bottom navigation panel.
|
||||
"""
|
||||
|
||||
# :class:`~kivymd.uix.colorpicker.MDColorPicker` class.
|
||||
color_picker = ObjectProperty()
|
||||
|
||||
def generates_list_colors(
|
||||
self,
|
||||
instance_color_list_tab,
|
||||
instance_tab_color_list: TabColorList,
|
||||
instance_tabs_label: MDTabsLabel,
|
||||
tab_label_text: str,
|
||||
) -> None:
|
||||
"""
|
||||
Generates list of colors.
|
||||
Called when you click the tab of :class:`~TabColorList` class.
|
||||
"""
|
||||
|
||||
if not tab_label_text:
|
||||
tab_label_text = "Red"
|
||||
if not instance_tab_color_list.rv.data:
|
||||
for hue in _colors[tab_label_text]:
|
||||
color = get_color_from_hex(_colors[tab_label_text][hue])
|
||||
if tab_label_text == "Light":
|
||||
text_color = (0, 0, 0, 1)
|
||||
elif tab_label_text == "Dark":
|
||||
text_color = (1, 1, 1, 1)
|
||||
else:
|
||||
text_color = text_colors[tab_label_text][hue]
|
||||
instance_tab_color_list.rv.data.append(
|
||||
{
|
||||
"viewclass": "ColorListItem",
|
||||
"color": color,
|
||||
"hue_code": hue,
|
||||
"text_color": text_color,
|
||||
"on_press": lambda x=color: self.on_press_color_item(x),
|
||||
}
|
||||
)
|
||||
|
||||
def on_press_color_item(self, color: list) -> None:
|
||||
"""Called when you click on the color item from the list of colors."""
|
||||
|
||||
rgb = [int(value * 255) for value in color[:-1]]
|
||||
self.color_picker._rgb = rgb
|
||||
self.background_color = color
|
||||
self.color_picker.dispatch("on_select_color", color)
|
||||
|
||||
|
||||
class ColorListItem(RectangularRippleBehavior, ButtonBehavior, MDBoxLayout):
|
||||
"""Implements the item for the list of :class:`~TabColorList` class."""
|
||||
|
||||
color = ColorProperty()
|
||||
text_color = ColorProperty()
|
||||
hue_code = StringProperty()
|
||||
|
||||
|
||||
class MDColorPicker(BaseDialog):
|
||||
adjacent_color_constants = ListProperty([0.299, 0.887, 0.411])
|
||||
"""
|
||||
A list of values that are used to create the gradient. These values are
|
||||
selected empirically. Each of these values will be added to the selected
|
||||
``RGB`` value, thus creating colors that are close in value.
|
||||
|
||||
:attr:`adjacent_color_constants` is an :class:`~kivy.properties.ListProperty`
|
||||
and defaults to `[0.299, 0.887, 0.411]`.
|
||||
"""
|
||||
|
||||
default_color = ColorProperty(None, allownone=True)
|
||||
"""
|
||||
Default color value in (r, g, b, a) or string format. The set color value
|
||||
will be used when you open the dialog.
|
||||
|
||||
:attr:`default_color` is an :class:`~kivy.properties.ColorProperty`
|
||||
and defaults to `None`.
|
||||
"""
|
||||
|
||||
type_color = OptionProperty("RGB", options=["RGBA", "HEX", "RGB"])
|
||||
"""
|
||||
Type of color.
|
||||
Available options are: `'RGBA'`, `'HEX'`, `'RGB'`.
|
||||
|
||||
:attr:`type_color` is an :class:`~kivy.properties.OptionProperty`
|
||||
and defaults to `'RGB'`.
|
||||
"""
|
||||
|
||||
background_down_button_selected_type_color = ColorProperty([1, 1, 1, 0.3])
|
||||
"""
|
||||
Button background for choosing a color type ('RGBA', 'HEX', 'HSL', 'RGB')
|
||||
in (r, g, b, a) or string format.
|
||||
|
||||
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/color-picker-background-down-button-selected-type-color.png
|
||||
:align: center
|
||||
|
||||
:attr:`background_down_button_selected_type_color` is an
|
||||
:class:`~kivy.properties.ColorProperty` and defaults to `[1, 1, 1, 0.3]`.
|
||||
"""
|
||||
|
||||
radius_color_scale = VariableListProperty([8])
|
||||
"""
|
||||
The radius value for the color scale.
|
||||
|
||||
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/color-picker-gradient-scale-radius.png
|
||||
:align: center
|
||||
|
||||
:attr:`radius` is an :class:`~kivy.properties.VariableListProperty`
|
||||
and defaults to `[8, 8, 8, 8]`.
|
||||
"""
|
||||
|
||||
text_button_ok = StringProperty("SELECT")
|
||||
"""
|
||||
Color selection button text.
|
||||
|
||||
:attr:`text_button_ok` is an :class:`~kivy.properties.StringProperty`
|
||||
and defaults to `'SELECT'`.
|
||||
"""
|
||||
|
||||
text_button_cancel = StringProperty("CANCEL")
|
||||
"""
|
||||
Cancel button text.
|
||||
|
||||
:attr:`text_button_cancel` is an :class:`~kivy.properties.StringProperty`
|
||||
and defaults to `'CANCEL'`.
|
||||
"""
|
||||
|
||||
selected_color = None
|
||||
# One of the objects of classes:
|
||||
# :class:`~GradientTab`, :class:`~ColorListTab`, :class:`~SliderTab`.
|
||||
_current_tab = ObjectProperty()
|
||||
# The `RGB` value for the transparency preview widget of the selected
|
||||
# color.
|
||||
_rgb = ListProperty()
|
||||
# The opacity value for the transparency preview widget of the selected
|
||||
# color.
|
||||
_opacity_value_selected_color = NumericProperty(1)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.gradient_tab = None
|
||||
self.register_event_type("on_select_color")
|
||||
self.register_event_type("on_switch_tabs")
|
||||
self.register_event_type("on_release")
|
||||
self.on_background_down_button_selected_type_color(
|
||||
None, self.background_down_button_selected_type_color
|
||||
)
|
||||
|
||||
self.on_background_down_button_selected_type_color(
|
||||
None, self.background_down_button_selected_type_color
|
||||
)
|
||||
Clock.schedule_once(lambda x: self.on_type_color(self), 1)
|
||||
|
||||
def update_color_slider_item_bottom_navigation(self, color: list) -> None:
|
||||
"""
|
||||
Updates the color of the slider that sets the transparency value of the
|
||||
selected color and the color of bottom navigation items.
|
||||
"""
|
||||
|
||||
if "select_alpha_channel_widget" in self._current_tab.ids:
|
||||
self._current_tab.ids.select_alpha_channel_widget.ids.slider.color = (
|
||||
color
|
||||
)
|
||||
self.ids.bottom_navigation.text_color_active = color
|
||||
|
||||
def update_color_type_buttons(self, color: list) -> None:
|
||||
"""
|
||||
Updating button colors (display buttons of type of color) to match the
|
||||
selected color.
|
||||
"""
|
||||
|
||||
for instance_toggle_button in self.ids.type_color_button_box.children:
|
||||
if instance_toggle_button.state != "down":
|
||||
instance_toggle_button.md_bg_color = color
|
||||
instance_toggle_button.background_normal = color
|
||||
|
||||
def get_rgb(self, color: list) -> list:
|
||||
"""Returns an ``RGB`` list of values from 0 to 255."""
|
||||
|
||||
return [
|
||||
int(value * 255)
|
||||
for value in (color[:-1] if len(color) == 4 else color)
|
||||
]
|
||||
|
||||
def on_background_down_button_selected_type_color(
|
||||
self, instance_color_picker, color: list
|
||||
) -> None:
|
||||
def set_background_down(interval: Union[float, int]) -> None:
|
||||
for (
|
||||
instance_toggle_button
|
||||
) in self.ids.type_color_button_box.children:
|
||||
instance_toggle_button.background_down = color
|
||||
if self.type_color == instance_toggle_button.text:
|
||||
instance_toggle_button.state = "down"
|
||||
|
||||
Clock.schedule_once(set_background_down)
|
||||
|
||||
def on_type_color(
|
||||
self,
|
||||
instance_color_picker,
|
||||
type_color: str = "",
|
||||
interval: Union[float, int] = 0,
|
||||
) -> None:
|
||||
"""Called when buttons are clicked to set the color type."""
|
||||
|
||||
if not type_color:
|
||||
type_color = self.type_color
|
||||
|
||||
if self._rgb:
|
||||
rgb = self._rgb if self._rgb[0] > 1 else self.get_rgb(self._rgb)
|
||||
opacity = self._opacity_value_selected_color
|
||||
color = ""
|
||||
|
||||
if type_color == "RGB":
|
||||
self.selected_color = [value for value in rgb]
|
||||
color = f"RGB({', '.join([str(value) for value in self.selected_color])})"
|
||||
elif type_color == "RGBA":
|
||||
self.selected_color = [x / 255.0 for x in rgb] + [opacity]
|
||||
color = f"RGBA({', '.join([str(x / 255.0) for x in rgb])}, {opacity})"
|
||||
elif type_color == "HEX":
|
||||
self.selected_color = get_hex_from_color(
|
||||
[x / 255.0 for x in rgb] + [opacity]
|
||||
)
|
||||
color = f"HEX({self.selected_color})"
|
||||
|
||||
self.ids.lbl_color_value.text = color
|
||||
|
||||
def on_open(self) -> None:
|
||||
"""Default open event handler."""
|
||||
|
||||
if not self.ids.bottom_navigation_gradient.children:
|
||||
self.gradient_tab = GradientTab(color_picker=self)
|
||||
self._current_tab = self.gradient_tab
|
||||
self.ids.bottom_navigation_gradient.add_widget(self.gradient_tab)
|
||||
|
||||
super().on_open()
|
||||
|
||||
def on_select_color(self, color: list) -> None:
|
||||
"""Called when a gradient image is clicked."""
|
||||
|
||||
if len(color) == 3:
|
||||
color += [self._opacity_value_selected_color]
|
||||
|
||||
self.ids.header.md_bg_color = color
|
||||
self._rgb = color[:-1]
|
||||
self.on_type_color(self, self.type_color)
|
||||
self.update_color_type_buttons(color)
|
||||
self.update_color_slider_item_bottom_navigation(color)
|
||||
|
||||
def on_switch_tabs(
|
||||
self,
|
||||
bottom_navigation_instance,
|
||||
bottom_navigation_item_instance,
|
||||
name_tab,
|
||||
) -> None:
|
||||
"""Called when switching tabs of bottom navigation."""
|
||||
|
||||
if name_tab == "bottom navigation gradient":
|
||||
self._current_tab = self.gradient_tab
|
||||
bottom_navigation_item_instance.children[0].updated_canvas(
|
||||
None,
|
||||
None,
|
||||
self._rgb if self._rgb[0] > 1 else self.get_rgb(self._rgb),
|
||||
)
|
||||
instance_slider_tab = (
|
||||
bottom_navigation_instance.ids.tab_manager.get_screen(
|
||||
"tune"
|
||||
).children[0]
|
||||
)
|
||||
select_alpha_channel_widget = (
|
||||
self.gradient_tab.ids.select_alpha_channel_widget
|
||||
)
|
||||
select_alpha_channel_widget.ids.slider.value = (
|
||||
instance_slider_tab.ids.select_alpha_channel_widget.ids.slider.value
|
||||
)
|
||||
select_alpha_channel_widget.ids.slider.color = [
|
||||
x / 255.0 for x in self._rgb
|
||||
] + [1]
|
||||
elif name_tab == "tune":
|
||||
if self._rgb[0] <= 1:
|
||||
color = self.get_rgb(self._rgb)
|
||||
else:
|
||||
color = self._rgb
|
||||
instance_slider_tab = self.ids.tune.children[0]
|
||||
self._current_tab = instance_slider_tab
|
||||
instance_slider_tab.ids.slider_red.ids.slider.value = color[0]
|
||||
instance_slider_tab.ids.slider_green.ids.slider.value = color[1]
|
||||
instance_slider_tab.ids.slider_blue.ids.slider.value = color[2]
|
||||
instance_slider_tab.ids.select_alpha_channel_widget.ids.slider.value = (
|
||||
self._opacity_value_selected_color
|
||||
)
|
||||
elif name_tab == "view headline":
|
||||
color = self._rgb + [1]
|
||||
color_list_tabs = self.ids.view_headline.children[0]
|
||||
self._current_tab = color_list_tabs
|
||||
try:
|
||||
color_list_tabs.background_color = color
|
||||
except ValueError:
|
||||
color_list_tabs.background_color = [x / 255.0 for x in color][
|
||||
:-1
|
||||
] + [1]
|
||||
if not color_list_tabs.get_tab_list():
|
||||
for color in _colors.keys():
|
||||
tab_widget = TabColorList(title=str(color))
|
||||
color_list_tabs.add_widget(tab_widget)
|
||||
|
||||
def on_release(self, *args):
|
||||
"""Called when the `SELECT` button is pressed"""
|
||||
|
||||
def _get_selected_color(self, selected_color: Union[list, str]) -> list:
|
||||
"""
|
||||
Convert [0-255, 0-255, 0-255] and '#rrggbb' to kivy color format.
|
||||
Return kivy color format.
|
||||
"""
|
||||
|
||||
rgba = [0, 0, 0, 0]
|
||||
if isinstance(selected_color, list):
|
||||
if selected_color[0] > 1:
|
||||
rgba = [x / 255.0 for x in selected_color] + [
|
||||
self._opacity_value_selected_color
|
||||
]
|
||||
else:
|
||||
rgba = selected_color
|
||||
elif isinstance(selected_color, str):
|
||||
rgba = get_color_from_hex(selected_color)[:-1] + [
|
||||
self._opacity_value_selected_color
|
||||
]
|
||||
return rgba
|
|
@ -1,5 +1,5 @@
|
|||
from .datepicker import ( # NOQA F401
|
||||
BaseDialogPicker,
|
||||
DatePickerInputField,
|
||||
MDDatePicker,
|
||||
MDDockedDatePicker,
|
||||
MDModalDatePicker,
|
||||
MDModalInputDatePicker,
|
||||
)
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -1,392 +1,448 @@
|
|||
#:import os os
|
||||
#:import date datetime.date
|
||||
#:import calendar calendar
|
||||
#:import platform platform
|
||||
#:import Clock kivy.clock.Clock
|
||||
#:import images_path kivymd.images_path
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# MODAL INPUT RULES
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
<MDModalInputDatePickerInputField>
|
||||
mode: "outlined"
|
||||
validator: "date"
|
||||
|
||||
|
||||
<DatePickerBaseTooltip>
|
||||
on_enter:
|
||||
self.tooltip_text = "" if self.owner \
|
||||
and self.owner._input_date_dialog_open \
|
||||
or self.owner._select_year_dialog_open \
|
||||
else self.hint_text
|
||||
|
||||
|
||||
<DatePickerIconTooltipButton>
|
||||
|
||||
|
||||
<MDDatePicker>
|
||||
_calendar_layout: _calendar_layout
|
||||
<MDModalInputDatePicker>
|
||||
orientation: "vertical"
|
||||
padding: 0, dp(16), 0, dp(16)
|
||||
size_hint: None, None
|
||||
size:
|
||||
(dp(328), dp(512) - root._shift_dialog_height) \
|
||||
if root.theme_cls.device_orientation == "portrait" \
|
||||
else (dp(528), dp(328) - root._shift_dialog_height)
|
||||
size: dp(328), dp(280)
|
||||
pos_hint: {"center_x": .5, "center_y": .5}
|
||||
|
||||
MDRelativeLayout:
|
||||
id: container
|
||||
background: os.path.join(images_path, "transparent.png")
|
||||
MDLabel:
|
||||
id: supporting_label
|
||||
adaptive_size: True
|
||||
text: root.supporting_text
|
||||
padding: dp(16), 0, 0, dp(36)
|
||||
font_style: "Label"
|
||||
role: "large"
|
||||
|
||||
canvas:
|
||||
Color:
|
||||
rgb: root.primary_color or app.theme_cls.primary_color
|
||||
RoundedRectangle:
|
||||
size:
|
||||
(dp(328), dp(120)) \
|
||||
if root.theme_cls.device_orientation == "portrait" \
|
||||
else (dp(168), dp(328) - root._shift_dialog_height)
|
||||
pos:
|
||||
(0, root.height - dp(120)) \
|
||||
if root.theme_cls.device_orientation == "portrait" \
|
||||
else (0, 0)
|
||||
radius:
|
||||
(root.radius[0], root.radius[1], dp(0), dp(0)) \
|
||||
if root.theme_cls.device_orientation == "portrait" \
|
||||
else (root.radius[0], dp(0), dp(0), root.radius[3])
|
||||
Color:
|
||||
rgba: root.accent_color or app.theme_cls.bg_normal
|
||||
RoundedRectangle:
|
||||
size:
|
||||
(dp(328), dp(512) - dp(120) - root._shift_dialog_height) \
|
||||
if root.theme_cls.device_orientation == "portrait" \
|
||||
else (dp(360), dp(328) - root._shift_dialog_height)
|
||||
pos:
|
||||
(0, 0) \
|
||||
if root.theme_cls.device_orientation == "portrait" \
|
||||
else (dp(168), 0)
|
||||
radius:
|
||||
(dp(0), dp(0), root.radius[2], root.radius[3]) \
|
||||
if root.theme_cls.device_orientation == "portrait" \
|
||||
else (dp(0), root.radius[1], root.radius[2], dp(0))
|
||||
BoxLayout:
|
||||
size_hint_y: None
|
||||
height: self.minimum_height
|
||||
padding: dp(16), 0, dp(8), dp(16)
|
||||
|
||||
MDLabel:
|
||||
id: label_title
|
||||
font_style: "Body2"
|
||||
bold: True
|
||||
theme_text_color: "Custom"
|
||||
size_hint_x: None
|
||||
width: root.width
|
||||
adaptive_height: True
|
||||
text: root.title
|
||||
font_name: root.font_name
|
||||
pos:
|
||||
(dp(24), root.height - self.height - dp(18)) \
|
||||
if root.theme_cls.device_orientation == "portrait" \
|
||||
else (dp(24), root.height - self.height - dp(24))
|
||||
text_color: root.text_toolbar_color or root.specific_text_color
|
||||
id: current_month_name
|
||||
adaptive_size: True
|
||||
text: root._current_month_name
|
||||
text_color: self.theme_cls.onSurfaceVariantColor
|
||||
font_style: "Headline"
|
||||
role: "large"
|
||||
theme_line_height: "Custom"
|
||||
line_height: 1
|
||||
theme_font_size: "Custom"
|
||||
font_size: "32sp" if root.mode == "picker" else "20sp"
|
||||
pos_hint: {"center_y": .5}
|
||||
|
||||
MDLabel:
|
||||
id: label_full_date
|
||||
font_style: "H4"
|
||||
theme_text_color: "Custom"
|
||||
size_hint_x: None
|
||||
width: root.width
|
||||
adaptive_height: True
|
||||
font_name: root.font_name
|
||||
markup: True
|
||||
pos:
|
||||
(dp(24), root.height - dp(120) + dp(18)) \
|
||||
if root.theme_cls.device_orientation == "portrait" \
|
||||
else \
|
||||
( \
|
||||
dp(24) if not root._input_date_dialog_open else dp(168) + dp(24), \
|
||||
root.height - self.height - dp(96) \
|
||||
)
|
||||
text: root._date_label_text
|
||||
text_color:
|
||||
root.text_toolbar_color or root.specific_text_color \
|
||||
if root.theme_cls.device_orientation == "portrait" else \
|
||||
root.primary_color or self.theme_cls.primary_color \
|
||||
if root._input_date_dialog_open else \
|
||||
root.text_toolbar_color or root.specific_text_color
|
||||
|
||||
RecycleView:
|
||||
id: _year_layout
|
||||
key_viewclass: "viewclass"
|
||||
size_hint: None, None
|
||||
size: _calendar_layout.size
|
||||
pos: _calendar_layout.pos
|
||||
disabled: True
|
||||
|
||||
canvas.before:
|
||||
PushMatrix
|
||||
Scale:
|
||||
x: root._scale_year_layout
|
||||
y: root._scale_year_layout
|
||||
origin: self.center
|
||||
canvas.after:
|
||||
PopMatrix
|
||||
|
||||
SelectYearList:
|
||||
cols: 3
|
||||
default_size: dp(170), dp(36)
|
||||
default_size_hint: 1, None
|
||||
size_hint_y: None
|
||||
height: self.minimum_height
|
||||
Widget:
|
||||
|
||||
MDIconButton:
|
||||
id: edit_icon
|
||||
icon: "pencil"
|
||||
icon_size: "24sp"
|
||||
theme_icon_color: "Custom"
|
||||
on_release:
|
||||
root.transformation_to_dialog_input_date() \
|
||||
if not root._input_date_dialog_open else \
|
||||
Clock.schedule_once(root.transformation_from_dialog_input_date, .15)
|
||||
x:
|
||||
(root.width - self.width - dp(12)) \
|
||||
if root.theme_cls.device_orientation == "portrait" \
|
||||
else dp(12)
|
||||
y:
|
||||
(root.height - dp(120) + dp(12)) \
|
||||
if root.theme_cls.device_orientation == "portrait" \
|
||||
else dp(12)
|
||||
text_color: root.text_toolbar_color or root.specific_text_color
|
||||
id: icon_button
|
||||
icon: "calendar"
|
||||
on_release: root.dispatch("on_edit")
|
||||
|
||||
MDDivider:
|
||||
|
||||
MDModalInputDatePickerInputDateFieldContainer
|
||||
id: input_date_container
|
||||
padding: dp(16), 0, dp(16), dp(24)
|
||||
|
||||
MDModalInputDatePickerInputField:
|
||||
id: input_date_field
|
||||
date_picker: root
|
||||
date_format: root.date_format
|
||||
|
||||
MDTextFieldHintText:
|
||||
text: root.date_format
|
||||
|
||||
MDTextFieldHelperText:
|
||||
text: root.error_text
|
||||
mode: "on_error"
|
||||
|
||||
MDDatePickerButtonsContainer:
|
||||
date_picker: root
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# MODAL RULES
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
<MDModalDatePickerYearSelectableItem>
|
||||
size_hint_x: None
|
||||
valign: "middle"
|
||||
halign: "center"
|
||||
text_color:
|
||||
self.theme_cls.onSurfaceColor \
|
||||
if not root.selected else \
|
||||
self.theme_cls.onPrimaryColor
|
||||
|
||||
canvas.before:
|
||||
Color:
|
||||
rgba:
|
||||
self.theme_cls.primaryColor \
|
||||
if self.selected else \
|
||||
self.theme_cls.transparentColor
|
||||
RoundedRectangle:
|
||||
pos: self.x + dp(12), self.y + dp(6)
|
||||
size: self.width - dp(24), self.height - dp(8)
|
||||
radius: [(root.height / 2) - dp(4), ]
|
||||
|
||||
|
||||
<MDModalDatePickerMenuYearSelection>
|
||||
scale_value_x: 1.5
|
||||
scale_value_y: 1.5
|
||||
key_viewclass: "viewclass"
|
||||
key_size: "height"
|
||||
bar_width: 0
|
||||
|
||||
MDModalDatePickerContainerMenuYearSelection:
|
||||
cols: 3
|
||||
padding: dp(32), 0, 0, 0
|
||||
default_size: None, dp(48)
|
||||
default_size_hint: 1, None
|
||||
size_hint_y: None
|
||||
height: self.minimum_height
|
||||
multiselect: False
|
||||
touch_multiselect: True
|
||||
|
||||
|
||||
<MDModalDatePickerScrim>
|
||||
canvas:
|
||||
Color:
|
||||
rgba: self.color[:-1] + [self.alpha]
|
||||
Rectangle:
|
||||
pos: self.pos
|
||||
size: self.size
|
||||
|
||||
|
||||
<MDModalDatePickerYearSelectionItem>
|
||||
size_hint_y: None
|
||||
height: dp(48)
|
||||
|
||||
MDLabel:
|
||||
id: label
|
||||
adaptive_size: True
|
||||
text: root.text
|
||||
pos_hint: {"center_y": .5}
|
||||
padding: 0, 0, "8dp", 0
|
||||
font_style: "Label"
|
||||
role: "large"
|
||||
|
||||
MDDatePickerBaseMenuSelectionButton
|
||||
id: menu_selection_button
|
||||
pos_hint: {"center_y": .5}
|
||||
icon: "menu-right"
|
||||
date_picker: root.date_picker
|
||||
on_release: root.dispatch("on_open_menu")
|
||||
|
||||
Widget:
|
||||
|
||||
MDIconButton:
|
||||
id: chevron_left
|
||||
icon: "chevron-left"
|
||||
pos_hint: {"center_y": .5}
|
||||
on_release: root.dispatch("on_release", "prev")
|
||||
|
||||
MDIconButton:
|
||||
id: chevron_right
|
||||
icon: "chevron-right"
|
||||
pos_hint: {"center_y": .5}
|
||||
on_release: root.dispatch("on_release", "next")
|
||||
|
||||
|
||||
<MDModalDatePicker>
|
||||
calendar_layout: calendar_layout
|
||||
orientation: "vertical"
|
||||
padding: 0, 0, 0, "12dp"
|
||||
pos_hint: {'center_x': .5, 'center_y': .5}
|
||||
size_hint: None, None
|
||||
size: calendar_layout.width - self.padding[0] / 2, dp(520)
|
||||
|
||||
MDLabel:
|
||||
id: supporting_label
|
||||
adaptive_size: True
|
||||
text: root.supporting_text
|
||||
padding: dp(24), 0, 0, dp(36)
|
||||
font_style: "Label"
|
||||
role: "large"
|
||||
|
||||
BoxLayout:
|
||||
size_hint_y: None
|
||||
height: self.minimum_height
|
||||
padding: dp(24), 0, dp(12), dp(16)
|
||||
|
||||
MDLabel:
|
||||
id: label_month_selector
|
||||
font_style: "Body2"
|
||||
-text_size: None, None
|
||||
theme_text_color: "Custom"
|
||||
id: current_month_name
|
||||
adaptive_size: True
|
||||
text: calendar.month_name[root.month].capitalize() + " " + str(root.year)
|
||||
font_name: root.font_name
|
||||
pos:
|
||||
(dp(24), root.height - dp(120) - self.height - dp(20)) \
|
||||
if root.theme_cls.device_orientation == "portrait" \
|
||||
else (dp(168) + dp(24), label_title.y)
|
||||
text_color: root.text_color or app.theme_cls.text_color
|
||||
text: root._current_month_name
|
||||
text_color: self.theme_cls.onSurfaceVariantColor
|
||||
font_style: "Headline"
|
||||
role: "large"
|
||||
|
||||
DatePickerIconTooltipButton:
|
||||
id: triangle
|
||||
owner: root
|
||||
icon: "menu-down"
|
||||
ripple_scale: .5
|
||||
theme_icon_color: "Custom"
|
||||
hint_text: "Choose year"
|
||||
on_release:
|
||||
root.transformation_to_dialog_select_year() \
|
||||
if not root._select_year_dialog_open else \
|
||||
root.transformation_from_dialog_select_year()
|
||||
pos:
|
||||
(label_month_selector.width + dp(14), root.height - dp(123) - self.height) \
|
||||
if root.theme_cls.device_orientation == "portrait" \
|
||||
else (dp(180) + label_month_selector.width, label_title.y - dp(14))
|
||||
text_color: root.text_color or app.theme_cls.text_color
|
||||
md_bg_color_disabled: 0, 0, 0, 0
|
||||
Widget:
|
||||
|
||||
DatePickerIconTooltipButton:
|
||||
id: chevron_left
|
||||
owner: root
|
||||
icon: "chevron-left"
|
||||
on_release: root.change_month("prev")
|
||||
theme_icon_color: "Custom"
|
||||
hint_text: "Previous month"
|
||||
x:
|
||||
dp(228) if root.theme_cls.device_orientation == "portrait" \
|
||||
else dp(418)
|
||||
y:
|
||||
root.height - dp(120) - self.height / 2 - dp(30) \
|
||||
if root.theme_cls.device_orientation == "portrait" \
|
||||
else dp(272)
|
||||
text_color: root.text_color or app.theme_cls.text_color
|
||||
MDIconButton:
|
||||
id: icon_button
|
||||
icon: "pencil"
|
||||
on_release: root.dispatch("on_edit")
|
||||
|
||||
DatePickerIconTooltipButton:
|
||||
id: chevron_right
|
||||
owner: root
|
||||
icon: "chevron-right"
|
||||
on_release: root.change_month("next")
|
||||
theme_icon_color: "Custom"
|
||||
hint_text: "Next month"
|
||||
x:
|
||||
dp(272) if root.theme_cls.device_orientation == "portrait" \
|
||||
else dp(464)
|
||||
y:
|
||||
root.height - dp(120) - self.height / 2 - dp(30) \
|
||||
if root.theme_cls.device_orientation == "portrait" \
|
||||
else dp(272)
|
||||
text_color: root.text_color or app.theme_cls.text_color
|
||||
MDDivider:
|
||||
|
||||
# TODO: Replace the GridLayout with a RecycleView
|
||||
# if it improves performance.
|
||||
GridLayout:
|
||||
id: _calendar_layout
|
||||
cols: 7
|
||||
MDModalDatePickerYearSelectionItem:
|
||||
id: year_selection_items
|
||||
text: root._current_full_month_name
|
||||
date_picker: root
|
||||
padding: dp(24), 0, dp(12), 0
|
||||
|
||||
RelativeLayout:
|
||||
size_hint: None, None
|
||||
size: calendar_layout.size
|
||||
|
||||
MDCalendarLayout:
|
||||
id: calendar_layout
|
||||
padding: dp(12), 0, dp(12), 0
|
||||
|
||||
MDModalDatePickerMenuYearSelection
|
||||
id: year_selection_layout
|
||||
size_hint: None, None
|
||||
size:
|
||||
(dp(44 * 7), dp(40 * 7)) \
|
||||
if root.theme_cls.device_orientation == "portrait" \
|
||||
else (dp(46 * 7), dp(32 * 7))
|
||||
col_default_width:
|
||||
dp(42) if root.theme_cls.device_orientation == "portrait" \
|
||||
else dp(39)
|
||||
padding:
|
||||
(dp(2), 0) if root.theme_cls.device_orientation == "portrait" \
|
||||
else (dp(7), 0)
|
||||
spacing:
|
||||
(dp(2), 0) if root.theme_cls.device_orientation == "portrait" \
|
||||
else (dp(7), 0)
|
||||
pos:
|
||||
(dp(10), dp(56)) \
|
||||
if root.theme_cls.device_orientation == "portrait" \
|
||||
else (dp(168) + dp(20), dp(44))
|
||||
size: 0, 0
|
||||
|
||||
canvas.before:
|
||||
PushMatrix
|
||||
Scale:
|
||||
x: root._scale_calendar_layout
|
||||
y: root._scale_calendar_layout
|
||||
origin: self.center
|
||||
canvas.after:
|
||||
PopMatrix
|
||||
MDDatePickerButtonsContainer:
|
||||
date_picker: root
|
||||
|
||||
MDFlatButton:
|
||||
id: ok_button
|
||||
width: dp(32)
|
||||
pos: root.width - self.width, dp(10)
|
||||
text: "OK"
|
||||
theme_text_color: "Custom"
|
||||
font_name: root.font_name
|
||||
text_color: root.text_button_color or root.theme_cls.primary_color
|
||||
on_release: root.on_ok_button_pressed()
|
||||
###############################################################################
|
||||
#
|
||||
# DOCKED RULES
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
MDFlatButton:
|
||||
id: cancel_button
|
||||
text: "CANCEL"
|
||||
on_release: root.dispatch("on_cancel", None)
|
||||
theme_text_color: "Custom"
|
||||
pos: root.width - self.width - ok_button.width - dp(10), dp(10)
|
||||
font_name: root.font_name
|
||||
text_color: root.text_button_color or root.theme_cls.primary_color
|
||||
|
||||
|
||||
<DatePickerDaySelectableItem>
|
||||
<MDDockedDatePicker>
|
||||
calendar_layout: calendar_layout
|
||||
size_hint: None, None
|
||||
size:
|
||||
(dp(42), dp(42)) \
|
||||
if root.theme_cls.device_orientation == "portrait" \
|
||||
else (dp(32), dp(32))
|
||||
disabled: True
|
||||
size: calendar_layout.width - self.padding[0] / 2, dp(406)
|
||||
orientation: "vertical"
|
||||
padding: "12dp", 0, "12dp", "12dp"
|
||||
|
||||
BoxLayout:
|
||||
id: month_year_selection_items_container
|
||||
size_hint_y: None
|
||||
height: self.minimum_height
|
||||
padding: 0, 0, 0, "12dp"
|
||||
|
||||
MDDockedDatePickerMonthSelectionItem:
|
||||
id: month_selection_items
|
||||
text: root._current_month_name
|
||||
date_picker: root
|
||||
|
||||
Widget:
|
||||
|
||||
MDDockedDatePickerYearSelectionItem:
|
||||
id: year_selection_items
|
||||
text: str(root.year)
|
||||
date_picker: root
|
||||
|
||||
RelativeLayout:
|
||||
size_hint: None, None
|
||||
size: calendar_layout.size
|
||||
|
||||
MDCalendarLayout:
|
||||
id: calendar_layout
|
||||
|
||||
MDDockedDatePickerMenuMonthYearSelection
|
||||
id: month_year_selection_layout
|
||||
size_hint: None, None
|
||||
size: 0, 0
|
||||
|
||||
MDDatePickerButtonsContainer:
|
||||
id: button_container
|
||||
date_picker: root
|
||||
|
||||
|
||||
<MDDockedDatePickerMenuMonthYearSelection>
|
||||
scale_value_x: 0
|
||||
scale_value_y: 0
|
||||
key_viewclass: "viewclass"
|
||||
key_size: "height"
|
||||
bar_width: 0
|
||||
|
||||
MDDockedDatePickerContainerMenuMonthYearSelection:
|
||||
padding: dp(8), 0, 0, 0
|
||||
default_size: None, dp(48)
|
||||
default_size_hint: 1, None
|
||||
size_hint_y: None
|
||||
height: self.minimum_height
|
||||
orientation: "vertical"
|
||||
multiselect: False
|
||||
touch_multiselect: True
|
||||
|
||||
|
||||
<MDDockedDatePickerMenuSelectionItem>
|
||||
spacing: "8dp"
|
||||
size_hint_y: None
|
||||
|
||||
MDIcon:
|
||||
icon: "check"
|
||||
pos_hint: {"center_y": .5}
|
||||
icon_color:
|
||||
self.theme_cls.transparentColor \
|
||||
if not root.selected else \
|
||||
self.theme_cls.onSurfaceColor
|
||||
|
||||
MDLabel:
|
||||
text: root.month_year_name
|
||||
|
||||
|
||||
<MDDockedDatePickerBaseSelectionContainer>
|
||||
size_hint: None, None
|
||||
size: self.minimum_size
|
||||
|
||||
MDIconButton:
|
||||
id: chevron_left
|
||||
icon: "chevron-left"
|
||||
on_release: root.dispatch("on_release", "prev")
|
||||
|
||||
MDLabel:
|
||||
id: label
|
||||
adaptive_size: True
|
||||
text: root.text
|
||||
pos_hint: {"center_y": .5}
|
||||
padding: 0, 0, "8dp", 0
|
||||
font_style: "Label"
|
||||
role: "large"
|
||||
|
||||
MDDatePickerBaseMenuSelectionButton
|
||||
id: menu_selection_button
|
||||
pos_hint: {"center_y": .5}
|
||||
icon: "menu-right"
|
||||
date_picker: root.date_picker
|
||||
on_release: root.dispatch("on_open_menu")
|
||||
|
||||
MDIconButton:
|
||||
id: chevron_right
|
||||
icon: "chevron-right"
|
||||
on_release: root.dispatch("on_release", "next")
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# COMMON RULES
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
<MDBaseDatePicker>
|
||||
elevation_level: 0
|
||||
shadow_color: self.theme_cls.transparentColor
|
||||
|
||||
canvas.before:
|
||||
Color:
|
||||
rgba:
|
||||
self.theme_cls.surfaceContainerHighColor
|
||||
RoundedRectangle:
|
||||
size: self.size
|
||||
pos: self.pos
|
||||
radius: self.radius
|
||||
|
||||
|
||||
<MDCalendarLayout>
|
||||
cols: 7
|
||||
size_hint: None, None
|
||||
width: dp(46 * 7)
|
||||
height: self.minimum_height
|
||||
|
||||
|
||||
<MDDatePickerButtonsContainer>
|
||||
size_hint_y: None
|
||||
height: self.minimum_height
|
||||
padding: 0, 0, dp(12), 0
|
||||
|
||||
Widget:
|
||||
|
||||
MDButton:
|
||||
style: "text"
|
||||
on_release: root.date_picker.dispatch("on_cancel")
|
||||
|
||||
MDButtonText:
|
||||
text:
|
||||
root.date_picker.text_button_cancel \
|
||||
if root.date_picker else \
|
||||
""
|
||||
|
||||
MDButton:
|
||||
style: "text"
|
||||
on_release: root.date_picker.dispatch("on_ok")
|
||||
|
||||
MDButtonText:
|
||||
text:
|
||||
root.date_picker.text_button_ok \
|
||||
if root.date_picker else \
|
||||
""
|
||||
|
||||
|
||||
<MDDatePickerMenuButton>
|
||||
icon: "menu-right"
|
||||
|
||||
|
||||
<MDDatePickerWeekdayLabel>
|
||||
size_hint: None, None
|
||||
text_size: self.size
|
||||
halign: "center"
|
||||
valign: "middle"
|
||||
size: dp(40), dp(40)
|
||||
|
||||
|
||||
<MDDatePickerDaySelectableItem>
|
||||
size_hint: None, None
|
||||
size: dp(42), dp(42)
|
||||
halign: "center"
|
||||
radius: self.height / 2
|
||||
line_color:
|
||||
self.theme_cls.primaryColor \
|
||||
if self.is_today and self.date_picker.mark_today else \
|
||||
self.theme_cls.transparentColor
|
||||
text_color:
|
||||
self.theme_cls.onSurfaceColor \
|
||||
if not root.is_selected else \
|
||||
self.theme_cls.onPrimaryColor
|
||||
|
||||
# Fill marking the available dates of the range, if using the `range` mode
|
||||
# or use `min_date/max_date`.
|
||||
canvas.before:
|
||||
Color:
|
||||
rgba:
|
||||
(self.owner.selector_color or self.theme_cls.primary_color)[:-1] + [.3] \
|
||||
self.theme_cls.primaryColor[:-1] + [.3] \
|
||||
if self.is_in_range \
|
||||
else (0, 0, 0, 0)
|
||||
else \
|
||||
self.theme_cls.transparentColor
|
||||
RoundedRectangle:
|
||||
size:
|
||||
(dp(44), dp(32)) \
|
||||
if root.theme_cls.device_orientation == "portrait" \
|
||||
else \
|
||||
(dp(32), dp(28)) \
|
||||
(dp(42), dp(32)) \
|
||||
if self.is_range_end or self.is_week_end or self.is_month_end \
|
||||
else (dp(46), dp(28))
|
||||
pos:
|
||||
(self.x - dp(1.5), self.y + dp(5)) \
|
||||
if root.theme_cls.device_orientation == "portrait" else \
|
||||
(self.x, self.y + 1)
|
||||
else (dp(42), dp(32))
|
||||
pos: self.x, self.y + dp(6)
|
||||
radius:
|
||||
[
|
||||
self.width / 2 if self.is_range_start else 0,
|
||||
self.width / 2 if self.is_range_end else 0,
|
||||
self.width / 2 if self.is_range_end else 0,
|
||||
self.width / 2 if self.is_range_start else 0,
|
||||
dp(32) / 2 if self.is_range_start else 0,
|
||||
dp(32) / 2 if self.is_range_end else 0,
|
||||
dp(32) / 2 if self.is_range_end else 0,
|
||||
dp(32) / 2 if self.is_range_start else 0,
|
||||
]
|
||||
|
||||
# Selection circle.
|
||||
Color:
|
||||
rgba:
|
||||
root.owner.selector_color or self.theme_cls.primary_color \
|
||||
self.theme_cls.primaryColor \
|
||||
if root.is_selected and not self.disabled \
|
||||
else (0, 0, 0, 0)
|
||||
else self.theme_cls.transparentColor
|
||||
Ellipse:
|
||||
size:
|
||||
(dp(42), dp(42)) \
|
||||
if root.theme_cls.device_orientation == "portrait" \
|
||||
else (dp(32), dp(32))
|
||||
size: dp(42), dp(42)
|
||||
pos: self.pos
|
||||
|
||||
MDLabel:
|
||||
font_style: "Caption"
|
||||
size_hint_x: None
|
||||
halign: "center"
|
||||
text: root.text
|
||||
font_name: root.owner.font_name
|
||||
theme_text_color: "Custom"
|
||||
text_color:
|
||||
root.owner.accent_color or root.theme_cls.bg_normal \
|
||||
if root.is_selected else \
|
||||
root.owner.text_current_color or root.theme_cls.primary_color \
|
||||
if root.is_today else \
|
||||
root.owner.text_color or root.theme_cls.text_color
|
||||
|
||||
<DatePickerWeekdayLabel>
|
||||
font_style: "Caption"
|
||||
theme_text_color: "Custom"
|
||||
size_hint: None, None
|
||||
text_size: self.size
|
||||
halign: "center"
|
||||
valign:
|
||||
"middle" if root.theme_cls.device_orientation == "portrait" \
|
||||
else "center"
|
||||
size:
|
||||
(dp(40), dp(40)) if root.theme_cls.device_orientation == "portrait" \
|
||||
else (dp(32), dp(32))
|
||||
text_color: root.owner.text_weekday_color or app.theme_cls.disabled_hint_text_color
|
||||
|
||||
|
||||
<DatePickerYearSelectableItem>
|
||||
font_style: "Caption"
|
||||
size_hint_x: None
|
||||
valign: "middle"
|
||||
halign: "center"
|
||||
text: root.text
|
||||
theme_text_color: "Custom"
|
||||
text_color:
|
||||
(0, 0, 0, 0) \
|
||||
if self.owner is None else \
|
||||
self.owner.accent_color or self.owner.theme_cls.bg_normal \
|
||||
if self.selected else \
|
||||
self.owner.text_color or self.owner.theme_cls.text_color
|
||||
on_text: root.font_name = root.owner.font_name
|
||||
|
||||
canvas.before:
|
||||
Color:
|
||||
rgba:
|
||||
self.owner.selector_color or self.theme_cls.primary_color \
|
||||
if self.selected else \
|
||||
(0, 0, 0, 0)
|
||||
RoundedRectangle:
|
||||
pos: self.x + dp(12), self.y
|
||||
size: self.width - dp(24), self.height
|
||||
radius: [root.height / 2, ]
|
||||
|
||||
|
||||
<DatePickerInputFieldContainer>
|
||||
adaptive_height: True
|
||||
size_hint_x: None
|
||||
spacing: dp(8)
|
||||
opacity: 0
|
||||
width:
|
||||
self.owner.width - dp(48) \
|
||||
if root.owner.theme_cls.device_orientation == "portrait" \
|
||||
else self.owner.width - dp(168) - dp(48)
|
||||
y:
|
||||
self.owner.height - dp(123) - self.height - dp(20) \
|
||||
if root.owner.theme_cls.device_orientation == "portrait" \
|
||||
else self.owner.height - self.height - dp(24)
|
||||
x:
|
||||
dp(24) if root.owner.theme_cls.device_orientation == "portrait" \
|
||||
else dp(168) + dp(24)
|
||||
|
||||
|
||||
<DatePickerInputField>
|
||||
mode: "fill"
|
||||
hint_text: "dd/mm/yyyy"
|
||||
input_filter: root.input_filter
|
||||
fill_color: root.owner.input_field_background_color or (0, 0, 0, .15)
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1 +1,5 @@
|
|||
from .timepicker import MDTimePicker # NOQA F401
|
||||
from .timepicker import (
|
||||
MDTimePickerDialVertical,
|
||||
MDTimePickerDialHorizontal,
|
||||
MDTimePickerInput,
|
||||
) # NOQA F401
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -1,132 +1,275 @@
|
|||
<TimeInputLabel@MDLabel>:
|
||||
theme_text_color: "Custom"
|
||||
font_size: dp(10)
|
||||
halign: "left"
|
||||
valign: "bottom"
|
||||
adaptive_size: True
|
||||
###############################################################################
|
||||
#
|
||||
# INPUT RULES
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
|
||||
<AmPmSelectorLabel>
|
||||
halign: "center"
|
||||
valign: "center"
|
||||
theme_text_color: "Custom"
|
||||
|
||||
|
||||
<AmPmSelector>
|
||||
<MDTimePickerInput>
|
||||
size_hint: None, None
|
||||
size: dp(328), dp(248)
|
||||
_time_input: _time_input
|
||||
# _selector: _selector
|
||||
_am_pm_selector: _am_pm_selector
|
||||
|
||||
MDLabel:
|
||||
adaptive_size: True
|
||||
text: root.headline_text
|
||||
font_style: "Label"
|
||||
role: "large"
|
||||
padding: 0, 0, 0, dp(20)
|
||||
|
||||
BoxLayout:
|
||||
size_hint_y: None
|
||||
height: self.minimum_height
|
||||
spacing: dp(20)
|
||||
|
||||
BoxLayout:
|
||||
orientation: "vertical"
|
||||
size_hint_y: None
|
||||
height: self.minimum_height
|
||||
|
||||
MDTimePickerInputContainer:
|
||||
id: _time_input
|
||||
time_picker: root
|
||||
_readonly: False
|
||||
# root._get_time_input(*self.get_time())
|
||||
|
||||
BoxLayout:
|
||||
size_hint_y: None
|
||||
height: self.minimum_height
|
||||
padding: 0, dp(8), 0, 0
|
||||
|
||||
MDLabel:
|
||||
role: "small"
|
||||
adaptive_height: True
|
||||
text: "Hour"
|
||||
|
||||
MDLabel:
|
||||
role: "small"
|
||||
adaptive_height: True
|
||||
text: "Minute"
|
||||
padding_x: dp(20)
|
||||
|
||||
BoxLayout:
|
||||
size_hint: None, None
|
||||
size: self.minimum_size
|
||||
padding: 0, 0, 0, dp(26)
|
||||
|
||||
MDTimePickerAmPmSelector:
|
||||
id: _am_pm_selector
|
||||
size_hint: None, None
|
||||
size: dp(52), dp(80)
|
||||
on_selected:
|
||||
root.dispatch("on_am_pm", self.selected)
|
||||
root._get_am_pm(self.selected)
|
||||
|
||||
MDTimePickerButtonsContainer:
|
||||
time_picker: root
|
||||
icon: "clock-outline"
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# DIAL RULES
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
<MDTimePickerDialHorizontal>
|
||||
size_hint: None, None
|
||||
size: dp(574), dp(380)
|
||||
_time_input: _time_input
|
||||
_selector: _selector
|
||||
_am_pm_selector: _am_pm_selector
|
||||
|
||||
MDLabel:
|
||||
adaptive_size: True
|
||||
text: root.headline_text
|
||||
font_style: "Label"
|
||||
role: "large"
|
||||
padding: 0, 0, 0, dp(20)
|
||||
|
||||
BoxLayout:
|
||||
spacing: dp(52)
|
||||
|
||||
BoxLayout:
|
||||
orientation: "vertical"
|
||||
spacing: dp(16)
|
||||
padding: 0, 0, 0, dp(52)
|
||||
|
||||
MDTimePickerInputContainer:
|
||||
id: _time_input
|
||||
time_picker: root
|
||||
on_minute_select: _selector.switch_mode("minute")
|
||||
on_hour_select: _selector.switch_mode("hour")
|
||||
|
||||
MDTimePickerAmPmSelector:
|
||||
id: _am_pm_selector
|
||||
orientation: "horizontal"
|
||||
size_hint: None, None
|
||||
size: _time_input.width, dp(38)
|
||||
on_selected:
|
||||
root.dispatch("on_am_pm", self.selected)
|
||||
root._get_am_pm(self.selected)
|
||||
|
||||
MDTimePickerCircularSelector:
|
||||
id: _selector
|
||||
time_picker: root
|
||||
|
||||
MDTimePickerButtonsContainer:
|
||||
time_picker: root
|
||||
|
||||
|
||||
<MDTimePickerDialVertical>
|
||||
size_hint: None, None
|
||||
size: dp(324), dp(520)
|
||||
_time_input: _time_input
|
||||
_selector: _selector
|
||||
_am_pm_selector: _am_pm_selector
|
||||
|
||||
MDLabel:
|
||||
adaptive_size: True
|
||||
text: root.headline_text
|
||||
font_style: "Label"
|
||||
role: "large"
|
||||
padding: 0, 0, 0, dp(20)
|
||||
|
||||
BoxLayout:
|
||||
size_hint_y: None
|
||||
height: self.minimum_height
|
||||
spacing: dp(20)
|
||||
|
||||
MDTimePickerInputContainer:
|
||||
id: _time_input
|
||||
time_picker: root
|
||||
on_minute_select: _selector.switch_mode("minute")
|
||||
on_hour_select: _selector.switch_mode("hour")
|
||||
|
||||
MDTimePickerAmPmSelector:
|
||||
id: _am_pm_selector
|
||||
size_hint: None, None
|
||||
size: dp(52), dp(80)
|
||||
on_selected:
|
||||
root.dispatch("on_am_pm", self.selected)
|
||||
root._get_am_pm(self.selected)
|
||||
|
||||
Widget:
|
||||
size_hint_x: None
|
||||
width: dp(20)
|
||||
|
||||
MDTimePickerCircularSelector:
|
||||
id: _selector
|
||||
time_picker: root
|
||||
|
||||
MDTimePickerButtonsContainer:
|
||||
time_picker: root
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# COMMON RULES
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
<MDBaseTimePicker>
|
||||
canvas.before:
|
||||
Color:
|
||||
rgba: root.border_color
|
||||
rgba:
|
||||
self.theme_cls.surfaceContainerHighColor
|
||||
RoundedRectangle:
|
||||
size: self.size
|
||||
pos: self.pos
|
||||
radius: self.radius
|
||||
|
||||
orientation: "vertical"
|
||||
elevation_level: 0
|
||||
shadow_color: self.theme_cls.transparentColor
|
||||
pos_hint: {'center_x': .5, 'center_y': .5}
|
||||
padding: dp(24)
|
||||
opacity: 0
|
||||
|
||||
|
||||
<MDTimePickerButtonsContainer>
|
||||
size_hint_y: None
|
||||
height: self.minimum_height
|
||||
padding: 0, dp(24), 0, 0
|
||||
|
||||
MDIconButton:
|
||||
icon: root.icon
|
||||
on_release: root.time_picker.dispatch("on_edit")
|
||||
|
||||
Widget:
|
||||
|
||||
MDButton:
|
||||
style: "text"
|
||||
on_release: root.time_picker.dispatch("on_cancel")
|
||||
|
||||
MDButtonText:
|
||||
text:
|
||||
root.time_picker.text_button_cancel \
|
||||
if root.time_picker else \
|
||||
""
|
||||
|
||||
MDButton:
|
||||
style: "text"
|
||||
on_release: root.time_picker.dispatch("on_ok")
|
||||
|
||||
MDButtonText:
|
||||
text:
|
||||
root.time_picker.text_button_ok \
|
||||
if root.time_picker else \
|
||||
""
|
||||
|
||||
<MDTimePickerScrim>
|
||||
canvas:
|
||||
Color:
|
||||
rgba: self.color[:-1] + [self.alpha]
|
||||
Rectangle:
|
||||
pos: self.pos
|
||||
size: self.size
|
||||
radius: [root.border_radius, ]
|
||||
|
||||
#AM
|
||||
|
||||
<MDTimePickerInputTextField>
|
||||
canvas.after:
|
||||
Color:
|
||||
rgba: root._am_bg_color
|
||||
RoundedRectangle:
|
||||
pos:
|
||||
rgba:
|
||||
self.theme_cls.primaryColor \
|
||||
if self.focus else \
|
||||
self.theme_cls.transparentColor
|
||||
SmoothLine:
|
||||
width: 1
|
||||
rounded_rectangle:
|
||||
[ \
|
||||
self.pos[0] + root.border_width, \
|
||||
self.pos[1] + self.height/2 + self.border_width * 0.5 \
|
||||
] if self.orientation == "vertical" else \
|
||||
[ \
|
||||
self.pos[0] + root.border_width, \
|
||||
self.pos[1] + root.border_width \
|
||||
self.x,
|
||||
self.y, \
|
||||
self.width, \
|
||||
self.height, \
|
||||
*self.radius, \
|
||||
]
|
||||
size:
|
||||
[ \
|
||||
self.size[0] - root.border_width * 2, \
|
||||
self.size[1] / 2 - self.border_width * 1.5 \
|
||||
] if self.orientation == "vertical" else \
|
||||
[ \
|
||||
self.size[0] / 2 - root.border_width * 1.5, \
|
||||
self.size[1] - root.border_width * 2 \
|
||||
]
|
||||
radius:
|
||||
[root.border_radius, root.border_radius, 0, 0] \
|
||||
if self.orientation == "vertical" else \
|
||||
[root.border_radius, 0, 0, root.border_radius]
|
||||
|
||||
#PM
|
||||
Color:
|
||||
rgba: root._pm_bg_color
|
||||
RoundedRectangle:
|
||||
pos:
|
||||
[ \
|
||||
self.pos[0] + root.border_width, \
|
||||
self.pos[1] + self.border_width \
|
||||
] if self.orientation == "vertical" else \
|
||||
[ \
|
||||
self.pos[0] + root.size[0] / 2 + root.border_width / 2, \
|
||||
self.pos[1] + root.border_width \
|
||||
]
|
||||
size:
|
||||
[ \
|
||||
self.size[0] - root.border_width * 2, \
|
||||
self.size[1] / 2 - self.border_width * 1.5 \
|
||||
] if self.orientation == "vertical" else \
|
||||
[ \
|
||||
self.size[0] / 2 - root.border_width * 1.5, \
|
||||
self.size[1] - root.border_width * 2 \
|
||||
]
|
||||
radius:
|
||||
[0, 0, root.border_radius, root.border_radius] \
|
||||
if self.orientation == "vertical" else \
|
||||
[0 ,root.border_radius, root.border_radius, 0]
|
||||
|
||||
# AM
|
||||
AmPmSelectorLabel:
|
||||
text: "AM"
|
||||
on_release: root.selected = "am"
|
||||
text_color: root.text_color
|
||||
|
||||
AmPmSelectorLabel:
|
||||
text: "PM"
|
||||
on_release: root.selected = "pm"
|
||||
text_color: root.text_color
|
||||
|
||||
|
||||
<TimeInputTextField>
|
||||
size_hint: None, 1
|
||||
width: dp(96)
|
||||
mode: "fill"
|
||||
active_line: False
|
||||
mode: "filled"
|
||||
font_size: dp(56)
|
||||
radius: [dp(10), ]
|
||||
fill_color_normal:
|
||||
root.parent.parent.parent.accent_color \
|
||||
if root.parent.parent.parent.accent_color else \
|
||||
( \
|
||||
[*root.parent.bg_color_active[:3], 0.5] \
|
||||
if root.parent.state in ["hour", "minute"] else \
|
||||
[*root.bg_color[:3], 0.5] \
|
||||
)
|
||||
fill_color_focus:
|
||||
(1, 1, 1, 0.5) \
|
||||
if root.parent.parent.parent.primary_color else \
|
||||
self.theme_cls.bg_dark
|
||||
text_color_focus:
|
||||
root.parent.parent.parent.accent_color \
|
||||
if root.parent.parent.parent.accent_color else \
|
||||
self.theme_cls.primary_color
|
||||
|
||||
|
||||
<TimeInput>
|
||||
radius: [dp(12), ]
|
||||
size_hint: None, None
|
||||
theme_bg_color: "Custom"
|
||||
fill_color_focus: self.theme_cls.primaryContainerColor
|
||||
fill_color_normal: self.theme_cls.surfaceContainerHighestColor
|
||||
width: "96dp"
|
||||
selection_color: self.theme_cls.transparentColor
|
||||
-height: "80dp"
|
||||
-padding: [dp(16 if self.text else 48), dp(6), dp(16), dp(6)]
|
||||
|
||||
|
||||
<MDTimePickerInputContainer>
|
||||
size_hint_y: None
|
||||
height: "80dp"
|
||||
_hour: hour
|
||||
_minute: minute
|
||||
|
||||
TimeInputTextField:
|
||||
MDTimePickerInputTextField:
|
||||
id: hour
|
||||
num_type: "hour"
|
||||
pos: 0, 0
|
||||
text_color: root.text_color
|
||||
disabled: root.disabled
|
||||
on_text: root.dispatch("on_time_input")
|
||||
radius: root.hour_radius
|
||||
readonly: root._readonly
|
||||
on_text:
|
||||
root.time_picker._get_time_input(*root.get_time())
|
||||
root.time_picker.dispatch("on_time_input", "hour", self.text)
|
||||
on_select:
|
||||
root.dispatch("on_hour_select")
|
||||
root.state = "hour"
|
||||
|
@ -137,29 +280,100 @@
|
|||
size: dp(24), dp(80)
|
||||
halign: "center"
|
||||
valign: "center"
|
||||
theme_font_size: "Custom"
|
||||
font_size: dp(50)
|
||||
pos: dp(96), 0
|
||||
theme_text_color: "Custom"
|
||||
text_color: root.text_color
|
||||
|
||||
TimeInputTextField:
|
||||
MDTimePickerInputTextField:
|
||||
id: minute
|
||||
num_type: "minute"
|
||||
pos: dp(120), 0
|
||||
text_color: root.text_color
|
||||
disabled: root.disabled
|
||||
on_text: root.dispatch("on_time_input")
|
||||
radius: root.minute_radius
|
||||
readonly: root._readonly
|
||||
on_text:
|
||||
root.time_picker._get_time_input(*root.get_time())
|
||||
root.time_picker.dispatch("on_time_input", "minute", self.text)
|
||||
on_select:
|
||||
root.dispatch("on_minute_select")
|
||||
root.state = "minute"
|
||||
|
||||
|
||||
<CircularSelector>
|
||||
<MDTimePickerAmPmSelectorLabel>
|
||||
halign: "center"
|
||||
valign: "center"
|
||||
|
||||
|
||||
<MDTimePickerAmPmSelector>
|
||||
orientation: "vertical"
|
||||
line_color: self.theme_cls.outlineColor
|
||||
radius: [dp(12), ]
|
||||
|
||||
canvas.before:
|
||||
# AM
|
||||
Color:
|
||||
rgba:
|
||||
self.theme_cls.tertiaryContainerColor \
|
||||
if self.selected == "am" else \
|
||||
self.theme_cls.surfaceContainerHighColor
|
||||
RoundedRectangle:
|
||||
pos:
|
||||
[self.pos[0], self.pos[1] + self.height / 2] \
|
||||
if self.orientation == "vertical" else \
|
||||
[self.pos[0], self.pos[1]]
|
||||
size:
|
||||
[self.size[0], self.size[1] / 2] \
|
||||
if self.orientation == "vertical" else \
|
||||
[self.size[0] / 2, self.size[1]]
|
||||
radius:
|
||||
[dp(12), dp(12), 0, 0] \
|
||||
if self.orientation == "vertical" else \
|
||||
[dp(12), 0, 0, dp(12)]
|
||||
|
||||
# PM
|
||||
Color:
|
||||
rgba:
|
||||
self.theme_cls.tertiaryContainerColor \
|
||||
if self.selected == "pm" else \
|
||||
self.theme_cls.surfaceContainerHighColor
|
||||
RoundedRectangle:
|
||||
pos:
|
||||
[self.pos[0], self.pos[1]] \
|
||||
if self.orientation == "vertical" else \
|
||||
[self.pos[0] + root.size[0] / 2, self.pos[1]]
|
||||
size:
|
||||
[self.size[0], self.size[1] / 2] \
|
||||
if self.orientation == "vertical" else \
|
||||
[self.size[0] / 2, self.size[1]]
|
||||
radius:
|
||||
[0, 0, dp(12), dp(12)] \
|
||||
if self.orientation == "vertical" else \
|
||||
[0, dp(12), dp(12), 0]
|
||||
|
||||
MDTimePickerAmPmSelectorLabel:
|
||||
id: am_label
|
||||
text: "AM"
|
||||
on_release: root.selected = "am"
|
||||
|
||||
MDDivider:
|
||||
color: root.theme_cls.outlineColor
|
||||
orientation:
|
||||
"vertical" \
|
||||
if root.orientation == "horizontal" else \
|
||||
"horizontal"
|
||||
|
||||
MDTimePickerAmPmSelectorLabel:
|
||||
id: pm_label
|
||||
text: "PM"
|
||||
on_release: root.selected = "pm"
|
||||
|
||||
|
||||
<MDTimePickerCircularSelectorLabel>
|
||||
adaptive_size: True
|
||||
|
||||
|
||||
<MDTimePickerCircularSelector>
|
||||
circular_padding: dp(28)
|
||||
size_hint: None, None
|
||||
size: [dp(256), dp(256)]
|
||||
size: dp(256), dp(256)
|
||||
row_spacing: dp(40)
|
||||
on_selector_change: self.time_picker._get_dial_time(self)
|
||||
|
||||
canvas.before:
|
||||
PushMatrix
|
||||
|
@ -168,7 +382,7 @@
|
|||
x: root.scale
|
||||
y: root.scale
|
||||
Color:
|
||||
rgba: root.bg_color
|
||||
rgba: self.theme_cls.surfaceContainerHighestColor
|
||||
Ellipse:
|
||||
size: self.size
|
||||
pos: self.pos
|
||||
|
@ -178,7 +392,7 @@
|
|||
x: root.content_scale
|
||||
y: root.content_scale
|
||||
Color:
|
||||
rgb: root.selector_color
|
||||
rgb: self.theme_cls.primaryColor
|
||||
a: 0 if self.selector_pos == [0, 0] else 1
|
||||
Ellipse:
|
||||
size: self.selector_size, self.selector_size
|
||||
|
@ -188,153 +402,9 @@
|
|||
Ellipse:
|
||||
size: dp(10), dp(10)
|
||||
pos: [self.center[0] - dp(5), self.center[1] - dp(5)]
|
||||
Line:
|
||||
SmoothLine:
|
||||
points: [self.center, self.selector_pos]
|
||||
width: dp(1)
|
||||
canvas.after:
|
||||
PopMatrix
|
||||
PopMatrix
|
||||
|
||||
|
||||
<SelectorLabel>
|
||||
halign: "center"
|
||||
valign: "center"
|
||||
adaptive_size: True
|
||||
theme_text_color: "Custom"
|
||||
|
||||
|
||||
<MDTimePicker>
|
||||
auto_dismiss: True
|
||||
size_hint: None, None
|
||||
_time_input: _time_input
|
||||
_selector: _selector
|
||||
_am_pm_selector: _am_pm_selector
|
||||
_minute_label: _minute_label
|
||||
_hour_label: _hour_label
|
||||
|
||||
MDRelativeLayout:
|
||||
canvas.before:
|
||||
Color:
|
||||
rgba:
|
||||
root.primary_color \
|
||||
if root.primary_color \
|
||||
else root.theme_cls.bg_normal
|
||||
|
||||
RoundedRectangle:
|
||||
size: self.size
|
||||
radius: root.radius
|
||||
|
||||
MDLabel:
|
||||
id: label_title
|
||||
font_style: "Body2"
|
||||
bold: True
|
||||
theme_text_color: "Custom"
|
||||
size_hint_x: None
|
||||
width: root.width
|
||||
adaptive_height: True
|
||||
text: root.title
|
||||
font_name: root.font_name
|
||||
pos: (dp(24), root.height - self.height - dp(18))
|
||||
text_color:
|
||||
root.text_toolbar_color if root.text_toolbar_color \
|
||||
else root.theme_cls.text_color
|
||||
|
||||
TimeInput:
|
||||
id: _time_input
|
||||
bg_color:
|
||||
root.accent_color if root.accent_color else \
|
||||
root.theme_cls.primary_light
|
||||
bg_color_active:
|
||||
root.selector_color if root.selector_color \
|
||||
else root.theme_cls.primary_color
|
||||
text_color:
|
||||
root.input_field_text_color if root.input_field_text_color else \
|
||||
root.theme_cls.text_color
|
||||
on_time_input: root._get_time_input(*self.get_time())
|
||||
on_hour_select: _selector.switch_mode("hour")
|
||||
on_minute_select: _selector.switch_mode("minute")
|
||||
minute_radius: root.minute_radius
|
||||
hour_radius: root.hour_radius
|
||||
|
||||
TimeInputLabel:
|
||||
id: _hour_label
|
||||
text: "Hour"
|
||||
opacity: 0
|
||||
text_color:
|
||||
root.text_toolbar_color if root.text_toolbar_color else \
|
||||
root.theme_cls.secondary_text_color
|
||||
|
||||
TimeInputLabel:
|
||||
id: _minute_label
|
||||
text: "Minute"
|
||||
opacity: 0
|
||||
text_color:
|
||||
root.text_toolbar_color if root.text_toolbar_color else \
|
||||
root.theme_cls.secondary_text_color
|
||||
|
||||
AmPmSelector:
|
||||
id: _am_pm_selector
|
||||
owner: root
|
||||
border_color:
|
||||
root.accent_color if root.accent_color else \
|
||||
root.theme_cls.primary_color
|
||||
border_radius: root.am_pm_radius
|
||||
bg_color:
|
||||
root.primary_color if root.primary_color else \
|
||||
root.theme_cls.bg_normal
|
||||
border_width: root.am_pm_border_width
|
||||
bg_color_active:
|
||||
root.selector_color if root.selector_color else \
|
||||
root.theme_cls.primary_light
|
||||
text_color:
|
||||
root.input_field_text_color if root.input_field_text_color else \
|
||||
root.theme_cls.text_color
|
||||
on_selected: root._get_am_pm(self.selected)
|
||||
|
||||
CircularSelector:
|
||||
id: _selector
|
||||
text_color:
|
||||
root.text_color if root.text_color else \
|
||||
root.theme_cls.text_color
|
||||
bg_color:
|
||||
root.accent_color if root.accent_color else \
|
||||
root.theme_cls.primary_light
|
||||
selector_color:
|
||||
root.primary_color if root.primary_color else \
|
||||
root.theme_cls.primary_color
|
||||
font_name: root.font_name
|
||||
on_selector_change: root._get_dial_time(_selector)
|
||||
|
||||
MDIconButton:
|
||||
id: input_clock_switch
|
||||
icon: "keyboard"
|
||||
pos: dp(12), dp(8)
|
||||
theme_icon_color: "Custom"
|
||||
icon_size: "24dp"
|
||||
on_release: root._switch_input()
|
||||
icon_color:
|
||||
root.text_toolbar_color if root.text_toolbar_color else \
|
||||
root.theme_cls.secondary_text_color
|
||||
|
||||
MDFlatButton:
|
||||
id: cancel_button
|
||||
text: "CANCEL"
|
||||
on_release: root.dispatch("on_cancel", None)
|
||||
theme_text_color: "Custom"
|
||||
pos: root.width - self.width - ok_button.width - dp(10), dp(10)
|
||||
font_name: root.font_name
|
||||
text_color:
|
||||
root.theme_cls.primary_color \
|
||||
if not root.text_button_color else root.text_button_color
|
||||
|
||||
MDFlatButton:
|
||||
id: ok_button
|
||||
width: dp(32)
|
||||
pos: root.width - self.width, dp(10)
|
||||
text: "OK"
|
||||
theme_text_color: "Custom"
|
||||
font_name: root.font_name
|
||||
text_color:
|
||||
root.theme_cls.primary_color \
|
||||
if not root.text_button_color else root.text_button_color
|
||||
on_release: root.dispatch("on_save", root._get_data())
|
||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue