Textured NSWindow Background Gradient

I am trying to generate my own textured NSWindow so it appears with a different gradient to the default metallic appearing one.

So far I've subclassed NSWindow with no success as below.

import Cocoa

class PSWindow: NSWindow {

    override init(contentRect: NSRect, styleMask aStyle: Int, backing bufferingType: NSBackingStoreType, defer flag: Bool) {
        super.init(contentRect: contentRect, styleMask: aStyle, backing: bufferingType, defer: flag)

        let gradient: NSGradient = NSGradient(startingColor: NSColor(red: 48 / 255, green: 35 / 255, blue: 174 / 255, alpha: 1), endingColor: NSColor(red: 200 / 255, green: 109 / 255, blue: 215 / 255, alpha: 1))

        gradient.drawInRect(contentRect, angle: 45)
    }
}

Am I even going about this the correct way?

Upvotes: 1

Views: 1196

Answers (1)

Marek H
Marek H

Reputation: 5576

NSWindow is a subclass of NSResponder and you shouldn't be drawing within it.

Solutions:

  1. You should override "contentView" variable (custom window subclass) and set its layer to CAGradientLayer which you create in the set method of "contentView"

  2. Create custom subclass of NSView and set the it to be the view of custom window in the Storyboard/XIB. In the view you either override drawInRect or use layer approach.

Additionally look here How to draw custom NSWindow

Quick dirty code follows

import Cocoa

class CustomWindow : NSWindow {
  override init(contentRect: NSRect, styleMask aStyle: Int, backing bufferingType: NSBackingStoreType, defer flag: Bool) {
    super.init(contentRect: contentRect, styleMask: aStyle, backing: bufferingType, defer: flag)
  }

  override var contentView: AnyObject {
    set {
      var view = newValue as! NSView
      view.wantsLayer = true
      let colorTop = NSColor(red: 48 / 255, green: 35 / 255, blue: 174 / 255, alpha: 1).CGColor
      let colorBottom = NSColor(red: 200 / 255, green: 109 / 255, blue: 215 / 255, alpha: 1).CGColor
      let gradient  = CAGradientLayer()
      gradient.colors = [ colorTop, colorBottom]
      gradient.locations = [ 0.0, 1.0]
      view.layer = gradient
      super.contentView = view

    }
    get {
      return super.contentView
    }
  }

  required init?(coder: NSCoder) {
      fatalError("init(coder:) has not been implemented")
  }

}

Window with background

Solution 2:

import Cocoa

class CustomView : NSView {

  override func drawRect(dirtyRect: NSRect) {
    let colorTop = NSColor(red: 48 / 255, green: 35 / 255, blue: 174 / 255, alpha: 1)
    let colorBottom = NSColor(red: 200 / 255, green: 109 / 255, blue: 215 / 255, alpha: 1)
    let gradient = NSGradient(colors: [colorTop, colorBottom])
    gradient.drawInRect(dirtyRect, angle: 45)
  }
}

Solution2

If you need custom titlebar then look here. It's a lot of work.

PS: Remember that actual drawing is done in NSView

Upvotes: 4

Related Questions