117 lines
3.1 KiB
Python
117 lines
3.1 KiB
Python
"""Pop-up menus."""
|
|
|
|
import logging
|
|
|
|
import tkinter as tk
|
|
import tkinter.font as tkFont
|
|
|
|
import functools
|
|
|
|
|
|
class menu(object):
|
|
"""Draws a hierarchical popup menu
|
|
|
|
:param config: Global config singleton, passed on from modules
|
|
:param parent: If given, this menu is a leave of the "parent" menu
|
|
:param leave: If set to True, close this menu when mouse leaves the area (defaults to True)
|
|
"""
|
|
|
|
def __init__(self, config, parent=None, leave=True):
|
|
self.running = True
|
|
|
|
self.parent = parent
|
|
|
|
self._root = parent.root() if parent else tk.Tk()
|
|
self._root.withdraw()
|
|
self._menu = tk.Menu(self._root, tearoff=0)
|
|
self._menu.bind("<FocusOut>", self.__on_focus_out)
|
|
self._font_size = tkFont.Font(size=config.popup_font_size())
|
|
|
|
if leave:
|
|
self._menu.bind("<Leave>", self.__on_focus_out)
|
|
elif not parent:
|
|
self.add_menuitem("close", self.__on_focus_out)
|
|
self.add_separator()
|
|
|
|
self._menu.bind("<ButtonRelease-1>", self.release)
|
|
|
|
"""Returns the root node of this menu
|
|
|
|
:return: root node
|
|
"""
|
|
|
|
def root(self):
|
|
return self._root
|
|
|
|
"""Returns the menu
|
|
|
|
:return: menu
|
|
"""
|
|
|
|
def menu(self):
|
|
return self._menu
|
|
|
|
def __on_focus_out(self, event=None):
|
|
self.running = False
|
|
self._root.destroy()
|
|
|
|
def __on_click(self, callback):
|
|
self._root.destroy()
|
|
callback()
|
|
|
|
def release(self, event=None):
|
|
self.running=False
|
|
if self.parent:
|
|
self.parent.release(event)
|
|
|
|
"""Adds a cascading submenu to the current menu
|
|
|
|
:param menuitem: label to display for the submenu
|
|
:param submenu: submenu to show
|
|
"""
|
|
|
|
def add_cascade(self, menuitem, submenu):
|
|
self._menu.add_cascade(label=menuitem, menu=submenu.menu(), font=self._font_size)
|
|
|
|
"""Adds an item to the current menu
|
|
|
|
:param menuitem: label to display for the entry
|
|
:param callback: method to invoke on click
|
|
"""
|
|
|
|
def add_menuitem(self, menuitem, callback):
|
|
self._menu.add_command(
|
|
label=menuitem, command=functools.partial(self.__on_click, callback), font=self._font_size,
|
|
)
|
|
|
|
"""Adds a separator to the menu in the current location"""
|
|
|
|
def add_separator(self):
|
|
self._menu.add_separator()
|
|
|
|
"""Shows this menu
|
|
|
|
:param event: i3wm event that triggered the menu (dict that contains "x" and "y" fields)
|
|
:param offset_x: x-axis offset from mouse position for the menu (defaults to 0)
|
|
:param offset_y: y-axis offset from mouse position for the menu (defaults to 0)
|
|
"""
|
|
|
|
def show(self, event, offset_x=0, offset_y=0):
|
|
try:
|
|
self._menu.tk_popup(event["x"] + offset_x, event["y"] + offset_y)
|
|
finally:
|
|
self._menu.grab_release()
|
|
|
|
while self.running == True:
|
|
try:
|
|
self._root.update_idletasks()
|
|
self._root.update()
|
|
except:
|
|
self.running = False
|
|
try:
|
|
self._root.destroy()
|
|
except:
|
|
pass
|
|
|
|
|
|
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
|