Search code examples
macoscocoaxcode4.2nsoutlineview

NSOutlineView custom view for cells without using NSTableRowView


I want to know how to set the background of a selected item in an NSOutlineView. By setting the SelectionHighlightStyle to NSTableViewSelectionHighlightStyleSourceList, I get the standard intense blue highlight mode.

I was able to change the background of the selected NSTextFieldCell, but the left part of the background of the row was still the standard blue. Furthermore, I can't define a gradient.

So I figured out I have to use a custom view and found NSTableRowView. But since I'm working on 10.6.8, I wondered if there was any other possibility to create a custom gradient highlight style. And even better would be an alternate approach to using NSTableRowView as a whole.

I did not find any information to realize this in any Class Reference or delegation. If there is nothing like this, how did Apple design and develop the source list in XCode 4.2? The color blue is much lighter and the top element has two rows of line.


Solution

  • View-Based NSTableViews/NSOutlineViews are only available on 10.7 and above, so any solution that uses NSTableRowView won't work if you're trying to support 10.6.8. The way I would do this is to use a custom NSOutlineView subclass. Then override -highlightSelectionInClipRect: and -drawBackgroundInClipRect:. In -highlightSelectionInClipRect:, you'll draw the gradient highlight for the selected row(s), which you can get using -selectedRowIndexes and -rectOfRow.

    The code to do all this won't be terribly simple, but I've done it before, so it's definitely possible. One gotcha that caused me some serious headaches at one point is that internally, -drawBackgroundInClipRect: is called from both -[NSOutlineView drawRect] and directly by -[NSClipView drawRect]. The caller of the method determines the coordinate space that the clipRect argument is in. You can use this snippet of code to make sure it's in the NSTableView's coordinate space:

    - (void)drawBackgroundInClipRect:(NSRect)clipRect
    {
        clipRect = [self convertRect:clipRect fromView:[NSView focusView]];
    
        // Now do your background drawing. 
        // Easy if it's a solid background, more complex if you want alternating row colors
    }
    

    With all of that said, this becomes much easier if you can go ahead and just use a View-Based NSTableView/NSOutlineView and drop support for 10.6. You don't have to subclass NSOutlineView at all in that case, and can do all your custom drawing in simple NSTableRowView and NSTableCellView subclasses.