I have searched here, Google, Apple Documentation, gitHub, etc. and cannot find any information on how to use the Content Filters to set the color of the NSProgressIndicator. I want to do this in macOS.
I have read this post that talks about modifying the NSProgressIndicator programmatically.
However, I set up a Content Filter, namely False Color, on my NSProgressIndicator in IB. It has two colors, Color 1 and Color 2. I set Color 1 to green, and I set color 2 to red.
By setting the Content Filter, False Color, Color 1 to a custom green color, my NSProgressIndicator is now green by default. So, this tells me it is pulling that color from my Content Filter, Color 1, but I do not know how it is doing that.
How would I set the color of the NSProgressIndicator to Content Filter, Color 2, programmatically?
I would post code on how I am approaching this, but I don't even know how to start.
Another post mentioned setting the .appearance, but that lead me to this repository , which doesn't seem to be what I am looking for. I'm willing to do my homework and figure this out, but I'm coming up empty handed using the Content Filters as set in IB.
EDIT 1: After further investigation, if I perform a print(progressBar.contentFilters) I can then see the two colors that were set in the IB's Content Filter, False Colors settings. This is the printout:
[<CIFalseColor: 0x6000026039c0>
inputImage=nil
inputColor0=<CIColor 0x600000cc4570 (0 0.976805 0 1) devicergb>
inputColor1=<CIColor 0x600000cc45d0 (1 0.149131 0 1) devicergb>
]
So now the question is, how do I make the progressBar use the color that is defined as inputColor1?
EDIT 2: So, after messing around with this for a few more hours, I was able to get a halfway working solution, for now. I say halfway because the call to the progress.contentFilters = [Filter Name] causes a complete Window refresh, which looks like a bright single flicker after the first darkGreen filter is applied in the viewDidLoad method (No flickers occur for the initial setting of the filter).
@IBOutlet weak var progressBar: NSProgressIndicator!
// Set the filter properties
let darkGreenFilter = CIFilter(name: "CIFalseColor")!
let redFilter = CIFilter(name: "CIFalseColor")!
// Set the CIColors for the two filters
let darkGreenCIColor = CIColor(red: 0, green: 0.6, blue: 0.4, alpha: 1)
let redCIColor = CIColor(red: 1, green: 0, blue: 0, alpha: 1)
// Set a boolean flag that the progressBar color was changed
var progressBarColorChanged = false
Then in the viewDidLoad:
// Set the values for the filters
darkGreenFilter.setValue(darkGreenCIColor, forKey: "inputColor0")
redFilter.setValue(redCIColor, forKey: "inputColor0")
// Set the progress indicator to dark green
progressBar.contentFilters = [darkGreenFilter]
// Set the progress to zero (removes the colored bar)
progressBar.doubleValue = 0
Then in a later method that monitors the status of the progressBar
if progressBar.doubleValue > 0.75 && !progressBarColorChanged {
progressBar.contentFilters = [redFilter]
progressBarColorChanged = true
}
Then once execution is complete I use a reset method to put it all back
progressBar.contentFilter = [darkGreen]
progressBar.doubleValue = 0
progressBarColorChanged = false
I'm slowly getting there. Anyone have any suggestions on how to do this better, or how I can eliminate that pesky screen flicker?
Coming back around to this. Here's my answer
Swift 5.4 / macOS
import Cocoa
class ViewController: NSViewController {
let greenFilter = CIFilter(name: "CIFalseColor")!
let greenCIColor = CIColor(red: 0.3333, green: 0.8667, blue: 0.0, alpha: 1.0)
let darkGreenCIColor = CIColor(red: 0, green: 0.5373, blue: 0.1137, alpha: 1.0)
let redFilter = CIFilter(name: "CIFalseColor")!
let redCIColor = CIColor(red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0)
let darkRedCIColor = CIColor(red: 0.6275, green: 0.0, blue: 0.0078, alpha: 1.0)
var redFilterColorChange = false
var progressBar: NSProgressIndicator?
var timer = Timer()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
let progressFrame = NSRect(x: view.frame.midX-view.frame.width/2+30, y: view.frame.midY-10, width: view.frame.width-60, height: 20)
progressBar = NSProgressIndicator(frame: progressFrame)
self.view.addSubview(progressBar!)
progressBar?.contentFilters = []
if NSApp.effectiveAppearance.name == .darkAqua {
greenFilter.setValue(darkGreenCIColor, forKey: "inputColor0")
redFilter.setValue(darkRedCIColor, forKey: "inputColor0")
} else {
greenFilter.setValue(greenCIColor, forKey: "inputColor0")
redFilter.setValue(redCIColor, forKey: "inputColor0")
}
// Apply the filter
progressBar?.contentFilters = [greenFilter]
progressBar?.isHidden = false
progressBar?.isIndeterminate = false
progressBar?.doubleValue = 0
progressBar?.maxValue = 1.0
startTimer()
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
func startTimer() {
print("Starting timer")
timer = Timer.scheduledTimer(timeInterval: 0.1, target: self, selector: #selector(updateProgress), userInfo: nil, repeats: true)
print("Progress bar frame = \(progressBar!.frame)")
}
@objc func updateProgress() {
if progressBar!.doubleValue < 1.0 {
if progressBar!.doubleValue > 0.75 && !redFilterColorChange {
progressBar?.contentFilters = [redFilter]
redFilterColorChange = true
}
progressBar?.doubleValue += 0.01
print("Progress bar value = \(progressBar!.doubleValue)")
} else {
timer.invalidate()
progressBar?.contentFilters = [greenFilter]
progressBar?.doubleValue = 0
progressBar?.isHidden = true
}
}
}