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