Mercurial > libervia-desktop-kivy
comparison cagou/core/menu.py @ 222:a676cb07c1cb
core (menu): TouchMenuBehaviour:
moved code showing ModernMenu on item from file sharing plugin to a generic behaviour, so it can be re-used elsewhere.
author | Goffi <goffi@goffi.org> |
---|---|
date | Tue, 26 Jun 2018 20:26:21 +0200 |
parents | e42e0c45d384 |
children | 15e47bbb192c |
comparison
equal
deleted
inserted
replaced
221:e1a385a791cc | 222:a676cb07c1cb |
---|---|
26 from kivy.uix.boxlayout import BoxLayout | 26 from kivy.uix.boxlayout import BoxLayout |
27 from kivy.uix.label import Label | 27 from kivy.uix.label import Label |
28 from kivy.uix.popup import Popup | 28 from kivy.uix.popup import Popup |
29 from cagou.core.utils import FilterBehavior | 29 from cagou.core.utils import FilterBehavior |
30 from kivy import properties | 30 from kivy import properties |
31 from kivy.garden import contextmenu | 31 from kivy.garden import contextmenu, modernmenu |
32 from sat_frontends.quick_frontend import quick_menus | 32 from sat_frontends.quick_frontend import quick_menus |
33 from kivy.core.window import Window | 33 from kivy.core.window import Window |
34 from kivy.animation import Animation | 34 from kivy.animation import Animation |
35 from kivy.metrics import dp | 35 from kivy.metrics import dp |
36 from kivy.clock import Clock | |
36 from cagou import G | 37 from cagou import G |
38 from functools import partial | |
37 import webbrowser | 39 import webbrowser |
38 | 40 |
39 ABOUT_TITLE = _(u"About {}".format(C.APP_NAME)) | 41 ABOUT_TITLE = _(u"About {}".format(C.APP_NAME)) |
40 ABOUT_CONTENT = _(u"""Cagou (Salut à Toi) v{version} | 42 ABOUT_CONTENT = _(u"""Cagou (Salut à Toi) v{version} |
41 | 43 |
76 self.parent.hide() | 78 self.parent.hide() |
77 selected = G.host.selected_widget | 79 selected = G.host.selected_widget |
78 profile = None | 80 profile = None |
79 if selected is not None: | 81 if selected is not None: |
80 try: | 82 try: |
81 profile = selected.profile | 83 # FIXME: handle multi-profiles |
84 profile = next(iter(selected.profiles)) | |
82 except AttributeError: | 85 except AttributeError: |
83 pass | 86 pass |
84 | 87 |
85 if profile is None: | 88 if profile is None: |
86 try: | 89 try: |
127 self.add_widget(main_menu) | 130 self.add_widget(main_menu) |
128 caller = main_menu | 131 caller = main_menu |
129 else: | 132 else: |
130 context_menu = contextmenu.ContextMenu() | 133 context_menu = contextmenu.ContextMenu() |
131 caller.add_widget(context_menu) | 134 caller.add_widget(context_menu) |
132 # FIXME: next line is needed after parent is set to avoid a display bug in contextmenu | 135 # FIXME: next line is needed after parent is set to avoid |
136 # a display bug in contextmenu | |
133 # TODO: fix this upstream | 137 # TODO: fix this upstream |
134 context_menu._on_visible(False) | 138 context_menu._on_visible(False) |
135 | 139 |
136 caller = context_menu | 140 caller = context_menu |
137 | 141 |
264 class TransferMenu(SideMenu): | 268 class TransferMenu(SideMenu): |
265 """transfer menu which handle display and callbacks""" | 269 """transfer menu which handle display and callbacks""" |
266 # callback will be called with path to file to transfer | 270 # callback will be called with path to file to transfer |
267 # profiles if set will be sent to transfer widget, may be used to get specific files | 271 # profiles if set will be sent to transfer widget, may be used to get specific files |
268 profiles = properties.ObjectProperty() | 272 profiles = properties.ObjectProperty() |
269 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") | 273 transfer_txt = _(u"Beware! The file will be sent to your server and stay unencrypted " |
270 send_txt = _(u"The file will be sent unencrypted directly to your contact (without transiting by the server), except in some cases") | 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") | |
271 items_layout = properties.ObjectProperty() | 278 items_layout = properties.ObjectProperty() |
272 size_hint_close = (1, 0) | 279 size_hint_close = (1, 0) |
273 size_hint_open = (1, 0.5) | 280 size_hint_open = (1, 0.5) |
274 | 281 |
275 def __init__(self, **kwargs): | 282 def __init__(self, **kwargs): |
293 if not external: | 300 if not external: |
294 self._closeUI(wid) | 301 self._closeUI(wid) |
295 self.callback( | 302 self.callback( |
296 file_path, | 303 file_path, |
297 cleaning_cb, | 304 cleaning_cb, |
298 transfer_type = C.TRANSFER_UPLOAD if self.ids['upload_btn'].state == "down" else C.TRANSFER_SEND) | 305 transfer_type = (C.TRANSFER_UPLOAD |
299 wid = plug_info['factory'](plug_info, onTransferCb, self.cancel_cb, self.profiles) | 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) | |
300 if not external: | 311 if not external: |
301 G.host.showExtraUI(wid) | 312 G.host.showExtraUI(wid) |
302 | 313 |
303 | 314 |
304 class EntitiesSelectorMenu(SideMenu, FilterBehavior): | 315 class EntitiesSelectorMenu(SideMenu, FilterBehavior): |
334 self.do_filter(self.layout.children, | 345 self.do_filter(self.layout.children, |
335 text, | 346 text, |
336 lambda c: c.jid, | 347 lambda c: c.jid, |
337 width_cb=lambda c: c.width, | 348 width_cb=lambda c: c.width, |
338 height_cb=lambda c: dp(70)) | 349 height_cb=lambda c: dp(70)) |
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) |