objective-ccocoanstextview

How can I set [NSTextView selectedTextAttributes] on a background window?


The default value for [NSTextView selectedTextAttributes] is unusable in my app, because i allow the user to select colors (syntax highlighting) that are almost exactly the same as the background color.

I have written some math to determine a suitable color and can use this to set it:

textView.selectedTextAttributes = @{
  NSBackgroundColorAttributeName: [NSColor yellowColor],
  NSForegroundColorAttributeName: [NSColor redColor]
  };

But when the window is in the background, it still uses the system default light grey.

I've attached screenshots of the above code with active vs inactive window. — how can I change the selected text background colour of the inactive window?

active inactive


Solution

  • You can override the colour by overriding drawing method of NSLayoutManager.

    final class LayoutManager1: NSLayoutManager {
        override func fillBackgroundRectArray(rectArray: UnsafePointer<NSRect>, count rectCount: Int, forCharacterRange charRange: NSRange, color: NSColor) {
            let color1 = color == NSColor.secondarySelectedControlColor() ? NSColor.redColor() : color
            color1.setFill()
            super.fillBackgroundRectArray(rectArray, count: rectCount, forCharacterRange: charRange, color: color1)
            color.setFill()
        }
    }
    

    And replace NSTextView's layout manager to it.

    textView.textContainer!.replaceLayoutManager(layoutManager1)
    

    Here's full working example.


    As @Kyle asks for reason of setFill, I add some update.

    From Apple manual:

    ... the charRange and color parameters are passed in merely for informational purposes; the color is already set in the graphics state. If for any reason you modify it, you must restore it before returning from this method. ...

    Which means passing-in other color into super call has no effect, and you just need to NSColor.setFill to make it work with super call. Also, the manual requires to set it back to original one.