]> git.sesse.net Git - vlc/blob - modules/gui/macosx/misc.m
macosx: move re-useable code from VLCControls to a custom class
[vlc] / modules / gui / macosx / misc.m
1 /*****************************************************************************
2  * misc.m: code not specific to vlc
3  *****************************************************************************
4  * Copyright (C) 2003-2011 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
8  *          Felix Paul Kühne <fkuehne at videolan dot org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 #import <Cocoa/Cocoa.h>
26 #import <Carbon/Carbon.h>
27
28 #import "intf.h"                                          /* VLCApplication */
29 #import "misc.h"
30 #import "playlist.h"
31 #import "controls.h"
32 #import <vlc_url.h>
33
34 /*****************************************************************************
35  * NSImage (VLCAdditions)
36  *
37  *  Addition to NSImage
38  *****************************************************************************/
39 @implementation NSImage (VLCAdditions)
40 + (id)imageWithSystemName:(int)name
41 {
42     /* ugly Carbon stuff following...
43      * regrettably, you can't get the icons through clean Cocoa */
44
45     /* retrieve our error icon */
46     NSImage * icon;
47     IconRef ourIconRef;
48     int returnValue;
49     returnValue = GetIconRef(kOnSystemDisk, 'macs', name, &ourIconRef);
50     icon = [[[NSImage alloc] initWithSize:NSMakeSize(32,32)] autorelease];
51     [icon lockFocus];
52     CGRect rect = CGRectMake(0,0,32,32);
53     PlotIconRefInContext((CGContextRef)[[NSGraphicsContext currentContext]
54         graphicsPort],
55         &rect,
56         kAlignNone,
57         kTransformNone,
58         NULL /*inLabelColor*/,
59         kPlotIconRefNormalFlags,
60         (IconRef)ourIconRef);
61     [icon unlockFocus];
62     returnValue = ReleaseIconRef(ourIconRef);
63     return icon;
64 }
65
66 + (id)imageWithWarningIcon
67 {
68     static NSImage * imageWithWarningIcon = nil;
69     if( !imageWithWarningIcon )
70     {
71         imageWithWarningIcon = [[[self class] imageWithSystemName:'caut'] retain];
72     }
73     return imageWithWarningIcon;
74 }
75
76 + (id)imageWithErrorIcon
77 {
78     static NSImage * imageWithErrorIcon = nil;
79     if( !imageWithErrorIcon )
80     {
81         imageWithErrorIcon = [[[self class] imageWithSystemName:'stop'] retain];
82     }
83     return imageWithErrorIcon;
84 }
85
86 @end
87 /*****************************************************************************
88  * NSAnimation (VLCAdditions)
89  *
90  *  Missing extension to NSAnimation
91  *****************************************************************************/
92
93 @implementation NSAnimation (VLCAdditions)
94 /* fake class attributes  */
95 static NSMapTable *VLCAdditions_userInfo = NULL;
96
97 + (void)load
98 {
99     /* init our fake object attribute */
100     VLCAdditions_userInfo = NSCreateMapTable(NSNonRetainedObjectMapKeyCallBacks, NSObjectMapValueCallBacks, 16);
101 }
102
103 - (void)dealloc
104 {
105     NSMapRemove(VLCAdditions_userInfo, self);
106     [super dealloc];
107 }
108
109 - (void)setUserInfo: (void *)userInfo
110 {
111     NSMapInsert(VLCAdditions_userInfo, self, (void*)userInfo);
112 }
113
114 - (void *)userInfo
115 {
116     return NSMapGet(VLCAdditions_userInfo, self);
117 }
118 @end
119
120 /*****************************************************************************
121  * NSScreen (VLCAdditions)
122  *
123  *  Missing extension to NSScreen
124  *****************************************************************************/
125
126 @implementation NSScreen (VLCAdditions)
127
128 static NSMutableArray *blackoutWindows = NULL;
129
130 + (void)load
131 {
132     /* init our fake object attribute */
133     blackoutWindows = [[NSMutableArray alloc] initWithCapacity:1];
134 }
135
136 + (NSScreen *)screenWithDisplayID: (CGDirectDisplayID)displayID
137 {
138     int i;
139
140     for( i = 0; i < [[NSScreen screens] count]; i++ )
141     {
142         NSScreen *screen = [[NSScreen screens] objectAtIndex: i];
143         if([screen displayID] == displayID)
144             return screen;
145     }
146     return nil;
147 }
148
149 - (BOOL)isMainScreen
150 {
151     return ([self displayID] == [[[NSScreen screens] objectAtIndex:0] displayID]);
152 }
153
154 - (BOOL)isScreen: (NSScreen*)screen
155 {
156     return ([self displayID] == [screen displayID]);
157 }
158
159 - (CGDirectDisplayID)displayID
160 {
161         return (CGDirectDisplayID)[[[self deviceDescription] objectForKey: @"NSScreenNumber"] intValue];
162 }
163
164 - (void)blackoutOtherScreens
165 {
166     unsigned int i;
167
168     /* Free our previous blackout window (follow blackoutWindow alloc strategy) */
169     [blackoutWindows makeObjectsPerformSelector:@selector(close)];
170     [blackoutWindows removeAllObjects];
171
172     for(i = 0; i < [[NSScreen screens] count]; i++)
173     {
174         NSScreen *screen = [[NSScreen screens] objectAtIndex: i];
175         VLCWindow *blackoutWindow;
176         NSRect screen_rect;
177
178         if([self isScreen: screen])
179             continue;
180
181         screen_rect = [screen frame];
182         screen_rect.origin.x = screen_rect.origin.y = 0;
183
184         /* blackoutWindow alloc strategy
185             - The NSMutableArray blackoutWindows has the blackoutWindow references
186             - blackoutOtherDisplays is responsible for alloc/releasing its Windows
187         */
188         blackoutWindow = [[VLCWindow alloc] initWithContentRect: screen_rect styleMask: NSBorderlessWindowMask
189                 backing: NSBackingStoreBuffered defer: NO screen: screen];
190         [blackoutWindow setBackgroundColor:[NSColor blackColor]];
191         [blackoutWindow setLevel: NSFloatingWindowLevel]; /* Disappear when Expose is triggered */
192
193         [blackoutWindow displayIfNeeded];
194         [blackoutWindow orderFront: self animate: YES];
195
196         [blackoutWindows addObject: blackoutWindow];
197         [blackoutWindow release];
198
199         if( [screen isMainScreen ] )
200            SetSystemUIMode( kUIModeAllHidden, kUIOptionAutoShowMenuBar);
201     }
202 }
203
204 + (void)unblackoutScreens
205 {
206     unsigned int i;
207
208     for(i = 0; i < [blackoutWindows count]; i++)
209     {
210         VLCWindow *blackoutWindow = [blackoutWindows objectAtIndex: i];
211         [blackoutWindow closeAndAnimate: YES];
212     }
213
214    SetSystemUIMode( kUIModeNormal, 0);
215 }
216
217 @end
218
219 /*****************************************************************************
220  * VLCWindow
221  *
222  *  Missing extension to NSWindow
223  *****************************************************************************/
224
225 @implementation VLCWindow
226 - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask
227     backing:(NSBackingStoreType)backingType defer:(BOOL)flag
228 {
229     self = [super initWithContentRect:contentRect styleMask:styleMask backing:backingType defer:flag];
230     if( self )
231     {
232         b_isset_canBecomeKeyWindow = NO;
233         /* we don't want this window to be restored on relaunch */
234         if ([self respondsToSelector:@selector(setRestorable:)])
235             [self setRestorable:NO];
236     }
237     return self;
238 }
239 - (void)setCanBecomeKeyWindow: (BOOL)canBecomeKey
240 {
241     b_isset_canBecomeKeyWindow = YES;
242     b_canBecomeKeyWindow = canBecomeKey;
243 }
244
245 - (BOOL)canBecomeKeyWindow
246 {
247     if(b_isset_canBecomeKeyWindow)
248         return b_canBecomeKeyWindow;
249
250     return [super canBecomeKeyWindow];
251 }
252
253 - (void)closeAndAnimate: (BOOL)animate
254 {
255     NSInvocation *invoc;
256
257     if (!animate)
258     {
259         [super close];
260         return;
261     }
262
263     invoc = [NSInvocation invocationWithMethodSignature:[super methodSignatureForSelector:@selector(close)]];
264     [invoc setTarget: self];
265
266     if (![self isVisible] || [self alphaValue] == 0.0)
267     {
268         [super close];
269         return;
270     }
271
272     [self orderOut: self animate: YES callback: invoc];
273 }
274
275 - (void)orderOut: (id)sender animate: (BOOL)animate
276 {
277     NSInvocation *invoc = [NSInvocation invocationWithMethodSignature:[super methodSignatureForSelector:@selector(orderOut:)]];
278     [invoc setTarget: self];
279     [invoc setArgument: sender atIndex: 0];
280     [self orderOut: sender animate: animate callback: invoc];
281 }
282
283 - (void)orderOut: (id)sender animate: (BOOL)animate callback:(NSInvocation *)callback
284 {
285     NSViewAnimation *anim;
286     NSViewAnimation *current_anim;
287     NSMutableDictionary *dict;
288
289     if (!animate)
290     {
291         [self orderOut: sender];
292         return;
293     }
294
295     dict = [[NSMutableDictionary alloc] initWithCapacity:2];
296
297     [dict setObject:self forKey:NSViewAnimationTargetKey];
298
299     [dict setObject:NSViewAnimationFadeOutEffect forKey:NSViewAnimationEffectKey];
300     anim = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict, nil]];
301     [dict release];
302
303     [anim setAnimationBlockingMode:NSAnimationNonblocking];
304     [anim setDuration:0.9];
305     [anim setFrameRate:30];
306     [anim setUserInfo: callback];
307
308     @synchronized(self) {
309         current_anim = self->animation;
310
311         if ([[[current_anim viewAnimations] objectAtIndex:0] objectForKey: NSViewAnimationEffectKey] == NSViewAnimationFadeOutEffect && [current_anim isAnimating])
312         {
313             [anim release];
314         }
315         else
316         {
317             if (current_anim)
318             {
319                 [current_anim stopAnimation];
320                 [anim setCurrentProgress:1.0-[current_anim currentProgress]];
321                 [current_anim release];
322             }
323             else
324                 [anim setCurrentProgress:1.0 - [self alphaValue]];
325             self->animation = anim;
326             [self setDelegate: self];
327             [anim startAnimation];
328         }
329     }
330 }
331
332 - (void)orderFront: (id)sender animate: (BOOL)animate
333 {
334     NSViewAnimation *anim;
335     NSViewAnimation *current_anim;
336     NSMutableDictionary *dict;
337
338     if (!animate)
339     {
340         [super orderFront: sender];
341         [self setAlphaValue: 1.0];
342         return;
343     }
344
345     if (![self isVisible])
346     {
347         [self setAlphaValue: 0.0];
348         [super orderFront: sender];
349     }
350     else if ([self alphaValue] == 1.0)
351     {
352         [super orderFront: self];
353         return;
354     }
355
356     dict = [[NSMutableDictionary alloc] initWithCapacity:2];
357
358     [dict setObject:self forKey:NSViewAnimationTargetKey];
359
360     [dict setObject:NSViewAnimationFadeInEffect forKey:NSViewAnimationEffectKey];
361     anim = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict, nil]];
362     [dict release];
363
364     [anim setAnimationBlockingMode:NSAnimationNonblocking];
365     [anim setDuration:0.5];
366     [anim setFrameRate:30];
367
368     @synchronized(self) {
369         current_anim = self->animation;
370
371         if ([[[current_anim viewAnimations] objectAtIndex:0] objectForKey: NSViewAnimationEffectKey] == NSViewAnimationFadeInEffect && [current_anim isAnimating])
372         {
373             [anim release];
374         }
375         else
376         {
377             if (current_anim)
378             {
379                 [current_anim stopAnimation];
380                 [anim setCurrentProgress:1.0 - [current_anim currentProgress]];
381                 [current_anim release];
382             }
383             else
384                 [anim setCurrentProgress:[self alphaValue]];
385             self->animation = anim;
386             [self setDelegate: self];
387             [self orderFront: sender];
388             [anim startAnimation];
389         }
390     }
391 }
392
393 - (void)animationDidEnd:(NSAnimation*)anim
394 {
395     if ([self alphaValue] <= 0.0)
396     {
397         NSInvocation * invoc;
398         [super orderOut: nil];
399         [self setAlphaValue: 1.0];
400         if ((invoc = [anim userInfo]))
401             [invoc invoke];
402     }
403 }
404 @end
405
406 /*****************************************************************************
407  * VLCControllerWindow
408  *****************************************************************************/
409
410 @implementation VLCControllerWindow
411
412 - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask
413     backing:(NSBackingStoreType)backingType defer:(BOOL)flag
414 {
415     /* FIXME: this should enable the SnowLeopard window style, however, it leads to ugly artifacts
416      *        needs some further investigation! -- feepk
417      BOOL b_useTextured = YES;
418
419     if( [[NSWindow class] instancesRespondToSelector:@selector(setContentBorderThickness:forEdge:)] )
420     {
421         b_useTextured = NO;
422         styleMask ^= NSTexturedBackgroundWindowMask;
423     } */
424
425     self = [super initWithContentRect:contentRect styleMask:styleMask //& ~NSTitledWindowMask
426     backing:backingType defer:flag];
427
428     [[VLCMain sharedInstance] updateTogglePlaylistState];
429
430     /* FIXME: see above...
431     if(! b_useTextured )
432     {
433         [self setContentBorderThickness:28.0 forEdge:NSMinYEdge];
434     }
435     */
436
437     /* we want to be moveable regardless of our style */
438     [self setMovableByWindowBackground: YES];
439
440     /* we don't want this window to be restored on relaunch */
441     if ([self respondsToSelector:@selector(setRestorable:)])
442         [self setRestorable:NO];
443
444     return self;
445 }
446
447 - (BOOL)performKeyEquivalent:(NSEvent *)o_event
448 {
449     /* We indeed want to prioritize Cocoa key equivalent against libvlc,
450        so we perform the menu equivalent now. */
451     if([[NSApp mainMenu] performKeyEquivalent:o_event])
452         return TRUE;
453
454     return [[VLCMain sharedInstance] hasDefinedShortcutKey:o_event] ||
455            [(VLCControls *)[[VLCMain sharedInstance] controls] keyEvent:o_event];
456 }
457
458 @end
459
460
461
462 /*****************************************************************************
463  * VLCControllerView
464  *****************************************************************************/
465
466 @implementation VLCControllerView
467
468 - (void)dealloc
469 {
470     [self unregisterDraggedTypes];
471     [super dealloc];
472 }
473
474 - (void)awakeFromNib
475 {
476     [self registerForDraggedTypes:[NSArray arrayWithObjects:NSTIFFPboardType,
477         NSFilenamesPboardType, nil]];
478 }
479
480 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
481 {
482     if ((NSDragOperationGeneric & [sender draggingSourceOperationMask])
483                 == NSDragOperationGeneric)
484     {
485         return NSDragOperationGeneric;
486     }
487     else
488     {
489         return NSDragOperationNone;
490     }
491 }
492
493 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
494 {
495     return YES;
496 }
497
498 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
499 {
500     NSPasteboard *o_paste = [sender draggingPasteboard];
501     NSArray *o_types = [NSArray arrayWithObjects: NSFilenamesPboardType, nil];
502     NSString *o_desired_type = [o_paste availableTypeFromArray:o_types];
503     NSData *o_carried_data = [o_paste dataForType:o_desired_type];
504
505     if( o_carried_data )
506     {
507         if ([o_desired_type isEqualToString:NSFilenamesPboardType])
508         {
509             int i;
510             NSArray *o_array = [NSArray array];
511             NSArray *o_values = [[o_paste propertyListForType: NSFilenamesPboardType]
512                         sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
513
514             for( i = 0; i < (int)[o_values count]; i++)
515             {
516                 NSDictionary *o_dic;
517                 char *psz_uri = make_URI([[o_values objectAtIndex:i] UTF8String], NULL);
518                 if( !psz_uri )
519                     continue;
520
521                 o_dic = [NSDictionary dictionaryWithObject:[NSString stringWithCString:psz_uri encoding:NSUTF8StringEncoding] forKey:@"ITEM_URL"];
522
523                 free( psz_uri );
524                 o_array = [o_array arrayByAddingObject: o_dic];
525             }
526             [(VLCPlaylist *)[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:NO];
527             return YES;
528         }
529     }
530     [self setNeedsDisplay:YES];
531     return YES;
532 }
533
534 - (void)concludeDragOperation:(id <NSDraggingInfo>)sender
535 {
536     [self setNeedsDisplay:YES];
537 }
538
539 @end
540
541 /*****************************************************************************
542  * VLBrushedMetalImageView
543  *****************************************************************************/
544
545 @implementation VLBrushedMetalImageView
546
547 - (BOOL)mouseDownCanMoveWindow
548 {
549     return YES;
550 }
551
552 - (void)dealloc
553 {
554     [self unregisterDraggedTypes];
555     [super dealloc];
556 }
557
558 - (void)awakeFromNib
559 {
560     [self registerForDraggedTypes:[NSArray arrayWithObjects:NSTIFFPboardType,
561         NSFilenamesPboardType, nil]];
562 }
563
564 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
565 {
566     if ((NSDragOperationGeneric & [sender draggingSourceOperationMask])
567                 == NSDragOperationGeneric)
568     {
569         return NSDragOperationGeneric;
570     }
571     else
572     {
573         return NSDragOperationNone;
574     }
575 }
576
577 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
578 {
579     return YES;
580 }
581
582 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
583 {
584     NSPasteboard *o_paste = [sender draggingPasteboard];
585     NSArray *o_types = [NSArray arrayWithObjects: NSFilenamesPboardType, nil];
586     NSString *o_desired_type = [o_paste availableTypeFromArray:o_types];
587     NSData *o_carried_data = [o_paste dataForType:o_desired_type];
588     BOOL b_autoplay = config_GetInt( VLCIntf, "macosx-autoplay" );
589
590     if( o_carried_data )
591     {
592         if ([o_desired_type isEqualToString:NSFilenamesPboardType])
593         {
594             int i;
595             NSArray *o_array = [NSArray array];
596             NSArray *o_values = [[o_paste propertyListForType: NSFilenamesPboardType]
597                         sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
598
599             for( i = 0; i < (int)[o_values count]; i++)
600             {
601                 NSDictionary *o_dic;
602                 char *psz_uri = make_URI([[o_values objectAtIndex:i] UTF8String], NULL);
603                 if( !psz_uri )
604                     continue;
605
606                 o_dic = [NSDictionary dictionaryWithObject:[NSString stringWithCString:psz_uri encoding:NSUTF8StringEncoding] forKey:@"ITEM_URL"];
607                 free( psz_uri );
608
609                 o_array = [o_array arrayByAddingObject: o_dic];
610             }
611             if( b_autoplay )
612                 [[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:NO];
613             else
614                 [[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:YES];
615             return YES;
616         }
617     }
618     [self setNeedsDisplay:YES];
619     return YES;
620 }
621
622 - (void)concludeDragOperation:(id <NSDraggingInfo>)sender
623 {
624     [self setNeedsDisplay:YES];
625 }
626
627 @end
628
629
630 /*****************************************************************************
631  * MPSlider
632  *****************************************************************************/
633 @implementation MPSlider
634
635 void _drawKnobInRect(NSRect knobRect)
636 {
637     // Center knob in given rect
638     knobRect.origin.x += (int)((float)(knobRect.size.width - 7)/2.0);
639     knobRect.origin.y += (int)((float)(knobRect.size.height - 7)/2.0);
640
641     // Draw diamond
642     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 3, knobRect.origin.y + 6, 1, 1), NSCompositeSourceOver);
643     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 2, knobRect.origin.y + 5, 3, 1), NSCompositeSourceOver);
644     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 1, knobRect.origin.y + 4, 5, 1), NSCompositeSourceOver);
645     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 0, knobRect.origin.y + 3, 7, 1), NSCompositeSourceOver);
646     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 1, knobRect.origin.y + 2, 5, 1), NSCompositeSourceOver);
647     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 2, knobRect.origin.y + 1, 3, 1), NSCompositeSourceOver);
648     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 3, knobRect.origin.y + 0, 1, 1), NSCompositeSourceOver);
649 }
650
651 void _drawFrameInRect(NSRect frameRect)
652 {
653     // Draw frame
654     NSRectFillUsingOperation(NSMakeRect(frameRect.origin.x, frameRect.origin.y, frameRect.size.width, 1), NSCompositeSourceOver);
655     NSRectFillUsingOperation(NSMakeRect(frameRect.origin.x, frameRect.origin.y + frameRect.size.height-1, frameRect.size.width, 1), NSCompositeSourceOver);
656     NSRectFillUsingOperation(NSMakeRect(frameRect.origin.x, frameRect.origin.y, 1, frameRect.size.height), NSCompositeSourceOver);
657     NSRectFillUsingOperation(NSMakeRect(frameRect.origin.x+frameRect.size.width-1, frameRect.origin.y, 1, frameRect.size.height), NSCompositeSourceOver);
658 }
659
660 - (void)drawRect:(NSRect)rect
661 {
662     // Draw default to make sure the slider behaves correctly
663     [[NSGraphicsContext currentContext] saveGraphicsState];
664     NSRectClip(NSZeroRect);
665     [super drawRect:rect];
666     [[NSGraphicsContext currentContext] restoreGraphicsState];
667
668     // Full size
669     rect = [self bounds];
670     int diff = (int)(([[self cell] knobThickness] - 7.0)/2.0) - 1;
671     rect.origin.x += diff-1;
672     rect.origin.y += diff;
673     rect.size.width -= 2*diff-2;
674     rect.size.height -= 2*diff;
675
676     // Draw dark
677     NSRect knobRect = [[self cell] knobRectFlipped:NO];
678     [[[NSColor blackColor] colorWithAlphaComponent:0.6] set];
679     _drawFrameInRect(rect);
680     _drawKnobInRect(knobRect);
681
682     // Draw shadow
683     [[[NSColor blackColor] colorWithAlphaComponent:0.1] set];
684     rect.origin.x++;
685     rect.origin.y++;
686     knobRect.origin.x++;
687     knobRect.origin.y++;
688     _drawFrameInRect(rect);
689     _drawKnobInRect(knobRect);
690 }
691
692 @end
693
694 /*****************************************************************************
695  * TimeLineSlider
696  *****************************************************************************/
697
698 @implementation TimeLineSlider
699
700 - (void)drawKnobInRect:(NSRect)knobRect
701 {
702     NSRect image_rect;
703     NSImage *img = [NSImage imageNamed:@"progression-knob"];
704     image_rect.size = [img size];
705     image_rect.origin.x = 0;
706     image_rect.origin.y = 0;
707     knobRect.origin.x += (knobRect.size.width - image_rect.size.width) / 2;
708     knobRect.size.width = image_rect.size.width;
709     knobRect.size.height = image_rect.size.height;
710     [img drawInRect:knobRect fromRect:image_rect operation:NSCompositeSourceOver fraction:1];
711 }
712
713 - (void)drawRect:(NSRect)rect
714 {
715     /* Draw default to make sure the slider behaves correctly */
716     [[NSGraphicsContext currentContext] saveGraphicsState];
717     NSRectClip(NSZeroRect);
718     [super drawRect:rect];
719     [[NSGraphicsContext currentContext] restoreGraphicsState];
720
721     NSRect knobRect = [[self cell] knobRectFlipped:NO];
722     knobRect.origin.y+=1;
723     [self drawKnobInRect: knobRect];
724 }
725
726 @end
727
728 /*****************************************************************************
729  * ITSlider
730  *****************************************************************************/
731
732 @implementation ITSlider
733
734 - (void)drawKnobInRect:(NSRect)knobRect
735 {
736     NSRect image_rect;
737     NSImage *img = [NSImage imageNamed:@"volume-slider-knob"];
738     image_rect.size = [img size];
739     image_rect.origin.x = 0;
740     image_rect.origin.y = 0;
741     knobRect.origin.x += (knobRect.size.width - image_rect.size.width) / 2;
742     knobRect.size.width = image_rect.size.width;
743     knobRect.size.height = image_rect.size.height;
744     [img drawInRect:knobRect fromRect:image_rect operation:NSCompositeSourceOver fraction:1];
745 }
746
747 - (void)drawRect:(NSRect)rect
748 {
749     /* Draw default to make sure the slider behaves correctly */
750     [[NSGraphicsContext currentContext] saveGraphicsState];
751     NSRectClip(NSZeroRect);
752     [super drawRect:rect];
753     [[NSGraphicsContext currentContext] restoreGraphicsState];
754
755     NSRect knobRect = [[self cell] knobRectFlipped:NO];
756     knobRect.origin.y+=2;
757     [self drawKnobInRect: knobRect];
758 }
759
760 @end
761
762 /*****************************************************************************
763  * VLCTimeField implementation
764  *****************************************************************************
765  * we need this to catch our click-event in the controller window
766  *****************************************************************************/
767
768 @implementation VLCTimeField
769 - (void)mouseDown: (NSEvent *)ourEvent
770 {
771     if( [ourEvent clickCount] > 1 )
772         [[[VLCMain sharedInstance] controls] goToSpecificTime: nil];
773     else
774         [[VLCMain sharedInstance] timeFieldWasClicked: self];
775 }
776 @end