The small one inspires the big one

Here is a story from the current development process of the next major release of NeoFinder for Mac. We thought you might find this as fascinating as we do.

There is one interesting feature from NeoFinder for iOS that people really seem to like a lot, and this is the cool Find context menu in the Inspector. You have already seen and used it, right?

ios findmenuSimply tap a field on your iPhone or iPad, and NeoFinder iOS offers you to either copy the text content of that field to the clipboard, or to Find similar items.

And find similar is really smart. If you select the name of an artist, as shown here, NeoFinder iOS will search for all other songs of that artist. If you tap on the year of a song, all other songs from that year will be found, and so on. This works for many values, try it out now if you haven’t done so.

This great feature was added to the latest version of NeoFinder for iOS, and people really loved it immediately.

So, naturally, we thought about bringing this feature back from the small iOS device to the big Macintosh. It shouldn’t be so hard, we thought.

We were wrong.

Here is why, and what we did about that. There is a lot of technical stuff deep from the bowels of software development in here that is certainly very interesting for our fellow Cocoa coders, so stay with me for a while.

NeoFinder for Mac uses the NSTextField to display both the descritive label (in bold), and the content itself. Nothing unusual here so far, everyone does that.

As many other user interface elements in Cocoa, NSTextField inherits from NSView, and that has a method called setMenu: which allows you to prepare and assign a contextual menu for it.

So we tried that, prepared a proper NSMenu, and assigned it, but nothing happened.


The NSTextField still displayed the regular contextual menu supplied by Apple, and there was no trace at all of our own Find command in it:

mac os x regular context menuWe were absolutely baffled.

After a long search, and many failed experiments, we finally got a clue. NeoFinder uses this method: [textField setSelectable:YES];

This makes a lot of sense, as that allows you to select parts of the actual text, to copy it, or do any other inexplicable things with it that you may need.

However, Cocoa plays some nasty tricks under the hood for this to work. You see, NSTextField doesn’t really actually allow the selection of text!

So as soon as you click into it, it will be silently swapped out and replaced with a special NSTextView, called the Field Editor. The NSTextView is a far more complex and powerful version of the simple NSTextField, and allows the selection of text among many other things.

So our own NSTextField is no longer there for us when the context click happens.


One possible solution was to give up on the selectability of the text. But we are not about giving up, and the selection of text was too important for us.

So we found a different way.

We have subclassed NSTextField, and in that subclass, we catch the event that will make the context menu appear. It is called rightMouseDown, and we have added some special code there:

- (void)rightMouseDown:(NSEvent*)event
    if ([self isSelectable] == NO)
        [super rightMouseDown:event];
    // display our own contextual menu
    NSMenu        *theMenu = [self menuForEvent:event];
    [NSMenu popUpContextMenu:theMenu withEvent:event forView:self];

Now all is working exactly as it should:

mac os x findmenu

So both clicks are still working for each of these fields. You can click inside it to select text, or you can right-click at the field, and get the new Find command.

Stay tuned for this really exciting cool new feature in the next major release of NeoFinder Mac!