diff src/libs/garden/garden.contextmenu/app_menu.py @ 83:741a7d6d8c28

garden: added contextmenu
author Goffi <goffi@goffi.org>
date Sat, 24 Dec 2016 14:16:58 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/libs/garden/garden.contextmenu/app_menu.py	Sat Dec 24 14:16:58 2016 +0100
@@ -0,0 +1,117 @@
+from kivy.uix.relativelayout import RelativeLayout
+from kivy.uix.stacklayout import StackLayout
+from kivy.uix.behaviors import ToggleButtonBehavior
+from kivy.uix.togglebutton import ToggleButton
+from kivy.lang import Builder
+import kivy.properties as kp
+import os
+
+from .context_menu import AbstractMenu, AbstractMenuItem, AbstractMenuItemHoverable
+
+
+class AppMenu(StackLayout, AbstractMenu):
+    bounding_box = kp.ObjectProperty(None)
+
+    def __init__(self, *args, **kwargs):
+        super(AppMenu, self).__init__(*args, **kwargs)
+        self.hovered_menu_item = None
+
+    def update_height(self):
+        max_height = 0
+        for widget in self.menu_item_widgets:
+            if widget.height > max_height:
+                max_height = widget.height
+        return max_height
+
+    def on_children(self, obj, new_children):
+        for w in new_children:
+            # bind events that update app menu height when any of its children resize
+            w.bind(on_size=self.update_height)
+            w.bind(on_height=self.update_height)
+
+    def get_context_menu_root_parent(self):
+        return self
+
+    def self_or_submenu_collide_with_point(self, x, y):
+        collide_widget = None
+
+        # Iterate all siblings and all children
+        for widget in self.menu_item_widgets:
+            widget_pos = widget.to_window(0, 0)
+            if widget.collide_point(x - widget_pos[0], y - widget_pos[1]) and not widget.disabled:
+                if self.hovered_menu_item is None:
+                    self.hovered_menu_item = widget
+
+                if self.hovered_menu_item != widget:
+                    self.hovered_menu_item = widget
+                    for sibling in widget.siblings:
+                        sibling.state = 'normal'
+
+                    if widget.state == 'normal':
+                        widget.state = 'down'
+                        widget.on_release()
+
+                    for sib in widget.siblings:
+                        sib.hovered = False
+            elif widget.get_submenu() is not None and not widget.get_submenu().visible:
+                widget.state = 'normal'
+
+        return collide_widget
+
+    def close_all(self):
+        for submenu in [w.get_submenu() for w in self.menu_item_widgets if w.get_submenu() is not None]:
+            submenu.hide()
+        for w in self.menu_item_widgets:
+            w.state = 'normal'
+
+    def hide_app_menus(self, obj, pos):
+        if not self.collide_point(pos.x, pos.y):
+            for w in [w for w in self.menu_item_widgets if not w.disabled and w.get_submenu().visible]:
+                submenu = w.get_submenu()
+                if submenu.self_or_submenu_collide_with_point(pos.x, pos.y) is None:
+                    self.close_all()
+                    self._cancel_hover_timer()
+
+
+class AppMenuTextItem(ToggleButton, AbstractMenuItem):
+    label = kp.ObjectProperty(None)
+    text = kp.StringProperty('')
+    font_size = kp.NumericProperty(14)
+    color = kp.ListProperty([1, 1, 1, 1])
+
+    def on_release(self):
+        submenu = self.get_submenu()
+
+        if self.state == 'down':
+            root = self._root_parent
+            submenu.bounding_box_widget = root.bounding_box if root.bounding_box else root.parent
+
+            submenu.bind(visible=self.on_visible)
+            submenu.show(self.x, self.y - 1)
+
+            for sibling in self.siblings:
+                if sibling.get_submenu() is not None:
+                    sibling.state = 'normal'
+                    sibling.get_submenu().hide()
+
+            self.parent._setup_hover_timer()
+        else:
+            self.parent._cancel_hover_timer()
+            submenu.hide()
+
+    def on_visible(self, *args):
+        submenu = self.get_submenu()
+        if self.width > submenu.get_max_width():
+            submenu.width = self.width
+
+    def _check_submenu(self):
+        super(AppMenuTextItem, self)._check_submenu()
+        self.disabled = (self.get_submenu() is None)
+
+    # def on_mouse_down(self):
+    #     print('on_mouse_down')
+    #     return True
+
+
+_path = os.path.dirname(os.path.realpath(__file__))
+Builder.load_file(os.path.join(_path, 'app_menu.kv'))