diff --git a/examples/widgets/bubble_test.py b/examples/widgets/bubble_test.py index 83a53f87a..7032a7ea6 100644 --- a/examples/widgets/bubble_test.py +++ b/examples/widgets/bubble_test.py @@ -14,10 +14,8 @@ from kivy.uix.bubble import Bubble Builder.load_string(''' size_hint: (None, None) - size: (150, 50) + size: (160, 120) pos_hint: {'center_x': .5, 'y': .6} - arrow_pos: 'bottom_mid' - orientation: 'horizontal' BubbleButton: text: 'Cut' BubbleButton: diff --git a/kivy/uix/bubble.py b/kivy/uix/bubble.py index f4fafd1f5..340ad9945 100644 --- a/kivy/uix/bubble.py +++ b/kivy/uix/bubble.py @@ -61,9 +61,11 @@ from kivy.uix.image import Image from kivy.uix.widget import Widget from kivy.uix.scatter import Scatter from kivy.uix.gridlayout import GridLayout +from kivy.uix.boxlayout import BoxLayout from kivy.uix.button import Button from kivy.properties import ObjectProperty, StringProperty, OptionProperty, \ - ListProperty + ListProperty, BooleanProperty +from kivy.clock import Clock from kivy.base import EventLoop @@ -120,6 +122,15 @@ class Bubble(GridLayout): default to 'atlas://data/images/defaulttheme/bubble_arrow'. ''' + show_arrow = BooleanProperty(True) + ''' Indicates whether to show arrow. + + .. versionadded:: 1.8.0 + + :data:`show_arrow` is a :class:`~kivy.properties.BooleanProperty`, + default to `True`. + ''' + arrow_pos = OptionProperty('bottom_mid', options=('left_top', 'left_mid', 'left_bottom', 'top_left', 'top_mid', 'top_right', 'right_top', 'right_mid', @@ -159,7 +170,7 @@ class Bubble(GridLayout): def __init__(self, **kwargs): self._prev_arrow_pos = None - self._arrow_layout = GridLayout(rows=1) + self._arrow_layout = BoxLayout() self._bk_img = Image( source=self.background_image, allow_stretch=True, keep_ratio=False, color=self.background_color) @@ -170,7 +181,6 @@ class Bubble(GridLayout): super(Bubble, self).__init__(**kwargs) content.parent = None self.add_widget(content) - self.arrow_pos = kwargs.get('arrow_pos', 'bottom_mid') self.on_arrow_pos() def add_widget(self, *l): @@ -202,6 +212,12 @@ class Bubble(GridLayout): else: content.clear_widgets() + def on_show_arrow(self, instance, value): + self._arrow_img.opacity = int(value) + + def on_parent(self, instance, value): + Clock.schedule_once(self._update_arrow) + def on_pos(self, instance, pos): lt = self.limit_to if lt and lt is not object: @@ -240,9 +256,12 @@ class Bubble(GridLayout): def on_arrow_pos(self, *l): self_content = self.content - if not (self_content and self.canvas): + if not self_content: + Clock.schedule_once(self.on_arrow_pos) + return + if self_content not in self.children: + Clock.schedule_once(self.on_arrow_pos) return - self_arrow_pos = self.arrow_pos if self._prev_arrow_pos == self_arrow_pos: return @@ -251,13 +270,13 @@ class Bubble(GridLayout): self_arrow_layout = self._arrow_layout self_arrow_layout.clear_widgets() self_arrow_img = self._arrow_img - self_arrow_img.pos = (0, 0) - + self._sctr = self._arrow_img self.clear_widgets(do_super=True) self_content.parent = None self_arrow_img.size_hint = (1, None) self_arrow_img.height = self_arrow_img.texture_size[1] + self_arrow_img.pos = 0, 0 widget_list = [] arrow_list = [] parent = self_arrow_img.parent @@ -266,9 +285,8 @@ class Bubble(GridLayout): if self_arrow_pos[0] == 'b' or self_arrow_pos[0] == 't': self.cols = 1 - self.rows = 2 - self_arrow_layout.rows = 1 - self_arrow_layout.cols = 3 + self.rows = 3 + self_arrow_layout.orientation = 'horizontal' self_arrow_img.width = self.width / 3 self_arrow_layout.size_hint = (1, None) self_arrow_layout.height = self_arrow_img.height @@ -299,30 +317,30 @@ class Bubble(GridLayout): arrow_list = (Widget(), Widget(), sctr) widget_list = (self_arrow_layout, self_content) elif self_arrow_pos[0] == 'l' or self_arrow_pos[0] == 'r': - self.cols = 2 + self.cols = 3 self.rows = 1 self_arrow_img.width = self.height / 3 - self_arrow_layout.rows = 3 + self_arrow_layout.orientation = 'vertical' self_arrow_layout.cols = 1 self_arrow_layout.size_hint = (None, 1) self_arrow_layout.width = self_arrow_img.height rotation = -90 if self_arrow_pos[0] == 'l' else 90 - sctr = Scatter(do_translation=False, - rotation=rotation, - do_rotation=False, - do_scale=False, - size_hint=(None, None), - size=self_arrow_img.size) + self._sctr = sctr = Scatter(do_translation=False, + rotation=rotation, + do_rotation=False, + do_scale=False, + size_hint=(None, None), + size=(self_arrow_img.size)) sctr.add_widget(self_arrow_img) - lenarrow_pos = len(self_arrow_pos) - if self_arrow_pos[lenarrow_pos - 4:] == '_top': + if self_arrow_pos[-4:] == '_top': arrow_list = (Widget(size_hint=(1, .07)), sctr, Widget(size_hint=(1, .3))) - elif self_arrow_pos[lenarrow_pos - 4:] == '_mid': + elif self_arrow_pos[-4:] == '_mid': arrow_list = (Widget(), sctr, Widget()) - elif self_arrow_pos[lenarrow_pos - 7:] == '_bottom': + Clock.schedule_once(self._update_arrow) + elif self_arrow_pos[-7:] == '_bottom': arrow_list = (Widget(), Widget(), sctr) if self_arrow_pos[0] == 'l': @@ -340,3 +358,6 @@ class Bubble(GridLayout): for widg in widget_list: add(widg) + def _update_arrow(self, *dt): + if self.arrow_pos in ('left_mid', 'right_mid'): + self._sctr.center_y = self._arrow_layout.center_y