├── img
├── color.gif
└── grad.gif
├── LICENSE.txt
├── README.md
└── JCGGColorSlider.swift
/img/color.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacquesCedric/JCGGColorSlider/HEAD/img/color.gif
--------------------------------------------------------------------------------
/img/grad.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jacquesCedric/JCGGColorSlider/HEAD/img/grad.gif
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 | -----------
3 |
4 | Copyright (c) 2019 Jacob Gold
5 | Permission is hereby granted, free of charge, to any person
6 | obtaining a copy of this software and associated documentation
7 | files (the "Software"), to deal in the Software without
8 | restriction, including without limitation the rights to use,
9 | copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the
11 | Software is furnished to do so, subject to the following
12 | conditions:
13 |
14 | The above copyright notice and this permission notice shall be
15 | included in all copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 | OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # JCGGColorSlider  [](http://perso.crans.org/besson/LICENSE.html)
2 | > A colorful subclass of NSSlider.
3 |
4 | An NSSlider subclass. Supports colored sliders, including gradients. Can match knob color to that of location on the slider.
5 |
6 |
7 |
8 |
9 | ## Installation
10 | Clone the source and copy `JCGGColorSlider.swift` to your project.
11 |
12 | ## Use
13 | Simply assign an NSSlider to subclass `JCGGColorSlider`. Slider can be configured with the following options:
14 |
15 | * barColor - The color of the `NSSlider` bar
16 | * barGradient - Overrides `barColor`, assign a gradient to the slider
17 | * knobColor - Color of the knob
18 | * knobColorFromLocation - overrides `knobColor`, setting the knob's color to that of it's location on the slider bar
19 | * bezelMargin - effects the thickness of the slider bar
20 |
21 | ### Example - Rainbow gradient
22 |
23 |
24 | 1. Create an NSSlider and assign its subclass to `JCGGColorSlider`
25 | 2. Create a rainbow gradient
26 | 3. Assign gradient to NSSlider
27 | 4. Set knob to match color
28 |
29 | ```
30 | // 1
31 | let exampleSlider = JCGGSlider.init(frame: example)
32 |
33 | // 2
34 | let rainbow = NSGradient.init(colors: Array(0...10).map{ NSColor.init(calibratedHue: CGFloat($0) / 10, saturation: 1.0, brightness: 1.0, alpha: 1.0) })!
35 |
36 | // 3
37 | exampleSlider.barGradient = rainbow
38 |
39 | // 4
40 | exampleSlider.knobColorFromLocation = true
41 | ```
42 |
43 | ## License
44 | `JCGGColorSlider` is available under the MIT license. See the LICENSE file for more details.
--------------------------------------------------------------------------------
/JCGGColorSlider.swift:
--------------------------------------------------------------------------------
1 | //
2 | // JCGGSliderCell.swift
3 | //
4 | // Created by Jacob Gold on 19/3/19.
5 | // Copyright © 2019 Jacob Gold. All rights reserved.
6 | // MIT license
7 | //
8 |
9 | import Cocoa
10 |
11 |
12 | @IBDesignable public class JCGGColorSlider: NSSlider {
13 | var barBackgroundColor: NSColor = NSColor.darkGray
14 |
15 | public var barGradient: NSGradient = NSGradient.init(colors: [NSColor.systemBlue])!
16 | // Rainbow example
17 | // var barGradient = NSGradient.init(colors: Array(0...10).map{ NSColor.init(calibratedHue: CGFloat($0) / 10, saturation: 1.0, brightness: 1.0, alpha: 1.0) })!
18 |
19 | // Can't do complex gradients with inspectable, so this will do.
20 | @IBInspectable public var barColor: NSColor {
21 | set(newValue) {
22 | barGradient = NSGradient.init(colors: [newValue])!
23 | self.needsDisplay = true
24 | }
25 | get {
26 | return barGradient.interpolatedColor(atLocation: 1.0)
27 | }
28 | }
29 |
30 | // The color of the knob
31 | public var knobColor: NSColor = NSColor.white
32 |
33 | // Should the knob color relate to its position on the slider
34 | fileprivate var _knobColorFromLocation: Bool = true
35 | @IBInspectable public var knobColorFromLocation: Bool {
36 | set(newValue) {
37 | _knobColorFromLocation = newValue
38 | }
39 | get {
40 | return _knobColorFromLocation
41 | }
42 | }
43 |
44 | // Determines the margins on the bar component.
45 | public let bezelMargin: CGFloat = 8
46 |
47 |
48 |
49 | override public func draw(_ dirtyRect: NSRect) {
50 | if (self.isVertical) {
51 | // Bar styling
52 | barBackgroundColor.setFill()
53 | let bezelFrame = bounds.insetBy(dx: bezelMargin, dy: bezelMargin / 2)
54 | let bar = NSBezierPath(roundedRect: bezelFrame, xRadius: bezelFrame.width * 0.5, yRadius: bezelFrame.width * 0.5)
55 | bar.fill()
56 | barGradient.draw(in: bar, angle: -90.0)
57 |
58 | let innerRect = bounds.insetBy(dx: 0, dy: bounds.width / 2)
59 |
60 | // Knob config
61 | let knobY: CGFloat
62 | if maxValue - minValue == 0 {
63 | knobY = innerRect.maxY
64 | } else {
65 | knobY = innerRect.maxY - CGFloat((doubleValue - minValue) / maxValue) * innerRect.height
66 | }
67 |
68 | // Knob shadow
69 | let shadowPath = NSBezierPath(ovalIn: NSRect(x: 0, y: (knobY - bounds.width * 0.5), width: bounds.width, height: bounds.width).insetBy(dx: 1.0, dy: 1.5))
70 | NSColor.init(white: 0.3, alpha: 0.3).setFill()
71 | shadowPath.fill()
72 |
73 | // Knob iteself
74 | let knobPath = NSBezierPath(ovalIn: NSRect(x: 0, y: (knobY - bounds.width * 0.5), width: bounds.width, height: bounds.width).insetBy(dx: 2, dy: 2))
75 | knobColor.setFill()
76 | knobPath.fill()
77 |
78 |
79 | // Knob color from location, if enabled
80 | if (_knobColorFromLocation) {
81 | let amount:CGFloat = CGFloat(floatValue / Float(maxValue))
82 | knobColor = barGradient.interpolatedColor(atLocation: amount)
83 | knobColor.setFill()
84 | knobPath.fill()
85 | }
86 | }
87 | else {
88 | // Bar styling
89 | barBackgroundColor.setFill()
90 | let bezelFrame = bounds.insetBy(dx: bezelMargin / 2, dy: bezelMargin)
91 | let bar = NSBezierPath(roundedRect: bezelFrame, xRadius: bezelFrame.height * 0.5, yRadius: bezelFrame.height * 0.5)
92 | bar.fill()
93 | barGradient.draw(in: bar, angle: 0.0)
94 |
95 | let innerRect = bounds.insetBy(dx: bounds.height / 2, dy: 0)
96 |
97 | // Knob config
98 |
99 | let knobX: CGFloat
100 | if maxValue - minValue == 0 {
101 | knobX = innerRect.minX
102 | } else {
103 | knobX = innerRect.minX + CGFloat((doubleValue - minValue) / maxValue) * innerRect.width
104 | }
105 |
106 | // Knob shadow
107 | let shadowPath = NSBezierPath(ovalIn: NSRect(x: (knobX - bounds.height * 0.5), y: 0, width: bounds.height, height: bounds.height).insetBy(dx: 1.5, dy: 1.0))
108 | NSColor.init(white: 0.3, alpha: 0.3).setFill()
109 | shadowPath.fill()
110 |
111 | // Knob iteself
112 | let knobPath = NSBezierPath(ovalIn: NSRect(x: knobX - bounds.height * 0.5, y: 0, width: bounds.height, height: bounds.height).insetBy(dx: 2, dy: 2))
113 | knobColor.setFill()
114 | knobPath.fill()
115 |
116 | // Knob color from location, if enabled
117 | if (_knobColorFromLocation) {
118 | let amount:CGFloat = CGFloat(floatValue / Float(maxValue))
119 | knobColor = barGradient.interpolatedColor(atLocation: amount)
120 | knobColor.setFill()
121 | knobPath.fill()
122 | }
123 | }
124 |
125 | }
126 | }
127 |
--------------------------------------------------------------------------------