Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hide/Show menu item in application's main menu by pressing Option key

Tags:

cocoa

nsmenu

I want to add a menu item into the application's main menu that will be used quite rare. I want it to be hidden by default and show it only when user hold down Option key. How do i do this?

It seems that I should handle flagsChanged:, but it is NSResponder's method and NSMenu does not inherits from NSResponder? I tried it inside main window controller, and it works when I press Option key before I click on menu. The following use case doe not work: click on menu item (there is no item), press option key — my item should appear, release option key — item should disappear.

I've also tried NSEvent's addLocalMonitorForEventsMatchingMask:handler: and addGlobalMonitorForEventsMatchingMask:handler: for NSFlagsChangedMask but when option key pressed while main menu is open neither local or global handlers are not fired.

How can I do this?

like image 473
Vladimir Prudnikov Avatar asked Jun 26 '12 13:06

Vladimir Prudnikov


People also ask

How do I hide menu items in MFC?

It's not possible to hide a menu in Win32, MFC is just a wrapper over this framework. You've got to remove this menu item when not needed and then insert it back at the same location using InsertMenu, have a look at MF_BYPOSITION and MF_BYCOMMAND.

How do I hide items on my toolbar?

The best way to hide all items in a menu with just one command is to use "group" on your menu xml. Just add all menu items that will be in your overflow menu inside the same group. Then, on your activity (preferable at onCreateOptionsMenu), use command setGroupVisible to set all menu items visibility to false or true.

Which menu item is not typically found in the File menu?

The menu item that is not typically found in File menu is 'Copy'.

How do I Hide and show a menu item in Android Actionbar?

This example demonstrates how do I hide and show a menu item in the Android ActionBar. Step 1 − Create a new project in Android Studio, go to File ⇒ New Project and fill all required details to create a new project. Step 2 − Add the following code to res/layout/activity_main.xml. Step 3 − Add the following code to src/MainActivity.java

How do I show/hide a menu item in the plugin?

Choose Show or hide from the first drop-down box. It instructs the plugin to show/hide the chosen menu item if the following conditions are matched. Set your condition in the next box.

How do I hide the app list in Windows 10 Start menu?

This tutorial will show you how to hide or show the app list in the Start menu for your account in Windows 10. This doesn't apply to full screen Start. 1 Open Settings, and click/tap on the Personalization icon. 3 When finished, you can close Settings if you like. They're still not getting it!

How to hide WordPress menu items based on user roles?

Hide WordPress Menu by User-Roles. Nav Menu Roles is another popular plugin to hide menu items based on user roles. So you can show some items to certain users only and hide the same from others as well. After installing, go to Menus to manage item visibility. Set Display mode for each item regardless of the reader’s role on the site.


Video Answer


4 Answers

There's some complex answers here but it's actually very simple:

Create 2 menuitems. The first is the default with whatever keyEquivalent and title you want. The second is what will be shown when the modifier key is down - again with separate keyEquivalent and title. On the second menuitem, enable 'Alternate' and everything else will happen automatically.

The required modifier is detected by comparing the 2 keyEquivalent values.

like image 95
martinjbaker Avatar answered Sep 30 '22 11:09

martinjbaker


Add the following to applicationDidFinishLaunching.

// Dynamically update QCServer menu when option key is pressed
NSMenu *submenu = [[[NSApp mainMenu] itemWithTitle:@"QCServer"] submenu];    
NSTimer *t = [NSTimer timerWithTimeInterval:0.1 target:self selector:@selector(updateMenu:) userInfo:submenu repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:t forMode:NSEventTrackingRunLoopMode];

then add

- (void)updateMenu:(NSTimer *)t {

    static NSMenuItem *menuItem = nil;
    static BOOL isShowing = YES;

    // Get global modifier key flag, [[NSApp currentEvent] modifierFlags] doesn't update while menus are down
    CGEventRef event = CGEventCreate (NULL);
    CGEventFlags flags = CGEventGetFlags (event);
    BOOL optionKeyIsPressed = (flags & kCGEventFlagMaskAlternate) == kCGEventFlagMaskAlternate;
    CFRelease(event);

    NSMenu *menu = [t userInfo];

    if (!menuItem) {
        // View Batch Jobs...
         menuItem = [menu itemAtIndex:6];
        [menuItem retain];
    }

    if (!isShowing && optionKeyIsPressed) {
        [menu insertItem:menuItem atIndex:6];
        [menuItem setEnabled:YES];
        isShowing = YES;
    } else if (isShowing && !optionKeyIsPressed) {
        [menu removeItem:menuItem];
        isShowing = NO;
    }

    NSLog(@"optionKeyIsPressed %d", optionKeyIsPressed);
}

The timer only fires while controls are being tracked so it's not too much of a performance hit.

like image 33
naughton Avatar answered Oct 09 '22 22:10

naughton


When constructing the menu include the optional item and mark it as hidden. Then set your class instance as the menu's delegate and add a run loop observer while the menu is open to control the optional item's hidden state.

@implementation AppController {
    CFRunLoopObserverRef _menuObserver;
}

- (void)updateMenu {
    BOOL hideOptionalMenuItems = ([NSEvent modifierFlags] & NSAlternateKeyMask) != NSAlternateKeyMask;
    [self.optionalMenuItem setHidden:hideOptionalMenuItems];
}

- (void)menuWillOpen:(NSMenu *)menu {
    [self updateMenu];

    if (_menuObserver == NULL) {
        _menuObserver = CFRunLoopObserverCreateWithHandler(NULL, kCFRunLoopBeforeWaiting, true, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
            [self updateMenu];
        });

        CFRunLoopAddObserver(CFRunLoopGetCurrent(), _menuObserver, kCFRunLoopCommonModes);
    }
}

- (void)menuDidClose:(NSMenu *)menu {
    if (_menuObserver != NULL) {
        CFRunLoopObserverInvalidate(_menuObserver);
        CFRelease(_menuObserver);
        _menuObserver = NULL;
    }
}
like image 11
Matt Stevens Avatar answered Oct 09 '22 22:10

Matt Stevens


The best way you can achieve this is by using two menu items, the first menu item uses a custom view of height 0, and is disabled, then right under it is an "alternate" item. (You will have to set this item's keyEquivalentModifierMask to NSAlternateKeyMask) With this arrangement, when you press the option key, NSMenu will automatically replace the zero-height menu item with the alternate item which will have the effect of making a menu item magically appear.

No need for timers, updates or flag change notifications.

This functionality is described in the documentation here: Managing Alternates

like image 10
Psycho Avatar answered Oct 09 '22 22:10

Psycho