]> git.sesse.net Git - vlc/blob - modules/gui/macosx/misc.m
macosx: added options to modify the subtitle outline to the simple preferences
[vlc] / modules / gui / macosx / misc.m
1 /*****************************************************************************
2  * misc.m: code not specific to vlc
3  *****************************************************************************
4  * Copyright (C) 2003-2011 VLC authors and VideoLAN
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 "CompatibilityFixes.h"
29 #import "intf.h"                                          /* VLCApplication */
30 #import "MainWindow.h"
31 #import "misc.h"
32 #import "playlist.h"
33 #import "controls.h"
34 #import "CoreInteraction.h"
35 #import <vlc_url.h>
36
37 /*****************************************************************************
38  * NSAnimation (VLCAdditions)
39  *
40  *  Missing extension to NSAnimation
41  *****************************************************************************/
42
43 @implementation NSAnimation (VLCAdditions)
44 /* fake class attributes  */
45 static NSMapTable *VLCAdditions_userInfo = NULL;
46
47 + (void)load
48 {
49     /* init our fake object attribute */
50     VLCAdditions_userInfo = NSCreateMapTable(NSNonRetainedObjectMapKeyCallBacks, NSObjectMapValueCallBacks, 16);
51 }
52
53 - (void)dealloc
54 {
55     NSMapRemove(VLCAdditions_userInfo, self);
56     [super dealloc];
57 }
58
59 - (void)setUserInfo: (void *)userInfo
60 {
61     NSMapInsert(VLCAdditions_userInfo, self, (void*)userInfo);
62 }
63
64 - (void *)userInfo
65 {
66     return NSMapGet(VLCAdditions_userInfo, self);
67 }
68 @end
69
70 /*****************************************************************************
71  * NSScreen (VLCAdditions)
72  *
73  *  Missing extension to NSScreen
74  *****************************************************************************/
75
76 @implementation NSScreen (VLCAdditions)
77
78 static NSMutableArray *blackoutWindows = NULL;
79
80 + (void)load
81 {
82     /* init our fake object attribute */
83     blackoutWindows = [[NSMutableArray alloc] initWithCapacity:1];
84 }
85
86 + (NSScreen *)screenWithDisplayID: (CGDirectDisplayID)displayID
87 {
88     NSUInteger count = [[NSScreen screens] count];
89
90     for( NSUInteger i = 0; i < count; i++ )
91     {
92         NSScreen *screen = [[NSScreen screens] objectAtIndex: i];
93         if([screen displayID] == displayID)
94             return screen;
95     }
96     return nil;
97 }
98
99 - (BOOL)isMainScreen
100 {
101     return ([self displayID] == [[[NSScreen screens] objectAtIndex:0] displayID]);
102 }
103
104 - (BOOL)isScreen: (NSScreen*)screen
105 {
106     return ([self displayID] == [screen displayID]);
107 }
108
109 - (CGDirectDisplayID)displayID
110 {
111     return (CGDirectDisplayID)[[[self deviceDescription] objectForKey: @"NSScreenNumber"] intValue];
112 }
113
114 - (void)blackoutOtherScreens
115 {
116     /* Free our previous blackout window (follow blackoutWindow alloc strategy) */
117     [blackoutWindows makeObjectsPerformSelector:@selector(close)];
118     [blackoutWindows removeAllObjects];
119
120     NSUInteger screenCount = [[NSScreen screens] count];
121     for(NSUInteger i = 0; i < screenCount; i++)
122     {
123         NSScreen *screen = [[NSScreen screens] objectAtIndex: i];
124         VLCWindow *blackoutWindow;
125         NSRect screen_rect;
126
127         if([self isScreen: screen])
128             continue;
129
130         screen_rect = [screen frame];
131         screen_rect.origin.x = screen_rect.origin.y = 0;
132
133         /* blackoutWindow alloc strategy
134             - The NSMutableArray blackoutWindows has the blackoutWindow references
135             - blackoutOtherDisplays is responsible for alloc/releasing its Windows
136         */
137         blackoutWindow = [[VLCWindow alloc] initWithContentRect: screen_rect styleMask: NSBorderlessWindowMask
138                 backing: NSBackingStoreBuffered defer: NO screen: screen];
139         [blackoutWindow setBackgroundColor:[NSColor blackColor]];
140         [blackoutWindow setLevel: NSFloatingWindowLevel]; /* Disappear when Expose is triggered */
141
142         [blackoutWindow displayIfNeeded];
143         [blackoutWindow orderFront: self animate: YES];
144
145         [blackoutWindows addObject: blackoutWindow];
146         [blackoutWindow release];
147
148         if( [screen isMainScreen] )
149         {
150             if (OSX_LEOPARD)
151                 SetSystemUIMode( kUIModeAllHidden, kUIOptionAutoShowMenuBar);
152             else
153                 [NSApp setPresentationOptions:(NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar)];
154         }
155     }
156 }
157
158 + (void)unblackoutScreens
159 {
160     NSUInteger blackoutWindowCount = [blackoutWindows count];
161
162     for(NSUInteger i = 0; i < blackoutWindowCount; i++)
163     {
164         VLCWindow *blackoutWindow = [blackoutWindows objectAtIndex: i];
165         [blackoutWindow closeAndAnimate: YES];
166     }
167
168     if (OSX_LEOPARD)
169         SetSystemUIMode( kUIModeNormal, kUIOptionAutoShowMenuBar);
170     else
171         [NSApp setPresentationOptions:(NSApplicationPresentationDefault)];
172 }
173
174 @end
175
176 /*****************************************************************************
177  * VLCWindow
178  *
179  *  Missing extension to NSWindow
180  *****************************************************************************/
181
182 @implementation VLCWindow
183 - (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)styleMask
184     backing:(NSBackingStoreType)backingType defer:(BOOL)flag
185 {
186     self = [super initWithContentRect:contentRect styleMask:styleMask backing:backingType defer:flag];
187     if( self )
188     {
189         b_isFullscreen = NO;
190         b_isset_canBecomeKeyWindow = NO;
191         /* we don't want this window to be restored on relaunch */
192         if (OSX_LION)
193             [self setRestorable:NO];
194     }
195     return self;
196 }
197 - (void)setCanBecomeKeyWindow: (BOOL)canBecomeKey
198 {
199     b_isset_canBecomeKeyWindow = YES;
200     b_canBecomeKeyWindow = canBecomeKey;
201 }
202
203 - (BOOL)canBecomeKeyWindow
204 {
205     if(b_isset_canBecomeKeyWindow)
206         return b_canBecomeKeyWindow;
207
208     return [super canBecomeKeyWindow];
209 }
210
211 - (void)closeAndAnimate: (BOOL)animate
212 {
213     NSInvocation *invoc;
214
215     if (!animate)
216     {
217         [super close];
218         return;
219     }
220
221     invoc = [NSInvocation invocationWithMethodSignature:[super methodSignatureForSelector:@selector(close)]];
222     [invoc setTarget: self];
223
224     if (![self isVisible] || [self alphaValue] == 0.0)
225     {
226         [super close];
227         return;
228     }
229
230     [self orderOut: self animate: YES callback: invoc];
231 }
232
233 - (void)orderOut: (id)sender animate: (BOOL)animate
234 {
235     NSInvocation *invoc = [NSInvocation invocationWithMethodSignature:[super methodSignatureForSelector:@selector(orderOut:)]];
236     [invoc setTarget: self];
237     [invoc setArgument: sender atIndex: 0];
238     [self orderOut: sender animate: animate callback: invoc];
239 }
240
241 - (void)orderOut: (id)sender animate: (BOOL)animate callback:(NSInvocation *)callback
242 {
243     NSViewAnimation *anim;
244     NSViewAnimation *current_anim;
245     NSMutableDictionary *dict;
246
247     if (!animate)
248     {
249         [self orderOut: sender];
250         return;
251     }
252
253     dict = [[NSMutableDictionary alloc] initWithCapacity:2];
254
255     [dict setObject:self forKey:NSViewAnimationTargetKey];
256
257     [dict setObject:NSViewAnimationFadeOutEffect forKey:NSViewAnimationEffectKey];
258     anim = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict, nil]];
259     [dict release];
260
261     [anim setAnimationBlockingMode:NSAnimationNonblocking];
262     [anim setDuration:0.9];
263     [anim setFrameRate:30];
264     [anim setUserInfo: callback];
265
266     @synchronized(self) {
267         current_anim = self->animation;
268
269         if ([[[current_anim viewAnimations] objectAtIndex:0] objectForKey: NSViewAnimationEffectKey] == NSViewAnimationFadeOutEffect && [current_anim isAnimating])
270         {
271             [anim release];
272         }
273         else
274         {
275             if (current_anim)
276             {
277                 [current_anim stopAnimation];
278                 [anim setCurrentProgress:1.0-[current_anim currentProgress]];
279                 [current_anim release];
280             }
281             else
282                 [anim setCurrentProgress:1.0 - [self alphaValue]];
283             self->animation = anim;
284             [self setDelegate: self];
285             [anim startAnimation];
286         }
287     }
288 }
289
290 - (void)orderFront: (id)sender animate: (BOOL)animate
291 {
292     NSViewAnimation *anim;
293     NSViewAnimation *current_anim;
294     NSMutableDictionary *dict;
295
296     if (!animate)
297     {
298         [super orderFront: sender];
299         [self setAlphaValue: 1.0];
300         return;
301     }
302
303     if (![self isVisible])
304     {
305         [self setAlphaValue: 0.0];
306         [super orderFront: sender];
307     }
308     else if ([self alphaValue] == 1.0)
309     {
310         [super orderFront: self];
311         return;
312     }
313
314     dict = [[NSMutableDictionary alloc] initWithCapacity:2];
315
316     [dict setObject:self forKey:NSViewAnimationTargetKey];
317
318     [dict setObject:NSViewAnimationFadeInEffect forKey:NSViewAnimationEffectKey];
319     anim = [[NSViewAnimation alloc] initWithViewAnimations:[NSArray arrayWithObjects:dict, nil]];
320     [dict release];
321
322     [anim setAnimationBlockingMode:NSAnimationNonblocking];
323     [anim setDuration:0.5];
324     [anim setFrameRate:30];
325
326     @synchronized(self) {
327         current_anim = self->animation;
328
329         if ([[[current_anim viewAnimations] objectAtIndex:0] objectForKey: NSViewAnimationEffectKey] == NSViewAnimationFadeInEffect && [current_anim isAnimating])
330         {
331             [anim release];
332         }
333         else
334         {
335             if (current_anim)
336             {
337                 [current_anim stopAnimation];
338                 [anim setCurrentProgress:1.0 - [current_anim currentProgress]];
339                 [current_anim release];
340             }
341             else
342                 [anim setCurrentProgress:[self alphaValue]];
343             self->animation = anim;
344             [self setDelegate: self];
345             [self orderFront: sender];
346             [anim startAnimation];
347         }
348     }
349 }
350
351 - (void)animationDidEnd:(NSAnimation*)anim
352 {
353     if ([self alphaValue] <= 0.0)
354     {
355         NSInvocation * invoc;
356         [super orderOut: nil];
357         [self setAlphaValue: 1.0];
358         if ((invoc = [anim userInfo]))
359             [invoc invoke];
360     }
361 }
362
363 - (void)setFullscreen:(BOOL)b_var
364 {
365     b_isFullscreen = b_var;
366 }
367
368 - (BOOL)isFullscreen
369 {
370     return b_isFullscreen;
371 }
372
373 - (IBAction)fullscreen:(id)sender
374 {
375     [[VLCCoreInteraction sharedInstance] toggleFullscreen];
376 }
377
378 @end
379
380 /*****************************************************************************
381  * VLCControllerView
382  *****************************************************************************/
383
384 @implementation VLCControllerView
385
386 - (void)dealloc
387 {
388     [self unregisterDraggedTypes];
389     [super dealloc];
390 }
391
392 - (void)awakeFromNib
393 {
394     [self registerForDraggedTypes:[NSArray arrayWithObjects:NSTIFFPboardType,
395         NSFilenamesPboardType, nil]];
396 }
397
398 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
399 {
400     if ((NSDragOperationGeneric & [sender draggingSourceOperationMask])
401                 == NSDragOperationGeneric)
402     {
403         return NSDragOperationGeneric;
404     }
405     else
406     {
407         return NSDragOperationNone;
408     }
409 }
410
411 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
412 {
413     return YES;
414 }
415
416 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
417 {
418     NSPasteboard *o_paste = [sender draggingPasteboard];
419     NSArray *o_types = [NSArray arrayWithObjects: NSFilenamesPboardType, nil];
420     NSString *o_desired_type = [o_paste availableTypeFromArray:o_types];
421     NSData *o_carried_data = [o_paste dataForType:o_desired_type];
422
423     if( o_carried_data )
424     {
425         if ([o_desired_type isEqualToString:NSFilenamesPboardType])
426         {
427             NSArray *o_array = [NSArray array];
428             NSArray *o_values = [[o_paste propertyListForType: NSFilenamesPboardType] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
429             NSUInteger count = [o_values count];
430
431             input_thread_t * p_input = pl_CurrentInput( VLCIntf );
432             BOOL b_returned = NO;
433
434             if (count == 1 && p_input)
435             {
436                 b_returned = input_AddSubtitle( p_input, make_URI([[o_values objectAtIndex:0] UTF8String], NULL), true );
437                 vlc_object_release( p_input );
438                 if(!b_returned)
439                     return YES;
440             }
441             else if( p_input )
442                 vlc_object_release( p_input );
443
444             for( NSUInteger i = 0; i < count; i++)
445             {
446                 NSDictionary *o_dic;
447                 char *psz_uri = make_URI([[o_values objectAtIndex:i] UTF8String], NULL);
448                 if( !psz_uri )
449                     continue;
450
451                 o_dic = [NSDictionary dictionaryWithObject:[NSString stringWithCString:psz_uri encoding:NSUTF8StringEncoding] forKey:@"ITEM_URL"];
452
453                 free( psz_uri );
454                 o_array = [o_array arrayByAddingObject: o_dic];
455             }
456             [(VLCPlaylist *)[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:NO];
457             return YES;
458         }
459     }
460     [self setNeedsDisplay:YES];
461     return YES;
462 }
463
464 - (void)concludeDragOperation:(id <NSDraggingInfo>)sender
465 {
466     [self setNeedsDisplay:YES];
467 }
468
469 @end
470
471 /*****************************************************************************
472  * VLBrushedMetalImageView
473  *****************************************************************************/
474
475 @implementation VLBrushedMetalImageView
476
477 - (BOOL)mouseDownCanMoveWindow
478 {
479     return YES;
480 }
481
482 - (void)dealloc
483 {
484     [self unregisterDraggedTypes];
485     [super dealloc];
486 }
487
488 - (void)awakeFromNib
489 {
490     [self registerForDraggedTypes:[NSArray arrayWithObjects:NSTIFFPboardType,
491         NSFilenamesPboardType, nil]];
492     [self setImageScaling: NSScaleToFit];
493     [self setImageFrameStyle: NSImageFrameNone];
494     [self setImageAlignment: NSImageAlignCenter];
495 }
496
497 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
498 {
499     if ((NSDragOperationGeneric & [sender draggingSourceOperationMask])
500                 == NSDragOperationGeneric)
501     {
502         return NSDragOperationGeneric;
503     }
504     else
505     {
506         return NSDragOperationNone;
507     }
508 }
509
510 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
511 {
512     return YES;
513 }
514
515 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
516 {
517     NSPasteboard *o_paste = [sender draggingPasteboard];
518     NSArray *o_types = [NSArray arrayWithObjects: NSFilenamesPboardType, nil];
519     NSString *o_desired_type = [o_paste availableTypeFromArray:o_types];
520     NSData *o_carried_data = [o_paste dataForType:o_desired_type];
521     BOOL b_autoplay = config_GetInt( VLCIntf, "macosx-autoplay" );
522
523     if( o_carried_data )
524     {
525         if ([o_desired_type isEqualToString:NSFilenamesPboardType])
526         {
527             NSArray *o_array = [NSArray array];
528             NSArray *o_values = [[o_paste propertyListForType: NSFilenamesPboardType] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
529             NSUInteger count = [o_values count];
530
531             input_thread_t * p_input = pl_CurrentInput( VLCIntf );
532             BOOL b_returned = NO;
533
534             if (count == 1 && p_input)
535             {
536                 b_returned = input_AddSubtitle( p_input, make_URI([[o_values objectAtIndex:0] UTF8String], NULL), true );
537                 vlc_object_release( p_input );
538                 if(!b_returned)
539                     return YES;
540             }
541             else if( p_input )
542                 vlc_object_release( p_input );
543
544             for( NSUInteger i = 0; i < count; i++)
545             {
546                 NSDictionary *o_dic;
547                 char *psz_uri = make_URI([[o_values objectAtIndex:i] UTF8String], NULL);
548                 if( !psz_uri )
549                     continue;
550
551                 o_dic = [NSDictionary dictionaryWithObject:[NSString stringWithCString:psz_uri encoding:NSUTF8StringEncoding] forKey:@"ITEM_URL"];
552                 free( psz_uri );
553
554                 o_array = [o_array arrayByAddingObject: o_dic];
555             }
556             if( b_autoplay )
557                 [[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:NO];
558             else
559                 [[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:YES];
560             return YES;
561         }
562     }
563     [self setNeedsDisplay:YES];
564     return YES;
565 }
566
567 - (void)concludeDragOperation:(id <NSDraggingInfo>)sender
568 {
569     [self setNeedsDisplay:YES];
570 }
571
572 @end
573
574
575 /*****************************************************************************
576  * MPSlider
577  *****************************************************************************/
578 @implementation MPSlider
579
580 void _drawKnobInRect(NSRect knobRect)
581 {
582     // Center knob in given rect
583     knobRect.origin.x += (int)((float)(knobRect.size.width - 7)/2.0);
584     knobRect.origin.y += (int)((float)(knobRect.size.height - 7)/2.0);
585
586     // Draw diamond
587     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 3, knobRect.origin.y + 6, 1, 1), NSCompositeSourceOver);
588     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 2, knobRect.origin.y + 5, 3, 1), NSCompositeSourceOver);
589     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 1, knobRect.origin.y + 4, 5, 1), NSCompositeSourceOver);
590     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 0, knobRect.origin.y + 3, 7, 1), NSCompositeSourceOver);
591     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 1, knobRect.origin.y + 2, 5, 1), NSCompositeSourceOver);
592     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 2, knobRect.origin.y + 1, 3, 1), NSCompositeSourceOver);
593     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 3, knobRect.origin.y + 0, 1, 1), NSCompositeSourceOver);
594 }
595
596 void _drawFrameInRect(NSRect frameRect)
597 {
598     // Draw frame
599     NSRectFillUsingOperation(NSMakeRect(frameRect.origin.x, frameRect.origin.y, frameRect.size.width, 1), NSCompositeSourceOver);
600     NSRectFillUsingOperation(NSMakeRect(frameRect.origin.x, frameRect.origin.y + frameRect.size.height-1, frameRect.size.width, 1), NSCompositeSourceOver);
601     NSRectFillUsingOperation(NSMakeRect(frameRect.origin.x, frameRect.origin.y, 1, frameRect.size.height), NSCompositeSourceOver);
602     NSRectFillUsingOperation(NSMakeRect(frameRect.origin.x+frameRect.size.width-1, frameRect.origin.y, 1, frameRect.size.height), NSCompositeSourceOver);
603 }
604
605 - (void)drawRect:(NSRect)rect
606 {
607     // Draw default to make sure the slider behaves correctly
608     [[NSGraphicsContext currentContext] saveGraphicsState];
609     NSRectClip(NSZeroRect);
610     [super drawRect:rect];
611     [[NSGraphicsContext currentContext] restoreGraphicsState];
612
613     // Full size
614     rect = [self bounds];
615     int diff = (int)(([[self cell] knobThickness] - 7.0)/2.0) - 1;
616     rect.origin.x += diff-1;
617     rect.origin.y += diff;
618     rect.size.width -= 2*diff-2;
619     rect.size.height -= 2*diff;
620
621     // Draw dark
622     NSRect knobRect = [[self cell] knobRectFlipped:NO];
623     [[[NSColor blackColor] colorWithAlphaComponent:0.6] set];
624     _drawFrameInRect(rect);
625     _drawKnobInRect(knobRect);
626
627     // Draw shadow
628     [[[NSColor blackColor] colorWithAlphaComponent:0.1] set];
629     rect.origin.x++;
630     rect.origin.y++;
631     knobRect.origin.x++;
632     knobRect.origin.y++;
633     _drawFrameInRect(rect);
634     _drawKnobInRect(knobRect);
635 }
636
637 @end
638
639 /*****************************************************************************
640  * TimeLineSlider
641  *****************************************************************************/
642
643 @implementation TimeLineSlider
644
645 - (void)awakeFromNib
646 {
647     if (config_GetInt( VLCIntf, "macosx-interfacestyle" ))
648         o_knob_img = [NSImage imageNamed:@"progression-knob_dark"];
649     else
650         o_knob_img = [NSImage imageNamed:@"progression-knob"];
651     img_rect.size = [o_knob_img size];
652     img_rect.origin.x = img_rect.origin.y = 0;
653 }
654
655 - (void)dealloc
656 {
657     [o_knob_img release];
658     [super dealloc];
659 }
660
661 - (CGFloat)knobPosition
662 {
663     NSRect knobRect = [[self cell] knobRectFlipped:NO];
664     knobRect.origin.x += knobRect.size.width / 2;
665     return knobRect.origin.x;
666 }
667
668 - (void)drawKnobInRect:(NSRect)knobRect
669 {
670     knobRect.origin.x += (knobRect.size.width - img_rect.size.width) / 2;
671     knobRect.size.width = img_rect.size.width;
672     knobRect.size.height = img_rect.size.height;
673     [o_knob_img drawInRect:knobRect fromRect:img_rect operation:NSCompositeSourceOver fraction:1];
674 }
675
676 - (void)drawRect:(NSRect)rect
677 {
678     [[[VLCMain sharedInstance] mainWindow] drawFancyGradientEffectForTimeSlider];
679     msleep( 10000 ); //wait for the gradient to draw completely
680
681     /* Draw default to make sure the slider behaves correctly */
682     [[NSGraphicsContext currentContext] saveGraphicsState];
683     NSRectClip(NSZeroRect);
684     [super drawRect:rect];
685     [[NSGraphicsContext currentContext] restoreGraphicsState];
686
687     NSRect knobRect = [[self cell] knobRectFlipped:NO];
688     knobRect.origin.y+=1;
689     [self drawKnobInRect: knobRect];
690 }
691
692 @end
693
694 /*****************************************************************************
695  * ITSlider
696  *****************************************************************************/
697
698 @implementation ITSlider
699
700 - (void)awakeFromNib
701 {
702     BOOL b_dark = config_GetInt( VLCIntf, "macosx-interfacestyle" );
703     if (b_dark)
704         img = [NSImage imageNamed:@"volume-slider-knob_dark"];
705     else
706         img = [NSImage imageNamed:@"volume-slider-knob"];
707
708     image_rect.size = [img size];
709     image_rect.origin.x = 0;
710
711     if (b_dark)
712         image_rect.origin.y = -1;
713     else
714         image_rect.origin.y = 0;
715 }
716
717 - (void)drawKnobInRect:(NSRect)knobRect
718 {
719     knobRect.origin.x += (knobRect.size.width - image_rect.size.width) / 2;
720     knobRect.size.width = image_rect.size.width;
721     knobRect.size.height = image_rect.size.height;
722     [img drawInRect:knobRect fromRect:image_rect operation:NSCompositeSourceOver fraction:1];
723 }
724
725 - (void)drawRect:(NSRect)rect
726 {
727     /* Draw default to make sure the slider behaves correctly */
728     [[NSGraphicsContext currentContext] saveGraphicsState];
729     NSRectClip(NSZeroRect);
730     [super drawRect:rect];
731     [[NSGraphicsContext currentContext] restoreGraphicsState];
732
733     NSRect knobRect = [[self cell] knobRectFlipped:NO];
734     knobRect.origin.y+=2;
735     [self drawKnobInRect: knobRect];
736 }
737
738 @end
739
740 /*****************************************************************************
741  * VLCTimeField implementation
742  *****************************************************************************
743  * we need this to catch our click-event in the controller window
744  *****************************************************************************/
745
746 @implementation VLCTimeField
747 + (void)initialize{
748     NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
749     NSDictionary *appDefaults = [NSDictionary dictionaryWithObject:@"NO" forKey:@"DisplayTimeAsTimeRemaining"];
750
751     [defaults registerDefaults:appDefaults];
752 }
753
754 - (void)awakeFromNib
755 {
756     NSColor *o_string_color;
757     if (!config_GetInt( VLCIntf, "macosx-interfacestyle"))
758         o_string_color = [NSColor colorWithCalibratedRed:0.229 green:0.229 blue:0.229 alpha:100.0];
759     else
760         o_string_color = [NSColor colorWithCalibratedRed:0.64 green:0.64 blue:0.64 alpha:100.0];
761
762     textAlignment = NSCenterTextAlignment;
763     o_string_attributes_dict = [[NSDictionary dictionaryWithObjectsAndKeys: o_string_color, NSForegroundColorAttributeName, [NSFont titleBarFontOfSize:10.0], NSFontAttributeName, nil] retain];
764 }
765
766 - (void)setAlignment:(NSTextAlignment)alignment
767 {
768     textAlignment = alignment;
769     [self setStringValue:[self stringValue]];
770 }
771
772 - (void)dealloc
773 {
774     [o_string_shadow release];
775     [o_string_attributes_dict release];
776     [super dealloc];
777 }
778
779 - (void)setStringValue:(NSString *)string
780 {
781     if (!o_string_shadow)
782     {
783         o_string_shadow = [[NSShadow alloc] init];
784         [o_string_shadow setShadowColor: [NSColor colorWithCalibratedWhite:1.0 alpha:0.5]];
785         [o_string_shadow setShadowOffset:NSMakeSize(0.0, -1.5)];
786         [o_string_shadow setShadowBlurRadius:0.0];
787     }
788
789     NSMutableAttributedString *o_attributed_string = [[NSMutableAttributedString alloc] initWithString:string attributes: o_string_attributes_dict];
790     NSUInteger i_stringLength = [string length];
791
792     [o_attributed_string addAttribute: NSShadowAttributeName value: o_string_shadow range: NSMakeRange(0, i_stringLength)];
793     [o_attributed_string setAlignment: textAlignment range: NSMakeRange(0, i_stringLength)];
794     [self setAttributedStringValue: o_attributed_string];
795     [o_attributed_string release];
796 }
797
798 - (void)mouseDown: (NSEvent *)ourEvent
799 {
800     if( [ourEvent clickCount] > 1 )
801         [[[VLCMain sharedInstance] controls] goToSpecificTime: nil];
802     else
803     {
804         if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DisplayTimeAsTimeRemaining"])
805             [[NSUserDefaults standardUserDefaults] setObject:@"NO" forKey:@"DisplayTimeAsTimeRemaining"];
806         else
807             [[NSUserDefaults standardUserDefaults] setObject:@"YES" forKey:@"DisplayTimeAsTimeRemaining"];
808     }
809 }
810
811 - (BOOL)timeRemaining
812 {
813     return [[NSUserDefaults standardUserDefaults] boolForKey:@"DisplayTimeAsTimeRemaining"];
814 }
815 @end
816
817 /*****************************************************************************
818  * VLCMainWindowSplitView implementation
819  * comment 1 + 2 taken from NSSplitView.h (10.7 SDK)
820  *****************************************************************************/
821 @implementation VLCMainWindowSplitView : NSSplitView
822 /* Return the color of the dividers that the split view is drawing between subviews. The default implementation of this method returns [NSColor clearColor] for the thick divider style. It will also return [NSColor clearColor] for the thin divider style when the split view is in a textured window. All other thin dividers are drawn with a color that looks good between two white panes. You can override this method to change the color of dividers.
823  */
824 - (NSColor *)dividerColor
825 {
826     return [NSColor colorWithCalibratedRed:.60 green:.60 blue:.60 alpha:1.];
827 }
828
829 /* Return the thickness of the dividers that the split view is drawing between subviews. The default implementation returns a value that depends on the divider style. You can override this method to change the size of dividers.
830  */
831 - (CGFloat)dividerThickness
832 {
833     return 1.0;
834 }
835
836 - (void)adjustSubviews
837 {
838     NSArray *o_subviews = [self subviews];
839     NSRect viewDimensions = [self frame];
840     NSRect leftViewDimensions = [[o_subviews objectAtIndex:0] frame];
841     NSRect rightViewDimensions = [[o_subviews objectAtIndex:1] frame];
842     CGFloat f_dividerThickness = [self dividerThickness];
843
844     leftViewDimensions.size.height = viewDimensions.size.height;
845     [[o_subviews objectAtIndex:0] setFrame: leftViewDimensions];
846
847     rightViewDimensions.origin.x = leftViewDimensions.size.width + f_dividerThickness;
848     rightViewDimensions.size.width = viewDimensions.size.width - leftViewDimensions.size.width - f_dividerThickness;
849     rightViewDimensions.size.height = viewDimensions.size.height;
850     [[o_subviews objectAtIndex:1] setFrame: rightViewDimensions];
851 }
852 @end
853
854 /*****************************************************************************
855  * VLCThreePartImageView interface
856  *****************************************************************************/
857 @implementation VLCThreePartImageView
858 - (void)dealloc
859 {
860     [o_left_img release];
861     [o_middle_img release];
862     [o_right_img release];
863
864     [super dealloc];
865 }
866
867 - (void)setImagesLeft:(NSImage *)left middle: (NSImage *)middle right:(NSImage *)right
868 {
869     if (o_left_img)
870         [o_left_img release];
871     if (o_middle_img)
872         [o_middle_img release];
873     if (o_right_img)
874         [o_right_img release];
875
876     o_left_img = [left retain];
877     o_middle_img = [middle retain];
878     o_right_img = [right retain];
879 }
880
881 - (void)drawRect:(NSRect)rect
882 {
883     NSRect bnds = [self bounds];
884     NSDrawThreePartImage( bnds, o_left_img, o_middle_img, o_right_img, NO, NSCompositeSourceOver, 1, NO );
885 }
886
887 @end
888
889 @implementation VLCThreePartDropView
890
891 - (BOOL)mouseDownCanMoveWindow
892 {
893     return YES;
894 }
895
896 - (void)dealloc
897 {
898     [self unregisterDraggedTypes];
899     [super dealloc];
900 }
901
902 - (void)awakeFromNib
903 {
904     [self registerForDraggedTypes:[NSArray arrayWithObjects:NSTIFFPboardType,
905                                    NSFilenamesPboardType, nil]];
906 }
907
908 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
909 {
910     if ((NSDragOperationGeneric & [sender draggingSourceOperationMask])
911         == NSDragOperationGeneric)
912     {
913         return NSDragOperationGeneric;
914     }
915     else
916     {
917         return NSDragOperationNone;
918     }
919 }
920
921 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
922 {
923     return YES;
924 }
925
926 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
927 {
928     NSPasteboard *o_paste = [sender draggingPasteboard];
929     NSArray *o_types = [NSArray arrayWithObjects: NSFilenamesPboardType, nil];
930     NSString *o_desired_type = [o_paste availableTypeFromArray:o_types];
931     NSData *o_carried_data = [o_paste dataForType:o_desired_type];
932     BOOL b_autoplay = config_GetInt( VLCIntf, "macosx-autoplay" );
933
934     if( o_carried_data )
935     {
936         if ([o_desired_type isEqualToString:NSFilenamesPboardType])
937         {
938             NSArray *o_array = [NSArray array];
939             NSArray *o_values = [[o_paste propertyListForType: NSFilenamesPboardType] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
940             NSUInteger count = [o_values count];
941
942             input_thread_t * p_input = pl_CurrentInput( VLCIntf );
943             BOOL b_returned = NO;
944
945             if (count == 1 && p_input)
946             {
947                 b_returned = input_AddSubtitle( p_input, make_URI([[o_values objectAtIndex:0] UTF8String], NULL), true );
948                 vlc_object_release( p_input );
949                 if(!b_returned)
950                     return YES;
951             }
952             else if( p_input )
953                 vlc_object_release( p_input );
954
955             for( NSUInteger i = 0; i < count; i++)
956             {
957                 NSDictionary *o_dic;
958                 char *psz_uri = make_URI([[o_values objectAtIndex:i] UTF8String], NULL);
959                 if( !psz_uri )
960                     continue;
961
962                 o_dic = [NSDictionary dictionaryWithObject:[NSString stringWithCString:psz_uri encoding:NSUTF8StringEncoding] forKey:@"ITEM_URL"];
963                 free( psz_uri );
964
965                 o_array = [o_array arrayByAddingObject: o_dic];
966             }
967             if( b_autoplay )
968                 [[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:NO];
969             else
970                 [[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:YES];
971             return YES;
972         }
973     }
974     [self setNeedsDisplay:YES];
975     return YES;
976 }
977
978 - (void)concludeDragOperation:(id <NSDraggingInfo>)sender
979 {
980     [self setNeedsDisplay:YES];
981 }
982
983 @end