Mercurial > libervia-desktop-kivy
annotate cagou/core/menu.py @ 260:145c29b5f2b5
core: improved getOrClone + use in chat and widgets_handler:
- getOrClone is now trying to re-use others instances of a widget if they have no parent, and will create a new widget only if nothing is found
- it is now used in widgets_handler's changeWidget
- it is now used in Chat factory, on existing widget
- new host method deleteUnusedWidgetInstances remove instances without parent. It is used by getOrClone.
author | Goffi <goffi@goffi.org> |
---|---|
date | Mon, 11 Mar 2019 08:39:43 +0100 |
parents | 15e47bbb192c |
children | 1b835bcfa663 |
rev | line source |
---|---|
51 | 1 #!/usr/bin/python |
2 # -*- coding: utf-8 -*- | |
3 | |
4 # Cagou: desktop/mobile frontend for Salut à Toi XMPP client | |
126 | 5 # Copyright (C) 2016-2018 Jérôme Poisson (goffi@goffi.org) |
51 | 6 |
7 # This program is free software: you can redistribute it and/or modify | |
8 # it under the terms of the GNU Affero General Public License as published by | |
9 # the Free Software Foundation, either version 3 of the License, or | |
10 # (at your option) any later version. | |
11 | |
12 # This program is distributed in the hope that it will be useful, | |
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 # GNU Affero General Public License for more details. | |
16 | |
17 # You should have received a copy of the GNU Affero General Public License | |
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
19 | |
20 | |
21 from sat.core.i18n import _ | |
22 from sat.core import log as logging | |
23 log = logging.getLogger(__name__) | |
24 from cagou.core.constants import Const as C | |
197
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
25 from cagou.core.common import JidToggle |
85
c2a7234d13d2
menu: use of garden's contextmenu for menus
Goffi <goffi@goffi.org>
parents:
53
diff
changeset
|
26 from kivy.uix.boxlayout import BoxLayout |
51 | 27 from kivy.uix.label import Label |
28 from kivy.uix.popup import Popup | |
197
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
29 from cagou.core.utils import FilterBehavior |
51 | 30 from kivy import properties |
222 | 31 from kivy.garden import contextmenu, modernmenu |
51 | 32 from sat_frontends.quick_frontend import quick_menus |
168
397f2fb67aab
core (menu): animate transfer menu opening/closing + close it on [ESC]/back
Goffi <goffi@goffi.org>
parents:
126
diff
changeset
|
33 from kivy.core.window import Window |
397f2fb67aab
core (menu): animate transfer menu opening/closing + close it on [ESC]/back
Goffi <goffi@goffi.org>
parents:
126
diff
changeset
|
34 from kivy.animation import Animation |
197
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
35 from kivy.metrics import dp |
222 | 36 from kivy.clock import Clock |
51 | 37 from cagou import G |
222 | 38 from functools import partial |
51 | 39 import webbrowser |
40 | |
41 ABOUT_TITLE = _(u"About {}".format(C.APP_NAME)) | |
184
c63922860f80
chat: show desktop notification and/or note when suitable
Goffi <goffi@goffi.org>
parents:
173
diff
changeset
|
42 ABOUT_CONTENT = _(u"""Cagou (Salut à Toi) v{version} |
51 | 43 |
44 Cagou is a libre communication tool based on libre standard XMPP. | |
45 | |
46 Cagou is part of the "Salut à Toi" project | |
47 more informations at [color=5500ff][ref=website]salut-a-toi.org[/ref][/color] | |
246 | 48 """) |
51 | 49 |
50 | |
51 class AboutContent(Label): | |
52 | |
53 def on_ref_press(self, value): | |
54 if value == "website": | |
55 webbrowser.open("https://salut-a-toi.org") | |
56 | |
57 | |
58 class AboutPopup(Popup): | |
59 | |
60 def on_touch_down(self, touch): | |
61 if self.collide_point(*touch.pos): | |
62 self.dismiss() | |
63 return super(AboutPopup, self).on_touch_down(touch) | |
64 | |
65 | |
85
c2a7234d13d2
menu: use of garden's contextmenu for menus
Goffi <goffi@goffi.org>
parents:
53
diff
changeset
|
66 class MainMenu(contextmenu.AppMenu): |
c2a7234d13d2
menu: use of garden's contextmenu for menus
Goffi <goffi@goffi.org>
parents:
53
diff
changeset
|
67 pass |
c2a7234d13d2
menu: use of garden's contextmenu for menus
Goffi <goffi@goffi.org>
parents:
53
diff
changeset
|
68 |
c2a7234d13d2
menu: use of garden's contextmenu for menus
Goffi <goffi@goffi.org>
parents:
53
diff
changeset
|
69 |
c2a7234d13d2
menu: use of garden's contextmenu for menus
Goffi <goffi@goffi.org>
parents:
53
diff
changeset
|
70 class MenuItem(contextmenu.ContextMenuTextItem): |
51 | 71 item = properties.ObjectProperty() |
72 | |
73 def on_item(self, instance, item): | |
74 self.text = item.name | |
75 | |
76 def on_release(self): | |
85
c2a7234d13d2
menu: use of garden's contextmenu for menus
Goffi <goffi@goffi.org>
parents:
53
diff
changeset
|
77 super(MenuItem, self).on_release() |
c2a7234d13d2
menu: use of garden's contextmenu for menus
Goffi <goffi@goffi.org>
parents:
53
diff
changeset
|
78 self.parent.hide() |
51 | 79 selected = G.host.selected_widget |
80 profile = None | |
81 if selected is not None: | |
82 try: | |
222 | 83 # FIXME: handle multi-profiles |
84 profile = next(iter(selected.profiles)) | |
51 | 85 except AttributeError: |
86 pass | |
87 | |
88 if profile is None: | |
89 try: | |
90 profile = list(selected.profiles)[0] | |
91 except (AttributeError, IndexError): | |
92 try: | |
93 profile = list(G.host.profiles)[0] | |
94 except IndexError: | |
95 log.warning(u"Can't find profile") | |
96 self.item.call(selected, profile) | |
97 | |
98 | |
85
c2a7234d13d2
menu: use of garden's contextmenu for menus
Goffi <goffi@goffi.org>
parents:
53
diff
changeset
|
99 class MenuSeparator(contextmenu.ContextMenuDivider): |
51 | 100 pass |
101 | |
102 | |
85
c2a7234d13d2
menu: use of garden's contextmenu for menus
Goffi <goffi@goffi.org>
parents:
53
diff
changeset
|
103 class RootMenuContainer(contextmenu.AppMenuTextItem): |
c2a7234d13d2
menu: use of garden's contextmenu for menus
Goffi <goffi@goffi.org>
parents:
53
diff
changeset
|
104 pass |
51 | 105 |
106 | |
85
c2a7234d13d2
menu: use of garden's contextmenu for menus
Goffi <goffi@goffi.org>
parents:
53
diff
changeset
|
107 class MenuContainer(contextmenu.ContextMenuTextItem): |
c2a7234d13d2
menu: use of garden's contextmenu for menus
Goffi <goffi@goffi.org>
parents:
53
diff
changeset
|
108 pass |
51 | 109 |
110 | |
85
c2a7234d13d2
menu: use of garden's contextmenu for menus
Goffi <goffi@goffi.org>
parents:
53
diff
changeset
|
111 class MenusWidget(BoxLayout): |
51 | 112 |
113 def update(self, type_, caller=None): | |
114 """Method to call when menus have changed | |
115 | |
116 @param type_(unicode): menu type like in sat.core.sat_main.importMenu | |
117 @param caller(Widget): instance linked to the menus | |
118 """ | |
119 self.menus_container = G.host.menus.getMainContainer(type_) | |
120 self.createMenus(caller) | |
121 | |
122 def _buildMenus(self, container, caller=None): | |
123 """Recursively build menus of the container | |
124 | |
125 @param container(quick_menus.MenuContainer): menu container | |
126 @param caller(Widget): instance linked to the menus | |
127 """ | |
128 if caller is None: | |
85
c2a7234d13d2
menu: use of garden's contextmenu for menus
Goffi <goffi@goffi.org>
parents:
53
diff
changeset
|
129 main_menu = MainMenu() |
c2a7234d13d2
menu: use of garden's contextmenu for menus
Goffi <goffi@goffi.org>
parents:
53
diff
changeset
|
130 self.add_widget(main_menu) |
c2a7234d13d2
menu: use of garden's contextmenu for menus
Goffi <goffi@goffi.org>
parents:
53
diff
changeset
|
131 caller = main_menu |
c2a7234d13d2
menu: use of garden's contextmenu for menus
Goffi <goffi@goffi.org>
parents:
53
diff
changeset
|
132 else: |
c2a7234d13d2
menu: use of garden's contextmenu for menus
Goffi <goffi@goffi.org>
parents:
53
diff
changeset
|
133 context_menu = contextmenu.ContextMenu() |
c2a7234d13d2
menu: use of garden's contextmenu for menus
Goffi <goffi@goffi.org>
parents:
53
diff
changeset
|
134 caller.add_widget(context_menu) |
222 | 135 # FIXME: next line is needed after parent is set to avoid |
136 # a display bug in contextmenu | |
85
c2a7234d13d2
menu: use of garden's contextmenu for menus
Goffi <goffi@goffi.org>
parents:
53
diff
changeset
|
137 # TODO: fix this upstream |
c2a7234d13d2
menu: use of garden's contextmenu for menus
Goffi <goffi@goffi.org>
parents:
53
diff
changeset
|
138 context_menu._on_visible(False) |
c2a7234d13d2
menu: use of garden's contextmenu for menus
Goffi <goffi@goffi.org>
parents:
53
diff
changeset
|
139 |
c2a7234d13d2
menu: use of garden's contextmenu for menus
Goffi <goffi@goffi.org>
parents:
53
diff
changeset
|
140 caller = context_menu |
c2a7234d13d2
menu: use of garden's contextmenu for menus
Goffi <goffi@goffi.org>
parents:
53
diff
changeset
|
141 |
51 | 142 for child in container.getActiveMenus(): |
143 if isinstance(child, quick_menus.MenuContainer): | |
85
c2a7234d13d2
menu: use of garden's contextmenu for menus
Goffi <goffi@goffi.org>
parents:
53
diff
changeset
|
144 if isinstance(caller, MainMenu): |
c2a7234d13d2
menu: use of garden's contextmenu for menus
Goffi <goffi@goffi.org>
parents:
53
diff
changeset
|
145 menu_container = RootMenuContainer() |
c2a7234d13d2
menu: use of garden's contextmenu for menus
Goffi <goffi@goffi.org>
parents:
53
diff
changeset
|
146 else: |
c2a7234d13d2
menu: use of garden's contextmenu for menus
Goffi <goffi@goffi.org>
parents:
53
diff
changeset
|
147 menu_container = MenuContainer() |
51 | 148 menu_container.text = child.name |
149 caller.add_widget(menu_container) | |
150 self._buildMenus(child, caller=menu_container) | |
151 elif isinstance(child, quick_menus.MenuSeparator): | |
152 wid = MenuSeparator() | |
153 caller.add_widget(wid) | |
154 elif isinstance(child, quick_menus.MenuItem): | |
155 wid = MenuItem(item=child) | |
156 caller.add_widget(wid) | |
157 else: | |
158 log.error(u"Unknown child type: {}".format(child)) | |
159 | |
160 def createMenus(self, caller): | |
161 self.clear_widgets() | |
162 self._buildMenus(self.menus_container, caller) | |
163 | |
164 def onAbout(self): | |
165 about = AboutPopup() | |
166 about.title = ABOUT_TITLE | |
246 | 167 about.content = AboutContent(text=ABOUT_CONTENT.format(version=G.host.version), |
168 markup=True) | |
51 | 169 about.open() |
86 | 170 |
171 | |
97
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
172 class TransferItem(BoxLayout): |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
173 plug_info = properties.DictProperty() |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
174 |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
175 def on_touch_up(self, touch): |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
176 if not self.collide_point(*touch.pos): |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
177 return super(TransferItem, self).on_touch_up(touch) |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
178 else: |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
179 transfer_menu = self.parent |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
180 while not isinstance(transfer_menu, TransferMenu): |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
181 transfer_menu = transfer_menu.parent |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
182 transfer_menu.do_callback(self.plug_info) |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
183 return True |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
184 |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
185 |
197
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
186 class SideMenu(BoxLayout): |
216
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
187 size_hint_close = (0, 1) |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
188 size_hint_open = (0.4, 1) |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
189 size_close = (100, 100) |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
190 size_open = (0, 0) |
197
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
191 bg_color = properties.ListProperty([0, 0, 0, 1]) |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
192 # callback will be called with arguments relevant to menu |
86 | 193 callback = properties.ObjectProperty() |
197
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
194 # call do_callback even when menu is cancelled |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
195 callback_on_close = properties.BooleanProperty(False) |
86 | 196 # cancel callback need to remove the widget for UI |
197 # will be called with the widget to remove as argument | |
198 cancel_cb = properties.ObjectProperty() | |
199 | |
200 def __init__(self, **kwargs): | |
197
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
201 super(SideMenu, self).__init__(**kwargs) |
86 | 202 if self.cancel_cb is None: |
197
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
203 self.cancel_cb = self.onMenuCancelled |
86 | 204 |
216
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
205 def _set_anim_kw(self, kw, size_hint, size): |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
206 """Set animation keywords |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
207 |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
208 for each value of size_hint it is used if not None, |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
209 else size is used. |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
210 If one value of size is bigger than the respective one of Window |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
211 the one of Window is used |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
212 """ |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
213 size_hint_x, size_hint_y = size_hint |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
214 width, height = size |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
215 if size_hint_x is not None: |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
216 kw['size_hint_x'] = size_hint_x |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
217 elif width is not None: |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
218 kw['width'] = min(width, Window.width) |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
219 |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
220 if size_hint_y is not None: |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
221 kw['size_hint_y'] = size_hint_y |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
222 elif height is not None: |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
223 kw['height'] = min(height, Window.height) |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
224 |
86 | 225 def show(self, caller_wid=None): |
168
397f2fb67aab
core (menu): animate transfer menu opening/closing + close it on [ESC]/back
Goffi <goffi@goffi.org>
parents:
126
diff
changeset
|
226 Window.bind(on_keyboard=self.key_input) |
97
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
227 G.host.app.root.add_widget(self) |
216
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
228 kw = {'d': 0.3, 't': 'out_back'} |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
229 self._set_anim_kw(kw, self.size_hint_open, self.size_open) |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
230 Animation(**kw).start(self) |
168
397f2fb67aab
core (menu): animate transfer menu opening/closing + close it on [ESC]/back
Goffi <goffi@goffi.org>
parents:
126
diff
changeset
|
231 |
397f2fb67aab
core (menu): animate transfer menu opening/closing + close it on [ESC]/back
Goffi <goffi@goffi.org>
parents:
126
diff
changeset
|
232 def hide(self): |
397f2fb67aab
core (menu): animate transfer menu opening/closing + close it on [ESC]/back
Goffi <goffi@goffi.org>
parents:
126
diff
changeset
|
233 Window.unbind(on_keyboard=self.key_input) |
216
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
234 kw = {'d': 0.2} |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
235 self._set_anim_kw(kw, self.size_hint_close, self.size_close) |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
236 anim = Animation(**kw) |
168
397f2fb67aab
core (menu): animate transfer menu opening/closing + close it on [ESC]/back
Goffi <goffi@goffi.org>
parents:
126
diff
changeset
|
237 anim.bind(on_complete=lambda anim, menu: self.parent.remove_widget(self)) |
397f2fb67aab
core (menu): animate transfer menu opening/closing + close it on [ESC]/back
Goffi <goffi@goffi.org>
parents:
126
diff
changeset
|
238 anim.start(self) |
197
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
239 if self.callback_on_close: |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
240 self.do_callback() |
97
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
241 |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
242 def on_touch_down(self, touch): |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
243 # we remove the menu if we click outside |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
244 # else we want to handle the event, but not |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
245 # transmit it to parents |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
246 if not self.collide_point(*touch.pos): |
168
397f2fb67aab
core (menu): animate transfer menu opening/closing + close it on [ESC]/back
Goffi <goffi@goffi.org>
parents:
126
diff
changeset
|
247 self.hide() |
86 | 248 else: |
197
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
249 return super(SideMenu, self).on_touch_down(touch) |
97
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
250 return True |
86 | 251 |
168
397f2fb67aab
core (menu): animate transfer menu opening/closing + close it on [ESC]/back
Goffi <goffi@goffi.org>
parents:
126
diff
changeset
|
252 def key_input(self, window, key, scancode, codepoint, modifier): |
397f2fb67aab
core (menu): animate transfer menu opening/closing + close it on [ESC]/back
Goffi <goffi@goffi.org>
parents:
126
diff
changeset
|
253 if key == 27: |
397f2fb67aab
core (menu): animate transfer menu opening/closing + close it on [ESC]/back
Goffi <goffi@goffi.org>
parents:
126
diff
changeset
|
254 self.hide() |
397f2fb67aab
core (menu): animate transfer menu opening/closing + close it on [ESC]/back
Goffi <goffi@goffi.org>
parents:
126
diff
changeset
|
255 return True |
397f2fb67aab
core (menu): animate transfer menu opening/closing + close it on [ESC]/back
Goffi <goffi@goffi.org>
parents:
126
diff
changeset
|
256 |
197
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
257 def onMenuCancelled(self, wid, cleaning_cb=None): |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
258 self._closeUI(wid) |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
259 if cleaning_cb is not None: |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
260 cleaning_cb() |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
261 |
86 | 262 def _closeUI(self, wid): |
263 G.host.closeUI() | |
264 | |
197
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
265 def do_callback(self, *args, **kwargs): |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
266 log.warning(u"callback not implemented") |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
267 |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
268 |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
269 class TransferMenu(SideMenu): |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
270 """transfer menu which handle display and callbacks""" |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
271 # callback will be called with path to file to transfer |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
272 # profiles if set will be sent to transfer widget, may be used to get specific files |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
273 profiles = properties.ObjectProperty() |
222 | 274 transfer_txt = _(u"Beware! The file will be sent to your server and stay unencrypted " |
275 u"there\nServer admin(s) can see the file, and they choose how, " | |
276 u"when and if it will be deleted") | |
277 send_txt = _(u"The file will be sent unencrypted directly to your contact " | |
278 u"(without transiting by the server), except in some cases") | |
197
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
279 items_layout = properties.ObjectProperty() |
216
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
280 size_hint_close = (1, 0) |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
281 size_hint_open = (1, 0.5) |
197
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
282 |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
283 def __init__(self, **kwargs): |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
284 super(TransferMenu, self).__init__(**kwargs) |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
285 if self.profiles is None: |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
286 self.profiles = iter(G.host.profiles) |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
287 for plug_info in G.host.getPluggedWidgets(type_=C.PLUG_TYPE_TRANSFER): |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
288 item = TransferItem( |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
289 plug_info = plug_info |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
290 ) |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
291 self.items_layout.add_widget(item) |
86 | 292 |
293 def do_callback(self, plug_info): | |
97
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
294 self.parent.remove_widget(self) |
86 | 295 if self.callback is None: |
97
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
296 log.warning(u"TransferMenu callback is not set") |
86 | 297 else: |
298 wid = None | |
88
3dc526bb4a5a
upload: plugin android gallery, first draft:
Goffi <goffi@goffi.org>
parents:
86
diff
changeset
|
299 external = plug_info.get('external', False) |
97
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
300 def onTransferCb(file_path, cleaning_cb=None): |
88
3dc526bb4a5a
upload: plugin android gallery, first draft:
Goffi <goffi@goffi.org>
parents:
86
diff
changeset
|
301 if not external: |
3dc526bb4a5a
upload: plugin android gallery, first draft:
Goffi <goffi@goffi.org>
parents:
86
diff
changeset
|
302 self._closeUI(wid) |
98
4d8c122b86a6
menu (upload): send transfer (i.e. P2P transfer) is now working
Goffi <goffi@goffi.org>
parents:
97
diff
changeset
|
303 self.callback( |
4d8c122b86a6
menu (upload): send transfer (i.e. P2P transfer) is now working
Goffi <goffi@goffi.org>
parents:
97
diff
changeset
|
304 file_path, |
4d8c122b86a6
menu (upload): send transfer (i.e. P2P transfer) is now working
Goffi <goffi@goffi.org>
parents:
97
diff
changeset
|
305 cleaning_cb, |
222 | 306 transfer_type = (C.TRANSFER_UPLOAD |
307 if self.ids['upload_btn'].state == "down" else C.TRANSFER_SEND)) | |
308 wid = plug_info['factory'](plug_info, | |
309 onTransferCb, | |
310 self.cancel_cb, | |
311 self.profiles) | |
88
3dc526bb4a5a
upload: plugin android gallery, first draft:
Goffi <goffi@goffi.org>
parents:
86
diff
changeset
|
312 if not external: |
3dc526bb4a5a
upload: plugin android gallery, first draft:
Goffi <goffi@goffi.org>
parents:
86
diff
changeset
|
313 G.host.showExtraUI(wid) |
197
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
314 |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
315 |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
316 class EntitiesSelectorMenu(SideMenu, FilterBehavior): |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
317 """allow to select entities from roster""" |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
318 profiles = properties.ObjectProperty() |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
319 layout = properties.ObjectProperty() |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
320 instructions = properties.StringProperty(_(u"Please select entities")) |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
321 filter_input = properties.ObjectProperty() |
216
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
322 size_hint_close = (None, 1) |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
323 size_hint_open = (None, 1) |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
324 size_open = (dp(250), 100) |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
325 size_close = (0, 100) |
197
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
326 |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
327 def __init__(self, **kwargs): |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
328 super(EntitiesSelectorMenu, self).__init__(**kwargs) |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
329 self.filter_input.bind(text=self.do_filter_input) |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
330 if self.profiles is None: |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
331 self.profiles = iter(G.host.profiles) |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
332 for profile in self.profiles: |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
333 for jid_, jid_data in G.host.contact_lists[profile].all_iter: |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
334 jid_wid = JidToggle( |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
335 jid=jid_, |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
336 profile=profile) |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
337 self.layout.add_widget(jid_wid) |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
338 |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
339 def do_callback(self): |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
340 if self.callback is not None: |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
341 jids = [c.jid for c in self.layout.children if c.state == 'down'] |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
342 self.callback(jids) |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
343 |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
344 def do_filter_input(self, filter_input, text): |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
345 self.layout.spacing = 0 if text else dp(5) |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
346 self.do_filter(self.layout.children, |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
347 text, |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
348 lambda c: c.jid, |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
349 width_cb=lambda c: c.width, |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
350 height_cb=lambda c: dp(70)) |
222 | 351 |
352 | |
353 class TouchMenu(modernmenu.ModernMenu): | |
354 pass | |
355 | |
356 | |
357 class TouchMenuItemBehaviour(object): | |
358 """Class to use on every item where a menu may appear | |
359 | |
360 main_wid attribute must be set to the class inheriting from TouchMenuBehaviour | |
361 do_item_action is the method called on simple click | |
362 getMenuChoices must return a list of menus for long press | |
363 menus there are dict as expected by ModernMenu | |
364 (translated text, index and callback) | |
365 """ | |
366 main_wid = properties.ObjectProperty() | |
367 click_timeout = properties.NumericProperty(0.4) | |
368 | |
369 def on_touch_down(self, touch): | |
370 if not self.collide_point(*touch.pos): | |
371 return | |
372 t = partial(self.open_menu, touch) | |
373 touch.ud['menu_timeout'] = t | |
374 Clock.schedule_once(t, self.click_timeout) | |
375 return super(TouchMenuItemBehaviour, self).on_touch_down(touch) | |
376 | |
377 def do_item_action(self, touch): | |
378 pass | |
379 | |
380 def on_touch_up(self, touch): | |
381 if touch.ud.get('menu_timeout'): | |
382 Clock.unschedule(touch.ud['menu_timeout']) | |
383 if self.collide_point(*touch.pos) and self.main_wid.menu is None: | |
384 self.do_item_action(touch) | |
385 return super(TouchMenuItemBehaviour, self).on_touch_up(touch) | |
386 | |
387 def open_menu(self, touch, dt): | |
388 self.main_wid.open_menu(self, touch) | |
389 del touch.ud['menu_timeout'] | |
390 | |
391 def getMenuChoices(self): | |
392 """return choice adapted to selected item | |
393 | |
394 @return (list[dict]): choices ad expected by ModernMenu | |
395 """ | |
396 return [] | |
397 | |
398 | |
399 class TouchMenuBehaviour(object): | |
400 """Class to handle a menu appearing on long press on items | |
401 | |
402 classes using this behaviour need to have a float_layout property | |
403 pointing the main FloatLayout. | |
404 """ | |
405 float_layout = properties.ObjectProperty() | |
406 | |
407 def __init__(self, *args, **kwargs): | |
408 super(TouchMenuBehaviour, self).__init__(*args, **kwargs) | |
409 self.menu = None | |
410 self.menu_item = None | |
411 | |
412 ## menu methods ## | |
413 | |
414 def clean_fl_children(self, layout, children): | |
415 """insure that self.menu and self.menu_item are None when menu is dimissed""" | |
416 if self.menu is not None and self.menu not in children: | |
417 self.menu = self.menu_item = None | |
418 | |
419 def clear_menu(self): | |
420 """remove menu if there is one""" | |
421 if self.menu is not None: | |
422 self.menu.dismiss() | |
423 self.menu = None | |
424 self.menu_item = None | |
425 | |
426 def open_menu(self, item, touch): | |
427 """open menu for item | |
428 | |
429 @param item(PathWidget): item when the menu has been requested | |
430 @param touch(kivy.input.MotionEvent): touch data | |
431 """ | |
432 if self.menu_item == item: | |
433 return | |
434 self.clear_menu() | |
435 pos = self.to_widget(*touch.pos) | |
436 choices = item.getMenuChoices() | |
437 if not choices: | |
438 return | |
439 self.menu = TouchMenu(choices=choices, | |
440 center=pos, | |
441 size_hint=(None, None)) | |
442 self.float_layout.add_widget(self.menu) | |
443 self.menu.start_display(touch) | |
444 self.menu_item = item | |
445 | |
446 def on_float_layout(self, wid, float_layout): | |
447 float_layout.bind(children=self.clean_fl_children) |