01fe5cab0869c349c4dc68617a5c9494bdf52616
[vlc.git] / modules / gui / macosx / VLCHUDSliderCell.m
1 /*****************************************************************************
2  * VLCHUDSliderCell.m: Custom slider cell UI for dark HUD Panels
3  *****************************************************************************
4  * Copyright (C) 2016 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Marvin Scholz <epirat07 -at- gmail -dot- com>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 #import "VLCHUDSliderCell.h"
25
26 @implementation VLCHUDSliderCell
27
28 - (instancetype)initWithCoder:(NSCoder *)coder
29 {
30     self = [super initWithCoder:coder];
31     if (self) {
32         // Custom colors for the slider
33         _sliderColor            = [NSColor colorWithCalibratedRed:0.318 green:0.318 blue:0.318 alpha:0.6];
34         _disabledSliderColor    = [NSColor colorWithCalibratedRed:0.318 green:0.318 blue:0.318 alpha:0.2];
35         _strokeColor            = [NSColor colorWithCalibratedRed:0.749 green:0.761 blue:0.788 alpha:1.0];
36         _disabledStrokeColor    = [NSColor colorWithCalibratedRed:0.749 green:0.761 blue:0.788 alpha:0.2];
37
38
39         // Custom knob gradients
40         _knobGradient           = [[NSGradient alloc] initWithStartingColor:[NSColor colorWithDeviceRed:0.251 green:0.251 blue:0.255 alpha:1.0]
41                                                                 endingColor:[NSColor colorWithDeviceRed:0.118 green:0.118 blue:0.118 alpha:1.0]];
42         _disableKnobGradient    = [[NSGradient alloc] initWithStartingColor:[NSColor colorWithDeviceRed:0.251 green:0.251 blue:0.255 alpha:1.0]
43                                                                 endingColor:[NSColor colorWithDeviceRed:0.118 green:0.118 blue:0.118 alpha:1.0]];
44     }
45     return self;
46 }
47
48 NSAffineTransform* RotationTransform(const CGFloat angle, const NSPoint point)
49 {
50     NSAffineTransform*  transform = [NSAffineTransform transform];
51     [transform translateXBy:point.x yBy:point.y];
52     [transform rotateByRadians:angle];
53     [transform translateXBy:-(point.x) yBy:-(point.y)];
54     return transform;
55 }
56
57 - (void) drawKnob:(NSRect)smallRect
58 {
59     NSBezierPath *path = [NSBezierPath bezierPath];
60     // Inset rect to have enough room for the stroke
61     smallRect = NSInsetRect(smallRect, 0.5, 0.5);
62
63     // Get min/max/mid coords for shape calculations
64     CGFloat minX = NSMinX(smallRect);
65     CGFloat minY = NSMinY(smallRect);
66     CGFloat maxX = NSMaxX(smallRect);
67     CGFloat maxY = NSMaxY(smallRect);
68     CGFloat midX = NSMidX(smallRect);
69     CGFloat midY = NSMidY(smallRect);
70
71     // Draw the knobs shape
72     if (self.numberOfTickMarks > 0) {
73         // We have tickmarks, draw an arrow-like shape
74         if (self.isVertical) {
75             // For some reason the rect is not alligned correctly at
76             // tickmarks and clipped, so this ugly thing is necessary:
77             maxY = maxY - 2;
78             midY = midY - 1;
79
80             // Right pointing arrow
81             [path moveToPoint:NSMakePoint(minX + 3, minY)];
82             [path lineToPoint:NSMakePoint(midX + 2, minY)];
83             [path lineToPoint:NSMakePoint(maxX, midY)];
84             [path lineToPoint:NSMakePoint(midX + 2, maxY)];
85             [path lineToPoint:NSMakePoint(minX + 3, maxY)];
86             [path appendBezierPathWithArcFromPoint:NSMakePoint(minX, maxY)
87                                            toPoint:NSMakePoint(minX, maxY - 3)
88                                             radius:2.5f];
89             [path lineToPoint:NSMakePoint(minX, maxY - 3)];
90             [path lineToPoint:NSMakePoint(minX, minY + 3)];
91             [path appendBezierPathWithArcFromPoint:NSMakePoint(minX, minY)
92                                            toPoint:NSMakePoint(minX + 3, minY)
93                                             radius:2.5f];
94             [path closePath];
95         } else {
96             // Down pointing arrow
97             [path moveToPoint:NSMakePoint(minX + 3, minY)];
98             [path lineToPoint:NSMakePoint(maxX - 3, minY)];
99             [path appendBezierPathWithArcFromPoint:NSMakePoint(maxX, minY)
100                                            toPoint:NSMakePoint(maxX, minY + 3)
101                                             radius:2.5f];
102             [path lineToPoint:NSMakePoint(maxX, minY + 3)];
103             [path lineToPoint:NSMakePoint(maxX, midY + 2)];
104             [path lineToPoint:NSMakePoint(midX, maxY)];
105             [path lineToPoint:NSMakePoint(minX, midY + 2)];
106             [path lineToPoint:NSMakePoint(minX, minY + 3)];
107             [path appendBezierPathWithArcFromPoint:NSMakePoint(minX, minY)
108                                            toPoint:NSMakePoint(minX + 3, minY)
109                                             radius:2.5f];
110             [path closePath];
111         }
112
113         // Rotate our knob if needed to the correct position
114         if (self.tickMarkPosition == NSTickMarkAbove) {
115             NSAffineTransform *transform = nil;
116             transform = RotationTransform(M_PI, NSMakePoint(midX, midY));
117             [path transformUsingAffineTransform:transform];
118         }
119     } else {
120         // We have no tickmarks, draw a round knob
121         [path appendBezierPathWithOvalInRect:NSInsetRect(smallRect, 0.5, 0.5)];
122     }
123
124     // Draw the knobs background
125     if (self.isEnabled && self.isHighlighted) {
126         [_knobGradient drawInBezierPath:path angle:270.0f];
127     } else if (self.isEnabled) {
128         [_knobGradient drawInBezierPath:path angle:90.0f];
129     } else {
130         [_disableKnobGradient drawInBezierPath:path angle:90.0f];
131     }
132
133     // Draw white stroke around the knob
134     if (self.isEnabled) {
135         [_strokeColor setStroke];
136     } else {
137         [_disabledStrokeColor setStroke];
138     }
139
140     [path setLineWidth:1.0];
141     [path stroke];
142 }
143
144 - (void)drawBarInside:(NSRect)fullRect flipped:(BOOL)flipped
145 {
146     NSBezierPath *path;
147
148     // Determine current position of knob
149     CGFloat knobPosition = (self.doubleValue - self.minValue) / (self.maxValue - self.minValue);
150
151     // Copy rect
152     NSRect activeRect = fullRect;
153
154     if (self.isVertical) {
155         // Calculate active rect (bottom part of slider)
156         if (flipped) {
157             activeRect.origin.y = (1 - knobPosition) * activeRect.size.height;
158             activeRect.size.height -= activeRect.origin.y - 1;
159         } else {
160             activeRect.size.height -= (1 - knobPosition) * activeRect.size.height - 1;
161         }
162     } else {
163         // Calculate active rect (left part of slider)
164         activeRect.size.width = knobPosition * (self.controlView.frame.size.width - 1.0);
165     }
166
167     // Draw inactive bar
168     [_disabledSliderColor setFill];
169     path = [NSBezierPath bezierPathWithRoundedRect:fullRect xRadius:2.0 yRadius:2.0];
170     [path fill];
171
172     // Draw active bar
173     [_sliderColor setFill];
174     path = [NSBezierPath bezierPathWithRoundedRect:activeRect xRadius:2.0 yRadius:2.0];
175     [path fill];
176 }
177
178 - (void)drawTickMarks
179 {
180     for (int i = 0; i < self.numberOfTickMarks; i++) {
181         NSRect tickMarkRect = [self rectOfTickMarkAtIndex:i];
182         if (self.isEnabled) {
183             [_strokeColor setFill];
184         } else {
185             [_disabledStrokeColor setFill];
186         }
187         NSRectFill(tickMarkRect);
188     }
189 }
190
191 @end