iTunes has a great user interface affordance for adding actions to text: clickable arrows embedded right next to the text. (Perhaps Apple wanted to avoid an interface filled with blue, underlined text.) I haven’t found any formal name for them in Apple’s HIG, so I call them link arrows (or jump arrows). Sadly, this is my third post on recreating link arrows. My first post was a first pass at the problem, whereas my second post looked a bit better but not great.
This time, the UI looks right, and clicking works as expected. I wrote up a small sample app to demo the link arrows; see Google Code.
The key is tracking. In the previous post, I used NSCell::hitTestForEvent to detect whether a click “hit” the link arrow image on a mouse down event, but then I immediately acted on it, without waiting for a mouse up event. Jarring and wrong.
I need to track what happens after that initial NSLeftMouseDown event. For this, I use NSCell::trackMouse to track all relevant mouse events until the next NSLeftMouseUp event. Thanks to Apple’s PhotoSearch sample app and Rowan Beentje’s Sequel Pro code for this much needed direction.
There are a couple corner cases I handle in trackMouse:
mouse down outside => mouse up inside (no click)
mouse down inside => mouse up outside (no click)
mouse down inside => mouse drag out => mouse drag in => mouse up inside (click)
</ul>
These mouse event sequences are what people expect from buttons, and I want people to think of the link arrows as buttons, as iTunes treats them.
Below is the main code from LinkArrowCell.m. The rest is just scaffolding.
Before I went with the trackMouse approach, I looked at subclassing NSCell and overriding startTrackingAt, continueTracking, stopTracking. For some reason, my overridden methods never triggered. Very odd as Apple's NSCell docs bring up the approach, and many developers refer to it working on various email lists like cocoa-dev. Still not sure why this path didn't work, but trackMouse certainly does.
Again, a sample project for this code is at Google Code.