SOLVED additional custom functionality in “Display...” menu. Possible? If yes, How?
-
Hey guys
Is there an easy way to add custom checkboxes/items into Display... menu in Glyph Window that would interact with custom methods/objects?I want to trigger with the checkboxes in this menu scripts that will draw some stuff with the drawing observers.
Also, I have some ideas to add some additional subviews with canvas groups, that will show some interesting things. I also would like to trigger them with those checkboxes.
I really Hope I made my question clear and I hope it is possible.
PS
if this menu is sacred, or something, is there option to create additional one on the same line? next to it?
-
added to the docs as an example: Custom display menu in the Glyph Window – thanks!
-
Cool, Thanks Guys! Will try first thing tomorrow
-
to get the checkboxes right you need to dive a bit into vanilla/AppKit objects...
from mojo.UI import CurrentGlyphWindow from vanilla import PopUpButton w = CurrentGlyphWindow() if w: bar = w.getGlyphStatusBar() if hasattr(bar, "myButton"): del bar.myButton def callback(sender): # toggle the state item = sender.getNSPopUpButton().selectedItem() item.setState_(not item.state()) print(sender.get()) bar.myButton = PopUpButton((120, 0, 85, 16), ["hello world…", 'A', 'B', 'C'], sizeStyle="small", callback=callback) bar.myButton.getNSPopUpButton().setPullsDown_(True) bar.myButton.getNSPopUpButton().setBordered_(False) for menuItem in bar.myButton.getNSPopUpButton().itemArray()[1:]: # set the state menuItem.setState_(True)
-
I imagine what is the best way to save the settings of my custom menu. So if I close RF, then after opening it will look the same (will have the same checkboxes checked). I've been thinking about storing data in .plist or .ini file next to the script. Is it a good solution?
you can use
setExtensionDefault
andgetExtensionDefault
for that:from mojo.extensions import setExtensionDefault, getExtensionDefault key = "com.rafalbuchner.toolName" myMenuItems = [('A', True), ('B', True), ('C', False)] setExtensionDefault(key, myMenuItems) print(getExtensionDefault(key))
-
here’s how you can make your custom menu look the same as the Display menu:
from mojo.UI import CurrentGlyphWindow from vanilla import PopUpButton w = CurrentGlyphWindow() if w: bar = w.getGlyphStatusBar() if hasattr(bar, "myButton"): del bar.myButton bar.myButton = PopUpButton((120, 0, 85, 16), ["hello world…", 'A', 'B', 'C'], sizeStyle="small") bar.myButton.getNSPopUpButton().setPullsDown_(True) bar.myButton.getNSPopUpButton().setBordered_(False)
-
I'm reopening this thread, because I thought, that maybe anyone of you would like to share the opinion about this script.
The script that I'm sharing with you is my solution for creating simple, generic custom display functionality.
I would like to know how to make the menu look more like the "Display...".
The stuff that I would like to do (but I don't know how to make it work):
- "Display..." has separate place next to each item's title for the check label
- "Display..."'s main title is a little bit smaller
- "Display..."'s main label doesn't have this white background with rounded corners
- I imagine what is the best way to save the settings of my custom menu. So if I close RF, then after opening it will look the same (will have the same checkboxes checked). I've been thinking about storing data in .plist or .ini file next to the script. Is it a good solution?
By the way, Feel free to use it anyhow you want. The example of how to use the script is at the bottom of it. Everything under
if __name__ == "__main__":
are the classes that build this thing.from mojo.UI import CurrentGlyphWindow from mojo.events import addObserver, removeObserver import vanilla from vanilla.vanillaBase import _reverseSizeStyleMap from AppKit import NSMenuItem class CustomMenuItem: """This object is made to interact with CustomDisplayOptions""" def __init__(self, title, observer, callback): self.title = title # title in the menu self.observer = observer self.callback = callback def addObservers(self): addObserver(self, "callback", self.observer) def removeObservers(self): removeObserver(self, self.observer) class CustomDisplayOptions: """it adds addtional slot with pupup menu that works similar to "Display…" menu in CurrentGlyphWindow""" def __init__(self, window, customDisplayMenuItems): self.window = window self.customDisplayMenuItems = customDisplayMenuItems self.bar = self.window.getGlyphStatusBar() self.initCustomMenuItems() if hasattr(self.bar, "displayMenu"): del self.bar.displayMenu self.bar.displayMenu = MyActionButton( (-75, 2, 60, 16), self.items, sizeStyle="mini") self.bar.displayMenu.setTitle("Show...") def initCustomMenuItems(self): itemObjs = [] if isinstance(self.customDisplayMenuItems[0],dict): # If the CustomDisplayOptions was list of dict as customDisplayMenuItems for menuItemDescritption in self.customDisplayMenuItems: title, observer, callback = menuItemDescritption["title"],menuItemDescritption["observer"],menuItemDescritption["callback"] itemObjs += [CustomMenuItem(title, observer, callback)] else: # If the CustomDisplayOptions was list of CustomMenuItem objects as customDisplayMenuItems itemObjs = self.customDisplayMenuItems self.items = [ dict(title=menuItem.title, callback=self.checkboxCallback) for menuItem in itemObjs ] self.itemObjsDict = {menuItem.title:menuItem for menuItem in itemObjs} self.checkboxValue = {item["title"]:False for item in self.items} def removeObservers(self): for itemTitle in self.itemObjsDict: self.itemObjsDict[itemTitle].removeObservers() def checkboxCallback(self, sender): # check box functionality itemTitle = sender.title() check = "✓ " if check in itemTitle: itemTitle = itemTitle.replace(check,"") if sender.title() == itemTitle: sender.setTitle_(check+itemTitle) self.checkboxValue[itemTitle] = True self.itemObjsDict[itemTitle].addObservers() else: sender.setTitle_(itemTitle) self.checkboxValue[itemTitle] = False self.itemObjsDict[itemTitle].removeObservers() class MyActionButton(vanilla.ActionButton): # Custom version without gearwheel def __init__(self,posSize, items, sizeStyle="regular", bordered=True): super(MyActionButton, self).__init__(posSize, items, sizeStyle="regular", bordered=True) def getFirstItem(self): sizeStyle = _reverseSizeStyleMap[self._nsObject.cell().controlSize()] firstActionItem = NSMenuItem.alloc().init() firstActionItem.setTitle_("") return firstActionItem class CustomDisplayMenuForCurrentGlyphWindow: """Environment that triggers objects described above""" def test(self): self.w = vanilla.FloatingWindow((100,100,100,100),"TEST") self.w.open() self.w.bind("close",self.testwinClosed) def testwinClosed(self,sender): removeObserver(self,"glyphWindowDidOpen") removeObserver(self,"glyphWindowWillClose") def __init__(self, customDisplayMenuItems): self.test() self.customDisplayMenuItems = customDisplayMenuItems addObserver(self, "glyphWindowDidOpen_Observer","glyphWindowDidOpen") addObserver(self, "glyphWindowWillClose_Observer","glyphWindowWillClose") def glyphWindowDidOpen_Observer(self, info): if not hasattr(self, "displayOpt"): self.displayOpt = CustomDisplayOptions(info["window"], self.customDisplayMenuItems) def glyphWindowWillClose_Observer(self, info): if hasattr(self, "displayOpt"): self.displayOpt.removeObservers() delattr(self, "displayOpt") if __name__ == "__main__": ### the example import mojo.drawingTools as dt # creating actions for the displaying def drawRedCirce(sender): dt.fill(1,0,0) dt.oval(0,0,100,100) drawRedCircle = drawRedCirce # if I won't do it, it throws error. I don't know how to go around that def drawBlueRect(sender): dt.fill(0,0,1) dt.rect(0,0,100,100) drawBlueRect = drawBlueRect # if I won't do it, it throws error. I don't know how to go around that # Creating list of special CustomMenuItems objects customDisplayMenuItems = [ dict(title="red circle", observer="draw", callback=drawRedCircle), dict(title="blue rect", observer="draw", callback=drawBlueRect), ] CustomDisplayMenuForCurrentGlyphWindow(customDisplayMenuItems)
-
@frederik
I think I figured it out, I will do it with the action popup buttonfrom vanilla import * class ActionPopUpButtonDemo(object): def __init__(self): self.w = Window((100, 40)) items = [ dict(title="first", callback=self.firstCallback), dict(title="second", callback=self.secondCallback), dict(title="third", items=[ dict(title="sub first", callback=self.subFirstCallback) ]) ] self.w.actionPopUpButton = ActionButton((10, 10, 30, 20), items, ) self.w.open() def firstCallback(self, sender): print("first") def secondCallback(self, sender): print("second") def subFirstCallback(self, sender): print("sub first") ActionPopUpButtonDemo()
-
Thanks, @frederik!
I promise, the last question (lately I'm a real pain :D ): is there an easy way to create popup menu with similar functionality to the display menu?What I mean is:
it is basically the list of the checkboxes that appear after you press the title "Display" which never changes.
I've been thinking of creating the button that will open a new window, but it wouldn't look that good
-
The "Display.." menu is not so easily accessible...
Since RF3.2 the statusbar is available to set data or adding other views.
from mojo.UI import CurrentGlyphWindow import vanilla w = CurrentGlyphWindow() bar = w.getGlyphStatusBar() # set info in the statusbar bar.set(["hello", "world"], fadeOut=True, warning=True) # add an other vanilla control if hasattr(bar, "myButton"): del bar.myButton bar.myButton = vanilla.Button((130, 2, 50, 16), "hit me", sizeStyle="mini")