Clifton Labrum
Clifton Labrum

Reputation: 14168

Force Custom NSView from PaintCode to Redraw

I created an icon in PaintCode that is drawn programmatically (but this question isn't necessarily specific to that tool) and I'm trying to get that icon to redraw.

I use a custom class like this:

class IconTabGeneral: NSView {
  override func draw(_ dirtyRect: NSRect) {
    StyleKitMac.drawTabGeneral()
  }
}

The drawTabGeneral() is a method in the StyleKitMac class (generated by PaintCode) that looks like this (I'll omit all the bezierPath details):

@objc dynamic public class func drawTabGeneral(frame targetFrame: NSRect = NSRect(x: 0, y: 0, width: 22, height: 22), resizing: ResizingBehavior = .aspectFit) {
  //// General Declarations
  let context = NSGraphicsContext.current!.cgContext

  //// Resize to Target Frame
  NSGraphicsContext.saveGraphicsState()
  let resizedFrame: NSRect = resizing.apply(rect: NSRect(x: 0, y: 0, width: 22, height: 22), target: targetFrame)
  context.translateBy(x: resizedFrame.minX, y: resizedFrame.minY)
  context.scaleBy(x: resizedFrame.width / 22, y: resizedFrame.height / 22)

  //// Bezier Drawing
  let bezierPath = NSBezierPath()
  ...
  bezierPath.close()
  StyleKitMac.accentColor.setFill() ⬅️Custom color set here 
  bezierPath.fill()

  NSGraphicsContext.restoreGraphicsState()
}

The accentColor defined there is a setting that can be changed by the user. I can't get my instance of IconTabGeneral to redraw to pick up the new color after the user changes it.

I've tried this without any luck:

iconGeneralTabInstance.needsDisplay = true

My understanding is that needsDisplay would force the draw function to fire again, but apparently not.

Any idea how I can get this icon to redraw and re-fill its bezierPath?

Upvotes: 1

Views: 232

Answers (2)

Clifton Labrum
Clifton Labrum

Reputation: 14168

I think I got it. It turns out the PaintCode-generated StyleKitMac class was caching the color. The icon was, in fact, being redrawn after needsDisplay was being set. So I just had to refresh the cache's color value.

Upvotes: 1

Stream
Stream

Reputation: 9493

How about using a NSImageView? Here is a working example:

import AppKit

enum StyleKit {
  static func drawIcon(frame: CGRect) {
    let circle = NSBezierPath(ovalIn: frame.insetBy(dx: 1, dy: 1))
    NSColor.controlAccentColor.setFill()
    circle.fill()
  }
}

let iconView = NSImageView()
iconView.image = .init(size: .init(width: 24, height: 24), flipped: true) { drawingRect in
  StyleKit.drawIcon(frame: drawingRect)
  return true
}

import PlaygroundSupport
PlaygroundPage.current.liveView = iconView

Upvotes: 1

Related Questions