Ask NSOutlineView for current selected row color to workaround bug?

I have a NSOutlienView. I use standard background color for selected rows (according to docs this is NSColor.alternateSelectedControlColor and NSColor.secondarySelectedControlColor).


I subclass NSTableRowview and I change the color of a label based on the current state. Something like this (ignore bad code formatting, can't format on these forums):


NSColor *labelColor;
//White if the window is key and app is active, otherwise black for the label because the white text on light gray highlight doesn't look good.
    if (self.window.isKeyWindow
        && NSApp.isActive && self.amISelected)
    {
        labelColor = [NSColor whiteColor];
    }
    else
    {
        labelColor = [NSColor blackColor];
    }


self.theLabel.textColor = labelColor;


The problem with this is my outline view can go hidden and come back. And when the outline view unhides, the selected row background color goes light gray even though the app is active and the window is key, so my label draws white text on the light gray background. I haven't been able to find a way around this. I'd imagine I'd be able to workaround this if there was a way to do something like this,


//just sniff the selected color to determine what text color to use...

if ([self.enclosingOutlineView.currentSelectedRowColor isEqual:NSColor.secondarySelectedControlColor])
{
   //do whatever
}
else
{
     //do whatever
}


But I don't see a way to do this? Sometimes I can workaround the problem by forcing the outline view to be first responder after it unhides and the selection color goes blue, but that's not great and doesn't always seem to work.

Accepted Reply

This seems to work so far:


if (self.window.isKeyWindow && NSApp.isActive && self.window.firstResponder == self.outlineView)
{
  //use light text color.
}
else
{
   //use dark text color..
}


I'm using a regular NSView not a NSTableCellView, if I remember correctly I did this because something with NSTableCellView highlighting wasn't working for me at the time, I set this up a long time ago. Perhaps I could try going back to subclassing NSTablecellView and implement backgroundStyle.

Replies

This seems to work so far:


if (self.window.isKeyWindow && NSApp.isActive && self.window.firstResponder == self.outlineView)
{
  //use light text color.
}
else
{
   //use dark text color..
}


I'm using a regular NSView not a NSTableCellView, if I remember correctly I did this because something with NSTableCellView highlighting wasn't working for me at the time, I set this up a long time ago. Perhaps I could try going back to subclassing NSTablecellView and implement backgroundStyle.

Instead of inspecting global state (which may not match NSOutlineView's own logic), you can override

-[NSTableCellView setBackgroundStyle:]
and react directly to the change in visual decoration. Don't forget to pass the
-setBackgroundStyle:
up to the superclass after you're done inspecting the value.
Post not yet marked as solved Up vote reply of .jsn Down vote reply of .jsn

I don't see a bug here. When you hide the outline view, something else becomes first responder (the window itself, if nothing else inside it). Showing the outline view doesn't automatically make it first responder again — it lost that state when it was hidden. Therefore, the selection color is light gray.


In that sense, your "workaround" is actually correct — thetext color should depend on whether the outline view is first responder.


However, you still have a lurking problem. If the selection color is itself light, using white text may not be a good choice. What you need is to ask for a text color suitable for the background color whatever it is. IIRC there is API for this, but I don't exactly remember what. I suggest you try +[NSColor selectedControlTextColor] or +[NSColor selectedTextColor] and see if one of those adapts automatically.


The other approach is to draw the text "incised" (double-shadowed) or outlined, forcing contrast against any background color.

>I don't see a bug here. When you hide the outline view, something else becomes first responder (the window itself, if nothing else inside it). Showing the outline view doesn't automatically make it first responder again — it lost that state when it was hidden.


What I was expecting when the outline view comes back from hidden (and the highlight goes light gray, but my text was still drawing white on light gray) was to get forwarded the change in background style so I could properly change the text color. But if I remember correctly I wasn't getting passed the right background style after coming back from hidden, so the wrong text color was being used so I resorted to checking if the app is active and if the window is key andif the outline view is first responder instead of relying on the background style. Perhaps I made a mistake on my end


I'll have to check this out in a smaller sample project when time permits.

Yes