Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSMenu highlight specific NSMenuItem

How to highlight a specific NSMenuItem? There is just the method highlightedItem on the NSMenu, but no setHighlightedItem

like image 839
Peter Lapisu Avatar asked Oct 31 '22 21:10

Peter Lapisu


1 Answers

UPDATE

By browsing through the OS X Runtime headers I found another method on NSMenu which doesn't require obtaining the Carbon menu implementation. The method is called highlightItem: and works as one would expect.

So essentially, the NSMenu category can be reduced to the following:

@interface NSMenu (HighlightItemUsingPrivateAPIs)

- (void)_highlightItem:(NSMenuItem*)menuItem;

@end

@implementation NSMenu (HighlightItemUsingPrivateAPIs)

- (void)_highlightItem:(NSMenuItem*)menuItem
{
    const SEL selHighlightItem = @selector(highlightItem:);

    if ([self respondsToSelector:selHighlightItem]) {
        [self performSelector:selHighlightItem withObject:menuItem];
    }
}

@end

ORIGINAL ANSWER

While there doesn't seem to be an official way of doing this, it's possible using private(!) APIs.

Here's a category I wrote for NSMenu that allows you to highlight an item at a specific index:

@interface NSMenu (HighlightItemUsingPrivateAPIs)

- (void)_highlightItemAtIndex:(NSInteger)index;

@end

@implementation NSMenu (HighlightItemUsingPrivateAPIs)

- (void)_highlightItemAtIndex:(NSInteger)index
{
    const SEL selMenuImpl = @selector(_menuImpl);

    if ([self respondsToSelector:selMenuImpl]) {
        id menuImpl = [self performSelector:selMenuImpl];

        const SEL selHighlightItemAtIndex = @selector(highlightItemAtIndex:);

        if (menuImpl &&
            [menuImpl respondsToSelector:selHighlightItemAtIndex]) {
            NSMethodSignature* signature = [[menuImpl class] instanceMethodSignatureForSelector:selHighlightItemAtIndex];

            NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature];
            [invocation setTarget:menuImpl];
            [invocation setSelector:selHighlightItemAtIndex];
            [invocation setArgument:&index atIndex:2];
            [invocation invoke];
        }
    }
}

@end

First, it gets the Carbon menu implementation (NSCarbonMenuImpl) of the NSMenu, then it proceeds to call highlightItemAtIndex: using the specified index. The category is written in such a way that it fails gracefully if Apple decides to change the private APIs that are being used here.

like image 106
lemonmojo Avatar answered Nov 08 '22 06:11

lemonmojo