Skip to content

Commit ce54926

Browse files
authored
Merge pull request #193 from robotools/list2menu
move VanillaMenuBuilder and add support for List2 contextual menu
2 parents ad03a54 + 855c03f commit ce54926

File tree

3 files changed

+88
-50
lines changed

3 files changed

+88
-50
lines changed

Lib/vanilla/vanillaList.py

Lines changed: 1 addition & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
from vanilla.nsSubclasses import getNSSubclass
88
from vanilla.vanillaBase import VanillaBaseObject, VanillaError, VanillaCallbackWrapper
9+
from vanilla.vanillaMenuBuilder import VanillaMenuBuilder
910

1011

1112
class VanillaTableViewSubclass(NSTableView):
@@ -195,55 +196,6 @@ def init(self):
195196
return super().init()
196197

197198

198-
def VanillaMenuBuilder(sender, items, menu, resetCallbackWrapper=True):
199-
"""
200-
Build a menu from a given set of items
201-
Each items must be a dict with the following keys:
202-
203-
* **title** title of the menu item (required)
204-
* **callback** callback when the menu item is clicked (optional)
205-
* **items** a list of sub menu items, this will build a sub menu for the given menu item.
206-
* **image** an image placed inside the menu item, must be a NSImage.
207-
* **state** a menu item state: must be either 0, 1 or -1 (on, off or mixed).
208-
* **enabled** enable the menu item, must be a bool.
209-
"""
210-
if resetCallbackWrapper:
211-
sender._menuItemCallbackWrappers = []
212-
for item in items:
213-
if isinstance(item, NSMenuItem):
214-
menu.addItem_(item)
215-
elif item == "----":
216-
item = NSMenuItem.separatorItem()
217-
menu.addItem_(item)
218-
else:
219-
title = item["title"]
220-
callback = item.get("callback")
221-
subItems = item.get("items")
222-
image = item.get("image")
223-
state = item.get("state")
224-
enabled = item.get("enabled")
225-
226-
menuItem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(title, "", "")
227-
if callback:
228-
wrapper = VanillaCallbackWrapper(callback)
229-
sender._menuItemCallbackWrappers.append(wrapper)
230-
menuItem.setTarget_(wrapper)
231-
menuItem.setAction_("action:")
232-
if subItems:
233-
subMenu = NSMenu.alloc().init()
234-
VanillaMenuBuilder(sender, subItems, subMenu, resetCallbackWrapper=False)
235-
menuItem.setSubmenu_(subMenu)
236-
237-
if image is not None:
238-
menuItem.setImage_(image)
239-
if state is not None:
240-
menuItem.setState_(state)
241-
if enabled is not None:
242-
menuItem.setEnabled_(enabled)
243-
244-
menu.addItem_(menuItem)
245-
246-
247199
class List(VanillaBaseObject):
248200

249201
"""

Lib/vanilla/vanillaList2.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
from vanilla.vanillaBase import VanillaBaseObject, VanillaCallbackWrapper, osVersionCurrent, osVersion10_16
1010
from vanilla.vanillaScrollView import ScrollView
1111
from vanilla.dragAndDrop import DropTargetProtocolMixIn, dropOperationMap, makePasteboardItem
12+
from vanilla.vanillaMenuBuilder import VanillaMenuBuilder
13+
1214

1315
simpleDataTypes = (
1416
str,
@@ -313,6 +315,12 @@ def draggingExited_(self, draggingInfo):
313315
def canDragRowsWithIndexes_atPoint_(self, indexes, point):
314316
return self.vanillaWrapper()._validateRowsForDrag(indexes)
315317

318+
# contextual menu support
319+
320+
def menuForEvent_(self, event):
321+
wrapper = self.vanillaWrapper()
322+
return wrapper._menuForEvent(event)
323+
316324

317325
class List2(ScrollView, DropTargetProtocolMixIn):
318326

@@ -395,7 +403,7 @@ class List2(ScrollView, DropTargetProtocolMixIn):
395403
396404
**editCallback** Callback to be called after an item has been edited.
397405
398-
# **menuCallback** Callback to be called when a contextual menu is requested.
406+
**menuCallback** Callback to be called when a contextual menu is requested.
399407
400408
# **enableDelete** A boolean representing if items in the list can be deleted via the interface.
401409
@@ -510,6 +518,7 @@ def __init__(self,
510518
selectionCallback=None,
511519
doubleClickCallback=None,
512520
editCallback=None,
521+
menuCallback=None,
513522
allowsGroupRows=False,
514523
floatsGroupRows=False,
515524
groupRowCellClass=None,
@@ -544,6 +553,8 @@ def __init__(self,
544553
self._doubleClickTarget = VanillaCallbackWrapper(doubleClickCallback)
545554
self._tableView.setTarget_(self._doubleClickTarget)
546555
self._tableView.setDoubleAction_("action:")
556+
# contextual menu
557+
self._menuCallback = menuCallback
547558
# behavior attributes
548559
self._allowsSelection = allowsSelection
549560
self._tableView.setAllowsEmptySelection_(allowsEmptySelection)
@@ -870,6 +881,29 @@ def _getPasteboardDataForIndex(self, index):
870881
return None
871882
return makePasteboardItem(typesAndValues)
872883

884+
# contextual menu
885+
886+
def _menuForEvent(self, event):
887+
# this method is called by the NSTableView subclass to request a contextual menu
888+
# if there is a menuCallack convert a the incomming items to an nsmenu
889+
if self._menuCallback is not None:
890+
items = self._menuCallback(self)
891+
# if the list is empty or None, dont do anything
892+
if items:
893+
menu = AppKit.NSMenu.alloc().init()
894+
VanillaMenuBuilder(self, items, menu)
895+
return menu
896+
# if a menu is been set by setMenu
897+
if self._menu is not None:
898+
return self._menu
899+
return None
900+
901+
_menu = None
902+
903+
def setMenu(self, items):
904+
self._menu = menu = AppKit.NSMenu.alloc().init()
905+
VanillaMenuBuilder(self, items, menu)
906+
873907
# Drop
874908

875909
_allowDropOnRow = None

Lib/vanilla/vanillaMenuBuilder.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
from AppKit import NSMenuItem, NSMenu
2+
3+
from vanilla.vanillaBase import VanillaCallbackWrapper
4+
5+
6+
def VanillaMenuBuilder(sender, items, menu, resetCallbackWrapper=True):
7+
"""
8+
Build a menu from a given set of items
9+
Each items must be a dict with the following keys:
10+
11+
* **title** title of the menu item (required)
12+
* **callback** callback when the menu item is clicked (optional)
13+
* **items** a list of sub menu items, this will build a sub menu for the given menu item.
14+
* **image** an image placed inside the menu item, must be a NSImage.
15+
* **state** a menu item state: must be either 0, 1 or -1 (on, off or mixed).
16+
* **enabled** enable the menu item, must be a bool.
17+
"""
18+
if resetCallbackWrapper:
19+
sender._menuItemCallbackWrappers = []
20+
for item in items:
21+
if isinstance(item, NSMenuItem):
22+
menu.addItem_(item)
23+
elif item == "----":
24+
item = NSMenuItem.separatorItem()
25+
menu.addItem_(item)
26+
else:
27+
title = item["title"]
28+
callback = item.get("callback")
29+
subItems = item.get("items")
30+
image = item.get("image")
31+
state = item.get("state")
32+
enabled = item.get("enabled")
33+
34+
menuItem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(title, "", "")
35+
if callback:
36+
wrapper = VanillaCallbackWrapper(callback)
37+
sender._menuItemCallbackWrappers.append(wrapper)
38+
menuItem.setTarget_(wrapper)
39+
menuItem.setAction_("action:")
40+
if subItems:
41+
subMenu = NSMenu.alloc().init()
42+
VanillaMenuBuilder(sender, subItems, subMenu, resetCallbackWrapper=False)
43+
menuItem.setSubmenu_(subMenu)
44+
45+
if image is not None:
46+
menuItem.setImage_(image)
47+
if state is not None:
48+
menuItem.setState_(state)
49+
if enabled is not None:
50+
menuItem.setEnabled_(enabled)
51+
52+
menu.addItem_(menuItem)

0 commit comments

Comments
 (0)