The Cat That Ate the Rat…

Writing bugs often makes me more productive.

That, or writing requests for help.

For instance, I have a custom NSView, whose contents, mostly text, are completely laid out by a cross-platform engine, i.e. not by Cocoa. So I can’t use NSTextView.

But I want it to act like an NSTextView. For instance, I want to be able to select text just like an NSTextView, and I want a blinking cursor just like an NSTextView.

So I started writing up a query to the Cocoa-dev mailing list about this. But you don’t get much respect, or much help, if you aren’t as specific about what you need as you can be.

So first, I had to determine what I didn’t know. Which meant trying to implement it, and documenting where I got stuck.

Turns out, I didn’t get stuck, at least for the first part.

How do I get started learning about something new? Well, if I can guess an API name, I’ll start with the documentation, but usually I can’t. So I search http://search.lists.apple.com based on the words I do know, like “selected text color”. If there are a lot of false matches from other frameworks, I’ll restrict the search to Cocoa-dev, but sometimes the answer is, say, a Carbon API, so I’m inclusive at first.

I find that the spare, high-level style of Apple’s developer documentation sometimes leaves me scratching my head. Is this really what I need? The mailing lists are great for this sort of clarification.

So I find out the API I need for the selected text background is the appropriately-named:

-[NSColor selectedTextBackgroundColor]

And the post that gave me that also pointed me to the “Accessing System Colors” documentation topic, which helpfully mentioned the notification:

NSSystemColorsDidChangeNotification

which allows me to change the color in my application immediately if the user chooses a different highlight color from System Preferences.

But I wasn’t done because, when an application window is no longer foremost, the selection color changes from the user-choosable highlight color to a gray color.

I was unable to find a specific question about that, but I found another post that talked about matching API colors via the Developer color palette in the color panel. (Cmd-Shift-C in TextEdit.) There isn’t a nonForemostSelectedTextBackgroundColor system color, but there is a secondarySelectedControlColor that matches the non-foremost selected text color in TextEdit, and has a name that at least could apply to my situation.

So I have something that works, and gets its information as much from the system as possible, so it’s as future-proof as possible while still being custom. And I didn’t need to ask any questions! Except…

The same routine didn’t get me an answer as to the best, most system-friendly way to show a blinking caret. I could do the whole thing myself, but that might look weird in the radically overhauled UI in Mac OS X 10.9 “Puddy Tat,” eh? And I’d rather not have an NSTextView whose sole function is to show that caret – seems like a fragile, hacky solution.

So I have a question after all.

Fraction Jackson

I was getting a strange smearing effect when I tried to scroll in the main view of my application’s window.

I knew my content-drawing routines were being invoked correctly. I knew that the effect seemed to be happening somewhere in the depths of Cocoa, not in my code. But that’s all I knew.

Turns out, it’s because I was setting my view frames to fractional values (they’re floats, after all), but my content engine was still drawing things per integer coordinates.

This is the kind of thing that unit testing won’t help.

My goal was “make resizing the window and then scrolling through the main view work.” Can’t write a test for that because “work” means “look right,” and you can’t test for that when you don’t know how to make it look right yet.

It’s one part experimenting and one part perseverance and one part lightbulb going off after things go wrong.

And I find myself working through these kinds of issues a lot.

Anyone who says “Always write your tests first” can stick that in their pipe and smoke it.