177 lines
6.1 KiB
Python
177 lines
6.1 KiB
Python
|
# -*- coding: utf-8 -*-
|
||
|
|
||
|
from kivy.lang import Builder
|
||
|
from kivy.properties import StringProperty, ObjectProperty, ListProperty
|
||
|
from kivy.metrics import dp
|
||
|
from kivy.uix.modalview import ModalView
|
||
|
from kivy.animation import Animation
|
||
|
from kivymd.theming import ThemableBehavior
|
||
|
from kivymd.elevationbehavior import ElevationBehavior
|
||
|
from kivymd.button import MDFlatButton
|
||
|
|
||
|
Builder.load_string('''
|
||
|
<MDDialog>:
|
||
|
canvas:
|
||
|
Color:
|
||
|
rgba: self.theme_cls.bg_light
|
||
|
Rectangle:
|
||
|
size: self.size
|
||
|
pos: self.pos
|
||
|
|
||
|
_container: container
|
||
|
_action_area: action_area
|
||
|
elevation: 12
|
||
|
GridLayout:
|
||
|
cols: 1
|
||
|
|
||
|
GridLayout:
|
||
|
cols: 1
|
||
|
padding: dp(24), dp(24), dp(24), 0
|
||
|
spacing: dp(20)
|
||
|
MDLabel:
|
||
|
text: root.title
|
||
|
font_style: 'Title'
|
||
|
theme_text_color: 'Primary'
|
||
|
halign: 'left'
|
||
|
valign: 'middle'
|
||
|
size_hint_y: None
|
||
|
text_size: self.width, None
|
||
|
height: self.texture_size[1]
|
||
|
|
||
|
BoxLayout:
|
||
|
id: container
|
||
|
|
||
|
AnchorLayout:
|
||
|
anchor_x: 'right'
|
||
|
anchor_y: 'center'
|
||
|
size_hint: 1, None
|
||
|
height: dp(48)
|
||
|
padding: dp(8), dp(8)
|
||
|
spacing: dp(4)
|
||
|
|
||
|
GridLayout:
|
||
|
id: action_area
|
||
|
rows: 1
|
||
|
size_hint: None, None if len(root._action_buttons) > 0 else 1
|
||
|
height: dp(36) if len(root._action_buttons) > 0 else 0
|
||
|
width: self.minimum_width
|
||
|
''')
|
||
|
|
||
|
|
||
|
class MDDialog(ThemableBehavior, ElevationBehavior, ModalView):
|
||
|
title = StringProperty('')
|
||
|
|
||
|
content = ObjectProperty(None)
|
||
|
|
||
|
background_color = ListProperty([0, 0, 0, .2])
|
||
|
|
||
|
_container = ObjectProperty()
|
||
|
_action_buttons = ListProperty([])
|
||
|
_action_area = ObjectProperty()
|
||
|
|
||
|
def __init__(self, **kwargs):
|
||
|
super(MDDialog, self).__init__(**kwargs)
|
||
|
self.bind(_action_buttons=self._update_action_buttons,
|
||
|
auto_dismiss=lambda *x: setattr(self.shadow, 'on_release',
|
||
|
self.shadow.dismiss if self.auto_dismiss else None))
|
||
|
|
||
|
def add_action_button(self, text, action=None):
|
||
|
"""Add an :class:`FlatButton` to the right of the action area.
|
||
|
|
||
|
:param icon: Unicode character for the icon
|
||
|
:type icon: str or None
|
||
|
:param action: Function set to trigger when on_release fires
|
||
|
:type action: function or None
|
||
|
"""
|
||
|
button = MDFlatButton(text=text,
|
||
|
size_hint=(None, None),
|
||
|
height=dp(36))
|
||
|
if action:
|
||
|
button.bind(on_release=action)
|
||
|
button.text_color = self.theme_cls.primary_color
|
||
|
button.background_color = self.theme_cls.bg_light
|
||
|
self._action_buttons.append(button)
|
||
|
|
||
|
def add_widget(self, widget):
|
||
|
if self._container:
|
||
|
if self.content:
|
||
|
raise PopupException(
|
||
|
'Popup can have only one widget as content')
|
||
|
self.content = widget
|
||
|
else:
|
||
|
super(MDDialog, self).add_widget(widget)
|
||
|
|
||
|
def open(self, *largs):
|
||
|
'''Show the view window from the :attr:`attach_to` widget. If set, it
|
||
|
will attach to the nearest window. If the widget is not attached to any
|
||
|
window, the view will attach to the global
|
||
|
:class:`~kivy.core.window.Window`.
|
||
|
'''
|
||
|
if self._window is not None:
|
||
|
Logger.warning('ModalView: you can only open once.')
|
||
|
return self
|
||
|
# search window
|
||
|
self._window = self._search_window()
|
||
|
if not self._window:
|
||
|
Logger.warning('ModalView: cannot open view, no window found.')
|
||
|
return self
|
||
|
self._window.add_widget(self)
|
||
|
self._window.bind(on_resize=self._align_center,
|
||
|
on_keyboard=self._handle_keyboard)
|
||
|
self.center = self._window.center
|
||
|
self.bind(size=self._align_center)
|
||
|
a = Animation(_anim_alpha=1., d=self._anim_duration)
|
||
|
a.bind(on_complete=lambda *x: self.dispatch('on_open'))
|
||
|
a.start(self)
|
||
|
return self
|
||
|
|
||
|
def dismiss(self, *largs, **kwargs):
|
||
|
'''Close the view if it is open. If you really want to close the
|
||
|
view, whatever the on_dismiss event returns, you can use the *force*
|
||
|
argument:
|
||
|
::
|
||
|
|
||
|
view = ModalView(...)
|
||
|
view.dismiss(force=True)
|
||
|
|
||
|
When the view is dismissed, it will be faded out before being
|
||
|
removed from the parent. If you don't want animation, use::
|
||
|
|
||
|
view.dismiss(animation=False)
|
||
|
|
||
|
'''
|
||
|
if self._window is None:
|
||
|
return self
|
||
|
if self.dispatch('on_dismiss') is True:
|
||
|
if kwargs.get('force', False) is not True:
|
||
|
return self
|
||
|
if kwargs.get('animation', True):
|
||
|
Animation(_anim_alpha=0., d=self._anim_duration).start(self)
|
||
|
else:
|
||
|
self._anim_alpha = 0
|
||
|
self._real_remove_widget()
|
||
|
return self
|
||
|
|
||
|
def on_content(self, instance, value):
|
||
|
if self._container:
|
||
|
self._container.clear_widgets()
|
||
|
self._container.add_widget(value)
|
||
|
|
||
|
def on__container(self, instance, value):
|
||
|
if value is None or self.content is None:
|
||
|
return
|
||
|
self._container.clear_widgets()
|
||
|
self._container.add_widget(self.content)
|
||
|
|
||
|
def on_touch_down(self, touch):
|
||
|
if self.disabled and self.collide_point(*touch.pos):
|
||
|
return True
|
||
|
return super(MDDialog, self).on_touch_down(touch)
|
||
|
|
||
|
def _update_action_buttons(self, *args):
|
||
|
self._action_area.clear_widgets()
|
||
|
for btn in self._action_buttons:
|
||
|
btn.ids._label.texture_update()
|
||
|
btn.width = btn.ids._label.texture_size[0] + dp(16)
|
||
|
self._action_area.add_widget(btn)
|