Mercurial > libervia-desktop-kivy
comparison cagou/core/menu.py @ 197:c7d15ef4bfa8
core (menu): new EntitiesSelectorMenu:
TransferMenu base has been moved to a "SlideMenu" base class, which is used to create a new "EntitiesSelectorMenu".
This later widget allows user to select entities from her roster, and the selected jids are then sent back to user.
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 23 May 2018 21:27:28 +0200 |
parents | c63922860f80 |
children | e42e0c45d384 |
comparison
equal
deleted
inserted
replaced
196:519b3a29743c | 197:c7d15ef4bfa8 |
---|---|
20 | 20 |
21 from sat.core.i18n import _ | 21 from sat.core.i18n import _ |
22 from sat.core import log as logging | 22 from sat.core import log as logging |
23 log = logging.getLogger(__name__) | 23 log = logging.getLogger(__name__) |
24 from cagou.core.constants import Const as C | 24 from cagou.core.constants import Const as C |
25 from cagou.core.common import JidToggle | |
25 from kivy.uix.boxlayout import BoxLayout | 26 from kivy.uix.boxlayout import BoxLayout |
26 from kivy.uix.label import Label | 27 from kivy.uix.label import Label |
27 from kivy.uix.popup import Popup | 28 from kivy.uix.popup import Popup |
29 from cagou.core.utils import FilterBehavior | |
28 from kivy import properties | 30 from kivy import properties |
29 from kivy.garden import contextmenu | 31 from kivy.garden import contextmenu |
30 from sat_frontends.quick_frontend import quick_menus | 32 from sat_frontends.quick_frontend import quick_menus |
31 from kivy.core.window import Window | 33 from kivy.core.window import Window |
32 from kivy.animation import Animation | 34 from kivy.animation import Animation |
35 from kivy.metrics import dp | |
33 from cagou import G | 36 from cagou import G |
34 import webbrowser | 37 import webbrowser |
35 | 38 |
36 ABOUT_TITLE = _(u"About {}".format(C.APP_NAME)) | 39 ABOUT_TITLE = _(u"About {}".format(C.APP_NAME)) |
37 ABOUT_CONTENT = _(u"""Cagou (Salut à Toi) v{version} | 40 ABOUT_CONTENT = _(u"""Cagou (Salut à Toi) v{version} |
173 transfer_menu = transfer_menu.parent | 176 transfer_menu = transfer_menu.parent |
174 transfer_menu.do_callback(self.plug_info) | 177 transfer_menu.do_callback(self.plug_info) |
175 return True | 178 return True |
176 | 179 |
177 | 180 |
178 class TransferMenu(BoxLayout): | 181 class SideMenu(BoxLayout): |
179 """transfer menu which handle display and callbacks""" | 182 base_size_hint_close = (0, 1) |
180 # callback will be called with path to file to transfer | 183 base_size_hint_open = (0.4, 1) |
184 bg_color = properties.ListProperty([0, 0, 0, 1]) | |
185 # callback will be called with arguments relevant to menu | |
181 callback = properties.ObjectProperty() | 186 callback = properties.ObjectProperty() |
187 # call do_callback even when menu is cancelled | |
188 callback_on_close = properties.BooleanProperty(False) | |
182 # cancel callback need to remove the widget for UI | 189 # cancel callback need to remove the widget for UI |
183 # will be called with the widget to remove as argument | 190 # will be called with the widget to remove as argument |
184 cancel_cb = properties.ObjectProperty() | 191 cancel_cb = properties.ObjectProperty() |
192 | |
193 def __init__(self, **kwargs): | |
194 super(SideMenu, self).__init__(**kwargs) | |
195 if self.cancel_cb is None: | |
196 self.cancel_cb = self.onMenuCancelled | |
197 | |
198 def show(self, caller_wid=None): | |
199 Window.bind(on_keyboard=self.key_input) | |
200 G.host.app.root.add_widget(self) | |
201 Animation(size_hint=self.base_size_hint_open, d=0.3, t='out_back').start(self) | |
202 | |
203 def hide(self): | |
204 Window.unbind(on_keyboard=self.key_input) | |
205 anim = Animation(size_hint=self.base_size_hint_close, d=0.2) | |
206 anim.bind(on_complete=lambda anim, menu: self.parent.remove_widget(self)) | |
207 anim.start(self) | |
208 if self.callback_on_close: | |
209 self.do_callback() | |
210 | |
211 def on_touch_down(self, touch): | |
212 # we remove the menu if we click outside | |
213 # else we want to handle the event, but not | |
214 # transmit it to parents | |
215 if not self.collide_point(*touch.pos): | |
216 self.hide() | |
217 else: | |
218 return super(SideMenu, self).on_touch_down(touch) | |
219 return True | |
220 | |
221 def key_input(self, window, key, scancode, codepoint, modifier): | |
222 if key == 27: | |
223 self.hide() | |
224 return True | |
225 | |
226 def onMenuCancelled(self, wid, cleaning_cb=None): | |
227 self._closeUI(wid) | |
228 if cleaning_cb is not None: | |
229 cleaning_cb() | |
230 | |
231 def _closeUI(self, wid): | |
232 G.host.closeUI() | |
233 | |
234 def do_callback(self, *args, **kwargs): | |
235 log.warning(u"callback not implemented") | |
236 | |
237 | |
238 class TransferMenu(SideMenu): | |
239 """transfer menu which handle display and callbacks""" | |
240 # callback will be called with path to file to transfer | |
185 # profiles if set will be sent to transfer widget, may be used to get specific files | 241 # profiles if set will be sent to transfer widget, may be used to get specific files |
186 profiles = properties.ObjectProperty() | 242 profiles = properties.ObjectProperty() |
187 transfer_txt = _(u"Beware! The file will be sent to your server and stay unencrypted there\nServer admin(s) can see the file, and they choose how, when and if it will be deleted") | 243 transfer_txt = _(u"Beware! The file will be sent to your server and stay unencrypted there\nServer admin(s) can see the file, and they choose how, when and if it will be deleted") |
188 send_txt = _(u"The file will be sent unencrypted directly to your contact (without transiting by the server), except in some cases") | 244 send_txt = _(u"The file will be sent unencrypted directly to your contact (without transiting by the server), except in some cases") |
189 items_layout = properties.ObjectProperty() | 245 items_layout = properties.ObjectProperty() |
246 base_size_hint_close = (1, 0) | |
247 base_size_hint_open = (1, 0.5) | |
190 | 248 |
191 def __init__(self, **kwargs): | 249 def __init__(self, **kwargs): |
192 super(TransferMenu, self).__init__(**kwargs) | 250 super(TransferMenu, self).__init__(**kwargs) |
193 if self.cancel_cb is None: | |
194 self.cancel_cb = self.onTransferCancelled | |
195 if self.profiles is None: | 251 if self.profiles is None: |
196 self.profiles = iter(G.host.profiles) | 252 self.profiles = iter(G.host.profiles) |
197 for plug_info in G.host.getPluggedWidgets(type_=C.PLUG_TYPE_TRANSFER): | 253 for plug_info in G.host.getPluggedWidgets(type_=C.PLUG_TYPE_TRANSFER): |
198 item = TransferItem( | 254 item = TransferItem( |
199 plug_info = plug_info | 255 plug_info = plug_info |
200 ) | 256 ) |
201 self.items_layout.add_widget(item) | 257 self.items_layout.add_widget(item) |
202 | |
203 def show(self, caller_wid=None): | |
204 self.size_hint_y = 0 | |
205 Window.bind(on_keyboard=self.key_input) | |
206 G.host.app.root.add_widget(self) | |
207 Animation(size_hint_y=0.5, d=0.3, t='out_back').start(self) | |
208 | |
209 def hide(self): | |
210 Window.unbind(on_keyboard=self.key_input) | |
211 anim = Animation(size_hint_y=0, d=0.2) | |
212 anim.bind(on_complete=lambda anim, menu: self.parent.remove_widget(self)) | |
213 anim.start(self) | |
214 | |
215 def on_touch_down(self, touch): | |
216 # we remove the menu if we click outside | |
217 # else we want to handle the event, but not | |
218 # transmit it to parents | |
219 if not self.collide_point(*touch.pos): | |
220 self.hide() | |
221 else: | |
222 return super(TransferMenu, self).on_touch_down(touch) | |
223 return True | |
224 | |
225 def key_input(self, window, key, scancode, codepoint, modifier): | |
226 if key == 27: | |
227 self.hide() | |
228 return True | |
229 | |
230 def _closeUI(self, wid): | |
231 G.host.closeUI() | |
232 | |
233 def onTransferCancelled(self, wid, cleaning_cb=None): | |
234 self._closeUI(wid) | |
235 if cleaning_cb is not None: | |
236 cleaning_cb() | |
237 | 258 |
238 def do_callback(self, plug_info): | 259 def do_callback(self, plug_info): |
239 self.parent.remove_widget(self) | 260 self.parent.remove_widget(self) |
240 if self.callback is None: | 261 if self.callback is None: |
241 log.warning(u"TransferMenu callback is not set") | 262 log.warning(u"TransferMenu callback is not set") |
250 cleaning_cb, | 271 cleaning_cb, |
251 transfer_type = C.TRANSFER_UPLOAD if self.ids['upload_btn'].state == "down" else C.TRANSFER_SEND) | 272 transfer_type = C.TRANSFER_UPLOAD if self.ids['upload_btn'].state == "down" else C.TRANSFER_SEND) |
252 wid = plug_info['factory'](plug_info, onTransferCb, self.cancel_cb, self.profiles) | 273 wid = plug_info['factory'](plug_info, onTransferCb, self.cancel_cb, self.profiles) |
253 if not external: | 274 if not external: |
254 G.host.showExtraUI(wid) | 275 G.host.showExtraUI(wid) |
276 | |
277 | |
278 class EntitiesSelectorMenu(SideMenu, FilterBehavior): | |
279 """allow to select entities from roster""" | |
280 profiles = properties.ObjectProperty() | |
281 layout = properties.ObjectProperty() | |
282 instructions = properties.StringProperty(_(u"Please select entities")) | |
283 filter_input = properties.ObjectProperty() | |
284 | |
285 def __init__(self, **kwargs): | |
286 super(EntitiesSelectorMenu, self).__init__(**kwargs) | |
287 self.filter_input.bind(text=self.do_filter_input) | |
288 if self.profiles is None: | |
289 self.profiles = iter(G.host.profiles) | |
290 for profile in self.profiles: | |
291 for jid_, jid_data in G.host.contact_lists[profile].all_iter: | |
292 jid_wid = JidToggle( | |
293 jid=jid_, | |
294 profile=profile) | |
295 self.layout.add_widget(jid_wid) | |
296 | |
297 def do_callback(self): | |
298 if self.callback is not None: | |
299 jids = [c.jid for c in self.layout.children if c.state == 'down'] | |
300 self.callback(jids) | |
301 | |
302 def do_filter_input(self, filter_input, text): | |
303 self.layout.spacing = 0 if text else dp(5) | |
304 self.do_filter(self.layout.children, | |
305 text, | |
306 lambda c: c.jid, | |
307 width_cb=lambda c: c.width, | |
308 height_cb=lambda c: dp(70)) |