macOS: Correct target to 10.7 for AudioEffects xib
[vlc.git] / modules / gui / macosx / VLCHUDSliderCell.m
1 //
2 //  VLCHUDSliderCell.m
3 //  BGHUDAppKit
4 //
5 //  Created by BinaryGod on 5/30/08.
6 //
7 //  Copyright (c) 2008, Tim Davis (BinaryMethod.com, binary.god@gmail.com)
8 //  All rights reserved.
9 //
10 //  Redistribution and use in source and binary forms, with or without modification,
11 //  are permitted provided that the following conditions are met:
12 //
13 //              Redistributions of source code must retain the above copyright notice, this
14 //      list of conditions and the following disclaimer.
15 //
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.
19 //
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.
23 //
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.
34
35 #import "VLCHUDSliderCell.h"
36
37 @implementation VLCHUDSliderCell
38
39 - (instancetype)initWithCoder:(NSCoder *)coder
40 {
41     self = [super initWithCoder:coder];
42     if (self) {
43         // Custom colors for the slider
44         _sliderColor            = [NSColor colorWithCalibratedRed:0.318 green:0.318 blue:0.318 alpha:0.6];
45         _disabledSliderColor    = [NSColor colorWithCalibratedRed:0.318 green:0.318 blue:0.318 alpha:0.2];
46         _strokeColor            = [NSColor colorWithCalibratedRed:0.749 green:0.761 blue:0.788 alpha:1.0];
47         _disabledStrokeColor    = [NSColor colorWithCalibratedRed:0.749 green:0.761 blue:0.788 alpha:0.2];
48
49         // Custom knob gradients
50         _knobGradient           = [[NSGradient alloc] initWithStartingColor:[NSColor colorWithDeviceRed:0.251 green:0.251 blue:0.255 alpha:1.0]
51                                                                 endingColor:[NSColor colorWithDeviceRed:0.118 green:0.118 blue:0.118 alpha:1.0]];
52         _disableKnobGradient    = [[NSGradient alloc] initWithStartingColor:[NSColor colorWithDeviceRed:0.251 green:0.251 blue:0.255 alpha:1.0]
53                                                                 endingColor:[NSColor colorWithDeviceRed:0.118 green:0.118 blue:0.118 alpha:1.0]];
54     }
55     return self;
56 }
57
58 NSAffineTransform* RotationTransform(const CGFloat angle, const NSPoint point)
59 {
60     NSAffineTransform*  transform = [NSAffineTransform transform];
61     [transform translateXBy:point.x yBy:point.y];
62     [transform rotateByRadians:angle];
63     [transform translateXBy:-(point.x) yBy:-(point.y)];
64     return transform;
65 }
66
67 #pragma clang diagnostic push
68 #pragma clang diagnostic ignored "-Wpartial-availability"
69 - (void) drawKnob:(NSRect)smallRect
70 {
71     NSBezierPath *path = [NSBezierPath bezierPath];
72     // Inset rect to have enough room for the stroke
73     smallRect = NSInsetRect(smallRect, 1.0, 1.0);
74
75     // Get min/max/mid coords for shape calculations
76     CGFloat minX = NSMinX(smallRect);
77     CGFloat minY = NSMinY(smallRect);
78     CGFloat maxX = NSMaxX(smallRect);
79     CGFloat maxY = NSMaxY(smallRect);
80     CGFloat midX = NSMidX(smallRect);
81     CGFloat midY = NSMidY(smallRect);
82
83     // Draw the knobs shape
84     if (self.numberOfTickMarks > 0) {
85         // We have tickmarks, draw an arrow-like shape
86         if (self.isVertical) {
87             // For some reason the rect is not alligned correctly at
88             // tickmarks and clipped, so this ugly thing is necessary:
89             maxY = maxY - 2;
90             midY = midY - 1;
91
92             // Right pointing arrow
93             [path moveToPoint:NSMakePoint(minX + 3, minY)];
94             [path lineToPoint:NSMakePoint(midX + 2, minY)];
95             [path lineToPoint:NSMakePoint(maxX, midY)];
96             [path lineToPoint:NSMakePoint(midX + 2, maxY)];
97             [path lineToPoint:NSMakePoint(minX + 3, maxY)];
98             [path appendBezierPathWithArcFromPoint:NSMakePoint(minX, maxY)
99                                            toPoint:NSMakePoint(minX, maxY - 3)
100                                             radius:2.5f];
101             [path lineToPoint:NSMakePoint(minX, maxY - 3)];
102             [path lineToPoint:NSMakePoint(minX, minY + 3)];
103             [path appendBezierPathWithArcFromPoint:NSMakePoint(minX, minY)
104                                            toPoint:NSMakePoint(minX + 3, minY)
105                                             radius:2.5f];
106             [path closePath];
107         } else {
108             // Down pointing arrow
109             [path moveToPoint:NSMakePoint(minX + 3, minY)];
110             [path lineToPoint:NSMakePoint(maxX - 3, minY)];
111             [path appendBezierPathWithArcFromPoint:NSMakePoint(maxX, minY)
112                                            toPoint:NSMakePoint(maxX, minY + 3)
113                                             radius:2.5f];
114             [path lineToPoint:NSMakePoint(maxX, minY + 3)];
115             [path lineToPoint:NSMakePoint(maxX, midY + 2)];
116             [path lineToPoint:NSMakePoint(midX, maxY)];
117             [path lineToPoint:NSMakePoint(minX, midY + 2)];
118             [path lineToPoint:NSMakePoint(minX, minY + 3)];
119             [path appendBezierPathWithArcFromPoint:NSMakePoint(minX, minY)
120                                            toPoint:NSMakePoint(minX + 3, minY)
121                                             radius:2.5f];
122             [path closePath];
123         }
124
125         // Rotate our knob if needed to the correct position
126         if (self.tickMarkPosition == NSTickMarkAbove) {
127             NSAffineTransform *transform = nil;
128             transform = RotationTransform(M_PI, NSMakePoint(midX, midY));
129             [path transformUsingAffineTransform:transform];
130         }
131     } else {
132         // We have no tickmarks, draw a round knob
133         [path appendBezierPathWithOvalInRect:NSInsetRect(smallRect, 0.5, 0.5)];
134     }
135
136     // Draw the knobs background
137     if (self.isEnabled && self.isHighlighted) {
138         [_knobGradient drawInBezierPath:path angle:270.0f];
139     } else if (self.isEnabled) {
140         [_knobGradient drawInBezierPath:path angle:90.0f];
141     } else {
142         [_disableKnobGradient drawInBezierPath:path angle:90.0f];
143     }
144
145     // Draw white stroke around the knob
146     if (self.isEnabled) {
147         [_strokeColor setStroke];
148     } else {
149         [_disabledStrokeColor setStroke];
150     }
151
152     [path setLineWidth:1.0];
153     [path stroke];
154 }
155
156 - (void)drawBarInside:(NSRect)fullRect flipped:(BOOL)flipped
157 {
158     if (self.isVertical) {
159         return [self drawVerticalBarInFrame:fullRect];
160     } else {
161         return [self drawHorizontalBarInFrame:fullRect];
162     }
163 }
164 #pragma clang diagnostic pop
165
166 - (void)drawVerticalBarInFrame:(NSRect)frame
167 {
168     // Adjust frame based on ControlSize
169     switch ([self controlSize]) {
170
171         case NSRegularControlSize:
172
173             if ([self numberOfTickMarks] != 0) {
174                 if ([self tickMarkPosition] == NSTickMarkRight) {
175                     frame.origin.x += 4;
176                 } else {
177                     frame.origin.x += frame.size.width - 9;
178                 }
179             } else {
180                 frame.origin.x = frame.origin.x + (((frame.origin.x + frame.size.width) /2) - 2.5f);
181             }
182             frame.origin.x += 0.5f;
183             frame.origin.y += 2.5f;
184             frame.size.height -= 6;
185             frame.size.width = 5;
186             break;
187
188         case NSSmallControlSize:
189
190             if ([self numberOfTickMarks] != 0) {
191                 if ([self tickMarkPosition] == NSTickMarkRight) {
192                     frame.origin.x += 3;
193                 } else {
194                     frame.origin.x += frame.size.width - 8;
195                 }
196             } else {
197                 frame.origin.x = frame.origin.x + (((frame.origin.x + frame.size.width) /2) - 2.5f);
198             }
199             frame.origin.y += 0.5f;
200             frame.size.height -= 1;
201             frame.origin.x += 0.5f;
202             frame.size.width = 5;
203             break;
204
205         case NSMiniControlSize:
206
207             if ([self numberOfTickMarks] != 0) {
208                 if ([self tickMarkPosition] == NSTickMarkRight) {
209                     frame.origin.x += 2.5f;
210                 } else {
211                     frame.origin.x += frame.size.width - 6.5f;
212                 }
213             } else {
214                 frame.origin.x = frame.origin.x + (((frame.origin.x + frame.size.width) /2) - 2);
215             }
216             frame.origin.x += 1;
217             frame.origin.y += 0.5f;
218             frame.size.height -= 1;
219             frame.size.width = 3;
220             break;
221     }
222     
223     // Draw Bar
224     NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect: frame xRadius: 2 yRadius: 2];
225     
226     if ([self isEnabled]) {
227         [_sliderColor set];
228         [path fill];
229
230         [_strokeColor set];
231         [path stroke];
232     } else {
233         [_disabledSliderColor set];
234         [path fill];
235
236         [_disabledStrokeColor set];
237         [path stroke];
238     }
239 }
240
241 - (void)drawHorizontalBarInFrame:(NSRect)frame
242 {
243     // Adjust frame based on ControlSize
244     switch ([self controlSize]) {
245
246         case NSRegularControlSize:
247
248             if ([self numberOfTickMarks] != 0) {
249                 if ([self tickMarkPosition] == NSTickMarkBelow) {
250                     frame.origin.y += 4;
251                 } else {
252                     frame.origin.y += frame.size.height - 10;
253                 }
254             } else {
255                 frame.origin.y = frame.origin.y + (((frame.origin.y + frame.size.height) /2) - 2.5f);
256             }
257             frame.origin.x += 2.5f;
258             frame.origin.y += 0.5f;
259             frame.size.width -= 5;
260             frame.size.height = 5;
261             break;
262
263         case NSSmallControlSize:
264
265             if ([self numberOfTickMarks] != 0) {
266                 if ([self tickMarkPosition] == NSTickMarkBelow) {
267                     frame.origin.y += 2;
268                 } else {
269                     frame.origin.y += frame.size.height - 8;
270                 }
271             } else {
272                 frame.origin.y = frame.origin.y + (((frame.origin.y + frame.size.height) /2) - 2.5f);
273             }
274             frame.origin.x += 0.5f;
275             frame.origin.y += 0.5f;
276             frame.size.width -= 1;
277             frame.size.height = 5;
278             break;
279
280         case NSMiniControlSize:
281
282             if ([self numberOfTickMarks] != 0) {
283                 if ([self tickMarkPosition] == NSTickMarkBelow) {
284                     frame.origin.y += 2;
285                 } else {
286                     frame.origin.y += frame.size.height - 6;
287                 }
288             } else {
289                 frame.origin.y = frame.origin.y + (((frame.origin.y + frame.size.height) /2) - 2);
290             }
291             frame.origin.x += 0.5f;
292             frame.origin.y += 0.5f;
293             frame.size.width -= 1;
294             frame.size.height = 3;
295             break;
296     }
297     
298     // Draw Bar
299     NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:frame xRadius:2 yRadius:2];
300     
301     if ([self isEnabled]) {
302         [_sliderColor set];
303         [path fill];
304         
305         [_strokeColor set];
306         [path stroke];
307     } else {
308         [_disabledSliderColor set];
309         [path fill];
310         
311         [_disabledStrokeColor set];
312         [path stroke];
313     }
314 }
315
316 - (void)drawTickMarks
317 {
318     for (int i = 0; i < self.numberOfTickMarks; i++) {
319         NSRect tickMarkRect = [self rectOfTickMarkAtIndex:i];
320         if (self.isEnabled) {
321             [_strokeColor setFill];
322         } else {
323             [_disabledStrokeColor setFill];
324         }
325         NSRectFill(tickMarkRect);
326     }
327 }
328
329 @end