annotate src/libs/garden/garden.contextmenu/context_menu.py @ 88:3dc526bb4a5a

upload: plugin android gallery, first draft: - added "external" key in PLUGIN_INFO which indicate that a plugin doesn't create a widget when set to True - callback and cancel_cb method in UploadMenu now use a cleaning_cb arguments which can be None. If set, the callback will be called without argument once the file is uploaded - the AndroidGallery plugin looks for images on Android, then save the content to a temporary file an upload it, then clean the file. This plugin is only active on android platform.
author Goffi <goffi@goffi.org>
date Sun, 25 Dec 2016 22:53:50 +0100
parents 2caee196d19a
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
83
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
1 from kivy.uix.gridlayout import GridLayout
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
2 from kivy.uix.relativelayout import RelativeLayout
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
3 from kivy.core.window import Window
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
4 from kivy.uix.behaviors import ButtonBehavior
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
5 from kivy.lang import Builder
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
6 from kivy.clock import Clock
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
7 from functools import partial
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
8
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
9 import kivy.properties as kp
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
10 import os
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
11
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
12
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
13 class AbstractMenu(object):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
14 cancel_handler_widget = kp.ObjectProperty(None)
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
15 bounding_box_widget = kp.ObjectProperty(None)
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
16
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
17 def __init__(self, *args, **kwargs):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
18 self.clock_event = None
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
19
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
20 def add_item(self, widget):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
21 self.add_widget(widget)
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
22
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
23 def add_text_item(self, text, on_release=None):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
24 item = ContextMenuTextItem(text=text)
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
25 if on_release:
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
26 item.bind(on_release=on_release)
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
27 self.add_item(item)
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
28
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
29 def get_height(self):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
30 height = 0
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
31 for widget in self.children:
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
32 height += widget.height
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
33 return height
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
34
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
35 def hide_submenus(self):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
36 for widget in self.menu_item_widgets:
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
37 widget.hovered = False
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
38 widget.hide_submenu()
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
39
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
40 def self_or_submenu_collide_with_point(self, x, y):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
41 raise NotImplementedError()
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
42
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
43 def on_cancel_handler_widget(self, obj, widget):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
44 self.cancel_handler_widget.bind(on_touch_down=self.hide_app_menus)
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
45
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
46 def hide_app_menus(self, obj, pos):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
47 raise NotImplementedError()
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
48
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
49 @property
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
50 def menu_item_widgets(self):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
51 """
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
52 Return all children that are subclasses of ContextMenuItem
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
53 """
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
54 return [w for w in self.children if issubclass(w.__class__, AbstractMenuItem)]
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
55
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
56 def _setup_hover_timer(self):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
57 if self.clock_event is None:
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
58 self.clock_event = Clock.schedule_interval(partial(self._check_mouse_hover), 0.05)
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
59
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
60 def _check_mouse_hover(self, obj):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
61 self.self_or_submenu_collide_with_point(*Window.mouse_pos)
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
62
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
63 def _cancel_hover_timer(self):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
64 if self.clock_event:
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
65 self.clock_event.cancel()
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
66 self.clock_event = None
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
67
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
68
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
69 class ContextMenu(GridLayout, AbstractMenu):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
70 visible = kp.BooleanProperty(False)
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
71 spacer = kp.ObjectProperty(None)
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
72
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
73 def __init__(self, *args, **kwargs):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
74 super(ContextMenu, self).__init__(*args, **kwargs)
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
75 self.orig_parent = None
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
76 # self._on_visible(False)
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
77
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
78 def hide(self):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
79 self.visible = False
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
80
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
81 def show(self, x=None, y=None):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
82 self.visible = True
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
83 self._add_to_parent()
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
84 self.hide_submenus()
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
85
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
86 root_parent = self.bounding_box_widget if self.bounding_box_widget is not None else self.get_context_menu_root_parent()
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
87 if root_parent is None:
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
88 return
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
89
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
90 point_relative_to_root = root_parent.to_local(*self.to_window(x, y))
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
91
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
92 # Choose the best position to open the menu
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
93 if x is not None and y is not None:
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
94 if point_relative_to_root[0] + self.width < root_parent.width:
84
2caee196d19a garden: context menu fixes:
Goffi <goffi@goffi.org>
parents: 83
diff changeset
95 pos_x = x
83
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
96 else:
84
2caee196d19a garden: context menu fixes:
Goffi <goffi@goffi.org>
parents: 83
diff changeset
97 pos_x = x - self.width
83
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
98 if issubclass(self.parent.__class__, AbstractMenuItem):
84
2caee196d19a garden: context menu fixes:
Goffi <goffi@goffi.org>
parents: 83
diff changeset
99 pos_x -= self.parent.width
83
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
100
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
101 if point_relative_to_root[1] - self.height < 0:
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
102 pos_y = y
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
103 if issubclass(self.parent.__class__, AbstractMenuItem):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
104 pos_y -= self.parent.height + self.spacer.height
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
105 else:
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
106 pos_y = y - self.height
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
107
84
2caee196d19a garden: context menu fixes:
Goffi <goffi@goffi.org>
parents: 83
diff changeset
108 self.pos = pos_x, pos_y
83
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
109
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
110 def self_or_submenu_collide_with_point(self, x, y):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
111 queue = self.menu_item_widgets
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
112 collide_widget = None
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
113
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
114 # Iterate all siblings and all children
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
115 while len(queue) > 0:
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
116 widget = queue.pop(0)
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
117 submenu = widget.get_submenu()
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
118 if submenu is not None and widget.hovered:
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
119 queue += submenu.menu_item_widgets
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
120
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
121 widget_pos = widget.to_window(0, 0)
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
122 if widget.collide_point(x - widget_pos[0], y - widget_pos[1]) and not widget.disabled:
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
123 widget.hovered = True
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
124
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
125 collide_widget = widget
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
126 for sib in widget.siblings:
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
127 sib.hovered = False
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
128 elif submenu and submenu.visible:
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
129 widget.hovered = True
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
130 else:
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
131 widget.hovered = False
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
132
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
133 return collide_widget
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
134
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
135 def _on_visible(self, new_visibility):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
136 if new_visibility:
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
137 self.size = self.get_max_width(), self.get_height()
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
138 self._add_to_parent()
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
139 # @todo: Do we need to remove self from self.parent.__context_menus? Probably not.
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
140
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
141 elif self.parent and not new_visibility:
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
142 self.orig_parent = self.parent
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
143
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
144 '''
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
145 We create a set that holds references to all context menus in the parent widget.
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
146 It's necessary to keep at least one reference to this context menu. Otherwise when
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
147 removed from parent it might get de-allocated by GC.
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
148 '''
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
149 if not hasattr(self.parent, '_ContextMenu__context_menus'):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
150 self.parent.__context_menus = set()
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
151 self.parent.__context_menus.add(self)
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
152
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
153 self.parent.remove_widget(self)
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
154 self.hide_submenus()
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
155 self._cancel_hover_timer()
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
156
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
157 def _add_to_parent(self):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
158 if not self.parent:
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
159 self.orig_parent.add_widget(self)
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
160 self.orig_parent = None
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
161
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
162 # Create the timer on the outer most menu object
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
163 if self._get_root_context_menu() == self:
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
164 self._setup_hover_timer()
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
165
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
166 def get_max_width(self):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
167 max_width = 0
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
168 for widget in self.menu_item_widgets:
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
169 width = widget.content_width if widget.content_width is not None else widget.width
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
170 if width is not None and width > max_width:
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
171 max_width = width
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
172
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
173 return max_width
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
174
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
175 def get_context_menu_root_parent(self):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
176 """
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
177 Return the bounding box widget for positioning sub menus. By default it's root context menu's parent.
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
178 """
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
179 if self.bounding_box_widget is not None:
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
180 return self.bounding_box_widget
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
181 root_context_menu = self._get_root_context_menu()
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
182 return root_context_menu.bounding_box_widget if root_context_menu.bounding_box_widget else root_context_menu.parent
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
183
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
184 def _get_root_context_menu(self):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
185 """
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
186 Return the outer most context menu object
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
187 """
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
188 root = self
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
189 while issubclass(root.parent.__class__, ContextMenuItem) \
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
190 or issubclass(root.parent.__class__, ContextMenu):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
191 root = root.parent
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
192 return root
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
193
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
194 def hide_app_menus(self, obj, pos):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
195 return self.self_or_submenu_collide_with_point(pos.x, pos.y) is None and self.hide()
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
196
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
197
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
198 class AbstractMenuItem(object):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
199 submenu = kp.ObjectProperty(None)
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
200
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
201 def get_submenu(self):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
202 return self.submenu if self.submenu != "" else None
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
203
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
204 def show_submenu(self, x=None, y=None):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
205 if self.get_submenu():
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
206 self.get_submenu().show(*self._root_parent.to_local(x, y))
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
207
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
208 def hide_submenu(self):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
209 submenu = self.get_submenu()
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
210 if submenu:
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
211 submenu.visible = False
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
212 submenu.hide_submenus()
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
213
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
214 def _check_submenu(self):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
215 if self.parent is not None and len(self.children) > 0:
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
216 submenus = [w for w in self.children if issubclass(w.__class__, ContextMenu)]
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
217 if len(submenus) > 1:
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
218 raise Exception('Menu item (ContextMenuItem) can have maximum one submenu (ContextMenu)')
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
219 elif len(submenus) == 1:
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
220 self.submenu = submenus[0]
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
221
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
222 @property
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
223 def siblings(self):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
224 return [w for w in self.parent.children if issubclass(w.__class__, AbstractMenuItem) and w != self]
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
225
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
226 @property
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
227 def content_width(self):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
228 return None
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
229
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
230 @property
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
231 def _root_parent(self):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
232 return self.parent.get_context_menu_root_parent()
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
233
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
234
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
235 class ContextMenuItem(RelativeLayout, AbstractMenuItem):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
236 submenu_arrow = kp.ObjectProperty(None)
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
237
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
238 def _check_submenu(self):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
239 super(ContextMenuItem, self)._check_submenu()
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
240 if self.get_submenu() is None:
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
241 self.submenu_arrow.opacity = 0
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
242 else:
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
243 self.submenu_arrow.opacity = 1
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
244
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
245
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
246 class AbstractMenuItemHoverable(object):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
247 hovered = kp.BooleanProperty(False)
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
248
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
249 def _on_hovered(self, new_hovered):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
250 if new_hovered:
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
251 spacer_height = self.parent.spacer.height if self.parent.spacer else 0
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
252 self.show_submenu(self.width, self.height + spacer_height)
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
253 else:
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
254 self.hide_submenu()
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
255
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
256
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
257 class ContextMenuText(ContextMenuItem):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
258 label = kp.ObjectProperty(None)
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
259 submenu_postfix = kp.StringProperty(' ...')
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
260 text = kp.StringProperty('')
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
261 font_size = kp.NumericProperty(14)
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
262 color = kp.ListProperty([1,1,1,1])
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
263
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
264 def __init__(self, *args, **kwargs):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
265 super(ContextMenuText, self).__init__(*args, **kwargs)
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
266
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
267 @property
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
268 def content_width(self):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
269 # keep little space for eventual arrow for submenus
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
270 return self.label.texture_size[0] + 10
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
271
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
272
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
273 class ContextMenuDivider(ContextMenuText):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
274 pass
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
275
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
276
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
277 class ContextMenuTextItem(ButtonBehavior, ContextMenuText, AbstractMenuItemHoverable):
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
278 pass
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
279
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
280
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
281 _path = os.path.dirname(os.path.realpath(__file__))
741a7d6d8c28 garden: added contextmenu
Goffi <goffi@goffi.org>
parents:
diff changeset
282 Builder.load_file(os.path.join(_path, 'context_menu.kv'))