1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
from AppKit import *
from objc import nil
from .base import Widget
class ContextMenuHandler(NSObject):
def initWithCallback_widget_i_(self, callback, widget, i):
self = super(ContextMenuHandler, self).init()
self.callback = callback
self.widget = widget
self.i = i
return self
def handleMenuItem_(self, sender):
self.callback(self.widget, self.i)
class MiroContextMenu(NSMenu):
# Works exactly like NSMenu, except it keeps a reference to the menu
# handler objects.
def init(self):
self = super(MiroContextMenu, self).init()
self.handlers = set()
return self
def addItem_(self, item):
if isinstance(item.target(), ContextMenuHandler):
self.handlers.add(item.target())
return NSMenu.addItem_(self, item)
class ContextMenu(object):
def __init__(self, options):
super(ContextMenu, self).__init__()
self.menu = MiroContextMenu.alloc().init()
for i, item_info in enumerate(options):
if item_info is None:
nsitem = NSMenuItem.separatorItem()
else:
label, callback = item_info
nsitem = NSMenuItem.alloc().init()
font_size = NSFont.systemFontSize()
font = NSFont.fontWithName_size_("Lucida Sans Italic",
font_size)
if font is None:
font = NSFont.systemFontOfSize_(font_size)
attributes = {NSFontAttributeName: font}
attributed_label = \
NSAttributedString.alloc().initWithString_attributes_(
label, attributes)
nsitem.setAttributedTitle_(attributed_label)
else:
nsitem.setTitle_(label)
if isinstance(callback, list):
submenu = ContextMenu(callback)
self.menu.setSubmenu_forItem_(submenu.menu, nsitem)
else:
handler = \
ContextMenuHandler.alloc().initWithCallback_widget_i_(
callback, self, i)
nsitem.setTarget_(handler)
nsitem.setAction_('handleMenuItem:')
self.menu.addItem_(nsitem)
def popup(self):
# support for non-window based popups thanks to
# http://stackoverflow.com/questions/9033534/how-can-i-pop-up-nsmenu-at-mouse-cursor-position
location = NSEvent.mouseLocation()
frame = NSMakeRect(location.x, location.y, 200, 200)
window = NSWindow.alloc().initWithContentRect_styleMask_backing_defer_(
frame,
NSBorderlessWindowMask,
NSBackingStoreBuffered,
NO)
window.setAlphaValue_(0)
window.makeKeyAndOrderFront_(NSApp)
location_in_window = window.convertScreenToBase_(location)
event = NSEvent.mouseEventWithType_location_modifierFlags_timestamp_windowNumber_context_eventNumber_clickCount_pressure_(
NSLeftMouseDown,
location_in_window,
0,
0,
window.windowNumber(),
nil,
0,
0,
0)
NSMenu.popUpContextMenu_withEvent_forView_(self.menu,
event,
window.contentView())
|