AndreMiras / KivyMD

Set of widgets for Kivy inspired by Google's Material Design.
MIT License
56 stars 22 forks source link

hint_text stays blank when added from python #14

Open BananaMasterz opened 4 years ago

BananaMasterz commented 4 years ago

`AddEm = MDTextField(hint_text=f"Hello 1"

                         )
    self.MainLayout.ids[f'text_inputs'].add_widget(AddEm
    )`

I have this. If I run it as is, I don't get any hint text, just blank. But if I do text=f"Hello 1" then it works and adds the text. Other properties of MDTextField work too. Also, if I add the hint_text=f"Hello 1" directly in the kv file, it also works and shows the hint correctly. Below I attach the specific textfield.py I'm importing.

`""" Components/Text Field

.. seealso::

`Material Design spec, Text fields <https://material.io/components/text-fields>`_

.. rubric:: Text fields let users enter and edit text.

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

KivyMD provides the following field classes for use:

.. Note:: :class:~MDTextField inherited from :class:~kivy.uix.textinput.TextInput. Therefore, most parameters and all events of the :class:~kivy.uix.textinput.TextInput class are also available in the :class:~MDTextField class.

.. MDTextField: MDTextField

:class:~MDTextField can be with helper text and without.

Without helper text mode

.. code-block:: kv

MDTextField:
    hint_text: "No helper text"

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-no-helper-mode.gif :align: center

Helper text mode on on_focus event

.. code-block:: kv

MDTextField:
    hint_text: "Helper text on focus"
    helper_text: "This will disappear when you click off"
    helper_text_mode: "on_focus"

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-helper-mode-on-focus.gif :align: center

Persistent helper text mode

.. code-block:: kv

MDTextField:
    hint_text: "Persistent helper text"
    helper_text: "Text is always here"
    helper_text_mode: "persistent"

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-helper-mode-persistent.gif :align: center

Helper text mode 'on_error'

To display an error in a text field when using the helper_text_mode: "on_error" parameter, set the "error" text field parameter to True:

.. code-block:: python

from kivy.lang import Builder

from kivymd.app import MDApp

KV = '''
BoxLayout:
    padding: "10dp"

    MDTextField:
        id: text_field_error
        hint_text: "Helper text on error (press 'Enter')"
        helper_text: "There will always be a mistake"
        helper_text_mode: "on_error"
        pos_hint: {"center_y": .5}
'''

class Test(MDApp):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.screen = Builder.load_string(KV)

    def build(self):
        self.screen.ids.text_field_error.bind(
            on_text_validate=self.set_error_message,
            on_focus=self.set_error_message,
        )
        return self.screen

    def set_error_message(self, instance_textfield):
        self.screen.ids.text_field_error.error = True

Test().run()

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-helper-mode-on-error.gif :align: center

Helper text mode 'on_error' (with required)

.. code-block:: kv

MDTextField:
    hint_text: "required = True"
    required: True
    helper_text_mode: "on_error"
    helper_text: "Enter text"

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

Text length control

.. code-block:: kv

MDTextField:
    hint_text: "Max text length = 5"
    max_text_length: 5

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

Multi line text

.. code-block:: kv

MDTextField:
    multiline: True
    hint_text: "Multi-line text"

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

Color mode

.. code-block:: kv

MDTextField:
    hint_text: "color_mode = 'accent'"
    color_mode: 'accent'

Available options are 'primary', 'accent' or 'custom'.

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

.. code-block:: kv

MDTextField:
    hint_text: "color_mode = 'custom'"
    color_mode: 'custom'
    helper_text_mode: "on_focus"
    helper_text: "Color is defined by 'line_color_focus' property"
    line_color_focus: 1, 0, 1, 1

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-color-mode-custom.gif :align: center

.. code-block:: kv

MDTextField:
    hint_text: "Line color normal"
    line_color_normal: app.theme_cls.accent_color

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

Rectangle mode

.. code-block:: kv

MDTextField:
    hint_text: "Rectangle mode"
    mode: "rectangle"

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

Fill mode

.. code-block:: kv

MDTextField:
    hint_text: "Fill mode"
    mode: "fill"
    fill_color: 0, 0, 0, .4

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

.. MDTextFieldRect: MDTextFieldRect

.. Note:: :class:~MDTextFieldRect inherited from :class:~kivy.uix.textinput.TextInput. You can use all parameters and attributes of the :class:~kivy.uix.textinput.TextInput class in the :class:~MDTextFieldRect class.

.. code-block:: kv

MDTextFieldRect:
    size_hint: 1, None
    height: "30dp"

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

.. Warning:: While there is no way to change the color of the border.

.. MDTextFieldRound: MDTextFieldRound

Without icon

.. code-block:: kv

MDTextFieldRound:
    hint_text: 'Empty field'

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

With left icon

.. Warning:: The icons in the :class:~MDTextFieldRound are static. You cannot bind events to them.

.. code-block:: kv

MDTextFieldRound:
    icon_left: "email"
    hint_text: "Field with left icon"

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-round-left-icon.png :align: center

With left and right icons

.. code-block:: kv

MDTextFieldRound:
    icon_left: 'key-variant'
    icon_right: 'eye-off'
    hint_text: 'Field with left and right icons'

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-round-left-right-icon.png :align: center

Control background color

.. code-block:: kv

MDTextFieldRound:
    icon_left: 'key-variant'
    normal_color: app.theme_cls.accent_color

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-round-normal-color.gif :align: center

.. code-block:: kv

MDTextFieldRound:
    icon_left: 'key-variant'
    normal_color: app.theme_cls.accent_color
    color_active: 1, 0, 0, 1

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-round-active-color.gif :align: center

With right icon

.. Note:: The icon on the right is available for use in all text fields.

.. code-block:: kv

MDTextField:
    hint_text: "Name"
    mode: "fill"
    fill_color: 0, 0, 0, .4
    icon_right: "arrow-down-drop-circle-outline"
    icon_right_color: app.theme_cls.primary_color

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-fill-mode-icon.png :align: center

.. code-block:: kv

MDTextField:
    hint_text: "Name"
    icon_right: "arrow-down-drop-circle-outline"
    icon_right_color: app.theme_cls.primary_color

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

.. code-block:: kv

MDTextField:
    hint_text: "Name"
    mode: "rectangle"
    icon_right: "arrow-down-drop-circle-outline"
    icon_right_color: app.theme_cls.primary_color

.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/text-field-rectangle-right-icon.png :align: center

.. seealso::

See more information in the :class:`~MDTextFieldRect` class.

"""

all = ( "MDTextField", "MDTextFieldRect", "MDTextFieldRound", )

import sys

from kivy.uix.label import Label from kivy.uix.textinput import TextInput from kivy.animation import Animation from kivy.graphics.context_instructions import Color from kivy.lang import Builder from kivy.properties import ( NumericProperty, StringProperty, BooleanProperty, OptionProperty, ListProperty, ObjectProperty, ) from kivy.metrics import dp from kivy.metrics import sp

from kivymd.font_definitions import theme_font_styles from kivymd.theming import ThemableBehavior from kivymd.uix.label import MDIcon

Builder.load_string( """

:import images_path kivymd.images_path

canvas.before: Clear # Disabled line. Color: rgba: self.line_color_normal if root.mode == "line" else (0, 0, 0, 0) Line: points: self.x, self.y + dp(16), self.x + self.width, self.y + dp(16) width: 1 dash_length: dp(3) dash_offset: 2 if self.disabled else 0 # Active line. Color: rgba: self._current_line_color if root.mode in ("line", "fill") and root.active_line else (0, 0, 0, 0) Rectangle: size: self._line_width, dp(2) pos: self.center_x - (self._line_width / 2), self.y + (dp(16) if root.mode != "fill" else 0) # Helper text. Color: rgba: self._current_error_color Rectangle: texture: self._msg_lbl.texture size: self._msg_lbl.texture_size[0] - (dp(3) if root.mode in ("fill", "rectangle") else 0), \ self._msg_lbl.texture_size[1] - (dp(3) if root.mode in ("fill", "rectangle") else 0) pos: self.x + (dp(8) if root.mode == "fill" else 0), self.y + (dp(3) if root.mode in ("fill", "rectangle") else 0) # Texture of right Icon. Color: rgba: self.icon_right_color Rectangle: texture: self._lbl_icon_right.texture size: self._lbl_icon_right.texture_size if self.icon_right else (0, 0) pos: (self.width + self.x) - (self._lbl_icon_right.texture_size[1]) - dp(8), \ self.center[1] - self._lbl_icon_right.texture_size[1] / 2 + (dp(8) if root.mode != "fill" else 0) \ if root.mode != "rectangle" else \ self.center[1] - self._lbl_icon_right.texture_size[1] / 2 - dp(4) Color: rgba: self._current_right_lbl_color Rectangle: texture: self._right_msg_lbl.texture size: self._right_msg_lbl.texture_size pos: self.width-self._right_msg_lbl.texture_size[0] + dp(45), self.y Color: rgba: (self._current_line_color if self.focus and not \ self._cursor_blink else (0, 0, 0, 0)) Rectangle: pos: (int(x) for x in self.cursor_pos) size: 1, -self.line_height # Hint text. Color: rgba: self._current_hint_text_color if not self.current_hint_text_color else self.current_hint_text_color Rectangle: texture: self._hint_lbl.texture size: self._hint_lbl.texture_size pos: self.x + (dp(8) if root.mode == "fill" else 0), self.y + self.height - self._hint_y Color: rgba: self.disabled_foreground_color if self.disabled else\ (self.hint_text_color if not self.text and not\ self.focus else self.foreground_color) # "rectangle" mode Color: rgba: self._current_line_color Line: width: dp(1) if root.mode == "rectangle" else dp(0.00001) points: ( self.x + root._line_blank_space_right_hint_text, self.top - self._hint_lbl.texture_size[1] // 2, self.right + dp(12), self.top - self._hint_lbl.texture_size[1] // 2, self.right + dp(12), self.y, self.x - dp(12), self.y, self.x - dp(12), self.top - self._hint_lbl.texture_size[1] // 2, self.x + root._line_blank_space_left_hint_text, self.top - self._hint_lbl.texture_size[1] // 2 ) # "fill" mode. canvas.after: Color: rgba: root.fill_color if root.mode == "fill" else (0, 0, 0, 0) RoundedRectangle: pos: self.x, self.y size: self.width, self.height + dp(8) radius: [10, 10, 0, 0, 0] font_name: "Roboto" if not root.font_name else root.font_name foreground_color: app.theme_cls.text_color font_size: "16sp" bold: False padding: 0 if root.mode != "fill" else "8dp", \ "16dp" if root.mode != "fill" else "24dp", \ 0 if root.mode != "fill" and not root.icon_right else ("14dp" if not root.icon_right else self._lbl_icon_right.texture_size[1] + dp(20)), \ "16dp" if root.mode == "fill" else "10dp" multiline: False size_hint_y: None height: self.minimum_height + (dp(8) if root.mode != "fill" else 0) size_hint_x: None width: self.texture_size[0] shorten: True shorten_from: "right" on_focus: root.anim_rect([root.x, root.y, root.right, root.y, root.right, \ root.top, root.x, root.top, root.x, root.y], 1) if root.focus \ else root.anim_rect([root.x - dp(60), root.y - dp(60), \ root.right + dp(60), root.y - dp(60), root.right + dp(60), root.top + dp(60), \ root.x - dp(60), root.top + dp(60), \ root.x - dp(60), root.y - dp(60)], 0) canvas.after: Color: rgba: root._primary_color Line: width: dp(1.5) points: ( self.x - dp(60), self.y - dp(60), self.right + dp(60), self.y - dp(60), self.right + dp(60), self.top + dp(60), self.x - dp(60), self.top + dp(60), self.x - dp(60), self.y - dp(60) ) : multiline: False size_hint: 1, None height: self.line_height + dp(10) background_active: f'{images_path}transparent.png' background_normal: f'{images_path}transparent.png' padding: self._lbl_icon_left.texture_size[1] + dp(10) if self.icon_left else dp(15), \ (self.height / 2) - (self.line_height / 2), \ self._lbl_icon_right.texture_size[1] + dp(20) if self.icon_right else dp(15), \ 0 canvas.before: Color: rgba: self.normal_color if not self.focus else self._color_active Ellipse: angle_start: 180 angle_end: 360 pos: self.pos[0] - self.size[1] / 2, self.pos[1] size: self.size[1], self.size[1] Ellipse: angle_start: 360 angle_end: 540 pos: self.size[0] + self.pos[0] - self.size[1]/2.0, self.pos[1] size: self.size[1], self.size[1] Rectangle: pos: self.pos size: self.size Color: rgba: self.line_color Line: points: self.pos[0] , self.pos[1], self.pos[0] + self.size[0], self.pos[1] Line: points: self.pos[0], self.pos[1] + self.size[1], self.pos[0] + self.size[0], self.pos[1] + self.size[1] Line: ellipse: self.pos[0] - self.size[1] / 2, self.pos[1], self.size[1], self.size[1], 180, 360 Line: ellipse: self.size[0] + self.pos[0] - self.size[1] / 2.0, self.pos[1], self.size[1], self.size[1], 360, 540 # Texture of left Icon. Color: rgba: self.icon_left_color Rectangle: texture: self._lbl_icon_left.texture size: self._lbl_icon_left.texture_size if self.icon_left \ else (0, 0) pos: self.x, \ self.center[1] - self._lbl_icon_right.texture_size[1] / 2 # Texture of right Icon. Color: rgba: self.icon_right_color Rectangle: texture: self._lbl_icon_right.texture size: self._lbl_icon_right.texture_size if self.icon_right \ else (0, 0) pos: (self.width + self.x) - (self._lbl_icon_right.texture_size[1]), \ self.center[1] - self._lbl_icon_right.texture_size[1] / 2 Color: rgba: root.theme_cls.disabled_hint_text_color if not self.focus \ else root.foreground_color """ ) class MDTextFieldRect(ThemableBehavior, TextInput): _primary_color = ListProperty([0, 0, 0, 0]) def __init__(self, **kwargs): super().__init__(**kwargs) self._update_primary_color() self.theme_cls.bind(primary_color=self._update_primary_color) self.root_color = Color() def _update_primary_color(self, *args): self._primary_color = self.theme_cls.primary_color self._primary_color[3] = 0 def anim_rect(self, points, alpha): instance_line = self.canvas.children[-1].children[-1] instance_color = self.canvas.children[-1].children[0] if alpha == 1: d_line = 0.3 d_color = 0.4 else: d_line = 0.05 d_color = 0.05 Animation(points=points, d=d_line, t="out_cubic").start(instance_line) Animation(a=alpha, d=d_color).start(instance_color) class FixedHintTextInput(TextInput): hint_text = StringProperty("") def on__hint_text(self, instance, value): pass def _refresh_hint_text(self): pass class TextfieldLabel(ThemableBehavior, Label): field = ObjectProperty() font_style = OptionProperty("Body1", options=theme_font_styles) def __init__(self, **kwargs): super().__init__(**kwargs) self.font_size = sp(self.theme_cls.font_styles[self.font_style][1]) class MDTextField(ThemableBehavior, FixedHintTextInput): helper_text = StringProperty("This field is required") """ Text for ``helper_text`` mode. :attr:`helper_text` is an :class:`~kivy.properties.StringProperty` and defaults to `'This field is required'`. """ helper_text_mode = OptionProperty( "none", options=["none", "on_error", "persistent", "on_focus"] ) """ Helper text mode. Available options are: `'on_error'`, `'persistent'`, `'on_focus'`. :attr:`helper_text_mode` is an :class:`~kivy.properties.OptionProperty` and defaults to `'none'`. """ max_text_length = NumericProperty(None) """ Maximum allowed value of characters in a text field. :attr:`max_text_length` is an :class:`~kivy.properties.NumericProperty` and defaults to `None`. """ required = BooleanProperty(False) """ Required text. If True then the text field requires text. :attr:`required` is an :class:`~kivy.properties.BooleanProperty` and defaults to `False`. """ color_mode = OptionProperty( "primary", options=["primary", "accent", "custom"] ) """ Color text mode. Available options are: `'primary'`, `'accent'`, `'custom'`. :attr:`color_mode` is an :class:`~kivy.properties.OptionProperty` and defaults to `'primary'`. """ mode = OptionProperty("line", options=["rectangle", "fill"]) """ Text field mode. Available options are: `'line'`, `'rectangle'`, `'fill'`. :attr:`mode` is an :class:`~kivy.properties.OptionProperty` and defaults to `'line'`. """ line_color_normal = ListProperty() """ Line color normal in ``rgba`` format. :attr:`line_color_normal` is an :class:`~kivy.properties.ListProperty` and defaults to `[]`. """ line_color_focus = ListProperty() """ Line color focus in ``rgba`` format. :attr:`line_color_focus` is an :class:`~kivy.properties.ListProperty` and defaults to `[]`. """ error_color = ListProperty() """ Error color in ``rgba`` format for ``required = True``. :attr:`error_color` is an :class:`~kivy.properties.ListProperty` and defaults to `[]`. """ fill_color = ListProperty([0, 0, 0, 0]) """ The background color of the fill in rgba format when the ``mode`` parameter is "fill". :attr:`fill_color` is an :class:`~kivy.properties.ListProperty` and defaults to `[0, 0, 0, 0]`. """ active_line = BooleanProperty(True) """ Show active line or not. :attr:`active_line` is an :class:`~kivy.properties.BooleanProperty` and defaults to `True`. """ error = BooleanProperty(False) """ If True, then the text field goes into ``error`` mode. :attr:`error` is an :class:`~kivy.properties.BooleanProperty` and defaults to `False`. """ current_hint_text_color = ListProperty() """ ``hint_text`` text color. :attr:`current_hint_text_color` is an :class:`~kivy.properties.ListProperty` and defaults to `[]`. """ icon_right = StringProperty() """Right icon. :attr:`icon_right` is an :class:`~kivy.properties.StringProperty` and defaults to `''`. """ icon_right_color = ListProperty([0, 0, 0, 1]) """Color of right icon in ``rgba`` format. :attr:`icon_right_color` is an :class:`~kivy.properties.ListProperty` and defaults to `[0, 0, 0, 1]`. """ _text_len_error = BooleanProperty(False) _hint_lbl_font_size = NumericProperty("16sp") _line_blank_space_right_hint_text = NumericProperty(0) _line_blank_space_left_hint_text = NumericProperty(0) _hint_y = NumericProperty("38dp") _line_width = NumericProperty(0) _current_line_color = ListProperty([0.0, 0.0, 0.0, 0.0]) _current_error_color = ListProperty([0.0, 0.0, 0.0, 0.0]) _current_hint_text_color = ListProperty([0.0, 0.0, 0.0, 0.0]) _current_right_lbl_color = ListProperty([0.0, 0.0, 0.0, 0.0]) def __init__(self, **kwargs): self._msg_lbl = TextfieldLabel( font_style="Caption", halign="left", valign="middle", text=self.helper_text, field=self, ) self._right_msg_lbl = TextfieldLabel( font_style="Caption", halign="right", valign="middle", text="", field=self, ) self._hint_lbl = TextfieldLabel( font_style="Subtitle1", halign="left", valign="middle", field=self ) self._lbl_icon_right = MDIcon(theme_text_color="Custom") super().__init__(**kwargs) self.line_color_normal = self.theme_cls.divider_color self.line_color_focus = self.theme_cls.primary_color self.error_color = self.theme_cls.error_color self._current_hint_text_color = self.theme_cls.disabled_hint_text_color self._current_line_color = self.theme_cls.primary_color self.bind( helper_text=self._set_msg, hint_text=self._set_hint, _hint_lbl_font_size=self._hint_lbl.setter("font_size"), helper_text_mode=self._set_message_mode, max_text_length=self._set_max_text_length, text=self.on_text, ) self.theme_cls.bind( primary_color=self._update_primary_color, theme_style=self._update_theme_style, accent_color=self._update_accent_color, ) self.has_had_text = False def _update_colors(self, color): self.line_color_focus = color if not self.error and not self._text_len_error: self._current_line_color = color if self.focus: self._current_line_color = color def _update_accent_color(self, *args): if self.color_mode == "accent": self._update_colors(self.theme_cls.accent_color) def _update_primary_color(self, *args): if self.color_mode == "primary": self._update_colors(self.theme_cls.primary_color) def _update_theme_style(self, *args): self.line_color_normal = self.theme_cls.divider_color if not any([self.error, self._text_len_error]): if not self.focus: self._current_hint_text_color = ( self.theme_cls.disabled_hint_text_color ) self._current_right_lbl_color = ( self.theme_cls.disabled_hint_text_color ) if self.helper_text_mode == "persistent": self._current_error_color = ( self.theme_cls.disabled_hint_text_color ) def on_icon_right(self, instance, value): self._lbl_icon_right.icon = value def on_icon_right_color(self, instance, value): self._lbl_icon_right.text_color = value def on_width(self, instance, width): if ( any([self.focus, self.error, self._text_len_error]) and instance is not None ): self._line_width = width self._msg_lbl.width = self.width self._right_msg_lbl.width = self.width def on_focus(self, *args): disabled_hint_text_color = self.theme_cls.disabled_hint_text_color Animation.cancel_all( self, "_line_width", "_hint_y", "_hint_lbl_font_size" ) if self.max_text_length is None: max_text_length = sys.maxsize else: max_text_length = self.max_text_length if len(self.text) > max_text_length or all( [self.required, len(self.text) == 0, self.has_had_text] ): self._text_len_error = True if self.error or all( [ self.max_text_length is not None and len(self.text) > self.max_text_length ] ): has_error = True else: if all([self.required, len(self.text) == 0, self.has_had_text]): has_error = True else: has_error = False if self.focus: if not self._line_blank_space_right_hint_text: self._line_blank_space_right_hint_text = self._hint_lbl.texture_size[ 0 ] - dp( 25 ) _fill_color = self.fill_color _fill_color[3] = self.fill_color[3] - 0.1 Animation( _line_blank_space_right_hint_text=self._line_blank_space_right_hint_text, _line_blank_space_left_hint_text=self._hint_lbl.x - dp(5), _current_hint_text_color=self.line_color_focus, fill_color=_fill_color, duration=0.2, t="out_quad", ).start(self) self.has_had_text = True Animation.cancel_all( self, "_line_width", "_hint_y", "_hint_lbl_font_size" ) if not self.text: Animation( _hint_y=dp(14), _hint_lbl_font_size=sp(12), duration=0.2, t="out_quad", ).start(self) Animation(_line_width=self.width, duration=0.2, t="out_quad").start( self ) if has_error: Animation( duration=0.2, _current_hint_text_color=self.error_color, _current_right_lbl_color=self.error_color, _current_line_color=self.error_color, ).start(self) if self.helper_text_mode == "on_error" and ( self.error or self._text_len_error ): Animation( duration=0.2, _current_error_color=self.error_color ).start(self) elif ( self.helper_text_mode == "on_error" and not self.error and not self._text_len_error ): Animation( duration=0.2, _current_error_color=(0, 0, 0, 0) ).start(self) elif self.helper_text_mode == "persistent": Animation( duration=0.2, _current_error_color=disabled_hint_text_color, ).start(self) elif self.helper_text_mode == "on_focus": Animation( duration=0.2, _current_error_color=disabled_hint_text_color, ).start(self) else: Animation( duration=0.2, _current_right_lbl_color=disabled_hint_text_color, ).start(self) Animation(duration=0.2, color=self.line_color_focus).start( self._hint_lbl ) if self.helper_text_mode == "on_error": Animation( duration=0.2, _current_error_color=(0, 0, 0, 0) ).start(self) if self.helper_text_mode == "persistent": Animation( duration=0.2, _current_error_color=disabled_hint_text_color, ).start(self) elif self.helper_text_mode == "on_focus": Animation( duration=0.2, _current_error_color=disabled_hint_text_color, ).start(self) else: _fill_color = self.fill_color _fill_color[3] = self.fill_color[3] + 0.1 Animation( fill_color=_fill_color, duration=0.2, t="out_quad", ).start(self) if not self.text: Animation( _hint_y=dp(38), _hint_lbl_font_size=sp(16), duration=0.2, t="out_quad", ).start(self) Animation( _line_blank_space_right_hint_text=0, _line_blank_space_left_hint_text=0, duration=0.2, t="out_quad", ).start(self) if has_error: Animation( duration=0.2, _current_line_color=self.error_color, _current_hint_text_color=self.error_color, _current_right_lbl_color=self.error_color, ).start(self) if self.helper_text_mode == "on_error" and ( self.error or self._text_len_error ): Animation( duration=0.2, _current_error_color=self.error_color ).start(self) elif ( self.helper_text_mode == "on_error" and not self.error and not self._text_len_error ): Animation( duration=0.2, _current_error_color=(0, 0, 0, 0) ).start(self) elif self.helper_text_mode == "persistent": Animation( duration=0.2, _current_error_color=disabled_hint_text_color, ).start(self) elif self.helper_text_mode == "on_focus": Animation( duration=0.2, _current_error_color=(0, 0, 0, 0) ).start(self) else: Animation(duration=0.2, color=(1, 1, 1, 1)).start( self._hint_lbl ) Animation( duration=0.2, _current_line_color=self.line_color_focus, _current_hint_text_color=disabled_hint_text_color, _current_right_lbl_color=(0, 0, 0, 0), ).start(self) if self.helper_text_mode == "on_error": Animation( duration=0.2, _current_error_color=(0, 0, 0, 0) ).start(self) elif self.helper_text_mode == "persistent": Animation( duration=0.2, _current_error_color=disabled_hint_text_color, ).start(self) elif self.helper_text_mode == "on_focus": Animation( duration=0.2, _current_error_color=(0, 0, 0, 0) ).start(self) Animation(_line_width=0, duration=0.2, t="out_quad").start(self) def on_text(self, instance, text): if len(text) > 0: self.has_had_text = True if self.max_text_length is not None: self._right_msg_lbl.text = f"{len(text)}/{self.max_text_length}" max_text_length = self.max_text_length else: max_text_length = sys.maxsize if len(text) > max_text_length or all( [self.required, len(self.text) == 0, self.has_had_text] ): self._text_len_error = True else: self._text_len_error = False if self.error or self._text_len_error: if self.focus: Animation( duration=0.2, _current_hint_text_color=self.error_color, _current_line_color=self.error_color, ).start(self) if self.helper_text_mode == "on_error" and ( self.error or self._text_len_error ): Animation( duration=0.2, _current_error_color=self.error_color ).start(self) if self._text_len_error: Animation( duration=0.2, _current_right_lbl_color=self.error_color ).start(self) else: if self.focus: disabled_hint_text_color = ( self.theme_cls.disabled_hint_text_color ) Animation( duration=0.2, _current_right_lbl_color=disabled_hint_text_color, ).start(self) Animation( duration=0.2, _current_hint_text_color=self.line_color_focus, _current_line_color=self.line_color_focus, ).start(self) if self.helper_text_mode == "on_error": Animation( duration=0.2, _current_error_color=(0, 0, 0, 0) ).start(self) if len(self.text) != 0 and not self.focus: self._hint_y = dp(14) self._hint_lbl_font_size = sp(12) def on_text_validate(self): self.has_had_text = True if self.max_text_length is None: max_text_length = sys.maxsize else: max_text_length = self.max_text_length if len(self.text) > max_text_length or all( [self.required, len(self.text) == 0, self.has_had_text] ): self._text_len_error = True def _set_hint(self, instance, text): self._hint_lbl.text = text def _set_msg(self, instance, text): self._msg_lbl.text = text self.helper_text = text def _set_message_mode(self, instance, text): self.helper_text_mode = text if self.helper_text_mode == "persistent": disabled_hint_text_color = self.theme_cls.disabled_hint_text_color Animation( duration=0.1, _current_error_color=disabled_hint_text_color ).start(self) def _set_max_text_length(self, instance, length): self.max_text_length = length self._right_msg_lbl.text = f"{len(self.text)}/{length}" def on_color_mode(self, instance, mode): if mode == "primary": self._update_primary_color() elif mode == "accent": self._update_accent_color() elif mode == "custom": self._update_colors(self.line_color_focus) def on_line_color_focus(self, *args): if self.color_mode == "custom": self._update_colors(self.line_color_focus) class MDTextFieldRound(ThemableBehavior, TextInput): icon_left = StringProperty() """Left icon. :attr:`icon_left` is an :class:`~kivy.properties.StringProperty` and defaults to `''`. """ icon_left_color = ListProperty([0, 0, 0, 1]) """Color of left icon in ``rgba`` format. :attr:`icon_left_color` is an :class:`~kivy.properties.ListProperty` and defaults to `[0, 0, 0, 1]`. """ icon_right = StringProperty() """Right icon. :attr:`icon_right` is an :class:`~kivy.properties.StringProperty` and defaults to `''`. """ icon_right_color = ListProperty([0, 0, 0, 1]) """Color of right icon. :attr:`icon_right_color` is an :class:`~kivy.properties.ListProperty` and defaults to `[0, 0, 0, 1]`. """ line_color = ListProperty() """Field line color. :attr:`line_color` is an :class:`~kivy.properties.ListProperty` and defaults to `[]`. """ normal_color = ListProperty() """Field color if `focus` is `False`. :attr:`normal_color` is an :class:`~kivy.properties.ListProperty` and defaults to `[]`. """ color_active = ListProperty() """Field color if `focus` is `True`. :attr:`color_active` is an :class:`~kivy.properties.ListProperty` and defaults to `[]`. """ _color_active = ListProperty() def __init__(self, **kwargs): super().__init__(**kwargs) self._lbl_icon_left = MDIcon(theme_text_color="Custom") self._lbl_icon_right = MDIcon(theme_text_color="Custom") self.cursor_color = self.theme_cls.primary_color if not self.normal_color: self.normal_color = self.theme_cls.primary_light if not self.line_color: self.line_color = self.theme_cls.primary_dark if not self.color_active: self._color_active = [0, 0, 0, 0.5] def on_focus(self, instance, value): if value: self.icon_left_color = self.theme_cls.primary_color self.icon_right_color = self.theme_cls.primary_color else: self.icon_left_color = self.theme_cls.text_color self.icon_right_color = self.theme_cls.text_color def on_icon_left(self, instance, value): self._lbl_icon_left.icon = value def on_icon_left_color(self, instance, value): self._lbl_icon_left.text_color = value def on_icon_right(self, instance, value): self._lbl_icon_right.icon = value def on_icon_right_color(self, instance, value): self._lbl_icon_right.text_color = value def on_color_active(self, instance, value): if value != [0, 0, 0, 0.5]: self._color_active = value self._color_active[-1] = 0.5 else: self._color_active = value `