# HG changeset patch # User souliane # Date 1447928345 -3600 # Node ID e4ae8e2b0afd90077743a5926ab339de2849f73b # Parent 26046f13e93b3a77a9b374bc6df42d2dda5bac8a browser_side: improve PopupMenuPanel comments + rename a button + better PEP8 compliance diff -r 26046f13e93b -r e4ae8e2b0afd src/browser/sat_browser/base_panel.py --- a/src/browser/sat_browser/base_panel.py Tue Nov 17 19:59:14 2015 +0100 +++ b/src/browser/sat_browser/base_panel.py Thu Nov 19 11:19:05 2015 +0100 @@ -37,91 +37,95 @@ class PopupMenuPanel(PopupPanel): - """This implementation of a popup menu (context menu) allow you to assign - two special methods which are common to all the items, in order to hide - certain items and also easily define their callbacks. The menu can be - bound to any of the mouse button (left, middle, right). + """Popup menu (contextual menu) with common callbacks for all the items. + + This implementation of a popup menu allow you to assign two special methods which + are common to all the items, in order to hide certain items and define their callbacks. + callbacks. The menu can be bound to any button of the mouse (left, middle, right). """ + def __init__(self, entries, hide=None, callback=None, vertical=True, style=None, **kwargs): """ - @param entries: a dict of dicts, where each sub-dict is representing - one menu item: the sub-dict key can be used as the item text and - description, but optional "title" and "desc" entries would be used - if they exists. The sub-dicts may be extended later to do - more complicated stuff or overwrite the common methods. - @param hide: function with 2 args: widget, key as string and - returns True if that item should be hidden from the context menu. - @param callback: function with 2 args: sender, key as string - @param vertical: True or False, to set the direction - @param item_style: alternative CSS class for the menu items - @param menu_style: supplementary CSS class for the sender widget + @param entries (dict{unicode: dict{unicode: unicode}: + - menu item keys + - values: dict{unicode: unicode}: + - item data lile "title", "desc"... + - value + @param hide (callable): function of signature Widget, unicode: bool + which takes the sender and the item key, and returns True if that + item has to be hidden from the context menu. + @param callback (callbable): function of signature Widget, unicode: None + which takes the sender and the item key. + @param vertical (bool): set the direction vertical or horizontal + @param item_style (unicode): alternative CSS class for the menu items + @param menu_style (unicode): supplementary CSS class for the sender widget """ PopupPanel.__init__(self, autoHide=True, **kwargs) - self._entries = entries - self._hide = hide - self._callback = callback + self.entries = entries + self.hideMenu = hide + self.callback = callback self.vertical = vertical self.style = {"selected": None, "menu": "itemKeyMenu", "item": "popupMenuItem"} if isinstance(style, dict): self.style.update(style) - self._senders = {} + self.senders = {} - def _show(self, sender): - """Popup the menu relative to this sender's position. - @param sender: the widget that has been clicked + def showMenu(self, sender): + """Popup the menu on the screen, where it fits to the sender's position. + + @param sender (Widget): the widget that has been clicked """ menu = VerticalPanel() if self.vertical is True else HorizontalPanel() menu.setStyleName(self.style["menu"]) def button_cb(item): - """You can not put that method in the loop and rely - on _key, because it is overwritten by each step. - You can rely on item.key instead, which is copied - from _key after the item creation. - @param item: the menu item that has been clicked - """ - if self._callback is not None: - self._callback(sender=sender, key=item.key) + # XXX: you can not put that method in the loop and rely on key + if self.callback is not None: + self.callback(sender=sender, key=item.key) self.hide(autoClosed=True) - for _key in self._entries.keys(): - entry = self._entries[_key] - if self._hide is not None and self._hide(sender=sender, key=_key) is True: + for key, entry in self.entries.iteritems(): + if self.hideMenu is not None and self.hideMenu(sender=sender, key=key) is True: continue - title = entry["title"] if "title" in entry.keys() else _key - item = Button(title, button_cb) - item.key = _key - item.setStyleName(self.style["item"]) - item.setTitle(entry["desc"] if "desc" in entry.keys() else title) + title = entry.get("title", key) + item = Button(title, button_cb, StyleName=self.style["item"]) + item.key = key # XXX: copy the key because we loop on it and it will change + item.setTitle(entry.get("desc", title)) menu.add(item) - if len(menu.getChildren()) == 0: - return + + if menu.getWidgetCount() == 0: + return # no item to display means no menu at all + self.add(menu) + if self.vertical is True: x = sender.getAbsoluteLeft() + sender.getOffsetWidth() y = sender.getAbsoluteTop() else: x = sender.getAbsoluteLeft() y = sender.getAbsoluteTop() + sender.getOffsetHeight() + self.setPopupPosition(x, y) self.show() + if self.style["selected"]: sender.addStyleDependentName(self.style["selected"]) - def _onHide(popup): + def onHide(popup): if self.style["selected"]: sender.removeStyleDependentName(self.style["selected"]) return PopupPanel.onHideImpl(self, popup) - self.onHideImpl = _onHide + self.onHideImpl = onHide def registerClickSender(self, sender, button=BUTTON_LEFT): """Bind the menu to the specified sender. - @param sender: the widget to which the menu should be bound - @param: BUTTON_LEFT, BUTTON_MIDDLE or BUTTON_RIGHT + + @param sender (Widget): bind the menu to this widget + @param (int): BUTTON_LEFT, BUTTON_MIDDLE or BUTTON_RIGHT """ - self._senders.setdefault(sender, []) - self._senders[sender].append(button) + self.senders.setdefault(sender, []) + self.senders[sender].append(button) if button == BUTTON_RIGHT: # WARNING: to disable the context menu is a bit tricky... @@ -129,13 +133,13 @@ # TODO: find a cleaner way to disable the context menu sender.getElement().setAttribute("oncontextmenu", "return false") - def _onBrowserEvent(event): + def onBrowserEvent(event): button = DOM.eventGetButton(event) - if DOM.eventGetType(event) == "mousedown" and button in self._senders[sender]: - self._show(sender) + if DOM.eventGetType(event) == "mousedown" and button in self.senders[sender]: + self.showMenu(sender) return sender.__class__.onBrowserEvent(sender, event) - sender.onBrowserEvent = _onBrowserEvent + sender.onBrowserEvent = onBrowserEvent def registerMiddleClickSender(self, sender): self.registerClickSender(sender, BUTTON_MIDDLE) diff -r 26046f13e93b -r e4ae8e2b0afd src/browser/sat_browser/dialog.py --- a/src/browser/sat_browser/dialog.py Tue Nov 17 19:59:14 2015 +0100 +++ b/src/browser/sat_browser/dialog.py Thu Nov 19 11:19:05 2015 +0100 @@ -512,10 +512,10 @@ """ HorizontalPanel.__init__(self) self.groups = groups - self.add(Label('Add group:')) + self.add(Label('New group:')) self.textbox = ExtTextBox(enter_cb=self.onGroupInput) self.add(self.textbox) - self.add(Button("add", lambda sender: self.onGroupInput(self.textbox))) + self.add(Button("Add", lambda sender: self.onGroupInput(self.textbox))) self.cb = cb def onGroupInput(self, sender):