NSMenu programmatically select item - objective-c

I'm writing a plugin for application - custom keyboard shortcut. I can traverse through its views.
I need to open popup menu, select item in it, then open its submenu and select some item in submenu.
For now I'm only able to open top popup menu by sending performClick: to related NSPopUpButton element.
How can I programmatically select item in menu and open its submenu?
I've tried:
call selectItem: on the NSPopUpButton (and related NSMenu). No luck and I see a notion in the doc: "Note that while a menu is tracking user input, programmatic changes to the menu such as adding, removing, or changing items on the menu is not reflected"
send keyboard events (using this answer). No luck - may be because I'm holding some keys at the moment of sending those events
to find any info on how to do it via Accessibility API, but I just can't find anything on how to use it on current Application (or even on any other application, but with Objective-C)

Use the NSMenu method - (void)performActionForItemAtIndex:(NSInteger)index
NSUInteger idx = [[[menuItem menu] itemArray] indexOfObject:menuItem];
[[menuItem menu] performActionForItemAtIndex:idx];

For opening submenu: performActionForItemAtIndex:
For selecting and opening menu:
selectItemAtIndex: + performClick:
Do not call performActionForItemAtIndex: on item that does not have submenu cause you might trigger action that might have been set by someone else.
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
NSMenu *menu = self.popup.menu;
NSMenuItem *item = [menu itemAtIndex:2];
[item setAction:#selector(terminate:)];
[item setTarget:NSApp];
}
- (IBAction)action:(id)sender {
//[self.popup.menu performActionForItemAtIndex:2]; -> if not submenu this will quit your app
[self.popup selectItemAtIndex:2]; //-> first select menu item
[self.popup performClick:nil]; //-> open menu - will not quit app
}

In addition to #LCC 's answer, you can also call indexOfItem on NSMenu
NSInteger index = [item.menu indexOfItem:item];
[item.menu performActionForItemAtIndex:index];

Related

NSEvent from a NSButton

I have a NSTableView and each row contains a button. I also have a menu associated with the table.
The issue is : I want to show the menu on click of button. If possible do not show on right click.
The action method is :
- (IBAction)showMenu:(NSButton *)button {
NSLog(#"show menu");
NSMenu *menu = [self.tableView menu];
NSEvent *event = [[NSEvent alloc] init];
[NSMenu popUpContextMenu:menu
withEvent:event
forView:button];
}
Here what to do with event? If I use nil then the menu is showed at bottom left corner, not next to the button.
Any guidance would be appreciated.
You could try using -[NSMenu popUpMenuPositioningItem:atLocation:inView:]. This method doesn't take an NSEvent argument. Instead, you give it a view and a location in the view's coordinate system, and the menu positions itself (or one of its items) over that location.
But I would suggest you don't use an NSButton at all. If you use an NSPopUpButton instead, it will take care of showing the menu at the correct location on a left-click.

Custom Created Window Getting Closed Automatically By Selecting Contextual Menu Option Automatically

I have builded a custom window; in this window I am showing nsbuttons.
I am showing a contextual menu if button clicked.
The problem is I don't want to close my window but somehow mouse exited event is getting triggered as soon as I choose option from nsmenu.
I want to prevent this effect.
I am not able to figure it out.
Any help would be appreciated.
Thanks in Advance
-(void)rightMouseDown:(NSEvent *)theEvent
{
NSMenu *theMenu = [[NSMenu alloc] initWithTitle:#"Contextual Menu"];
[[theMenu addItemWithTitle:#"Remove From List" action:#selector(removeWithIdentifier) keyEquivalent:#""] setTarget:self];
[[theMenu addItemWithTitle:#"Open" action:#selector(openAppWithIdentifier) keyEquivalent:#""] setTarget:self];
[theMenu popUpMenuPositioningItem:nil atLocation:NSMakePoint(self.bounds.size.width-20, self.bounds.size.height-10) inView:self];
}
-(void)removeWithIdentifier
{
//My custom view is getting mouse exited event from here
//I want prevent it.
}
Hey Friends I have got the answer.
I have found that If your window level is "NSPopUpMenuWindowLevel" and its
view has implemented any context menu over it then this view will always gets mouse exited event.
posting it for future reference.
thanks.

Best way to toggle "Show/Hide" menu item in Cocoa Desktop

My app has an 'inspector' panel defined by a .xib file and a custom window controller class: AdjustmentsWindow.xib and AdjustmentsWindowController.m.
I want to have a Window -> Show Adjustments menu item in the application's main menu bar, that when selected will show the adjustments window. I dropped and NSObject instance into the xib containing the main menu, and changed its class to "AdjustmentsWindowController". I also hooked the menu item's action to the controller's -showWindow: method. So far so good: The window controller is instanced on app launch, and when you select the menu item it shows its window.
But I want the same menu item to double as 'Hide Adjustments' when the window is already visible (effectively toggling visibility). So here is what I did:
AdjustmentsWindowController.m:
- (void) windowDidLoad
{
[super windowDidLoad];
[[self window] setDelegate:self];
}
- (void) showWindow:(id)sender
{
// (Sent by 'original' menu item or 'restored' menu item)
[super showWindow:sender];
// Modify menu item:
NSMenuItem* item = (NSMenuItem*) sender;
[item setTitle:#"Hide Adjustments"];
[item setAction:#selector(hideWindow:)];
}
- (void) hideWindow:(id) sender
{
// (Sent by 'modified' menu item)
NSMenuItem* item = (NSMenuItem*) sender;
// Modify back to original state:
[item setTitle:#"Show Adjustments"];
[item setAction:#selector(showWindow:)];
[self close];
}
- (void) windowWillClose:(NSNotification *)notification
{
// (Sent when user manually closes window)
NSMenu* menu = [[NSApplication sharedApplication] mainMenu];
// Find menu item and restore to its original state
NSMenuItem* windowItem = [menu itemWithTitle:#"Window"];
if ([windowItem hasSubmenu]) {
NSMenu* submenu = [windowItem submenu];
NSMenuItem* item = [submenu itemWithTitle:#"Hide Adjustments"];
[item setTitle:#"Show Adjustments"];
[item setAction:#selector(showWindow:)];
}
}
My question is, is this the right/smartest/most elegant way to achieve this? I mean, this is pretty standard behaviour in cocoa apps (cf. Numbers' "Inspector"), how does everyone else do it?
One way to improve it would be to avoid the code duplication of restoring the menu item to its original title/action. Also, ideally I would replace the title strings with calls to NSLocalizedString(). But perhaps there's a more elegant, standard approach that I don't know...
Application Menu and Pop-up List Programming Topics said
validateMenuItem: is also a good place to toggle titles or set state on menu items to make sure they're always correct.

Disable menu highlight when pressing shortcut key

I would like to disable the Application "menu highlight" that happens when you press a shortcut key assigned to an NSMenuItem that belongs to the specific menu in question.
The issue is that in the application you use the keyboard quite a bit and having the menus becoming highlighted all the time becomes a bit annoying but I still want to have the menus (including the shortcuts) there as it shows the user which actions that can be used.
Declare a custom NSMenuItem subclass and start using that custom class instead of NSMenuItem.
In this class you should override this method:
- (BOOL)isHighlighted
{
return NO;
}
This way you will not have the menu item highlighted.
EDIT
Try this:
[item setOnStateImage: item.offStateImage];
FFR: Look up the following methods in the docs:
- (BOOL)validateMenuItem:(NSMenuItem *)menuItem
Will work for both selecting the menu item and the associated command key.
Within your NSDocument provide a body for validateMenuItem
such as,
- (BOOL)validateMenuItem:(NSMenuItem *)menuItem
{
SEL theAction = [menuItem action];
if (theAction == #selector(openPreferencesPanel:)) {
return !_isCurrentlyModal; //A BOOL in MyDocument
}
return [super validateMenuItem:menuItem]; // Keep this for proper cut, paste, etc validation
}
In your case, the above selector might be highlight:. Check the nib/xib and inspect it. It might be attached to the First Responder. Copy the method name.
Also have a gander at for more general items (buttons, etc) and also includes menu items.
- (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)anItem

How to open a window on click on NSStatusItem?

I'm pretty new to cocoa, so please excuse me for any stupid mistakes I make.
I have a NSStatusItem, which I want to use to open up a menu. However as far as I know and have heard across different forms, without a custom view you are restricted to just a pop down menu. Is this true? And if so how do you make a custom view to do something (e.g. open a window in my case)? Thanks for any help.
No, it is not true. You need to set up the target and action for the status item to call a method which does what you want (opens the window).
// This goes where you set up the status item
NSStatusItem *statusItem; // You need to get this from the status bar
[statusItem setTarget:self];
[statusItem setAction:#selector(openWindow:)];
// This method is called when the status item is clicked
- (void)openWindow:(id)sender {
NSWindow *window = [self window]; // Get the window to open
[window makeKeyAndOrderFront:nil];
}
You may also want to call [NSApp activateIgnoringOtherApps:nil]; to your openWindow: method to ensure that the window you open is not behind some other application's window.