macOS: Add VLCHUDStepperCell
[vlc.git] / modules / gui / macosx / VLCHUDStepperCell.m
1 //
2 //  BGHUDStepperCell.m
3 //  BGHUDAppKit
4 //
5 //  Created by BinaryGod on 4/6/09.
6 //
7 //  Copyright 2009 Tyler Bunnell and Steve Audette
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 "VLCHUDStepperCell.h"
36
37 @implementation VLCHUDStepperCell {
38     int topButtonFlag;
39     int bottomButtonFlag;
40
41     BOOL topPressed;
42     BOOL bottomPressed;
43     BOOL isTopDown;
44     BOOL isBottomDown;
45 }
46
47 - (instancetype)initWithCoder:(NSCoder *)coder
48 {
49     self = [super initWithCoder:coder];
50     if (self) {
51         _dropShadow = [[NSShadow alloc] init];
52         [_dropShadow setShadowColor: [NSColor blackColor]];
53         [_dropShadow setShadowBlurRadius: 2];
54         [_dropShadow setShadowOffset: NSMakeSize( 0, -1)];
55
56         _strokeColor = [NSColor colorWithDeviceRed: 0.749f green: 0.761f blue: 0.788f alpha: 1.0f];
57         _disabledStrokeColor = [NSColor colorWithDeviceRed: 0.749f green: 0.761f blue: 0.788f alpha:0.2f];
58
59         _normalGradient    = [[NSGradient alloc] initWithStartingColor:[NSColor colorWithDeviceRed:0.251f green:0.251f blue:0.255f alpha:1.0f]
60                                                            endingColor:[NSColor colorWithDeviceRed:0.118f green:0.118f blue:0.118f alpha:1.0f]];
61         _disabledNormalComplexGradient = [[NSGradient alloc] initWithColorsAndLocations: [NSColor colorWithDeviceRed: 0.324f green: 0.331f blue: 0.347f alpha:0.5f],
62                                            (CGFloat)0, [NSColor colorWithDeviceRed: 0.245f green: 0.253f blue: 0.269f alpha: 0.5f], (CGFloat).5,
63                                            [NSColor colorWithDeviceRed: 0.206f green: 0.214f blue: 0.233f alpha: 0.5f], (CGFloat).5,
64                                            [NSColor colorWithDeviceRed: 0.139f green: 0.147f blue: 0.167f alpha: 0.5f], (CGFloat)1.0f, nil];
65         _pushedSolidFill = [NSColor colorWithDeviceRed: 0.941f green: 0.941f blue: 0.941f alpha: 0.5f];
66         _darkStrokeColor = [NSColor colorWithDeviceRed: 0.141f green: 0.141f blue: 0.141f alpha: 0.5f];
67     }
68     return self;
69 }
70
71 -(void)drawWithFrame:(NSRect) frame inView:(NSView *) controlView {
72     [self drawRoundRectButtonInFrame:frame];
73     [self drawArrowsInRect:frame];
74 }
75
76 -(NSRect)adjustFrame:(NSRect)frame
77 {
78     frame.origin.x += 3.5f;
79     frame.origin.y += 2.0f;
80     frame.size.width -= 7.0f;
81     frame.size.height -= 4.0f;
82     return frame;
83 }
84
85 -(BOOL)startTrackingAt:(NSPoint)startPoint inView:(NSView *)controlView
86 {
87     NSRect frame = [controlView bounds];
88
89     NSRect bottomRect = NSMakeRect(frame.origin.x,frame.origin.y,frame.size.width,frame.size.height/2);
90     NSRect topRect = NSMakeRect(frame.origin.x,frame.origin.y+(frame.size.height/2),frame.size.width,frame.size.height/2);
91
92     if(NSPointInRect(startPoint,topRect))
93     {
94         topPressed = isTopDown = YES;
95     }
96     if(NSPointInRect(startPoint,bottomRect))
97     {
98         bottomPressed = isBottomDown = YES;
99     }
100     [[self controlView] setNeedsDisplay:YES];
101
102     return [super startTrackingAt:startPoint inView:controlView];
103 }
104 -(BOOL)continueTracking:(NSPoint)lastPoint at:(NSPoint)currentPoint inView:(NSView *)controlView
105 {
106     NSRect frame = [controlView bounds];
107
108     NSRect bottomRect = NSMakeRect(frame.origin.x,frame.origin.y,frame.size.width,frame.size.height/2);
109     NSRect topRect = NSMakeRect(frame.origin.x,frame.origin.y+(frame.size.height/2),frame.size.width,frame.size.height/2);
110
111     if(isTopDown && topPressed && !NSPointInRect(currentPoint,topRect))
112     {
113         isTopDown = NO;
114         [[self controlView] setNeedsDisplay:YES];
115     }
116     if(!isTopDown && topPressed && NSPointInRect(currentPoint,topRect))
117     {
118         isTopDown = YES;
119         [[self controlView] setNeedsDisplay:YES];
120     }
121     if(isBottomDown && bottomPressed && !NSPointInRect(currentPoint,bottomRect))
122     {
123         isBottomDown = NO;
124         [[self controlView] setNeedsDisplay:YES];
125     }
126     if(!isBottomDown && bottomPressed && NSPointInRect(currentPoint,bottomRect))
127     {
128         isBottomDown = YES;
129         [[self controlView] setNeedsDisplay:YES];
130     }
131
132     return [super continueTracking:lastPoint at:currentPoint inView:controlView];
133 }
134 -(void)stopTracking:(NSPoint)lastPoint at:(NSPoint)stopPoint inView:(NSView *)controlView mouseIsUp:(BOOL)flag
135 {
136     isTopDown = isBottomDown = topPressed = bottomPressed = NO;
137     [[self controlView] setNeedsDisplay:YES];
138     [super stopTracking:lastPoint at:stopPoint inView:controlView mouseIsUp:flag];
139 }
140
141 -(void)drawRoundRectButtonInFrame:(NSRect)frame {
142
143     frame = [self adjustFrame:frame];
144
145     float cornerRadius = 4.0f;
146
147     //Draw the complete button
148
149     //Create Path
150     NSBezierPath *path = [[NSBezierPath alloc] init];
151
152     //Bottom Right Corner
153     [path moveToPoint:NSMakePoint(NSMaxX(frame), NSMinY(frame) + cornerRadius)];
154
155     //Right Edge
156     [path lineToPoint:NSMakePoint(NSMaxX(frame), NSMaxY(frame) - cornerRadius)];
157
158     //Top Right Curve
159     [path appendBezierPathWithArcWithCenter: NSMakePoint(NSMaxX(frame) - cornerRadius, NSMaxY(frame) - cornerRadius)
160                                      radius: cornerRadius
161                                  startAngle: 0
162                                    endAngle: 90];
163
164     //Top Edge
165     [path lineToPoint:NSMakePoint(NSMinX(frame) + cornerRadius, NSMaxY(frame))];
166
167     //Top Left Curve
168     [path appendBezierPathWithArcWithCenter:NSMakePoint(NSMinX(frame) + cornerRadius, NSMaxY(frame) - cornerRadius)
169                                      radius: cornerRadius
170                                  startAngle: 90
171                                    endAngle: 180];
172
173     //Left Edge
174     [path lineToPoint:NSMakePoint(NSMinX(frame), NSMinY(frame) + cornerRadius)];
175
176     //Left Bottom Curve
177     [path appendBezierPathWithArcWithCenter: NSMakePoint(NSMinX(frame) + cornerRadius, NSMinY(frame) + cornerRadius)
178                                      radius: cornerRadius
179                                  startAngle: 180
180                                    endAngle: 270];
181
182     //Bottom Edge
183     [path lineToPoint:NSMakePoint(NSMaxX(frame) - cornerRadius, NSMinY(frame))];
184
185     //Right Bottom Curve
186     [path appendBezierPathWithArcWithCenter:NSMakePoint(NSMaxX(frame) - cornerRadius, NSMinY(frame) + cornerRadius)
187                                      radius: cornerRadius
188                                  startAngle: 270
189                                    endAngle: 0];
190
191     [path closePath];
192
193
194     if([self isEnabled]) {
195
196         [_normalGradient drawInBezierPath:path relativeCenterPosition:NSZeroPoint];
197
198     } else {
199
200         [_disabledNormalComplexGradient drawInBezierPath:path relativeCenterPosition:NSZeroPoint];
201     }
202
203
204
205     //Check for anything being pushed
206     if([self isEnabled])
207     {
208         if(isTopDown)
209         {
210             NSRect topRect = NSMakeRect(frame.origin.x,frame.origin.y+(frame.size.height/2),frame.size.width,frame.size.height/2);
211             NSBezierPath *path = [[NSBezierPath alloc] init];
212             [path moveToPoint:NSMakePoint(NSMaxX(topRect), NSMinY(topRect))];
213             [path lineToPoint:NSMakePoint(NSMaxX(topRect), NSMaxY(topRect) - cornerRadius)];
214             [path appendBezierPathWithArcWithCenter: NSMakePoint(NSMaxX(topRect) - cornerRadius, NSMaxY(topRect) - cornerRadius)
215                                              radius: cornerRadius
216                                          startAngle: 0
217                                            endAngle: 90];
218             [path lineToPoint:NSMakePoint(NSMinX(topRect) + cornerRadius, NSMaxY(topRect))];
219             [path appendBezierPathWithArcWithCenter:NSMakePoint(NSMinX(topRect) + cornerRadius, NSMaxY(topRect) - cornerRadius)
220                                              radius: cornerRadius
221                                          startAngle: 90
222                                            endAngle: 180];
223             [path lineToPoint:NSMakePoint(NSMinX(topRect), NSMinY(topRect))];
224
225             [path closePath];
226
227             [_pushedSolidFill set];
228             [path fill];
229         }
230         else if(isBottomDown)
231         {
232             NSRect bottomRect = NSMakeRect(frame.origin.x,frame.origin.y,frame.size.width,frame.size.height/2);
233             NSBezierPath* path = [[NSBezierPath alloc] init];
234
235             [path moveToPoint:NSMakePoint(NSMinX(bottomRect), NSMaxY(bottomRect))];
236             [path lineToPoint:NSMakePoint(NSMinX(bottomRect), NSMinY(bottomRect) + cornerRadius)];
237             [path appendBezierPathWithArcWithCenter: NSMakePoint(NSMinX(bottomRect) + cornerRadius, NSMinY(bottomRect) + cornerRadius)
238                                              radius: cornerRadius
239                                          startAngle: 180
240                                            endAngle: 270];
241             [path lineToPoint:NSMakePoint(NSMaxX(bottomRect) - cornerRadius, NSMinY(bottomRect))];
242             [path appendBezierPathWithArcWithCenter:NSMakePoint(NSMaxX(bottomRect) - cornerRadius, NSMinY(bottomRect) + cornerRadius)
243                                              radius: cornerRadius
244                                          startAngle: 270
245                                            endAngle: 0];
246             [path lineToPoint:NSMakePoint(NSMaxX(bottomRect), NSMaxY(bottomRect))];
247
248             [path closePath];
249             [_pushedSolidFill set];
250             [path fill];
251         }
252     }
253
254     [NSGraphicsContext saveGraphicsState];
255
256     //Draw dark border color
257     if([self isEnabled]) {
258
259         [_dropShadow set];
260     }
261     [_darkStrokeColor set];
262     [path stroke];
263
264     [NSGraphicsContext restoreGraphicsState];
265
266     if([self isEnabled]) {
267
268         [_strokeColor set];
269     } else {
270
271         [_disabledStrokeColor set];
272     }
273
274     [path setLineWidth: 1.0f];
275     [path stroke];
276
277
278 }
279
280 -(void)drawArrowsInRect:(NSRect) frame {
281
282     CGFloat arrowWidth = 2.5f;
283     CGFloat arrowHeight = 2.0f;
284
285     frame = [self adjustFrame:frame];
286
287     NSRect bottomRect = NSMakeRect(frame.origin.x,frame.origin.y,frame.size.width,frame.size.height/2);
288     NSRect topRect = NSMakeRect(frame.origin.x,frame.origin.y+(frame.size.height/2),frame.size.width,frame.size.height/2);
289
290     NSBezierPath *arrow = [[NSBezierPath alloc] init];
291
292     NSPoint points[3];
293
294     points[0] = NSMakePoint(topRect.origin.x + (topRect.size.width /2), topRect.origin.y + ((topRect.size.height /2) + arrowHeight));
295     points[1] = NSMakePoint(topRect.origin.x + ((topRect.size.width /2) - arrowWidth), topRect.origin.y + ((topRect.size.height /2)-arrowHeight));
296     points[2] = NSMakePoint(topRect.origin.x + ((topRect.size.width /2) + arrowWidth), topRect.origin.y + ((topRect.size.height /2)-arrowHeight));
297     
298     
299     [arrow appendBezierPathWithPoints: points count: 3];
300     
301     if([self isEnabled]) {
302         if(isTopDown)
303             [_darkStrokeColor set];
304         else
305             [_strokeColor set];
306     } else {
307         [_disabledStrokeColor set];
308     }
309     
310     
311     [arrow fill];
312     
313     
314     arrow = [[NSBezierPath alloc] init];
315     
316     points[0] = NSMakePoint(bottomRect.origin.x + ((bottomRect.size.width /2) - arrowWidth), bottomRect.origin.y + ((bottomRect.size.height /2)+arrowHeight));
317     points[1] = NSMakePoint(bottomRect.origin.x + ((bottomRect.size.width /2) + arrowWidth), bottomRect.origin.y + ((bottomRect.size.height /2)+arrowHeight));
318     points[2] = NSMakePoint(bottomRect.origin.x + (bottomRect.size.width /2), frame.origin.y + ((bottomRect.size.height /2) - arrowHeight));
319     
320     [arrow appendBezierPathWithPoints: points count: 3];
321     
322     if([self isEnabled]) {
323         if(isBottomDown)
324             [_darkStrokeColor set];
325         else
326             [_strokeColor set];
327     } else {
328         [_disabledStrokeColor set];
329     }
330     
331     [arrow fill];
332 }
333
334 @end