diff --git a/bumblebee/popup.py b/bumblebee/popup.py new file mode 100644 index 0000000..5a288c4 --- /dev/null +++ b/bumblebee/popup.py @@ -0,0 +1,77 @@ +"""Pop-up menus.""" + +try: + import Tkinter as tk +except ImportError: + # python 3 + import tkinter as tk + +import logging + +class PopupMenu: + """The popup-menu.""" + + def __init__(self): + """Initialize.""" + # menu widget + self.root = tk.Tk() + self.root.withdraw() + self.menu = tk.Menu(self.root) + + # internal state + self._item_count = 0 + self._clicked_item = None + self._active = False + + # bind event of popup getting closed by clicking outside of its area + self.menu.bind('', + lambda event: self.root.after_idle( + self._dismiss_callback)) + + def add_menuitem(self, menuitem, callback=None): + """Add menu items.""" + item_count = self._item_count + + def click_callback(): + # call internal callback with item index + self._item_callback(item_count) + + # default to internal callback + if callback is None: + callback = click_callback + self.menu.add_command(label=menuitem, + command=click_callback) + + # track item index + self._item_count += 1 + + def _item_callback(self, which_item): + """Menu item click callback.""" + logging.debug('popup: item callback: {}'.format(which_item)) + self._clicked_item = which_item + self.root.destroy() + self._active = False + + def _dismiss_callback(self): + """Menu dismissed.""" + logging.debug('popup: menu dismissed') + if self._active is True: + self._clicked_item = None + self.root.destroy() + + def show(self, event): + """Show popup.""" + self._clicked_item = None + self.menu.tk_popup(event['x'], event['y']-50) + self._active = True + self.root.mainloop() + return self._clicked_item + + +def create_and_show_menu(event, *menuitems): + """Create a menu object and show.""" + menu_obj = PopupMenu() + for menuitem in menuitems: + menu_obj.add_menuitem(*menuitem) + + return menu_obj.show(event)