Mercurial > libervia-desktop-kivy
annotate cagou/core/menu.py @ 225:a3162b29cda1
plugin chat: fixed AttributeError when message is receved and a corresponding ChatWidget is not created yet
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 27 Jun 2018 22:23:20 +0200 |
parents | a676cb07c1cb |
children | 15e47bbb192c |
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] | |
184
c63922860f80
chat: show desktop notification and/or note when suitable
Goffi <goffi@goffi.org>
parents:
173
diff
changeset
|
48 """).format(version=C.APP_VERSION) |
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 | |
167 about.content = AboutContent(text=ABOUT_CONTENT, markup=True) | |
168 about.open() | |
86 | 169 |
170 | |
97
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
171 class TransferItem(BoxLayout): |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
172 plug_info = properties.DictProperty() |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
173 |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
174 def on_touch_up(self, touch): |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
175 if not self.collide_point(*touch.pos): |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
176 return super(TransferItem, self).on_touch_up(touch) |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
177 else: |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
178 transfer_menu = self.parent |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
179 while not isinstance(transfer_menu, TransferMenu): |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
180 transfer_menu = transfer_menu.parent |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
181 transfer_menu.do_callback(self.plug_info) |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
182 return True |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
183 |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
184 |
197
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
185 class SideMenu(BoxLayout): |
216
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
186 size_hint_close = (0, 1) |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
187 size_hint_open = (0.4, 1) |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
188 size_close = (100, 100) |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
189 size_open = (0, 0) |
197
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
190 bg_color = properties.ListProperty([0, 0, 0, 1]) |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
191 # callback will be called with arguments relevant to menu |
86 | 192 callback = properties.ObjectProperty() |
197
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
193 # call do_callback even when menu is cancelled |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
194 callback_on_close = properties.BooleanProperty(False) |
86 | 195 # cancel callback need to remove the widget for UI |
196 # will be called with the widget to remove as argument | |
197 cancel_cb = properties.ObjectProperty() | |
198 | |
199 def __init__(self, **kwargs): | |
197
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
200 super(SideMenu, self).__init__(**kwargs) |
86 | 201 if self.cancel_cb is None: |
197
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
202 self.cancel_cb = self.onMenuCancelled |
86 | 203 |
216
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
204 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
|
205 """Set animation keywords |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
206 |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
207 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
|
208 else size is used. |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
209 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
|
210 the one of Window is used |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
211 """ |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
212 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
|
213 width, height = size |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
214 if size_hint_x is not None: |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
215 kw['size_hint_x'] = size_hint_x |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
216 elif width is not None: |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
217 kw['width'] = min(width, Window.width) |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
218 |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
219 if size_hint_y is not None: |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
220 kw['size_hint_y'] = size_hint_y |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
221 elif height is not None: |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
222 kw['height'] = min(height, Window.height) |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
223 |
86 | 224 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
|
225 Window.bind(on_keyboard=self.key_input) |
97
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
226 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
|
227 kw = {'d': 0.3, 't': 'out_back'} |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
228 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
|
229 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
|
230 |
397f2fb67aab
core (menu): animate transfer menu opening/closing + close it on [ESC]/back
Goffi <goffi@goffi.org>
parents:
126
diff
changeset
|
231 def hide(self): |
397f2fb67aab
core (menu): animate transfer menu opening/closing + close it on [ESC]/back
Goffi <goffi@goffi.org>
parents:
126
diff
changeset
|
232 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
|
233 kw = {'d': 0.2} |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
234 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
|
235 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
|
236 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
|
237 anim.start(self) |
197
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
238 if self.callback_on_close: |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
239 self.do_callback() |
97
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
240 |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
241 def on_touch_down(self, touch): |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
242 # we remove the menu if we click outside |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
243 # 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
|
244 # transmit it to parents |
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
245 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
|
246 self.hide() |
86 | 247 else: |
197
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
248 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
|
249 return True |
86 | 250 |
168
397f2fb67aab
core (menu): animate transfer menu opening/closing + close it on [ESC]/back
Goffi <goffi@goffi.org>
parents:
126
diff
changeset
|
251 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
|
252 if key == 27: |
397f2fb67aab
core (menu): animate transfer menu opening/closing + close it on [ESC]/back
Goffi <goffi@goffi.org>
parents:
126
diff
changeset
|
253 self.hide() |
397f2fb67aab
core (menu): animate transfer menu opening/closing + close it on [ESC]/back
Goffi <goffi@goffi.org>
parents:
126
diff
changeset
|
254 return True |
397f2fb67aab
core (menu): animate transfer menu opening/closing + close it on [ESC]/back
Goffi <goffi@goffi.org>
parents:
126
diff
changeset
|
255 |
197
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
256 def onMenuCancelled(self, wid, cleaning_cb=None): |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
257 self._closeUI(wid) |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
258 if cleaning_cb is not None: |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
259 cleaning_cb() |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
260 |
86 | 261 def _closeUI(self, wid): |
262 G.host.closeUI() | |
263 | |
197
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
264 def do_callback(self, *args, **kwargs): |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
265 log.warning(u"callback not implemented") |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
266 |
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 class TransferMenu(SideMenu): |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
269 """transfer menu which handle display and callbacks""" |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
270 # callback will be called with path to file to transfer |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
271 # 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
|
272 profiles = properties.ObjectProperty() |
222 | 273 transfer_txt = _(u"Beware! The file will be sent to your server and stay unencrypted " |
274 u"there\nServer admin(s) can see the file, and they choose how, " | |
275 u"when and if it will be deleted") | |
276 send_txt = _(u"The file will be sent unencrypted directly to your contact " | |
277 u"(without transiting by the server), except in some cases") | |
197
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
278 items_layout = properties.ObjectProperty() |
216
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
279 size_hint_close = (1, 0) |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
280 size_hint_open = (1, 0.5) |
197
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
281 |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
282 def __init__(self, **kwargs): |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
283 super(TransferMenu, self).__init__(**kwargs) |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
284 if self.profiles is None: |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
285 self.profiles = iter(G.host.profiles) |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
286 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
|
287 item = TransferItem( |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
288 plug_info = plug_info |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
289 ) |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
290 self.items_layout.add_widget(item) |
86 | 291 |
292 def do_callback(self, plug_info): | |
97
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
293 self.parent.remove_widget(self) |
86 | 294 if self.callback is None: |
97
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
295 log.warning(u"TransferMenu callback is not set") |
86 | 296 else: |
297 wid = None | |
88
3dc526bb4a5a
upload: plugin android gallery, first draft:
Goffi <goffi@goffi.org>
parents:
86
diff
changeset
|
298 external = plug_info.get('external', False) |
97
5d2289127bb7
menu (upload): better menu using dedicated widget:
Goffi <goffi@goffi.org>
parents:
88
diff
changeset
|
299 def onTransferCb(file_path, cleaning_cb=None): |
88
3dc526bb4a5a
upload: plugin android gallery, first draft:
Goffi <goffi@goffi.org>
parents:
86
diff
changeset
|
300 if not external: |
3dc526bb4a5a
upload: plugin android gallery, first draft:
Goffi <goffi@goffi.org>
parents:
86
diff
changeset
|
301 self._closeUI(wid) |
98
4d8c122b86a6
menu (upload): send transfer (i.e. P2P transfer) is now working
Goffi <goffi@goffi.org>
parents:
97
diff
changeset
|
302 self.callback( |
4d8c122b86a6
menu (upload): send transfer (i.e. P2P transfer) is now working
Goffi <goffi@goffi.org>
parents:
97
diff
changeset
|
303 file_path, |
4d8c122b86a6
menu (upload): send transfer (i.e. P2P transfer) is now working
Goffi <goffi@goffi.org>
parents:
97
diff
changeset
|
304 cleaning_cb, |
222 | 305 transfer_type = (C.TRANSFER_UPLOAD |
306 if self.ids['upload_btn'].state == "down" else C.TRANSFER_SEND)) | |
307 wid = plug_info['factory'](plug_info, | |
308 onTransferCb, | |
309 self.cancel_cb, | |
310 self.profiles) | |
88
3dc526bb4a5a
upload: plugin android gallery, first draft:
Goffi <goffi@goffi.org>
parents:
86
diff
changeset
|
311 if not external: |
3dc526bb4a5a
upload: plugin android gallery, first draft:
Goffi <goffi@goffi.org>
parents:
86
diff
changeset
|
312 G.host.showExtraUI(wid) |
197
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
313 |
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 class EntitiesSelectorMenu(SideMenu, FilterBehavior): |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
316 """allow to select entities from roster""" |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
317 profiles = properties.ObjectProperty() |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
318 layout = properties.ObjectProperty() |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
319 instructions = properties.StringProperty(_(u"Please select entities")) |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
320 filter_input = properties.ObjectProperty() |
216
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
321 size_hint_close = (None, 1) |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
322 size_hint_open = (None, 1) |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
323 size_open = (dp(250), 100) |
e42e0c45d384
core (menu): allow to specify size in SideMenu:
Goffi <goffi@goffi.org>
parents:
197
diff
changeset
|
324 size_close = (0, 100) |
197
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
325 |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
326 def __init__(self, **kwargs): |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
327 super(EntitiesSelectorMenu, self).__init__(**kwargs) |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
328 self.filter_input.bind(text=self.do_filter_input) |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
329 if self.profiles is None: |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
330 self.profiles = iter(G.host.profiles) |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
331 for profile in self.profiles: |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
332 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
|
333 jid_wid = JidToggle( |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
334 jid=jid_, |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
335 profile=profile) |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
336 self.layout.add_widget(jid_wid) |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
337 |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
338 def do_callback(self): |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
339 if self.callback is not None: |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
340 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
|
341 self.callback(jids) |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
342 |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
343 def do_filter_input(self, filter_input, text): |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
344 self.layout.spacing = 0 if text else dp(5) |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
345 self.do_filter(self.layout.children, |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
346 text, |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
347 lambda c: c.jid, |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
348 width_cb=lambda c: c.width, |
c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
Goffi <goffi@goffi.org>
parents:
184
diff
changeset
|
349 height_cb=lambda c: dp(70)) |
222 | 350 |
351 | |
352 class TouchMenu(modernmenu.ModernMenu): | |
353 pass | |
354 | |
355 | |
356 class TouchMenuItemBehaviour(object): | |
357 """Class to use on every item where a menu may appear | |
358 | |
359 main_wid attribute must be set to the class inheriting from TouchMenuBehaviour | |
360 do_item_action is the method called on simple click | |
361 getMenuChoices must return a list of menus for long press | |
362 menus there are dict as expected by ModernMenu | |
363 (translated text, index and callback) | |
364 """ | |
365 main_wid = properties.ObjectProperty() | |
366 click_timeout = properties.NumericProperty(0.4) | |
367 | |
368 def on_touch_down(self, touch): | |
369 if not self.collide_point(*touch.pos): | |
370 return | |
371 t = partial(self.open_menu, touch) | |
372 touch.ud['menu_timeout'] = t | |
373 Clock.schedule_once(t, self.click_timeout) | |
374 return super(TouchMenuItemBehaviour, self).on_touch_down(touch) | |
375 | |
376 def do_item_action(self, touch): | |
377 pass | |
378 | |
379 def on_touch_up(self, touch): | |
380 if touch.ud.get('menu_timeout'): | |
381 Clock.unschedule(touch.ud['menu_timeout']) | |
382 if self.collide_point(*touch.pos) and self.main_wid.menu is None: | |
383 self.do_item_action(touch) | |
384 return super(TouchMenuItemBehaviour, self).on_touch_up(touch) | |
385 | |
386 def open_menu(self, touch, dt): | |
387 self.main_wid.open_menu(self, touch) | |
388 del touch.ud['menu_timeout'] | |
389 | |
390 def getMenuChoices(self): | |
391 """return choice adapted to selected item | |
392 | |
393 @return (list[dict]): choices ad expected by ModernMenu | |
394 """ | |
395 return [] | |
396 | |
397 | |
398 class TouchMenuBehaviour(object): | |
399 """Class to handle a menu appearing on long press on items | |
400 | |
401 classes using this behaviour need to have a float_layout property | |
402 pointing the main FloatLayout. | |
403 """ | |
404 float_layout = properties.ObjectProperty() | |
405 | |
406 def __init__(self, *args, **kwargs): | |
407 super(TouchMenuBehaviour, self).__init__(*args, **kwargs) | |
408 self.menu = None | |
409 self.menu_item = None | |
410 | |
411 ## menu methods ## | |
412 | |
413 def clean_fl_children(self, layout, children): | |
414 """insure that self.menu and self.menu_item are None when menu is dimissed""" | |
415 if self.menu is not None and self.menu not in children: | |
416 self.menu = self.menu_item = None | |
417 | |
418 def clear_menu(self): | |
419 """remove menu if there is one""" | |
420 if self.menu is not None: | |
421 self.menu.dismiss() | |
422 self.menu = None | |
423 self.menu_item = None | |
424 | |
425 def open_menu(self, item, touch): | |
426 """open menu for item | |
427 | |
428 @param item(PathWidget): item when the menu has been requested | |
429 @param touch(kivy.input.MotionEvent): touch data | |
430 """ | |
431 if self.menu_item == item: | |
432 return | |
433 self.clear_menu() | |
434 pos = self.to_widget(*touch.pos) | |
435 choices = item.getMenuChoices() | |
436 if not choices: | |
437 return | |
438 self.menu = TouchMenu(choices=choices, | |
439 center=pos, | |
440 size_hint=(None, None)) | |
441 self.float_layout.add_widget(self.menu) | |
442 self.menu.start_display(touch) | |
443 self.menu_item = item | |
444 | |
445 def on_float_layout(self, wid, float_layout): | |
446 float_layout.bind(children=self.clean_fl_children) |