"""Provides :class:`CustomDialog` and :class:`ReplacementItemsContent`."""
from functools import partial
from kivy.clock import Clock
from kivy.factory import Factory
from kivy.lang import Builder
from kivy.properties import (
BooleanProperty,
ListProperty,
ObjectProperty,
StringProperty,
)
from kivy.uix.behaviors import ButtonBehavior
from kivy.uix.boxlayout import BoxLayout
from kivymd.app import MDApp
from kivymd.uix.dialog import MDDialog
from .scroll_widgets import ScrollList
[docs]class CustomContentBase:
"""Base-class to be used for instances of :attr:`CustomDialog.content_cls`."""
[docs] def get_result(self):
"""Placeholder-function."""
[docs]class TextFieldContent(CustomContentBase, BoxLayout):
""":class:`kivy.uix.BoxLayout` containing a :class:`kivymd.uix.MDTextField`.
For use as:attr:`kivymd.uix.dialog.content_cls`.
"""
default_text = StringProperty("")
text_field = ObjectProperty()
def _focus(self, *_):
self.text_field.focus = 1
[docs] def focus(self):
"""Focus text-input."""
Clock.schedule_once(self._focus)
[docs] def on_parent(self, *_):
"""Call :meth:`focus`."""
self.focus()
[docs] def get_result(self):
"""Return current entry of the text_field."""
return self.text_field.text
[docs]class ItemsContent(ScrollList, CustomContentBase):
"""Scrollable list of items.
Items dispatch ``on_press``-events and itself dispatches ``on_item_press`` event.
"""
child_class_name = "BaseListItem"
[docs] data = ListProperty()
""":class:`~kivy.properties.ListProperty`."""
def __init__(self, **kwargs):
self.register_event_type("on_item_press")
self.child_bindings["on_press"] = partial(self.dispatch, "on_item_press")
super().__init__(**kwargs)
[docs] def on_item_press(self, *_):
"""Placeholder-function."""
[docs]class ReplacementItemsContent(ItemsContent):
"""Content for the ReplacementDialog."""
[docs] child_class_name = StringProperty("ReplacementItem")
""":class:`~kivy.properties.StringProperty` defaults to ``"ReplacementItem"``."""
[docs] def get_result(self):
"""Get user selection."""
return [
(child.lemma if child.take_lemma else child.word)
for child in self.root_for_children.children[::-1]
]
[docs]class ReplacementItem(ButtonBehavior, BoxLayout):
"""
Item displaying a word (:attr:`word`) and a possible replacement (:attr:`lemma`).
:attr:`lemma` can be edited and the selection of word vs replacement switches on click.
"""
[docs] lemma = StringProperty("")
""":class:`~kivy.properties.StringProperty` defaults to ``""``."""
[docs] word = StringProperty("")
""":class:`~kivy.properties.StringProperty` defaults to ``""``."""
[docs] take_lemma = BooleanProperty(False)
""":class:`~kivy.properties.BooleanProperty` defaults to ``False``. Indicates user choice."""
[docs] edit = BooleanProperty(False)
""":class:`~kivy.properties.BooleanProperty` defaults to ``False``. While ``True`` the :attr:`lemma` can be
edited."""
[docs] def on_press(self, *_):
"""Placeholder-function."""
[docs]class CustomDialog(MDDialog):
"""Custom dialog."""
type = "custom"
content_cls_name = StringProperty("CustomContentBase")
""":class:`~kivy.properties.StringProperty` defaults to ``"DialogButton"``."""
[docs] button_texts = ListProperty(["OK", "CANCEL"])
""":class:`~kivy.properties.ListProperty` defaults to ``["OK", "CANCEL"]``."""
[docs] callback = ObjectProperty()
""":class:`~kivy.properties.ObjectProperty` defaults to ``None``."""
"""Do not dismiss on click outside the dialog."""
def __init__(self, **kwargs):
button_cls = Factory.get(self.button_cls_name)
self.buttons = [
button_cls(text=button_text) for button_text in self.button_texts
]
for button in self.buttons:
button.bind(on_press=self.on_button_press)
if kwargs.get("content_cls_name"):
kwargs.setdefault(
"content_cls", Factory.get(kwargs.get("content_cls_name"))()
)
super().__init__(**kwargs)
self.content_cls.bind(on_item_press=self.on_item_press)
[docs] def on_item_press(self, content, item):
"""Placeholder-function."""
[docs] def set_data(self, data):
"""Set data of :attr:`content_cls`."""
self.content_cls.data = data
[docs]class ReplacementDialog(CustomDialog):
"""Dialog with optional replacements."""
def __init__(self, **kwargs):
kwargs["content_cls_name"] = "ReplacementItemsContent"
super().__init__(**kwargs)
[docs]class TextInputDialog(CustomDialog):
"""Dialog with one text field."""
[docs] default_text = StringProperty("")
""":~kivy.properties.StringProperty: defaults to "", the default text entry in the :~kivymd.uix.MDTextField:."""
def __init__(self, **kwargs):
default_text = kwargs.pop("default_text") if "default_text" in kwargs else ""
self.content_cls = TextFieldContent(default_text=default_text)
self.content_cls.text_field.bind(
on_text_validate=partial(self.on_button_press, callback_txt="OK")
)
self.bind(
default_text=self.content_cls.setter( # pylint: disable=no-member
"default_text"
)
)
super().__init__(**kwargs)
# pylint: disable = W,C,R,I,E
if __name__ == "__main__":
class _Example(MDApp):
dialog = None
def build(self):
return Builder.load_string(
"""
FloatLayout:
MDFlatButton:
text: "REPLACEMENT DIALOG"
pos_hint: {'center_x': .5, 'center_y': .3}
on_release: app.show_repl_dialog()
MDFlatButton:
text: "TEXT DIALOG"
pos_hint: {'center_x': .5, 'center_y': .6}
on_release: app.show_text_dialog()
"""
)
def show_repl_dialog(self):
self.dialog = CustomDialog(
title="test", content_cls=ReplacementItemsContent(), callback=print
)
self.dialog.content_cls.data = [
{"word": "aguento", "lemma": "aguentar"},
{"word": "deixa", "lemma": "deixar"},
{"word": "caminhada", "lemma": "caminhar"},
{"word": "pedras", "lemma": "pedrar"},
{"word": "almoçamos", "lemma": "almoçar"},
{"word": "limpinho", "lemma": "limpo"},
{"word": "quedas d’água", "lemma": "quedo d’água"},
{"word": "ansiosos", "lemma": "ansioso"},
]
self.dialog.open()
def show_text_dialog(self):
if isinstance(self.dialog, TextInputDialog):
self.dialog.default_text = "second call to text_input_dialog"
else:
self.dialog = TextInputDialog(
title="test",
default_text="this is a test",
callback=print,
)
self.dialog.open()
_Example().run()