''' Popup ===== .. versionadded:: 1.0.7 .. image:: images/popup.jpg :align: right The :class:`Popup` widget is used to create modal popups. By default, the popup will cover the whole "parent" window. When you are creating a popup, you must at least set a :attr:`Popup.title` and :attr:`Popup.content`. Remember that the default size of a Widget is size_hint=(1, 1). If you don't want your popup to be fullscreen, either use size hints with values less than 1 (for instance size_hint=(.8, .8)) or deactivate the size_hint and use fixed size attributes. .. versionchanged:: 1.4.0 The :class:`Popup` class now inherits from :class:`~kivy.uix.modalview.ModalView`. The :class:`Popup` offers a default layout with a title and a separation bar. Examples -------- Example of a simple 400x400 Hello world popup:: popup = Popup(title='Test popup', content=Label(text='Hello world'), size_hint=(None, None), size=(400, 400)) By default, any click outside the popup will dismiss/close it. If you don't want that, you can set :attr:`~kivy.uix.modalview.ModalView.auto_dismiss` to False:: popup = Popup(title='Test popup', content=Label(text='Hello world'), auto_dismiss=False) popup.open() To manually dismiss/close the popup, use :attr:`~kivy.uix.modalview.ModalView.dismiss`:: popup.dismiss() Both :meth:`~kivy.uix.modalview.ModalView.open` and :meth:`~kivy.uix.modalview.ModalView.dismiss` are bindable. That means you can directly bind the function to an action, e.g. to a button's on_press:: # create content and add to the popup content = Button(text='Close me!') popup = Popup(content=content, auto_dismiss=False) # bind the on_press event of the button to the dismiss function content.bind(on_press=popup.dismiss) # open the popup popup.open() Same thing in KV language only with :class:`Factory`: .. code-block:: kv #:import Factory kivy.factory.Factory : auto_dismiss: False Button: text: 'Close me!' on_release: root.dismiss() Button: text: 'Open popup' on_release: Factory.MyPopup().open() .. note:: Popup is a special widget. Don't try to add it as a child to any other widget. If you do, Popup will be handled like an ordinary widget and won't be created hidden in the background. .. code-block:: kv BoxLayout: MyPopup: # bad! Popup Events ------------ There are two events available: `on_open` which is raised when the popup is opening, and `on_dismiss` which is raised when the popup is closed. For `on_dismiss`, you can prevent the popup from closing by explicitly returning True from your callback:: def my_callback(instance): print('Popup', instance, 'is being dismissed but is prevented!') return True popup = Popup(content=Label(text='Hello world')) popup.bind(on_dismiss=my_callback) popup.open() ''' __all__ = ('Popup', 'PopupException') from kivy.core.text import DEFAULT_FONT from kivy.uix.modalview import ModalView from kivy.properties import (StringProperty, ObjectProperty, OptionProperty, NumericProperty, ColorProperty) class PopupException(Exception): '''Popup exception, fired when multiple content widgets are added to the popup. .. versionadded:: 1.4.0 ''' class Popup(ModalView): '''Popup class. See module documentation for more information. :Events: `on_open`: Fired when the Popup is opened. `on_dismiss`: Fired when the Popup is closed. If the callback returns True, the dismiss will be canceled. ''' title = StringProperty('No title') '''String that represents the title of the popup. :attr:`title` is a :class:`~kivy.properties.StringProperty` and defaults to 'No title'. ''' title_size = NumericProperty('14sp') '''Represents the font size of the popup title. .. versionadded:: 1.6.0 :attr:`title_size` is a :class:`~kivy.properties.NumericProperty` and defaults to '14sp'. ''' title_align = OptionProperty( 'left', options=['left', 'center', 'right', 'justify']) '''Horizontal alignment of the title. .. versionadded:: 1.9.0 :attr:`title_align` is a :class:`~kivy.properties.OptionProperty` and defaults to 'left'. Available options are left, center, right and justify. ''' title_font = StringProperty(DEFAULT_FONT) '''Font used to render the title text. .. versionadded:: 1.9.0 :attr:`title_font` is a :class:`~kivy.properties.StringProperty` and defaults to 'Roboto'. This value is taken from :class:`~kivy.config.Config`. ''' content = ObjectProperty(None) '''Content of the popup that is displayed just under the title. :attr:`content` is an :class:`~kivy.properties.ObjectProperty` and defaults to None. ''' title_color = ColorProperty([1, 1, 1, 1]) '''Color used by the Title. .. versionadded:: 1.8.0 :attr:`title_color` is a :class:`~kivy.properties.ColorProperty` and defaults to [1, 1, 1, 1]. .. versionchanged:: 2.0.0 Changed from :class:`~kivy.properties.ListProperty` to :class:`~kivy.properties.ColorProperty`. ''' separator_color = ColorProperty([47 / 255., 167 / 255., 212 / 255., 1.]) '''Color used by the separator between title and content. .. versionadded:: 1.1.0 :attr:`separator_color` is a :class:`~kivy.properties.ColorProperty` and defaults to [47 / 255., 167 / 255., 212 / 255., 1.]. .. versionchanged:: 2.0.0 Changed from :class:`~kivy.properties.ListProperty` to :class:`~kivy.properties.ColorProperty`. ''' separator_height = NumericProperty('2dp') '''Height of the separator. .. versionadded:: 1.1.0 :attr:`separator_height` is a :class:`~kivy.properties.NumericProperty` and defaults to 2dp. ''' # Internal properties used for graphical representation. _container = ObjectProperty(None) def add_widget(self, widget, *args, **kwargs): if self._container: if self.content: raise PopupException( 'Popup can have only one widget as content') self.content = widget else: super(Popup, self).add_widget(widget, *args, **kwargs) 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(Popup, self).on_touch_down(touch) if __name__ == '__main__': from kivy.base import runTouchApp from kivy.uix.button import Button from kivy.uix.label import Label from kivy.uix.gridlayout import GridLayout from kivy.core.window import Window # add popup content = GridLayout(cols=1) content_cancel = Button(text='Cancel', size_hint_y=None, height=40) content.add_widget(Label(text='This is a hello world')) content.add_widget(content_cancel) popup = Popup(title='Test popup', size_hint=(None, None), size=(256, 256), content=content, disabled=True) content_cancel.bind(on_release=popup.dismiss) layout = GridLayout(cols=3) for x in range(9): btn = Button(text=str(x)) btn.bind(on_release=popup.open) layout.add_widget(btn) Window.add_widget(layout) popup.open() runTouchApp()