Recently, when working on the next release of iSMARTtrain, I wanted to display an NSPopover containing the various options when a button in the toolbar was clicked. I mean, how hard can that be? – I’d already done it in the iPad version of Ergophase. Trivial!
Three hours later, it turns out, it’s not as straight-forward as I thought. Central to displaying an NSPopover is the following method call:-
(void)showRelativeToRect:(NSRect)positioningRect ofView:(NSView *)positioningView preferredEdge:(NSRectEdge)preferredEdge
Surely all I need to do is to get the view from the Toolbar button, pass it to this method, the popover’s displayed, and all is good with the world?
Well, unfortunately not.
For whatever reason, NSToolbarItem is inherited from NSObject, rather than NSControl, meaning that it has no View property that can be accessed (well, actually it does, but for the default button added in IB, view always returns Nil).
I posted my problem in Stackoverflow and, unusually, got no solution. Searching Apple’s developer forums turned up this post (http://devforums.apple.com/message/499986), which refered me to one of this year’s WWDC videos.
Once I’d seen that, everything became a bit clearer. The solution is to create an NSToolbarItem with a custom view containing an NSButton. When the button is clicked, pass the View of the button to the showRelativeToRect method, displaying the popover.
In the spirit of http://xkcd.com/979, I’m posting a really simple example with the code on github (http://github.com/tevendale/ToolbarPopover). One slight issue with the current code is the way the button behaves when clicked, but I’m sure someone smarter than me will manage to fix that.