5 // Created by BinaryGod on 5/30/08.
7 // Copyright (c) 2008, Tim Davis (BinaryMethod.com, binary.god@gmail.com)
8 // All rights reserved.
10 // Redistribution and use in source and binary forms, with or without modification,
11 // are permitted provided that the following conditions are met:
13 // Redistributions of source code must retain the above copyright notice, this
14 // list of conditions and the following disclaimer.
16 // Redistributions in binary form must reproduce the above copyright notice,
17 // this list of conditions and the following disclaimer in the documentation and/or
18 // other materials provided with the distribution.
20 // Neither the name of the BinaryMethod.com nor the names of its contributors
21 // may be used to endorse or promote products derived from this software without
22 // specific prior written permission.
24 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND
25 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 // IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
30 // OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 // POSSIBILITY OF SUCH DAMAGE.
35 #import "VLCHUDSliderCell.h"
36 #import "CompatibilityFixes.h"
38 @implementation VLCHUDSliderCell
40 - (instancetype)initWithCoder:(NSCoder *)coder
42 self = [super initWithCoder:coder];
44 // Custom colors for the slider
45 _sliderColor = [NSColor colorWithCalibratedRed:0.318 green:0.318 blue:0.318 alpha:0.6];
46 _disabledSliderColor = [NSColor colorWithCalibratedRed:0.318 green:0.318 blue:0.318 alpha:0.2];
47 _strokeColor = [NSColor colorWithCalibratedRed:0.749 green:0.761 blue:0.788 alpha:1.0];
48 _disabledStrokeColor = [NSColor colorWithCalibratedRed:0.749 green:0.761 blue:0.788 alpha:0.2];
50 // Custom knob gradients
51 _knobGradient = [[NSGradient alloc] initWithStartingColor:[NSColor colorWithDeviceRed:0.251 green:0.251 blue:0.255 alpha:1.0]
52 endingColor:[NSColor colorWithDeviceRed:0.118 green:0.118 blue:0.118 alpha:1.0]];
53 _disableKnobGradient = [[NSGradient alloc] initWithStartingColor:[NSColor colorWithDeviceRed:0.251 green:0.251 blue:0.255 alpha:1.0]
54 endingColor:[NSColor colorWithDeviceRed:0.118 green:0.118 blue:0.118 alpha:1.0]];
59 NSAffineTransform* RotationTransform(const CGFloat angle, const NSPoint point)
61 NSAffineTransform* transform = [NSAffineTransform transform];
62 [transform translateXBy:point.x yBy:point.y];
63 [transform rotateByRadians:angle];
64 [transform translateXBy:-(point.x) yBy:-(point.y)];
68 #pragma clang diagnostic push
69 #pragma clang diagnostic ignored "-Wpartial-availability"
70 - (void)drawKnob:(NSRect)smallRect
72 if (OSX_YOSEMITE_AND_HIGHER) {
73 return [super drawKnob:smallRect];
75 NSBezierPath *path = [NSBezierPath bezierPath];
76 // Inset rect to have enough room for the stroke
77 smallRect = NSInsetRect(smallRect, 1.0, 1.0);
79 // Get min/max/mid coords for shape calculations
80 CGFloat minX = NSMinX(smallRect);
81 CGFloat minY = NSMinY(smallRect);
82 CGFloat maxX = NSMaxX(smallRect);
83 CGFloat maxY = NSMaxY(smallRect);
84 CGFloat midX = NSMidX(smallRect);
85 CGFloat midY = NSMidY(smallRect);
87 // Draw the knobs shape
88 if (self.numberOfTickMarks > 0) {
89 // We have tickmarks, draw an arrow-like shape
90 if (self.isVertical) {
91 // For some reason the rect is not alligned correctly at
92 // tickmarks and clipped, so this ugly thing is necessary:
96 // Right pointing arrow
97 [path moveToPoint:NSMakePoint(minX + 3, minY)];
98 [path lineToPoint:NSMakePoint(midX + 2, minY)];
99 [path lineToPoint:NSMakePoint(maxX, midY)];
100 [path lineToPoint:NSMakePoint(midX + 2, maxY)];
101 [path lineToPoint:NSMakePoint(minX + 3, maxY)];
102 [path appendBezierPathWithArcFromPoint:NSMakePoint(minX, maxY)
103 toPoint:NSMakePoint(minX, maxY - 3)
105 [path lineToPoint:NSMakePoint(minX, maxY - 3)];
106 [path lineToPoint:NSMakePoint(minX, minY + 3)];
107 [path appendBezierPathWithArcFromPoint:NSMakePoint(minX, minY)
108 toPoint:NSMakePoint(minX + 3, minY)
112 // Down pointing arrow
113 [path moveToPoint:NSMakePoint(minX + 3, minY)];
114 [path lineToPoint:NSMakePoint(maxX - 3, minY)];
115 [path appendBezierPathWithArcFromPoint:NSMakePoint(maxX, minY)
116 toPoint:NSMakePoint(maxX, minY + 3)
118 [path lineToPoint:NSMakePoint(maxX, minY + 3)];
119 [path lineToPoint:NSMakePoint(maxX, midY + 2)];
120 [path lineToPoint:NSMakePoint(midX, maxY)];
121 [path lineToPoint:NSMakePoint(minX, midY + 2)];
122 [path lineToPoint:NSMakePoint(minX, minY + 3)];
123 [path appendBezierPathWithArcFromPoint:NSMakePoint(minX, minY)
124 toPoint:NSMakePoint(minX + 3, minY)
129 // Rotate our knob if needed to the correct position
130 if (self.tickMarkPosition == NSTickMarkAbove) {
131 NSAffineTransform *transform = nil;
132 transform = RotationTransform(M_PI, NSMakePoint(midX, midY));
133 [path transformUsingAffineTransform:transform];
136 // We have no tickmarks, draw a round knob
137 [path appendBezierPathWithOvalInRect:NSInsetRect(smallRect, 0.5, 0.5)];
140 // Draw the knobs background
141 if (self.isEnabled && self.isHighlighted) {
142 [_knobGradient drawInBezierPath:path angle:270.0f];
143 } else if (self.isEnabled) {
144 [_knobGradient drawInBezierPath:path angle:90.0f];
146 [_disableKnobGradient drawInBezierPath:path angle:90.0f];
149 // Draw white stroke around the knob
150 if (self.isEnabled) {
151 [_strokeColor setStroke];
153 [_disabledStrokeColor setStroke];
156 [path setLineWidth:1.0];
160 - (void)drawBarInside:(NSRect)fullRect flipped:(BOOL)flipped
162 if (OSX_YOSEMITE_AND_HIGHER) {
163 return [super drawBarInside:fullRect flipped:flipped];
165 if (self.isVertical) {
166 return [self drawVerticalBarInFrame:fullRect];
168 return [self drawHorizontalBarInFrame:fullRect];
171 #pragma clang diagnostic pop
173 - (void)drawVerticalBarInFrame:(NSRect)frame
175 // Adjust frame based on ControlSize
176 switch ([self controlSize]) {
178 case NSRegularControlSize:
180 if ([self numberOfTickMarks] != 0) {
181 if ([self tickMarkPosition] == NSTickMarkRight) {
184 frame.origin.x += frame.size.width - 9;
187 frame.origin.x = frame.origin.x + (((frame.origin.x + frame.size.width) /2) - 2.5f);
189 frame.origin.x += 0.5f;
190 frame.origin.y += 2.5f;
191 frame.size.height -= 6;
192 frame.size.width = 5;
195 case NSSmallControlSize:
197 if ([self numberOfTickMarks] != 0) {
198 if ([self tickMarkPosition] == NSTickMarkRight) {
201 frame.origin.x += frame.size.width - 8;
204 frame.origin.x = frame.origin.x + (((frame.origin.x + frame.size.width) /2) - 2.5f);
206 frame.origin.y += 0.5f;
207 frame.size.height -= 1;
208 frame.origin.x += 0.5f;
209 frame.size.width = 5;
212 case NSMiniControlSize:
214 if ([self numberOfTickMarks] != 0) {
215 if ([self tickMarkPosition] == NSTickMarkRight) {
216 frame.origin.x += 2.5f;
218 frame.origin.x += frame.size.width - 6.5f;
221 frame.origin.x = frame.origin.x + (((frame.origin.x + frame.size.width) /2) - 2);
224 frame.origin.y += 0.5f;
225 frame.size.height -= 1;
226 frame.size.width = 3;
231 NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect: frame xRadius: 2 yRadius: 2];
233 if ([self isEnabled]) {
240 [_disabledSliderColor set];
243 [_disabledStrokeColor set];
248 - (void)drawHorizontalBarInFrame:(NSRect)frame
250 // Adjust frame based on ControlSize
251 switch ([self controlSize]) {
253 case NSRegularControlSize:
255 if ([self numberOfTickMarks] != 0) {
256 if ([self tickMarkPosition] == NSTickMarkBelow) {
259 frame.origin.y += frame.size.height - 10;
262 frame.origin.y = frame.origin.y + (((frame.origin.y + frame.size.height) /2) - 2.5f);
264 frame.origin.x += 2.5f;
265 frame.origin.y += 0.5f;
266 frame.size.width -= 5;
267 frame.size.height = 5;
270 case NSSmallControlSize:
272 if ([self numberOfTickMarks] != 0) {
273 if ([self tickMarkPosition] == NSTickMarkBelow) {
276 frame.origin.y += frame.size.height - 8;
279 frame.origin.y = frame.origin.y + (((frame.origin.y + frame.size.height) /2) - 2.5f);
281 frame.origin.x += 0.5f;
282 frame.origin.y += 0.5f;
283 frame.size.width -= 1;
284 frame.size.height = 5;
287 case NSMiniControlSize:
289 if ([self numberOfTickMarks] != 0) {
290 if ([self tickMarkPosition] == NSTickMarkBelow) {
293 frame.origin.y += frame.size.height - 6;
296 frame.origin.y = frame.origin.y + (((frame.origin.y + frame.size.height) /2) - 2);
298 frame.origin.x += 0.5f;
299 frame.origin.y += 0.5f;
300 frame.size.width -= 1;
301 frame.size.height = 3;
306 NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:frame xRadius:2 yRadius:2];
308 if ([self isEnabled]) {
315 [_disabledSliderColor set];
318 [_disabledStrokeColor set];
323 #pragma clang diagnostic push
324 #pragma clang diagnostic ignored "-Wpartial-availability"
325 - (void)drawTickMarks
327 if (OSX_YOSEMITE_AND_HIGHER) {
328 return [super drawTickMarks];
330 for (int i = 0; i < self.numberOfTickMarks; i++) {
331 NSRect tickMarkRect = [self rectOfTickMarkAtIndex:i];
332 if (self.isEnabled) {
333 [_strokeColor setFill];
335 [_disabledStrokeColor setFill];
337 NSRectFill(tickMarkRect);
340 #pragma clang diagnostic pop