Can I open an NSMenu programatically? - macos

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.

Related

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.

How to embed an NSMenu inside a borderless window to create a fake menu bar

I am trying to create a fake menu bar in a cocoa application. I have been able to acomplish 95% of what I need, only the menu bar does not match mainMenu. See screen grab below of what I have so far.
I am using a "Pop Up Button" object in a xib to try to emulate the system menu bar. The problem is that it is a popup menu and does not look exactly like the mainMenu. Additionally, the title menu item does not hilite, and the popup menu has rounded corners that overlap the menu title. So, it's close, but no cigar.
Is it possible to create a fake menu bar inside a borderless window that matches the default system menu bar? If so, how?
I also tried using an NSStatusItem, which by default matches the system menu bar more closely than what I have been able to accomplish with a button, but I was unable to embed NSStatusItem into a window.
Ideally, if there is a way to embed an NSMenu directly in a windows view, that would be the best solution.
You'll need to create a custom button or view that looks and acts like the top-level item, then assign an NSMenu to your view's menu outlet.
You can then either implement menuForEvent: in your view and return your menu when the mouse is down, or alternatively call the NSMenu class method +popUpContextMenu:withEvent:forView: when the mouse is clicked.
This seems to be a slightly odd idea, by the way. Why do you want to do it?

Facing issue with internationalize MainMenu.xib for Cocoa based Mac OS X Application

I am working in a Cocoa based Mac OS X project and facing one issue with internationalize MainMenu.xib.
In the menu items, all titles are need to be internationalized programmatically. All the menu items like “cut”, ”copy”, ”paste” can be internationalized using setTitle except the undo and redo menu item title. Adding to this, after typing anything in the text fields of the project forms, the undo menu item title dynamically changed to “Undo Typing”. The same happens for “Redo” also.
I can set the titles of other menu and menuitems' title using,
[[[[NSApp mainMenu] itemAtIndex:1] submenu]setTitle:#"Edit_Test"]
for MainMenu.xib "Edit" menu and similarly,
[[[[[NSApp mainMenu] itemAtIndex:1] submenu]itemAtIndex:4]setTitle:#"Copy_Test"]
for NSMenuItem "Copy" which is in under "Edit" menu.
But If I use the same piece of code,
[[[[[NSApp mainMenu] itemAtIndex:1] submenu]itemAtIndex:0]setTitle:#"Undo_Test"]
the menuItem title still remain as "Undo"
NSUndoManager provides the methods undoMenuItemTitle and redoMenuItemTitle, but NSUndoManager does not send the -setTitle: messages to the "Undo" and "Redo" menu items.
So how can I track that dynamic change in title and make that "Undo Typing" internationalized also?
Is it possible to manually get the First responder of the MainMenu.xib and from that get the undomanager object? So that i can unbind the undo action that is currently present in the first responder with the undo menu item and perform undo operation manually or is it possible to just change the title programmatically without doing all these.
Please let me know if any one had come across this problem and resolved the issue.
Make a subclass of NSUndoManager and override the undoMenuTitleForUndoActionName: method and the redoMenuTitleForUndoActionName: method. Create instances of this subclass for each document (or managed object context, or other thing) that needs an undo manager.

Programmatically instantiating a NSPopUpButtonCell in Cocoa OSX

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.

How to make a keyboard shortcut to close dialog with Xcode/Interface Builder?

This seems awfully basic but here goes. If you are keyboard-oriented you get used to using Command-W to close windows all the time in OS X. I'd like to add that capability to the dialogs I am creating in Interface Builder for my program. I can see how to add a keyboard equivalent to a button action but what if I don't have a button?
Should I add an invisible button and put the shortcut on that? Seems clunky. Surely there is just some method I can override but what I've tried so far isn't working.
When you press Command + W, it's the exact same as choosing File -> Close from the menu bar. What Close does is send a performClose: message to the first responder. That, in turn, will check if the receiver or if the receiver's delegate implements windowShouldClose:, and the window will close if it returns YES (otherwise, it will call the close method).
So really, it depends on what type of dialog you've got here. If it's non-modal (essentially, if you can access the menu bar while it's running) and is an instance or subclass of NSWindow, then all you need to do is override the windowShouldClose: method in your dialog's delegate (or your dialog class, if you subclassed NSWindow or something) and make it return YES.
However, if the dialog is a modal dialog (you can't access the menu bar, switch windows, etc. while the dialog is running), then you can't do it this way. You could add an invisible button, but in all honesty, a modal dialog should not be closed by hitting Command-W, for that most certainly violates some Apple interface guideline out there. (Especially since, as Ande noted, it's standard practice to have Esc close/cancel a dialog.)
Adding an invisible button works just fine.
Is the dialog an NSWindow? Because by default the File->Close menu option is set to the performClose: action of the first responder, and already wired to command-w
If the dialog isn't a window simply make your dialog first responder and implement the performClose: action.
why don't you try this:
-(void)keyDown:(NSEvent *)theEvent{
//If the key is X or x it just closes the window
if ([theEvent.characters.uppercaseString isEqualToString:#"X"]) {
[self.window performClose:self];
}
}
or if you want to show a window you can instanciate and show it there instead of the performClose
Jasper was right about the code part. For interface builder(storyboard), there is a quick fix:
In your storyboard, hit "CMD+Shift+L" to bring up the components lib, select File Menu Item.
Add the file menu item to the Application Scene's Main Menu Node. (Remove unwanted file menus)
Now you have a keyboard shortcut to close a window.

Resources