Question

I'm trying to change the color of the scroller itself, it seems I need to overwrite something around drawKnob but I couldn't find any method which seemed appropriate.

One way I thought about was to inject a new style and get scroller to use it but again, I couldn't find anything about NSColor in NSScroller header.

Any idea?

Was it helpful?

Solution 2

I think you will have to write a subclass, and override drawKnob, maybe drawKnobSlotInRect: too depending on what you want to change.

OTHER TIPS

No need to redraw from scratch. It's as simple as this:

import AppKit

class CyanideScroller: NSScroller {
    private var _bkgrColour: NSColor = NSColor.black
    private var _knobColour: NSColor = NSColor.white
    private var isHorizontal = false

    var bkgrColour: NSColor {
        get { return _bkgrColour}
        set { _bkgrColour = newValue}
    }

    var knobColour: NSColor {
        get { return _knobColour}
        set { _knobColour = newValue}
    }

    override var frame: CGRect {
        didSet {
            let size = frame.size
            isHorizontal = size.width > size.height
        }
    }

    override func draw(_ dirtyRect: NSRect) {
        _bkgrColour.setFill()
        dirtyRect.fill()
        self.drawKnob()
    }


    override func drawKnob() {
        _knobColour.setFill()

        let dx, dy: CGFloat
        if isHorizontal {
            dx = 0; dy = 3
        } else {
            dx = 3; dy = 0
        }

        let frame = rect(for: .knob).insetBy(dx: dx, dy: dy)
        NSBezierPath.init(roundedRect: frame, xRadius: 3, yRadius: 3).fill()
    }

}

The CyanideScroller class is nice, I've just updated it a little bit. Above all I have made sure that the knob is drawn only if necessary. This is my class:

import AppKit

/**
 A custom object that controls scrolling of a document view
 within a scroll view or other type of container view.
 */
class CustomScroller: NSScroller {
    
    /**
     Depository of the horizontal Boolean value.
     */
    private var _isHorizontal: Bool = false
    
    /**
     A Boolean value that indicates whether the scroller is horizontal.
     */
    public var isHorizontal: Bool {
        return _isHorizontal
    }
    
    /**
     The background color.
     */
    public var backgroundColor: NSColor = NSColor.black
    
    /**
     The knob color.
     */
    public var knobColor: NSColor = NSColor.white
    
    /**
     A Boolean value that indicates whether the scroller draws its background.
     */
    public var drawsBackground: Bool = true
    
    override var frame: CGRect {
        didSet {
            let size = frame.size
            _isHorizontal = size.width > size.height
        }
    }
    
    override func draw(_ dirtyRect: NSRect) {
        if drawsBackground {
            backgroundColor.setFill()
            dirtyRect.fill()
        }
        if (usableParts == .allScrollerParts) {
            drawKnob()
        }
    }
    
    /**
     Draws the knob.
     */
    override func drawKnob() {
        knobColor.setFill()
        let dx, dy: CGFloat
        if _isHorizontal {
            dx = 0
            dy = 3
        } else {
            dx = 3
            dy = 0
        }
        let frame = rect(for: .knob).insetBy(dx: dx, dy: dy)
        let roundedPath = NSBezierPath(roundedRect: frame, xRadius: 3, yRadius: 3)
        roundedPath.fill()
    }
    
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top