Question

I am attempting to show an NSPopover from an NSTokenField token when the token is clicked.

These tokens have a built in way to show a menu, so from a design standpoint, it's not unlike that action.

However, there does not appear to be any (good) way to execute arbitrary code when a token is clicked.

I have managed to slip some code into - tokenField:menuForRepresentedObject:, but it's far from elegant.

Assuming that - tokenField:menuForRepresentedObject: is the only way to execute code when a token is clicked, I still have another problem: getting the NSRect that represents the token, so that the NSPopover can maintain a visual relationship with said token. I've tried to do some string juggling, figure out how tokens come first, etc., but it is far from reliable, and even requires an undocumented method.

Bottom Line: How do I show an NSPopover from the selected token in an NSTokenField?

Was it helpful?

Solution 2

This is what I ended up doing. I'm working on an open-source NSTokenField alternative with this capability built in.

// in an NSWindowController
- (NSMenu *)tokenField:(NSTokenField *)tokenField menuForRepresentedObject:(id)representedObject
{
    NSRect displayRect = NSMakeRect(([NSEvent mouseLocation].x - 2.5),
                                    ([NSEvent mouseLocation].y - 2.5),
                                    5, 5);
    displayRect = [self.window convertRectFromScreen: displayRect];


    // establish popover from displayRect ...
}

It looks pretty great, despite feeling very hacked (and being ocasionally 1px off).

OTHER TIPS

I think it can't be done (see my endeavours here). The problem is that an individual token is not exposed in such a way that you can reference its bounds in order to hook it up with a popover.

Another option is to use the ability of NSMenuItem to support an arbitrary view:

- (NSMenu *)tokenField:(NSTokenField *)tokenField menuForRepresentedObject:(id)representedObject {
    NSMenu *menu = [[NSMenu alloc] init];
    NSMenuItem *item = [NSMenuItem alloc] init];
    [item setRepresentedObject: representedObject];

    NSNib *nib = [[NSNib alloc] initWithNibNamed: @"token" bundle: nil];
    [nib instantiateWithOwner: item topLevelObjects: nil];

    [menu addItem: item];
    return menu;
}

Then you can create a User Interface where the File Owner is an NSMenuItem and it is connected to a custom view with everything you wanted in the Popover. You can use the representedObject for binding to values in the nib.

I'm at the very early stages of doing this. I haven't hooked up my NSManagedObjects to the Token Field yet, and I'm just using a string array for testing, but doing it this way does get a Popover like effect, except for the little corner pointer. Seems much nicer and simpler than many of the other hacks I've seen to do this while researching this.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top