annotate src/libs/garden/garden.contextmenu/context_menu.py @ 97:5d2289127bb7

menu (upload): better menu using dedicated widget: upload menu now use a decicated widget instead of context menu. The menu take half the size of the main window, and show each upload option as an icon. Use can select upload or P2P sending, and a short text message explains how the file will be transmitted.
author Goffi <goffi@goffi.org>
date Thu, 29 Dec 2016 23:47:07 +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'))