ad531fa044409c3cabac7844e00f699b94bd094a
[vlc.git] / modules / gui / macosx / misc.m
1 /*****************************************************************************
2  * misc.m: code not specific to vlc
3  *****************************************************************************
4  * Copyright (C) 2003-2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 #include <Cocoa/Cocoa.h>
25
26 #include "intf.h"                                          /* VLCApplication */
27 #include "misc.h"
28 #include "playlist.h"
29 #include "controls.h"
30
31 /*****************************************************************************
32  * VLCWindow
33  *
34  *  Missing extension to NSWindow
35  *****************************************************************************/
36
37 @implementation VLCWindow
38 - (id)initWithContentRect:(NSRect)contentRect styleMask:(unsigned int)styleMask
39     backing:(NSBackingStoreType)backingType defer:(BOOL)flag
40 {
41     self = [super initWithContentRect:contentRect styleMask:styleMask backing:backingType defer:flag];
42     if( self )
43         b_isset_canBecomeKeyWindow = NO;
44     return self;
45 }
46 - (void)setCanBecomeKeyWindow: (BOOL)canBecomeKey
47 {
48     b_isset_canBecomeKeyWindow = YES;
49     b_canBecomeKeyWindow = canBecomeKey;
50 }
51
52 - (BOOL)canBecomeKeyWindow
53 {
54     if(b_isset_canBecomeKeyWindow)
55         return b_canBecomeKeyWindow;
56
57     return [super canBecomeKeyWindow];
58 }
59 @end
60
61 /*****************************************************************************
62  * VLCControllerWindow
63  *****************************************************************************/
64
65 @implementation VLCControllerWindow
66
67 - (id)initWithContentRect:(NSRect)contentRect styleMask:(unsigned int)styleMask
68     backing:(NSBackingStoreType)backingType defer:(BOOL)flag
69 {
70     self = [super initWithContentRect:contentRect styleMask:styleMask //& ~NSTitledWindowMask
71     backing:backingType defer:flag];
72
73     [[VLCMain sharedInstance] updateTogglePlaylistState];
74
75     return( self );
76 }
77
78 - (BOOL)performKeyEquivalent:(NSEvent *)o_event
79 {
80     /* We indeed want to prioritize Cocoa key equivalent against libvlc,
81        so we perform the menu equivalent now. */
82     if([[NSApp mainMenu] performKeyEquivalent:o_event])
83         return TRUE;
84
85     return [[VLCMain sharedInstance] hasDefinedShortcutKey:o_event] ||
86            [(VLCControls *)[[VLCMain sharedInstance] getControls] keyEvent:o_event];
87 }
88
89 @end
90
91
92
93 /*****************************************************************************
94  * VLCControllerView
95  *****************************************************************************/
96
97 @implementation VLCControllerView
98
99 - (void)dealloc
100 {
101     [self unregisterDraggedTypes];
102     [super dealloc];
103 }
104
105 #if GC_ENABLED
106 - (void)finalize
107 {
108     /* dealloc doesn't get called on 10.5 if GC is enabled, so we need to provide the basic functionality here */
109     [self unregisterDraggedTypes];
110     [super finalize];
111 }
112 #endif
113
114 - (void)awakeFromNib
115 {
116     [self registerForDraggedTypes:[NSArray arrayWithObjects:NSTIFFPboardType, 
117         NSFilenamesPboardType, nil]];
118 }
119
120 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
121 {
122     if ((NSDragOperationGeneric & [sender draggingSourceOperationMask]) 
123                 == NSDragOperationGeneric)
124     {
125         return NSDragOperationGeneric;
126     }
127     else
128     {
129         return NSDragOperationNone;
130     }
131 }
132
133 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
134 {
135     return YES;
136 }
137
138 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
139 {
140     NSPasteboard *o_paste = [sender draggingPasteboard];
141     NSArray *o_types = [NSArray arrayWithObjects: NSFilenamesPboardType, nil];
142     NSString *o_desired_type = [o_paste availableTypeFromArray:o_types];
143     NSData *o_carried_data = [o_paste dataForType:o_desired_type];
144
145     if( o_carried_data )
146     {
147         if ([o_desired_type isEqualToString:NSFilenamesPboardType])
148         {
149             int i;
150             NSArray *o_array = [NSArray array];
151             NSArray *o_values = [[o_paste propertyListForType: NSFilenamesPboardType]
152                         sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
153
154             for( i = 0; i < (int)[o_values count]; i++)
155             {
156                 NSDictionary *o_dic;
157                 o_dic = [NSDictionary dictionaryWithObject:[o_values objectAtIndex:i] forKey:@"ITEM_URL"];
158                 o_array = [o_array arrayByAddingObject: o_dic];
159             }
160             [(VLCPlaylist *)[[VLCMain sharedInstance] getPlaylist] appendArray: o_array atPos: -1 enqueue:NO];
161             return YES;
162         }
163     }
164     [self setNeedsDisplay:YES];
165     return YES;
166 }
167
168 - (void)concludeDragOperation:(id <NSDraggingInfo>)sender
169 {
170     [self setNeedsDisplay:YES];
171 }
172
173 @end
174
175 /*****************************************************************************
176  * VLBrushedMetalImageView
177  *****************************************************************************/
178
179 @implementation VLBrushedMetalImageView
180
181 - (BOOL)mouseDownCanMoveWindow
182 {
183     return YES;
184 }
185
186 - (void)dealloc
187 {
188     [self unregisterDraggedTypes];
189     [super dealloc];
190 }
191
192 #if GC_ENABLED
193 - (void)finalize
194 {
195     /* dealloc doesn't get called on 10.5 if GC is enabled, so we need to provide the basic functionality here */
196     [self unregisterDraggedTypes];
197     [super finalize];
198 }
199 #endif
200
201 - (void)awakeFromNib
202 {
203     [self registerForDraggedTypes:[NSArray arrayWithObjects:NSTIFFPboardType, 
204         NSFilenamesPboardType, nil]];
205 }
206
207 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
208 {
209     if ((NSDragOperationGeneric & [sender draggingSourceOperationMask]) 
210                 == NSDragOperationGeneric)
211     {
212         return NSDragOperationGeneric;
213     }
214     else
215     {
216         return NSDragOperationNone;
217     }
218 }
219
220 - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
221 {
222     return YES;
223 }
224
225 - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
226 {
227     NSPasteboard *o_paste = [sender draggingPasteboard];
228     NSArray *o_types = [NSArray arrayWithObjects: NSFilenamesPboardType, nil];
229     NSString *o_desired_type = [o_paste availableTypeFromArray:o_types];
230     NSData *o_carried_data = [o_paste dataForType:o_desired_type];
231     BOOL b_autoplay = config_GetInt( VLCIntf, "macosx-autoplay" );
232
233     if( o_carried_data )
234     {
235         if ([o_desired_type isEqualToString:NSFilenamesPboardType])
236         {
237             int i;
238             NSArray *o_array = [NSArray array];
239             NSArray *o_values = [[o_paste propertyListForType: NSFilenamesPboardType]
240                         sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
241
242             for( i = 0; i < (int)[o_values count]; i++)
243             {
244                 NSDictionary *o_dic;
245                 o_dic = [NSDictionary dictionaryWithObject:[o_values objectAtIndex:i] forKey:@"ITEM_URL"];
246                 o_array = [o_array arrayByAddingObject: o_dic];
247             }
248             if( b_autoplay )
249                 [[[VLCMain sharedInstance] getPlaylist] appendArray: o_array atPos: -1 enqueue:NO];
250             else
251                 [[[VLCMain sharedInstance] getPlaylist] appendArray: o_array atPos: -1 enqueue:YES];
252             return YES;
253         }
254     }
255     [self setNeedsDisplay:YES];
256     return YES;
257 }
258
259 - (void)concludeDragOperation:(id <NSDraggingInfo>)sender
260 {
261     [self setNeedsDisplay:YES];
262 }
263
264 @end
265
266
267 /*****************************************************************************
268  * MPSlider
269  *****************************************************************************/
270 @implementation MPSlider
271
272 void _drawKnobInRect(NSRect knobRect)
273 {
274     // Center knob in given rect
275     knobRect.origin.x += (int)((float)(knobRect.size.width - 7)/2.0);
276     knobRect.origin.y += (int)((float)(knobRect.size.height - 7)/2.0);
277     
278     // Draw diamond
279     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 3, knobRect.origin.y + 6, 1, 1), NSCompositeSourceOver);
280     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 2, knobRect.origin.y + 5, 3, 1), NSCompositeSourceOver);
281     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 1, knobRect.origin.y + 4, 5, 1), NSCompositeSourceOver);
282     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 0, knobRect.origin.y + 3, 7, 1), NSCompositeSourceOver);
283     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 1, knobRect.origin.y + 2, 5, 1), NSCompositeSourceOver);
284     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 2, knobRect.origin.y + 1, 3, 1), NSCompositeSourceOver);
285     NSRectFillUsingOperation(NSMakeRect(knobRect.origin.x + 3, knobRect.origin.y + 0, 1, 1), NSCompositeSourceOver);
286 }
287
288 void _drawFrameInRect(NSRect frameRect)
289 {
290     // Draw frame
291     NSRectFillUsingOperation(NSMakeRect(frameRect.origin.x, frameRect.origin.y, frameRect.size.width, 1), NSCompositeSourceOver);
292     NSRectFillUsingOperation(NSMakeRect(frameRect.origin.x, frameRect.origin.y + frameRect.size.height-1, frameRect.size.width, 1), NSCompositeSourceOver);
293     NSRectFillUsingOperation(NSMakeRect(frameRect.origin.x, frameRect.origin.y, 1, frameRect.size.height), NSCompositeSourceOver);
294     NSRectFillUsingOperation(NSMakeRect(frameRect.origin.x+frameRect.size.width-1, frameRect.origin.y, 1, frameRect.size.height), NSCompositeSourceOver);
295 }
296
297 - (void)drawRect:(NSRect)rect
298 {
299     // Draw default to make sure the slider behaves correctly
300     [[NSGraphicsContext currentContext] saveGraphicsState];
301     NSRectClip(NSZeroRect);
302     [super drawRect:rect];
303     [[NSGraphicsContext currentContext] restoreGraphicsState];
304     
305     // Full size
306     rect = [self bounds];
307     int diff = (int)(([[self cell] knobThickness] - 7.0)/2.0) - 1;
308     rect.origin.x += diff-1;
309     rect.origin.y += diff;
310     rect.size.width -= 2*diff-2;
311     rect.size.height -= 2*diff;
312     
313     // Draw dark
314     NSRect knobRect = [[self cell] knobRectFlipped:NO];
315     [[[NSColor blackColor] colorWithAlphaComponent:0.6] set];
316     _drawFrameInRect(rect);
317     _drawKnobInRect(knobRect);
318     
319     // Draw shadow
320     [[[NSColor blackColor] colorWithAlphaComponent:0.1] set];
321     rect.origin.x++;
322     rect.origin.y++;
323     knobRect.origin.x++;
324     knobRect.origin.y++;
325     _drawFrameInRect(rect);
326     _drawKnobInRect(knobRect);
327 }
328
329 @end
330
331
332 /*****************************************************************************
333  * ITSlider
334  *****************************************************************************/
335
336 @implementation ITSlider
337
338 - (void)awakeFromNib
339 {
340     if ([[self cell] class] != [ITSliderCell class]) {
341         // replace cell
342         NSSliderCell *oldCell = [self cell];
343         NSSliderCell *newCell = [[[ITSliderCell alloc] init] autorelease];
344         [newCell setTag:[oldCell tag]];
345         [newCell setTarget:[oldCell target]];
346         [newCell setAction:[oldCell action]];
347         [newCell setControlSize:[oldCell controlSize]];
348         [newCell setType:[oldCell type]];
349         [newCell setState:[oldCell state]]; 
350         [newCell setAllowsTickMarkValuesOnly:[oldCell allowsTickMarkValuesOnly]];
351         [newCell setAltIncrementValue:[oldCell altIncrementValue]];
352         [newCell setControlTint:[oldCell controlTint]];
353         [newCell setKnobThickness:[oldCell knobThickness]];
354         [newCell setMaxValue:[oldCell maxValue]];
355         [newCell setMinValue:[oldCell minValue]];
356         [newCell setDoubleValue:[oldCell doubleValue]];
357         [newCell setNumberOfTickMarks:[oldCell numberOfTickMarks]];
358         [newCell setEditable:[oldCell isEditable]];
359         [newCell setEnabled:[oldCell isEnabled]];
360         [newCell setEntryType:[oldCell entryType]];
361         [newCell setHighlighted:[oldCell isHighlighted]];
362         [newCell setTickMarkPosition:[oldCell tickMarkPosition]];
363         [self setCell:newCell];
364     }
365 }
366
367 @end
368
369 /*****************************************************************************
370  * ITSliderCell
371  *****************************************************************************/
372 @implementation ITSliderCell
373
374 - (id)init
375 {
376     self = [super init];
377     _knobOff = [[NSImage imageNamed:@"volumeslider_normal"] retain];
378     _knobOn = [[NSImage imageNamed:@"volumeslider_blue"] retain];
379     b_mouse_down = FALSE;
380     return self;
381 }
382
383 - (void)dealloc
384 {
385     [_knobOff release];
386     [_knobOn release];
387     [super dealloc];
388 }
389
390 - (void)drawKnob:(NSRect)knob_rect
391 {
392     NSImage *knob;
393
394     if( b_mouse_down )
395         knob = _knobOn;
396     else
397         knob = _knobOff;
398
399     [[self controlView] lockFocus];
400     [knob compositeToPoint:NSMakePoint( knob_rect.origin.x + 1,
401         knob_rect.origin.y + knob_rect.size.height -2 )  
402         operation:NSCompositeSourceOver];
403     [[self controlView] unlockFocus];
404 }
405
406 - (void)stopTracking:(NSPoint)lastPoint at:(NSPoint)stopPoint inView: 
407         (NSView *)controlView mouseIsUp:(BOOL)flag
408 {
409     b_mouse_down = NO;
410     [self drawKnob];
411     [super stopTracking:lastPoint at:stopPoint inView:controlView mouseIsUp:flag];
412 }
413
414 - (BOOL)startTrackingAt:(NSPoint)startPoint inView:(NSView *)controlView
415 {
416     b_mouse_down = YES;
417     [self drawKnob];
418     return [super startTrackingAt:startPoint inView:controlView];
419 }
420
421 @end
422