Mercurial > libervia-desktop-kivy
diff 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 |
line wrap: on
line diff
--- a/cagou/core/menu.py Tue Jun 26 07:36:11 2018 +0200 +++ b/cagou/core/menu.py Tue Jun 26 20:26:21 2018 +0200 @@ -28,12 +28,14 @@ from kivy.uix.popup import Popup from cagou.core.utils import FilterBehavior from kivy import properties -from kivy.garden import contextmenu +from kivy.garden import contextmenu, modernmenu from sat_frontends.quick_frontend import quick_menus from kivy.core.window import Window from kivy.animation import Animation from kivy.metrics import dp +from kivy.clock import Clock from cagou import G +from functools import partial import webbrowser ABOUT_TITLE = _(u"About {}".format(C.APP_NAME)) @@ -78,7 +80,8 @@ profile = None if selected is not None: try: - profile = selected.profile + # FIXME: handle multi-profiles + profile = next(iter(selected.profiles)) except AttributeError: pass @@ -129,7 +132,8 @@ else: context_menu = contextmenu.ContextMenu() caller.add_widget(context_menu) - # FIXME: next line is needed after parent is set to avoid a display bug in contextmenu + # FIXME: next line is needed after parent is set to avoid + # a display bug in contextmenu # TODO: fix this upstream context_menu._on_visible(False) @@ -266,8 +270,11 @@ # callback will be called with path to file to transfer # profiles if set will be sent to transfer widget, may be used to get specific files profiles = properties.ObjectProperty() - 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") - send_txt = _(u"The file will be sent unencrypted directly to your contact (without transiting by the server), except in some cases") + transfer_txt = _(u"Beware! The file will be sent to your server and stay unencrypted " + u"there\nServer admin(s) can see the file, and they choose how, " + u"when and if it will be deleted") + send_txt = _(u"The file will be sent unencrypted directly to your contact " + u"(without transiting by the server), except in some cases") items_layout = properties.ObjectProperty() size_hint_close = (1, 0) size_hint_open = (1, 0.5) @@ -295,8 +302,12 @@ self.callback( file_path, cleaning_cb, - transfer_type = C.TRANSFER_UPLOAD if self.ids['upload_btn'].state == "down" else C.TRANSFER_SEND) - wid = plug_info['factory'](plug_info, onTransferCb, self.cancel_cb, self.profiles) + transfer_type = (C.TRANSFER_UPLOAD + if self.ids['upload_btn'].state == "down" else C.TRANSFER_SEND)) + wid = plug_info['factory'](plug_info, + onTransferCb, + self.cancel_cb, + self.profiles) if not external: G.host.showExtraUI(wid) @@ -336,3 +347,100 @@ lambda c: c.jid, width_cb=lambda c: c.width, height_cb=lambda c: dp(70)) + + +class TouchMenu(modernmenu.ModernMenu): + pass + + +class TouchMenuItemBehaviour(object): + """Class to use on every item where a menu may appear + + main_wid attribute must be set to the class inheriting from TouchMenuBehaviour + do_item_action is the method called on simple click + getMenuChoices must return a list of menus for long press + menus there are dict as expected by ModernMenu + (translated text, index and callback) + """ + main_wid = properties.ObjectProperty() + click_timeout = properties.NumericProperty(0.4) + + def on_touch_down(self, touch): + if not self.collide_point(*touch.pos): + return + t = partial(self.open_menu, touch) + touch.ud['menu_timeout'] = t + Clock.schedule_once(t, self.click_timeout) + return super(TouchMenuItemBehaviour, self).on_touch_down(touch) + + def do_item_action(self, touch): + pass + + def on_touch_up(self, touch): + if touch.ud.get('menu_timeout'): + Clock.unschedule(touch.ud['menu_timeout']) + if self.collide_point(*touch.pos) and self.main_wid.menu is None: + self.do_item_action(touch) + return super(TouchMenuItemBehaviour, self).on_touch_up(touch) + + def open_menu(self, touch, dt): + self.main_wid.open_menu(self, touch) + del touch.ud['menu_timeout'] + + def getMenuChoices(self): + """return choice adapted to selected item + + @return (list[dict]): choices ad expected by ModernMenu + """ + return [] + + +class TouchMenuBehaviour(object): + """Class to handle a menu appearing on long press on items + + classes using this behaviour need to have a float_layout property + pointing the main FloatLayout. + """ + float_layout = properties.ObjectProperty() + + def __init__(self, *args, **kwargs): + super(TouchMenuBehaviour, self).__init__(*args, **kwargs) + self.menu = None + self.menu_item = None + + ## menu methods ## + + def clean_fl_children(self, layout, children): + """insure that self.menu and self.menu_item are None when menu is dimissed""" + if self.menu is not None and self.menu not in children: + self.menu = self.menu_item = None + + def clear_menu(self): + """remove menu if there is one""" + if self.menu is not None: + self.menu.dismiss() + self.menu = None + self.menu_item = None + + def open_menu(self, item, touch): + """open menu for item + + @param item(PathWidget): item when the menu has been requested + @param touch(kivy.input.MotionEvent): touch data + """ + if self.menu_item == item: + return + self.clear_menu() + pos = self.to_widget(*touch.pos) + choices = item.getMenuChoices() + if not choices: + return + self.menu = TouchMenu(choices=choices, + center=pos, + size_hint=(None, None)) + self.float_layout.add_widget(self.menu) + self.menu.start_display(touch) + self.menu_item = item + + def on_float_layout(self, wid, float_layout): + float_layout.bind(children=self.clean_fl_children)