macOS: Add VLCHUDScroller
[vlc.git] / modules / gui / macosx / VLCHUDScroller.m
1 //  VLCHUDScroller.m
2 //  HUDScroller
3 //
4 //  Created by BinaryGod on 5/22/08.
5 //
6 //  Copyright (c) 2008, Tim Davis (BinaryMethod.com, binary.god@gmail.com)
7 //  All rights reserved.
8 //
9 //  Redistribution and use in source and binary forms, with or without modification,
10 //  are permitted provided that the following conditions are met:
11 //
12 //        Redistributions of source code must retain the above copyright notice, this
13 //    list of conditions and the following disclaimer.
14 //
15 //        Redistributions in binary form must reproduce the above copyright notice,
16 //    this list of conditions and the following disclaimer in the documentation and/or
17 //    other materials provided with the distribution.
18 //
19 //        Neither the name of the BinaryMethod.com nor the names of its contributors
20 //    may be used to endorse or promote products derived from this software without
21 //    specific prior written permission.
22 //
23 //    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND
24 //    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 //    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 //    IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 //    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 //    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
29 //    OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 //    WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 //    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 //    POSSIBILITY OF SUCH DAMAGE.
33
34 // Special thanks to Matt Gemmell (http://mattgemmell.com/) for helping me solve the
35 // transparent drawing issues.  Your awesome man!!!
36
37 #import "VLCHUDScroller.h"
38
39 @implementation VLCHUDScroller
40
41 - (instancetype)initWithCoder:(NSCoder *)coder
42 {
43     self = [super initWithCoder:coder];
44     if (self) {
45         _scrollerStroke = [NSColor colorWithDeviceRed: 0.749f green: 0.761f blue: 0.788f alpha: 1.0f];
46         _scrollerKnobGradient = [[NSGradient alloc] initWithStartingColor:[NSColor colorWithDeviceRed:0.631f green:0.639f blue:0.655f alpha:1.0f]
47                                                               endingColor:[NSColor colorWithDeviceRed:0.439f green:0.447f blue:0.471f alpha:1.0f]];
48         _scrollerTrackGradient = [[NSGradient alloc] initWithStartingColor:[NSColor colorWithDeviceRed:0.137f green:0.137f blue:0.137f alpha:.75f]
49                                                                endingColor:[NSColor colorWithDeviceRed:0.278f green:0.278f blue:0.278f alpha:.75f]];
50         _scrollerArrowNormalGradient = [[NSGradient alloc] initWithStartingColor:[NSColor colorWithDeviceRed:0.251f green:0.251f blue:0.255f alpha:0.5f]
51                                                                      endingColor:[NSColor colorWithDeviceRed:0.118f green:0.118f blue:0.118f alpha:0.5f]];
52         _scrollerArrowPushedGradient = [[NSGradient alloc] initWithStartingColor:[NSColor colorWithDeviceRed:0.451f green:0.451f blue:0.455f alpha:0.5f]
53                                                                                                  endingColor:[NSColor colorWithDeviceRed:0.318f green:0.318f blue:0.318f alpha:0.5f]];
54     }
55     return self;
56 }
57
58 #pragma mark Drawing Functions
59
60 - (void)drawRect:(NSRect)rect {
61     // See if we should use system default or supplied value
62     if ([self arrowsPosition] == NSScrollerArrowsDefaultSetting) {
63         arrowPosition = [[[NSUserDefaults standardUserDefaults] persistentDomainForName:NSGlobalDomain] valueForKey: @"AppleScrollBarVariant"];
64         if (arrowPosition == nil) {
65             arrowPosition = @"DoubleMax";
66         }
67     } else {
68         if ([self arrowsPosition] == NSScrollerArrowsNone) {
69             arrowPosition = @"None";
70         }
71     }
72
73     NSDisableScreenUpdates();
74
75     [[NSColor colorWithCalibratedWhite:0.0f alpha:0.7f] set];
76     NSRectFill([self bounds]);
77
78     // Draw knob-slot.
79     [self drawKnobSlotInRect:[self bounds] highlight:YES];
80
81     // Draw knob
82     [self drawKnob];
83
84     // Draw arrows
85     [self drawArrow:NSScrollerIncrementArrow highlight:([self hitPart] == NSScrollerIncrementLine)];
86     [self drawArrow:NSScrollerDecrementArrow highlight:([self hitPart] == NSScrollerDecrementLine)];
87
88     [[self window] invalidateShadow];
89
90     NSEnableScreenUpdates();
91 }
92
93 - (void)drawKnob {
94
95     if(![self isHoriz]) {
96
97         //Draw Knob
98         NSBezierPath *knob = [[NSBezierPath alloc] init];
99         NSRect knobRect = [self rectForPart:NSScrollerKnob];
100
101
102         [knob appendBezierPathWithArcWithCenter:NSMakePoint(knobRect.origin.x + ((knobRect.size.width - .5f) /2), (knobRect.origin.y + ((knobRect.size.width -2) /2)))
103                                          radius:(knobRect.size.width -2) /2
104                                      startAngle:180
105                                        endAngle:0];
106
107         [knob appendBezierPathWithArcWithCenter:NSMakePoint(knobRect.origin.x + ((knobRect.size.width - .5f) /2), ((knobRect.origin.y + knobRect.size.height) - ((knobRect.size.width -2) /2)))
108                                          radius:(knobRect.size.width -2) /2
109                                      startAngle:0
110                                        endAngle:180];
111
112         [_scrollerStroke set];
113         [knob fill];
114
115         knobRect.origin.x += 1;
116         knobRect.origin.y += 1;
117         knobRect.size.width -= 2;
118         knobRect.size.height -= 2;
119
120         knob = [[NSBezierPath alloc] init];
121
122         [knob appendBezierPathWithArcWithCenter:NSMakePoint(knobRect.origin.x + ((knobRect.size.width - .5f) /2), (knobRect.origin.y + ((knobRect.size.width -2) /2)))
123                                          radius:(knobRect.size.width -2) /2
124                                      startAngle:180
125                                        endAngle:0];
126
127         [knob appendBezierPathWithArcWithCenter:NSMakePoint(knobRect.origin.x + ((knobRect.size.width - .5f) /2), ((knobRect.origin.y + knobRect.size.height) - ((knobRect.size.width -2) /2)))
128                                          radius:(knobRect.size.width -2) /2
129                                      startAngle:0
130                                        endAngle:180];
131
132         [_scrollerKnobGradient drawInBezierPath:knob angle:0];
133
134     } else {
135
136         //Draw Knob
137         NSBezierPath *knob = [[NSBezierPath alloc] init];
138         NSRect knobRect = [self rectForPart:NSScrollerKnob];
139
140         [knob appendBezierPathWithArcWithCenter:NSMakePoint(knobRect.origin.x + ((knobRect.size.height - .5f) /2), (knobRect.origin.y + ((knobRect.size.height -1) /2)))
141                                          radius:(knobRect.size.height -1) /2
142                                      startAngle:90
143                                        endAngle:270];
144
145         [knob appendBezierPathWithArcWithCenter:NSMakePoint((knobRect.origin.x + knobRect.size.width) - ((knobRect.size.height - .5f) /2), (knobRect.origin.y + ((knobRect.size.height -1) /2)))
146                                          radius:(knobRect.size.height -1) /2
147                                      startAngle:270
148                                        endAngle:90];
149
150         [_scrollerStroke set];
151         [knob fill];
152
153         knobRect.origin.x += 1;
154         knobRect.origin.y += 1;
155         knobRect.size.width -= 2;
156         knobRect.size.height -= 2;
157
158         knob = [[NSBezierPath alloc] init];
159
160         [knob appendBezierPathWithArcWithCenter:NSMakePoint(knobRect.origin.x + ((knobRect.size.height - .5f) /2), (knobRect.origin.y + ((knobRect.size.height -1) /2)))
161                                          radius:(knobRect.size.height -1) /2
162                                      startAngle:90
163                                        endAngle:270];
164
165         [knob appendBezierPathWithArcWithCenter:NSMakePoint((knobRect.origin.x + knobRect.size.width) - ((knobRect.size.height - .5f) /2), (knobRect.origin.y + ((knobRect.size.height -1) /2)))
166                                          radius:(knobRect.size.height -1) /2
167                                      startAngle:270
168                                        endAngle:90];
169
170         [_scrollerKnobGradient drawInBezierPath:knob angle:90];
171
172     }
173 }
174
175 - (void)drawArrow:(NSScrollerArrow)arrow highlightPart:(NSUInteger)part {
176
177     if (arrow == NSScrollerDecrementArrow) {
178
179         if (part == (NSUInteger)-1 || part == 0) {
180             [self drawDecrementArrow: NO];
181         } else {
182             [self drawDecrementArrow: YES];
183         }
184     }
185
186     if (arrow == NSScrollerIncrementArrow) {
187
188         if(part == 1 || part == (NSUInteger)-1) {
189
190             [self drawIncrementArrow: NO];
191         } else {
192
193             [self drawIncrementArrow: YES];
194         }
195     }
196 }
197
198 - (void)drawKnobSlotInRect:(NSRect)rect highlight:(BOOL)highlight {
199
200     if (![self isHoriz]) {
201
202         // Draw Knob Slot
203         [_scrollerTrackGradient drawInRect:rect angle:0];
204
205         if ([arrowPosition isEqualToString:@"DoubleMax"]) {
206
207             // Adjust rect height for top base
208             rect.size.height = 8;
209
210             // Draw Top Base
211             NSBezierPath *path = [[NSBezierPath alloc] init];
212             NSPoint basePoints[4];
213
214             [path appendBezierPathWithArcWithCenter:NSMakePoint(rect.size.width /2, rect.size.height + (rect.size.width /2) -5)
215                                              radius:(rect.size.width ) /2
216                                          startAngle:180
217                                            endAngle:0];
218
219             // Add the rest of the points
220             basePoints[3] = NSMakePoint( rect.origin.x, rect.origin.y + rect.size.height);
221             basePoints[2] = NSMakePoint( rect.origin.x, rect.origin.y);
222             basePoints[1] = NSMakePoint( rect.origin.x + rect.size.width, rect.origin.y);
223             basePoints[0] = NSMakePoint( rect.origin.x + rect.size.width, rect.origin.y + rect.size.height);
224
225             [path appendBezierPathWithPoints:basePoints count:4];
226
227             [_scrollerArrowNormalGradient drawInBezierPath:path angle:0];
228
229         } else if ([arrowPosition isEqualToString:@"None"]) {
230
231             // Adjust rect height for top base
232             NSRect topRect = rect;
233             topRect.size.height = 8;
234
235             // Draw Top Base
236             NSBezierPath *path = [[NSBezierPath alloc] init];
237             NSPoint basePoints[4];
238
239             [path appendBezierPathWithArcWithCenter:NSMakePoint(topRect.size.width /2, topRect.size.height + (topRect.size.width /2) -5)
240                                              radius:(topRect.size.width ) /2
241                                          startAngle:180
242                                            endAngle:0];
243
244             // Add the rest of the points
245             basePoints[3] = NSMakePoint( topRect.origin.x, topRect.origin.y + topRect.size.height);
246             basePoints[2] = NSMakePoint( topRect.origin.x, topRect.origin.y);
247             basePoints[1] = NSMakePoint( topRect.origin.x + topRect.size.width, topRect.origin.y);
248             basePoints[0] = NSMakePoint( topRect.origin.x + topRect.size.width, topRect.origin.y + topRect.size.height);
249
250             [path appendBezierPathWithPoints:basePoints count:4];
251
252             [_scrollerArrowNormalGradient drawInBezierPath:path angle:0];
253
254
255             // Draw Decrement Button
256             NSRect bottomRect = rect;
257             bottomRect.origin.y = rect.size.height - 4;
258             bottomRect.size.height = 4;
259
260             path = [[NSBezierPath alloc] init];
261
262             // Add Notch
263             [path appendBezierPathWithArcWithCenter:NSMakePoint((bottomRect.size.width ) /2, (bottomRect.origin.y  - ((bottomRect.size.width ) /2) + 1))
264                                              radius:(bottomRect.size.width ) /2
265                                          startAngle:0
266                                            endAngle:180];
267
268             // Add the rest of the points
269             basePoints[0] = NSMakePoint( bottomRect.origin.x, bottomRect.origin.y);
270             basePoints[1] = NSMakePoint( bottomRect.origin.x, bottomRect.origin.y + bottomRect.size.height);
271             basePoints[2] = NSMakePoint( bottomRect.origin.x + bottomRect.size.width, bottomRect.origin.y + bottomRect.size.height);
272             basePoints[3] = NSMakePoint( bottomRect.origin.x + bottomRect.size.width, bottomRect.origin.y);
273
274             // Add Points to Path
275             [path appendBezierPathWithPoints:basePoints count:4];
276
277             [_scrollerArrowNormalGradient drawInBezierPath:path angle:0];
278         }
279     } else {
280
281         // Draw Knob Slot
282         [_scrollerTrackGradient drawInRect:rect angle:90];
283
284         if ([arrowPosition isEqualToString:@"DoubleMax"]) {
285
286             // Adjust rect height for top base
287             rect.size.width = 8;
288
289             // Draw Top Base
290             NSBezierPath *path = [[NSBezierPath alloc] init];
291             NSPoint basePoints[4];
292
293             [path appendBezierPathWithArcWithCenter:NSMakePoint((rect.size.height /2) +5, rect.origin.y + (rect.size.height /2) )
294                                              radius:(rect.size.height ) /2
295                                          startAngle:90
296                                            endAngle:270];
297
298             // Add the rest of the points
299             basePoints[2] = NSMakePoint( rect.origin.x, rect.origin.y + rect.size.height);
300             basePoints[1] = NSMakePoint( rect.origin.x, rect.origin.y);
301             basePoints[0] = NSMakePoint( rect.origin.x + rect.size.width, rect.origin.y);
302             basePoints[3] = NSMakePoint( rect.origin.x + rect.size.width, rect.origin.y + rect.size.height);
303
304             [path appendBezierPathWithPoints:basePoints count:4];
305
306             [_scrollerArrowNormalGradient drawInBezierPath:path angle:0];
307         } else if ([arrowPosition isEqualToString:@"None"]) {
308
309             // Adjust rect height for top base
310             NSRect topRect = rect;
311             topRect.size.width = 8;
312
313             // Draw Top Base
314             NSBezierPath *path = [[NSBezierPath alloc] init];
315             NSPoint basePoints[4];
316
317             [path appendBezierPathWithArcWithCenter:NSMakePoint((topRect.size.height /2) +5, topRect.origin.y + (topRect.size.height /2) )
318                                              radius:(topRect.size.height ) /2
319                                          startAngle:90
320                                            endAngle:270];
321
322             // Add the rest of the points
323             basePoints[2] = NSMakePoint( topRect.origin.x, topRect.origin.y + topRect.size.height);
324             basePoints[1] = NSMakePoint( topRect.origin.x, topRect.origin.y);
325             basePoints[0] = NSMakePoint( topRect.origin.x + topRect.size.width, topRect.origin.y);
326             basePoints[3] = NSMakePoint( topRect.origin.x + topRect.size.width, topRect.origin.y + topRect.size.height);
327
328             [path appendBezierPathWithPoints:basePoints count:4];
329
330             [_scrollerArrowNormalGradient drawInBezierPath:path angle:0];
331
332             // Bottom Base
333             // Draw Decrement Button
334             NSRect bottomRect = rect;
335             bottomRect.origin.x = rect.size.width - 4;
336             bottomRect.size.width = 4;
337
338             path = [[NSBezierPath alloc] init];
339
340             // Add Notch
341             [path appendBezierPathWithArcWithCenter:NSMakePoint(bottomRect.origin.x - ((bottomRect.size.height ) /2), (bottomRect.origin.y  + ((bottomRect.size.height ) /2) ))
342                                              radius:(bottomRect.size.height ) /2
343                                          startAngle:270
344                                            endAngle:90];
345
346             // Add the rest of the points
347             basePoints[3] = NSMakePoint( bottomRect.origin.x - (((bottomRect.size.height ) /2) -1), bottomRect.origin.y);
348             basePoints[0] = NSMakePoint( bottomRect.origin.x - (((bottomRect.size.height ) /2) -1), bottomRect.origin.y + bottomRect.size.height);
349             basePoints[1] = NSMakePoint( bottomRect.origin.x + bottomRect.size.width, bottomRect.origin.y + bottomRect.size.height);
350             basePoints[2] = NSMakePoint( bottomRect.origin.x + bottomRect.size.width, bottomRect.origin.y);
351
352             // Add Points to Path
353             [path appendBezierPathWithPoints:basePoints count:4];
354
355             [_scrollerArrowNormalGradient drawInBezierPath:path angle:90];
356         }
357     }
358 }
359
360 - (void)drawDecrementArrow:(bool)highlighted {
361
362     if (![self isHoriz]) {
363
364         if ([arrowPosition isEqualToString:@"DoubleMax"]) {
365
366             // Draw Decrement Button
367             NSRect rect = [self rectForPart: NSScrollerDecrementLine];
368             NSBezierPath *path = [[NSBezierPath alloc] init];
369             NSPoint basePoints[4];
370
371             // Add Notch
372             [path appendBezierPathWithArcWithCenter:NSMakePoint((rect.size.width ) /2, (rect.origin.y  - ((rect.size.width ) /2) + 1))
373                                              radius:(rect.size.width ) /2
374                                          startAngle:0
375                                            endAngle:180];
376
377             // Add the rest of the points
378             basePoints[0] = NSMakePoint( rect.origin.x, rect.origin.y);
379             basePoints[1] = NSMakePoint( rect.origin.x, rect.origin.y + rect.size.height);
380             basePoints[2] = NSMakePoint( rect.origin.x + rect.size.width, rect.origin.y + rect.size.height);
381             basePoints[3] = NSMakePoint( rect.origin.x + rect.size.width, rect.origin.y);
382
383             // Add Points to Path
384             [path appendBezierPathWithPoints:basePoints count:4];
385
386             // Fill Path
387             if (!highlighted) {
388                 [_scrollerArrowNormalGradient drawInBezierPath:path angle:0];
389             } else {
390                 [_scrollerArrowPushedGradient drawInBezierPath:path angle:0];
391             }
392
393             // Create Arrow Glyph
394             NSBezierPath *arrow = [[NSBezierPath alloc] init];
395
396             NSPoint points[3];
397             points[0] = NSMakePoint( rect.size.width /2, rect.origin.y + (rect.size.height /2) -3);
398             points[1] = NSMakePoint( (rect.size.width /2) +3.5f, rect.origin.y + (rect.size.height /2) +3);
399             points[2] = NSMakePoint( (rect.size.width /2) -3.5f, rect.origin.y + (rect.size.height /2) +3);
400
401             [arrow appendBezierPathWithPoints:points count:3];
402
403             [_scrollerStroke set];
404             [arrow fill];
405
406             // Create Devider Line
407             [_scrollerStroke set];
408
409             [NSBezierPath strokeLineFromPoint:NSMakePoint(0, (rect.origin.y + rect.size.height) +.5f)
410                                       toPoint:NSMakePoint(rect.size.width, (rect.origin.y + rect.size.height) +.5f)];
411
412         } else if ([arrowPosition isEqualToString: @"Single"]) {
413
414             NSRect rect = [self rectForPart: NSScrollerDecrementLine];
415
416             NSBezierPath *path = [[NSBezierPath alloc] init];
417             NSPoint basePoints[4];
418
419             [path appendBezierPathWithArcWithCenter:NSMakePoint(rect.size.width /2, rect.size.height + (rect.size.width /2) -3)
420                                              radius:(rect.size.width ) /2
421                                          startAngle:180
422                                            endAngle:0];
423
424             // Add the rest of the points
425             basePoints[3] = NSMakePoint( rect.origin.x, rect.origin.y + rect.size.height);
426             basePoints[2] = NSMakePoint( rect.origin.x, rect.origin.y);
427             basePoints[1] = NSMakePoint( rect.origin.x + rect.size.width, rect.origin.y);
428             basePoints[0] = NSMakePoint( rect.origin.x + rect.size.width, rect.origin.y + rect.size.height);
429
430             [path appendBezierPathWithPoints: basePoints count: 4];
431
432             // Fill Path
433             if (!highlighted) {
434                 [_scrollerArrowNormalGradient drawInBezierPath:path angle:0];
435             } else {
436
437                 [_scrollerArrowPushedGradient drawInBezierPath:path angle:0];
438             }
439
440             // Create Arrow Glyph
441             NSBezierPath *arrow = [[NSBezierPath alloc] init];
442
443             NSPoint points[3];
444             points[0] = NSMakePoint( rect.size.width /2, rect.origin.y + (rect.size.height /2) -3);
445             points[1] = NSMakePoint( (rect.size.width /2) +3.5f, rect.origin.y + (rect.size.height /2) +3);
446             points[2] = NSMakePoint( (rect.size.width /2) -3.5f, rect.origin.y + (rect.size.height /2) +3);
447
448             [arrow appendBezierPathWithPoints:points count:3];
449
450             [_scrollerStroke set];
451             [arrow fill];
452         }
453     } else {
454
455         if ([arrowPosition isEqualToString: @"DoubleMax"]) {
456
457             // Draw Decrement Button
458             NSRect rect = [self rectForPart:NSScrollerDecrementLine];
459             NSBezierPath *path = [[NSBezierPath alloc] init];
460             NSPoint basePoints[4];
461
462             // Add Notch
463             [path appendBezierPathWithArcWithCenter:NSMakePoint(rect.origin.x - ((rect.size.height ) /2), (rect.origin.y  + ((rect.size.height ) /2) ))
464                                              radius:(rect.size.height ) /2
465                                          startAngle:270
466                                            endAngle:90];
467
468             // Add the rest of the points
469             basePoints[3] = NSMakePoint( rect.origin.x - (((rect.size.height ) /2) -1), rect.origin.y);
470             basePoints[0] = NSMakePoint( rect.origin.x - (((rect.size.height ) /2) -1), rect.origin.y + rect.size.height);
471             basePoints[1] = NSMakePoint( rect.origin.x + rect.size.width, rect.origin.y + rect.size.height);
472             basePoints[2] = NSMakePoint( rect.origin.x + rect.size.width, rect.origin.y);
473
474             // Add Points to Path
475             [path appendBezierPathWithPoints:basePoints count:4];
476
477             // Fill Path
478             if (!highlighted) {
479                 [_scrollerArrowNormalGradient drawInBezierPath:path angle:90];
480             } else {
481                 [_scrollerArrowPushedGradient drawInBezierPath:path angle:90];
482             }
483
484             // Create Arrow Glyph
485             NSBezierPath *arrow = [[NSBezierPath alloc] init];
486
487             NSPoint points[3];
488             points[0] = NSMakePoint( rect.origin.x + (rect.size.width /2) -3, rect.size.height /2);
489             points[1] = NSMakePoint( rect.origin.x + (rect.size.height /2) +3, (rect.size.height /2) +3.5f);
490             points[2] = NSMakePoint( rect.origin.x + (rect.size.height /2) +3, (rect.size.height /2) -3.5f);
491
492             [arrow appendBezierPathWithPoints:points count:3];
493
494             [_scrollerStroke set];
495             [arrow fill];
496
497             // Create Devider Line
498             [_scrollerStroke set];
499
500             [NSBezierPath strokeLineFromPoint:NSMakePoint(rect.origin.x + rect.size.width -.5f, rect.origin.y)
501                                       toPoint:NSMakePoint(rect.origin.x + rect.size.width -.5f, rect.origin.y + rect.size.height)];
502
503         } else if ([arrowPosition isEqualToString: @"Single"]) {
504
505             NSRect rect = [self rectForPart: NSScrollerDecrementLine];
506
507             NSBezierPath *path = [[NSBezierPath alloc] init];
508             NSPoint basePoints[4];
509
510             [path appendBezierPathWithArcWithCenter:NSMakePoint(rect.origin.x + (rect.size.width -2) + ((rect.size.height ) /2), (rect.origin.y  + ((rect.size.height ) /2) ))
511                                              radius:(rect.size.height ) /2
512                                          startAngle:90
513                                            endAngle:270];
514
515             // Add the rest of the points
516             basePoints[2] = NSMakePoint( rect.origin.x, rect.origin.y + rect.size.height);
517             basePoints[1] = NSMakePoint( rect.origin.x, rect.origin.y);
518             basePoints[0] = NSMakePoint( rect.origin.x + rect.size.width, rect.origin.y);
519             basePoints[3] = NSMakePoint( rect.origin.x + rect.size.width, rect.origin.y + rect.size.height);
520
521             [path appendBezierPathWithPoints: basePoints count: 4];
522
523             // Fill Path
524             if (!highlighted) {
525                 [_scrollerArrowNormalGradient drawInBezierPath:path angle:90];
526             } else {
527                 [_scrollerArrowPushedGradient drawInBezierPath:path angle:90];
528             }
529
530             // Create Arrow Glyph
531             NSBezierPath *arrow = [[NSBezierPath alloc] init];
532
533             NSPoint points[3];
534             points[0] = NSMakePoint( rect.origin.x + (rect.size.width /2) -3, rect.size.height /2);
535             points[1] = NSMakePoint( rect.origin.x + (rect.size.height /2) +3, (rect.size.height /2) +3.5f);
536             points[2] = NSMakePoint( rect.origin.x + (rect.size.height /2) +3, (rect.size.height /2) -3.5f);
537
538             [arrow appendBezierPathWithPoints:points count:3];
539
540             [_scrollerStroke set];
541             [arrow fill];
542         }
543     }
544 }
545
546 - (void)drawIncrementArrow:(bool)highlighted {
547
548     if (![self isHoriz]) {
549
550         if ([arrowPosition isEqualToString:@"DoubleMax"]) {
551
552             // Draw Increment Button
553             NSRect rect = [self rectForPart: NSScrollerIncrementLine];
554
555             if(!highlighted) {
556
557                 [_scrollerArrowNormalGradient drawInRect:rect angle:0];
558             } else {
559
560                 [_scrollerArrowPushedGradient drawInRect:rect angle:0];
561             }
562
563             // Create Arrow Glyph
564             NSBezierPath *arrow = [[NSBezierPath alloc] init];
565
566             NSPoint points[3];
567             points[0] = NSMakePoint( rect.size.width /2, rect.origin.y + (rect.size.height /2) +3);
568             points[1] = NSMakePoint( (rect.size.width /2) +3.5f, rect.origin.y + (rect.size.height /2) -3);
569             points[2] = NSMakePoint( (rect.size.width /2) -3.5f, rect.origin.y + (rect.size.height /2) -3);
570
571             [arrow appendBezierPathWithPoints: points count: 3];
572
573             [_scrollerStroke set];
574             [arrow fill];
575         } else if ([arrowPosition isEqualToString:@"Single"]) {
576
577             // Draw Decrement Button
578             NSRect rect = [self rectForPart: NSScrollerIncrementLine];
579             NSBezierPath *path = [[NSBezierPath alloc] init];
580             NSPoint basePoints[4];
581
582             // Add Notch
583             [path appendBezierPathWithArcWithCenter:NSMakePoint((rect.size.width ) /2, (rect.origin.y  - ((rect.size.width ) /2) + 2))
584                                              radius:(rect.size.width ) /2
585                                          startAngle:0
586                                            endAngle:180];
587
588             // Add the rest of the points
589             basePoints[0] = NSMakePoint( rect.origin.x, rect.origin.y);
590             basePoints[1] = NSMakePoint( rect.origin.x, rect.origin.y + rect.size.height);
591             basePoints[2] = NSMakePoint( rect.origin.x + rect.size.width, rect.origin.y + rect.size.height);
592             basePoints[3] = NSMakePoint( rect.origin.x + rect.size.width, rect.origin.y);
593
594             // Add Points to Path
595             [path appendBezierPathWithPoints:basePoints count:4];
596
597             // Fill Path
598             if (!highlighted) {
599                 [_scrollerArrowNormalGradient drawInBezierPath:path angle:0];
600             } else {
601                 [_scrollerArrowPushedGradient drawInBezierPath:path angle:0];
602             }
603
604             // Create Arrow Glyph
605             NSBezierPath *arrow = [[NSBezierPath alloc] init];
606
607             NSPoint points[3];
608             points[0] = NSMakePoint( rect.size.width /2, rect.origin.y + (rect.size.height /2) +3);
609             points[1] = NSMakePoint( (rect.size.width /2) +3.5f, rect.origin.y + (rect.size.height /2) -3);
610             points[2] = NSMakePoint( (rect.size.width /2) -3.5f, rect.origin.y + (rect.size.height /2) -3);
611
612             [arrow appendBezierPathWithPoints:points count:3];
613
614             [_scrollerStroke set];
615             [arrow fill];
616         }
617     } else {
618
619         if ([arrowPosition isEqualToString:@"DoubleMax"]) {
620
621             // Draw Increment Button
622             NSRect rect = [self rectForPart:NSScrollerIncrementLine];
623
624             if (!highlighted) {
625                 [_scrollerArrowNormalGradient drawInRect:rect angle:90];
626             } else {
627                 [_scrollerArrowPushedGradient drawInRect:rect angle:90];
628             }
629
630             // Create Arrow Glyph
631             NSBezierPath *arrow = [[NSBezierPath alloc] init];
632
633             NSPoint points[3];
634             points[0] = NSMakePoint( rect.origin.x + (rect.size.width /2) +3, rect.size.height /2);
635             points[1] = NSMakePoint( rect.origin.x + (rect.size.height /2) -3, (rect.size.height /2) +3.5f);
636             points[2] = NSMakePoint( rect.origin.x + (rect.size.height /2) -3, (rect.size.height /2) -3.5f);
637
638             [arrow appendBezierPathWithPoints:points count:3];
639
640             [_scrollerStroke set];
641             [arrow fill];
642         } else if ([arrowPosition isEqualToString:@"Single"]) {
643
644             // Draw Decrement Button
645             NSRect rect = [self rectForPart:NSScrollerIncrementLine];
646             NSBezierPath *path = [[NSBezierPath alloc] init];
647             NSPoint basePoints[4];
648
649             // Add Notch
650             [path appendBezierPathWithArcWithCenter:NSMakePoint(rect.origin.x - (((rect.size.height ) /2) -2), (rect.origin.y  + ((rect.size.height ) /2) ))
651                                              radius:(rect.size.height ) /2
652                                          startAngle:270
653                                            endAngle:90];
654
655             // Add the rest of the points
656             basePoints[3] = NSMakePoint( rect.origin.x - (((rect.size.height ) /2) -1), rect.origin.y);
657             basePoints[0] = NSMakePoint( rect.origin.x - (((rect.size.height ) /2) -1), rect.origin.y + rect.size.height);
658             basePoints[1] = NSMakePoint( rect.origin.x + rect.size.width, rect.origin.y + rect.size.height);
659             basePoints[2] = NSMakePoint( rect.origin.x + rect.size.width, rect.origin.y);
660
661             // Add Points to Path
662             [path appendBezierPathWithPoints:basePoints count:4];
663
664             // Fill Path
665             if (!highlighted) {
666                 [_scrollerArrowNormalGradient drawInBezierPath:path angle:0];
667             } else {
668                 [_scrollerArrowPushedGradient drawInBezierPath:path angle:0];
669             }
670
671             // Create Arrow Glyph
672             NSBezierPath *arrow = [[NSBezierPath alloc] init];
673
674             NSPoint points[3];
675             points[0] = NSMakePoint( rect.origin.x + (rect.size.width /2) +3, rect.size.height /2);
676             points[1] = NSMakePoint( rect.origin.x + (rect.size.height /2) -3, (rect.size.height /2) +3.5f);
677             points[2] = NSMakePoint( rect.origin.x + (rect.size.height /2) -3, (rect.size.height /2) -3.5f);
678
679             [arrow appendBezierPathWithPoints:points count:3];
680
681             [_scrollerStroke set];
682             [arrow fill];
683         }
684     }
685 }
686
687 #pragma mark -
688 #pragma mark Helper Methods
689 - (NSUsableScrollerParts)usableParts {
690
691     if ([self arrowsPosition] != NSScrollerArrowsNone) {
692
693         if ([self isHoriz]) {
694
695             // Now Figure out if we can actually show all parts
696             CGFloat arrowSpace = NSWidth([self rectForPart: NSScrollerIncrementLine]) + NSWidth([self rectForPart: NSScrollerDecrementLine]) +
697                 NSMidY([self rectForPart: NSScrollerIncrementLine]);
698             CGFloat knobSpace = NSWidth([self rectForPart: NSScrollerKnob]);
699
700             if ((arrowSpace + knobSpace) > NSWidth([self bounds])) {
701
702                 if (arrowSpace > NSWidth([self bounds])) {
703                     return NSNoScrollerParts;
704                 } else {
705                     return NSOnlyScrollerArrows;
706                 }
707             }
708
709         } else {
710
711             // Now Figure out if we can actually show all parts
712             CGFloat arrowSpace = NSHeight([self rectForPart: NSScrollerIncrementLine]) + NSHeight([self rectForPart: NSScrollerDecrementLine]) +
713                 NSMidX([self rectForPart: NSScrollerIncrementLine]);
714             CGFloat knobSpace = NSHeight([self rectForPart: NSScrollerKnob]);
715
716             if ((arrowSpace + knobSpace) > NSHeight([self bounds])) {
717
718                 if (arrowSpace > NSHeight([self bounds])) {
719                     return NSNoScrollerParts;
720                 } else {
721                     return NSOnlyScrollerArrows;
722                 }
723             }
724         }
725     }
726
727     return NSAllScrollerParts;
728 }
729
730 - (bool)isHoriz {
731     if ([self bounds].size.width > [self bounds].size.height) {
732         return YES;
733     }
734     return NO;
735 }
736
737 @end