""" Components/Banner ================= .. seealso:: `Material Design spec, Banner `_ .. rubric:: A banner displays a prominent message and related optional actions. .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/banner.png :align: center Usage ===== .. code-block:: python from kivy.lang import Builder from kivy.factory import Factory from kivymd.app import MDApp Builder.load_string(''' MDBanner: id: banner text: ["One line string text example without actions."] # The widget that is under the banner. # It will be shifted down to the height of the banner. over_widget: screen vertical_pad: toolbar.height MDToolbar: id: toolbar title: "Example Banners" elevation: 10 pos_hint: {'top': 1} BoxLayout: id: screen orientation: "vertical" size_hint_y: None height: Window.height - toolbar.height OneLineListItem: text: "Banner without actions" on_release: banner.show() Widget: ''') class Test(MDApp): def build(self): return Factory.ExampleBanner() Test().run() .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/banner-example-1.gif :align: center .. rubric:: Banner type. By default, the banner is of the type ``'one-line'``: .. code-block:: kv MDBanner: text: ["One line string text example without actions."] .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/banner-one-line.png :align: center To use a two-line banner, specify the ``'two-line'`` :attr:`MDBanner.type` for the banner and pass the list of two lines to the :attr:`MDBanner.text` parameter: .. code-block:: kv MDBanner: type: "two-line" text: ["One line string text example without actions.", "This is the second line of the banner message."] .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/banner-two-line.png :align: center Similarly, create a three-line banner: .. code-block:: kv MDBanner: type: "three-line" text: ["One line string text example without actions.", "This is the second line of the banner message." "and this is the third line of the banner message."] .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/banner-three-line.png :align: center To add buttons to any type of banner, use the :attr:`MDBanner.left_action` and :attr:`MDBanner.right_action` parameters, which should take a list ['Button name', function]: .. code-block:: kv MDBanner: text: ["One line string text example without actions."] left_action: ["CANCEL", lambda x: None] Or two buttons: .. code-block:: kv MDBanner: text: ["One line string text example without actions."] left_action: ["CANCEL", lambda x: None] right_action: ["CLOSE", lambda x: None] .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/banner-actions.png :align: center If you want to use the icon on the left in the banner, add the prefix `'-icon'` to the banner type: .. code-block:: kv MDBanner: type: "one-line-icon" icon: f"{images_path}/kivymd.png" text: ["One line string text example without actions."] .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/banner-icon.png :align: center .. Note:: `See full example `_ """ __all__ = ("MDBanner",) from kivy.animation import Animation from kivy.clock import Clock from kivy.lang import Builder from kivy.metrics import dp from kivy.properties import ( ListProperty, NumericProperty, ObjectProperty, OptionProperty, StringProperty, ) from kivy.uix.widget import Widget from kivymd.uix.button import MDFlatButton from kivymd.uix.card import MDCard from kivymd.uix.list import ( OneLineAvatarListItem, OneLineListItem, ThreeLineAvatarListItem, ThreeLineListItem, TwoLineAvatarListItem, TwoLineListItem, ) Builder.load_string( """ #:import Window kivy.core.window.Window #:import Clock kivy.clock.Clock text: root.text_message[0] secondary_text: root.text_message[1] tertiary_text: root.text_message[2] divider: None _no_ripple_effect: True ImageLeftWidget: source: root.icon text: root.text_message[0] secondary_text: root.text_message[1] divider: None _no_ripple_effect: True ImageLeftWidget: source: root.icon text: root.text_message[0] divider: None _no_ripple_effect: True ImageLeftWidget: source: root.icon text: root.text_message[0] secondary_text: root.text_message[1] tertiary_text: root.text_message[2] divider: None _no_ripple_effect: True text: root.text_message[0] secondary_text: root.text_message[1] divider: None _no_ripple_effect: True text: root.text_message[0] divider: None _no_ripple_effect: True size_hint_y: None height: self.minimum_height banner_y: 0 orientation: "vertical" y: Window.height - self.banner_y canvas: Color: rgba: 0, 0, 0, 0 Rectangle: pos: self.pos size: self.size BoxLayout: id: container_message size_hint_y: None height: self.minimum_height BoxLayout: size_hint: None, None size: self.minimum_size pos_hint: {"right": 1} padding: 0, 0, "8dp", "8dp" spacing: "8dp" BoxLayout: id: left_action_box size_hint: None, None size: self.minimum_size BoxLayout: id: right_action_box size_hint: None, None size: self.minimum_size """ ) class MDBanner(MDCard): vertical_pad = NumericProperty(dp(68)) """ Indent the banner at the top of the screen. :attr:`vertical_pad` is an :class:`~kivy.properties.NumericProperty` and defaults to `dp(68)`. """ opening_transition = StringProperty("in_quad") """ The name of the animation transition. :attr:`opening_transition` is an :class:`~kivy.properties.StringProperty` and defaults to `'in_quad'`. """ icon = StringProperty("data/logo/kivy-icon-128.png") """Icon banner. :attr:`icon` is an :class:`~kivy.properties.StringProperty` and defaults to `'data/logo/kivy-icon-128.png'`. """ over_widget = ObjectProperty() """ The widget that is under the banner. It will be shifted down to the height of the banner. :attr:`over_widget` is an :class:`~kivy.properties.ObjectProperty` and defaults to `None`. """ text = ListProperty() """List of lines for banner text. Must contain no more than three lines for a `'one-line'`, `'two-line'` and `'three-line'` banner, respectively. :attr:`text` is an :class:`~kivy.properties.ListProperty` and defaults to `[]`. """ left_action = ListProperty() """The action of banner. To add one action, make a list [`'name_action'`, callback] where `'name_action'` is a string that corresponds to an action name and ``callback`` is the function called on a touch release event. :attr:`left_action` is an :class:`~kivy.properties.ListProperty` and defaults to `[]`. """ right_action = ListProperty() """Works the same way as :attr:`left_action`. :attr:`right_action` is an :class:`~kivy.properties.ListProperty` and defaults to `[]`. """ type = OptionProperty( "one-line", options=[ "one-line", "two-line", "three-line", "one-line-icon", "two-line-icon", "three-line-icon", ], allownone=True, ) """Banner type. . Available options are: (`"one-line"`, `"two-line"`, `"three-line"`, `"one-line-icon"`, `"two-line-icon"`, `"three-line-icon"`). :attr:`type` is an :class:`~kivy.properties.OptionProperty` and defaults to `'one-line'`. """ _type_message = None _progress = False def add_actions_buttons(self, box, data): if data: name_action_button, function_action_button = data action_button = MDFlatButton( text=f"[b]{name_action_button}[/b]", theme_text_color="Custom", text_color=self.theme_cls.primary_color, on_release=function_action_button, ) action_button.markup = True box.add_widget(action_button) def set_left_action(self): self.add_actions_buttons(self.ids.left_action_box, self.left_action) def set_right_action(self): self.add_actions_buttons(self.ids.right_action_box, self.right_action) def set_type_banner(self): self._type_message = { "three-line-icon": ThreeLineIconBanner, "two-line-icon": TwoLineIconBanner, "one-line-icon": OneLineIconBanner, "three-line": ThreeLineBanner, "two-line": TwoLineBanner, "one-line": OneLineBanner, }[self.type] def add_banner_to_container(self): self.ids.container_message.add_widget( self._type_message(text_message=self.text, icon=self.icon) ) def show(self): def show(interval): self.set_type_banner() self.set_left_action() self.set_right_action() self.add_banner_to_container() Clock.schedule_once(self.animation_display_banner, 0.1) if self._progress: return self._progress = True if self.ids.container_message.children: self.hide() Clock.schedule_once(show, 0.7) def animation_display_banner(self, i): Animation( banner_y=self.height + self.vertical_pad, d=0.15, t=self.opening_transition, ).start(self) anim = Animation( y=self.over_widget.y - self.height, d=0.15, t=self.opening_transition, ) anim.bind(on_complete=self._reset_progress) anim.start(self.over_widget) def hide(self): def hide(interval): anim = Animation(banner_y=0, d=0.15) anim.bind(on_complete=self._remove_banner) anim.start(self) Animation(y=self.over_widget.y + self.height, d=0.15).start( self.over_widget ) Clock.schedule_once(hide, 0.5) def _remove_banner(self, *args): self.ids.container_message.clear_widgets() self.ids.left_action_box.clear_widgets() self.ids.right_action_box.clear_widgets() def _reset_progress(self, *args): self._progress = False class BaseBanner(Widget): text_message = ListProperty(["", "", ""]) icon = StringProperty() def on_touch_down(self, touch): self.parent.parent.hide() class ThreeLineIconBanner(ThreeLineAvatarListItem, BaseBanner): pass class TwoLineIconBanner(TwoLineAvatarListItem, BaseBanner): pass class OneLineIconBanner(OneLineAvatarListItem, BaseBanner): pass class ThreeLineBanner(ThreeLineListItem, BaseBanner): pass class TwoLineBanner(TwoLineListItem, BaseBanner): pass class OneLineBanner(OneLineListItem, BaseBanner): pass