Programmatically instantiating a NSPopUpButtonCell in Cocoa OSX - cocoa

I have an openGL GUI interface and I need to have a popup menu that will be called when this a certain button is pressed in my openGL display. I want to display a menu similar to the one that pops up when you press an NSPopUPButton but I cannot use the Cocoa button itself. It seems that the best way to accomplish this is to use the NSPopupButtonCell. I cannot post my code here because I am writing the code in Lisp and accessing the Cocoa through an Objective-C bridge but I just wanted to see if the following pseudo code seems like it should display the menu or if there is an obvious flaw in my logic:
• Pseudo Code for function that is called when button is pressed:
• Initialize an NSPopUpButtonCell Using initTextCell: "test" pullsDown: NO
• allocate an NSMenu using alloc
• add two menu items using addItem:
• set the menu of the popUpButtonCell to be the menu that was just allocated using setMenu:
• Next I tried two methods to try and get the menu to actually be displayed,
first I tried using drawWithFrame:inView: and when that did not work I also tried
using drawBezelWithFrame:inView: eventhough the docs said not to use but I just
tried it out of desperation.
• finally, when the draw methods did not work I tried using performClick: on the
popupButtonCell to try and simulate the click.
None of these methods were successful in getting any sort of menu to be displayed. Is there some other way to programmatically pop up the menu contained in the cell?

I think you are looking for the trackMouse:inRect:ofView:untilMouseUp: method of NSCell
[theCell trackMouse:[NSApp currentEvent] inRect:NSZeroRect ofView:theView untilMouseUp:YES];

I think you would be better off using a plain NSMenu and calling +[NSMenu popUpContextMenu:withEvent:forView:]. If you're targetting only 10.6 and later, you might also check out -[NSMenu popUpMenuPositioningItem:atLocation:inView:], which gives you a little more control over the positioning of the menu. Just implement mouseDown: in your view, construct a menu (or load it from a nib file), and display it, and NSMenu should take care of all the details from there. Just make sure that the target and action for each NSMenuItem is set so that the action method gets called correctly when an item is selected.

Related

How to make a NSToolbar item toggle state

I have an NSToolbar with NSToolbarItem instances. One of the toolbar buttons is in one of two modes, depending on whether it currently operating (has been clicked) or not. I am handling this in code by changing the icon for the button to have a background rectangle when the command it represents is operational, but I can't help thinking there must be another way.
I've tried using the Selectable checkbox in XCode Interface Builder attribute inspector, and it sort of gives the result I want, except when it is selected I can't click any of the other toolbar items. I also can't see how to deselect it.
I'm a bit of a Cocoa noob so I expect the two state toggle thing is just waiting for me to find it, except so far I haven't been able to.
This seems like it would be a common thing to want to do, thing is how?

Can I open an NSMenu programatically?

Like the title says, I want to automatically open the menu at certain intervals. Preferably from within the program itself, as I am sure I could do something manually with applescripts+cron, which I don't want to use.
I am talking about a menu/button/whatever from the OSX menubar. Just to be clear. No custom views, just a plain nsmenu.
For opening an NSStatusItem menu, I found it easier to call the performClick method on the button belonging to the NSStatusItem. That way I didn't have to worry about properly passing an event or view to popUpContextMenu. Something like this:
statusItem.button?.performClick(nil)
You can programatically show an NSMenu by calling:
[NSMenu popUpContextMenu:YOUR_MENU withEvent:MOUSE_EVENT forView:YOUR_VIEW]
To construct the event you can use NSEvent's +mouseEventWithType:location:modifierFlags:timestamp:windowNumber:context:eventNumber:clickCount:pressure:
Note: if your menu is an NSStatusItem menu, you will have to set the item's view to be able to popUp the menu.

Can NSDatePicker have a contextual menu?

Ive been adding contextual menus to an OSX app I'm developing, and have successfully created a menu for a table view. However I'm having problems adding a contextual menu to a NSDatePicker. I've connected the 'menu' outlet to a NSMenu, but right clicking on the NSDatePicker doesn't bring up the menu.
I've checked the menu property on the date picker and it appears to be set correctly.
Is there an inherent issue with trying to create a contextual menu for a NSDatePicker? If so is there a way to get this working (short of reimplementing NSDatePicker)? I'd also prefer to avoid having an extra button to display the menu if at all possible - right clicking on the date picker is the obviously intuitive way this should work.
On OS X 10.9.5, class-dump shows that NSDatePicker overrides -rightMouseDown: (as well as -rightMouseDragged: and -rightMouseUp:). I'm guessing it doesn't call through to super and so is (accidentally?) blocking the contextual menu.
First, does right-dragging in a date picker do something unique? I've not been able to see it, but who knows. It may depend on the datePickerStyle and/or datePickerMode.
Also, I don't see an override of -mouseDown:. So, I bet that Control-clicking would bring up the contextual menu.
I recommend that you accept this limitation. However, if you really want to force the issue, you'll probably need to subclass NSDatePicker and override the -rightMouse... methods. For -rightMouseDown:, you could call NSMenu* menu = [self menuForEvent:theEvent] and, if that returns a menu, call [NSMenu popUpContextMenu:menu withEvent:theEvent forView:self]. Otherwise, do nothing (i.e. don't call through to super).
For the other two methods, you should probably just do nothing to prevent the superclass methods from getting confused by seeing right-drag and right-mouse-up events when it didn't get the right-mouse-down event.

FirstResponder as delegate for NSToolBar

I have a Mac app that consists of a window with a variable number of panes in it, each containing a tableview. The window has a toolbar with buttons, and I want the VC for the currently selected pane to handle validating the toolbar items, as well as being target for their actions.
If I could set first responder as delegate for the toolbar, this would be handled automatically, so my question is if that is possible! I have obviously googled around for this and some articles seem to hint that it is possible, but IB doesn't seem to let me do it.
An NSWindowController subclass would be better suited for this, that is the toolbar's delegate (it's natural role anyway) and can talk with the currently selected pane, using a custom protocol to decide on business logic.
Same goes for the UI/Menu action handlers; the window controller is perfect for this and your design will fit within it well.
It's not really got anything to do with the first responder as you are interested in the currently selected pane, not the first responder.

NSTextFinder action on NSTextView

I'm trying to capture all the NSTextFinderClient calls on my custom NSTextView subclass.
The show action is called on my -(void)performTextFinderAction:(id)sender override, but for find next, find previous, etc. it's not called.
Any ideas?
Thanks!
Edit:
If you create a new project and drag an NSTextView from interface builder, command-g and command-shift-g (find next and find previous) don't work when the find bar is first responder.
Why is this?
I need a custom subclass of NSTextView to respond to the find bar for every event.
I searched in the Apple's TextEdit source code because with TextEdit, the standard search bar within the Text View works fine for command-G (and other shortcuts) even the search field is the first responder.
I found the solution.
Go to your nib for the main menu, and select the "Find" (and related) menu items. They should be bound to the default action called "performFindPanelAction:." Now unbind them and bind to "performTextFinderAction:" of the First Responder instead.
You may not find that action in the First Responder's action list. So you need to add it by yourself in the First Responder's attributes inspector pane.
This was meant by the document below saying
Before OS X v10.7, the default action for these menu items was performFindPanelAction:. Whenever possible which you should update your implementation to use this new action.
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSResponder_Class/#//apple_ref/occ/instm/NSResponder/performTextFinderAction:
The find bar communicates privately with the client's NSTextFinder instead of calling NSResponder's -performTextFinderAction:. This is necessary to allow find to work when something besides the client has key focus.
What are you trying to accomplish?

Resources