]> git.sesse.net Git - vlc/blob - modules/gui/macosx/controls.m
f21da4fae69d1f102cbf2064e6ee08f9a1436fca
[vlc] / modules / gui / macosx / controls.m
1 /*****************************************************************************
2  * controls.m: MacOS X interface module
3  *****************************************************************************
4  * Copyright (C) 2002-2012 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
8  *          Christophe Massiot <massiot@via.ecp.fr>
9  *          Derk-Jan Hartman <hartman at videolan dot org>
10  *          Benjamin Pracht <bigben at videolan doit org>
11  *          Felix Paul Kühne <fkuehne at videolan dot org>
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26  *****************************************************************************/
27
28 /*****************************************************************************
29  * Preamble
30  *****************************************************************************/
31 #include <stdlib.h>                                      /* malloc(), free() */
32 #include <sys/param.h>                                    /* for MAXPATHLEN */
33 #include <string.h>
34
35 #import "intf.h"
36 #import "VideoView.h"
37 #import "open.h"
38 #import "controls.h"
39 #import "playlist.h"
40 #import "MainMenu.h"
41 #import "CoreInteraction.h"
42 #import <vlc_keys.h>
43
44 #pragma mark -
45 /*****************************************************************************
46  * VLCControls implementation
47  *****************************************************************************/
48 @implementation VLCControls
49
50 - (void)awakeFromNib
51 {
52     [o_specificTime_mi setTitle: _NS("Jump To Time")];
53     [o_specificTime_cancel_btn setTitle: _NS("Cancel")];
54     [o_specificTime_ok_btn setTitle: _NS("OK")];
55     [o_specificTime_sec_lbl setStringValue: _NS("sec.")];
56     [o_specificTime_goTo_lbl setStringValue: _NS("Jump to time")];
57
58     i_lastScrollWheelDirection = 0;
59 }
60
61
62 - (void)dealloc
63 {
64     [[NSNotificationCenter defaultCenter] removeObserver: self];
65
66     [super dealloc];
67 }
68
69 - (IBAction)play:(id)sender
70 {
71     [[VLCCoreInteraction sharedInstance] play];
72 }
73
74 - (IBAction)stop:(id)sender
75 {
76     [[VLCCoreInteraction sharedInstance] stop];
77 }
78
79 - (IBAction)prev:(id)sender
80 {
81     [[VLCCoreInteraction sharedInstance] previous];
82 }
83
84 - (IBAction)next:(id)sender
85 {
86     [[VLCCoreInteraction sharedInstance] next];
87 }
88
89 - (IBAction)random:(id)sender
90 {
91     [[VLCCoreInteraction sharedInstance] shuffle];
92 }
93
94 - (IBAction)repeat:(id)sender
95 {
96     vlc_value_t val;
97     intf_thread_t * p_intf = VLCIntf;
98     playlist_t * p_playlist = pl_Get( p_intf );
99
100     var_Get( p_playlist, "repeat", &val );
101     if(! val.b_bool )
102         [[VLCCoreInteraction sharedInstance] repeatOne];
103     else
104         [[VLCCoreInteraction sharedInstance] repeatOff];
105 }
106
107 - (IBAction)loop:(id)sender
108 {
109     vlc_value_t val;
110     intf_thread_t * p_intf = VLCIntf;
111     playlist_t * p_playlist = pl_Get( p_intf );
112
113     var_Get( p_playlist, "loop", &val );
114     if(! val.b_bool )
115         [[VLCCoreInteraction sharedInstance] repeatAll];
116     else
117         [[VLCCoreInteraction sharedInstance] repeatOff];
118 }
119
120 - (IBAction)quitAfterPlayback:(id)sender
121 {
122     vlc_value_t val;
123     playlist_t * p_playlist = pl_Get( VLCIntf );
124     var_ToggleBool( p_playlist, "play-and-exit" );
125 }
126
127 - (IBAction)forward:(id)sender
128 {
129     [[VLCCoreInteraction sharedInstance] forward];
130 }
131
132 - (IBAction)backward:(id)sender
133 {
134     [[VLCCoreInteraction sharedInstance] backward];
135 }
136
137 - (IBAction)volumeUp:(id)sender
138 {
139     [[VLCCoreInteraction sharedInstance] volumeUp];
140 }
141
142 - (IBAction)volumeDown:(id)sender
143 {
144     [[VLCCoreInteraction sharedInstance] volumeDown];
145 }
146
147 - (IBAction)mute:(id)sender
148 {
149     [[VLCCoreInteraction sharedInstance] mute];
150 }
151
152 - (IBAction)volumeSliderUpdated:(id)sender
153 {
154     [[VLCCoreInteraction sharedInstance] setVolume: [sender intValue]];
155 }
156
157 - (IBAction)showPosition: (id)sender
158 {
159     input_thread_t * p_input = pl_CurrentInput( VLCIntf );
160     if( p_input != NULL )
161     {
162         vout_thread_t *p_vout = input_GetVout( p_input );
163         if( p_vout != NULL )
164         {
165             var_SetInteger( VLCIntf->p_libvlc, "key-action", ACTIONID_POSITION );
166             vlc_object_release( p_vout );
167         }
168         vlc_object_release( p_input );
169     }
170 }
171
172 - (IBAction)telxTransparent:(id)sender
173 {
174     vlc_object_t *p_vbi;
175     p_vbi = (vlc_object_t *) vlc_object_find_name( pl_Get( VLCIntf ), "zvbi" );
176     if( p_vbi )
177     {
178         var_SetBool( p_vbi, "vbi-opaque", [sender state] );
179         [sender setState: ![sender state]];
180         vlc_object_release( p_vbi );
181     }
182 }
183
184 - (IBAction)telxNavLink:(id)sender
185 {
186     intf_thread_t * p_intf = VLCIntf;
187     vlc_object_t *p_vbi;
188     int i_page = 0;
189
190     if( [[sender title] isEqualToString: _NS("Index")] )
191         i_page = 'i' << 16;
192     else if( [[sender title] isEqualToString: _NS("Red")] )
193         i_page = 'r' << 16;
194     else if( [[sender title] isEqualToString: _NS("Green")] )
195         i_page = 'g' << 16;
196     else if( [[sender title] isEqualToString: _NS("Yellow")] )
197         i_page = 'y' << 16;
198     else if( [[sender title] isEqualToString: _NS("Blue")] )
199         i_page = 'b' << 16;
200     if( i_page == 0 ) return;
201
202     p_vbi = (vlc_object_t *) vlc_object_find_name( pl_Get( VLCIntf ), "zvbi" );
203     if( p_vbi )
204     {
205         var_SetInteger( p_vbi, "vbi-page", i_page );
206         vlc_object_release( p_vbi );
207     }
208 }
209
210 - (IBAction)lockVideosAspectRatio:(id)sender
211 {
212     [[VLCCoreInteraction sharedInstance] setAspectRatioLocked: ![sender state]];
213     [sender setState: [[VLCCoreInteraction sharedInstance] aspectRatioIsLocked]];
214 }
215
216 - (IBAction)addSubtitleFile:(id)sender
217 {
218     NSInteger i_returnValue = 0;
219     input_thread_t * p_input = pl_CurrentInput( VLCIntf );
220     if( !p_input ) return;
221
222     input_item_t *p_item = input_GetItem( p_input );
223     if( !p_item )
224     {
225         vlc_object_release( p_input );
226         return;
227     }
228
229     char *path = input_item_GetURI( p_item );
230     if( !path ) path = strdup( "" );
231
232     NSOpenPanel * openPanel = [NSOpenPanel openPanel];
233     [openPanel setCanChooseFiles: YES];
234     [openPanel setCanChooseDirectories: NO];
235     [openPanel setAllowsMultipleSelection: YES];
236     [openPanel setAllowedFileTypes: [NSArray arrayWithObjects: @"cdg",@"@idx",@"srt",@"sub",@"utf",@"ass",@"ssa",@"aqt",@"jss",@"psb",@"rt",@"smi",@"txt",@"smil", nil]];
237     [openPanel setDirectoryURL:[NSURL fileURLWithPath:[[NSString stringWithUTF8String:path] stringByExpandingTildeInPath]]];
238     i_returnValue = [openPanel runModal];
239     free( path );
240
241     if( i_returnValue == NSOKButton )
242     {
243         NSUInteger c = 0;
244         if( !p_input ) return;
245
246         c = [[openPanel URLs] count];
247
248         for (int i = 0; i < c ; i++)
249         {
250             msg_Dbg( VLCIntf, "loading subs from %s", [[[[openPanel URLs] objectAtIndex: i] path] UTF8String] );
251             if( input_AddSubtitle( p_input, [[[[openPanel URLs] objectAtIndex: i] path] UTF8String], TRUE ) )
252                 msg_Warn( VLCIntf, "unable to load subtitles from '%s'",
253                          [[[[openPanel URLs] objectAtIndex: i] path] UTF8String] );
254         }
255     }
256     vlc_object_release( p_input );
257 }
258
259 - (void)resetScrollWheelDirection
260 {
261     /* release the scroll direction 0.8 secs after the last event */
262     if (([NSDate timeIntervalSinceReferenceDate] - t_lastScrollEvent) >= 0.80)
263         i_lastScrollWheelDirection = 0;
264 }
265
266 - (void)scrollWheel:(NSEvent *)theEvent
267 {
268     intf_thread_t * p_intf = VLCIntf;
269     BOOL b_invertedEventFromDevice = NO;
270     CGFloat f_deltaY, f_deltaX = .0;
271
272     if (OSX_LION)
273     {
274         if ([theEvent isDirectionInvertedFromDevice])
275             b_invertedEventFromDevice = YES;
276     }
277
278     f_deltaY = [theEvent deltaY];
279     f_deltaX = [theEvent deltaX];
280
281     CGFloat f_yabsvalue = f_deltaY > 0.0f ? f_deltaY : -f_deltaY;
282     CGFloat f_xabsvalue = f_deltaX > 0.0f ? f_deltaX : -f_deltaX;
283
284     int i_yvlckey, i_xvlckey = 0;
285
286     if (b_invertedEventFromDevice)
287     {
288         if (f_deltaY > 0.0f)
289             i_yvlckey = KEY_MOUSEWHEELDOWN;
290         else
291             i_yvlckey = KEY_MOUSEWHEELUP;
292
293         if (f_deltaX > 0.0f)
294             i_xvlckey = KEY_MOUSEWHEELRIGHT;
295         else
296             i_xvlckey = KEY_MOUSEWHEELLEFT;
297     }
298     else
299     {
300         if (f_deltaY < 0.0f)
301             i_yvlckey = KEY_MOUSEWHEELDOWN;
302         else
303             i_yvlckey = KEY_MOUSEWHEELUP;
304
305         if (f_deltaX < 0.0f)
306             i_xvlckey = KEY_MOUSEWHEELRIGHT;
307         else
308             i_xvlckey = KEY_MOUSEWHEELLEFT;
309     }
310
311     /* in the following, we're forwarding either a x or a y event */
312     /* Multiple key events are send depending on the intensity of the event */
313     /* the opposite direction is being blocked for 0.8 secs */
314     if (f_yabsvalue > 0.05)
315     {
316         if (i_lastScrollWheelDirection < 0) // last was a X
317             return;
318
319         i_lastScrollWheelDirection = 1; // Y
320         for (NSUInteger i = 0; i < (int)(f_yabsvalue/4.+1.) && f_yabsvalue > 0.05 ; i++)
321             var_SetInteger( p_intf->p_libvlc, "key-pressed", i_yvlckey );
322
323         t_lastScrollEvent = [NSDate timeIntervalSinceReferenceDate];
324         [self performSelector:@selector(resetScrollWheelDirection)
325                    withObject: NULL
326                    afterDelay:1.00];
327         return;
328     }
329     if (f_xabsvalue > 0.05)
330     {
331         if (i_lastScrollWheelDirection > 0) // last was a Y
332             return;
333
334         i_lastScrollWheelDirection = -1; // X
335         for (NSUInteger i = 0; i < (int)(f_xabsvalue/6.+1.) && f_xabsvalue > 0.05; i++)
336             var_SetInteger( p_intf->p_libvlc, "key-pressed", i_xvlckey );
337
338         t_lastScrollEvent = [NSDate timeIntervalSinceReferenceDate];
339         [self performSelector:@selector(resetScrollWheelDirection)
340                    withObject: NULL
341                    afterDelay:1.00];
342     }
343 }
344
345 - (BOOL)keyEvent:(NSEvent *)o_event
346 {
347     BOOL eventHandled = NO;
348     unichar key = [[o_event charactersIgnoringModifiers] characterAtIndex: 0];
349
350     if( key )
351     {
352         input_thread_t * p_input = pl_CurrentInput( VLCIntf );
353         if( p_input != NULL )
354         {
355             vout_thread_t *p_vout = input_GetVout( p_input );
356
357             if( p_vout != NULL )
358             {
359                 /* Escape */
360                 if( key == (unichar) 0x1b )
361                 {
362                     if (var_GetBool( p_vout, "fullscreen" ))
363                     {
364                         [[VLCCoreInteraction sharedInstance] toggleFullscreen];
365                         eventHandled = YES;
366                     }
367                 }
368                 else if( key == ' ' )
369                 {
370                     [self play:self];
371                     eventHandled = YES;
372                 }
373                 vlc_object_release( p_vout );
374             }
375             vlc_object_release( p_input );
376         }
377     }
378     return eventHandled;
379 }
380
381 - (IBAction)goToSpecificTime:(id)sender
382 {
383     if( sender == o_specificTime_cancel_btn )
384     {
385         [NSApp endSheet: o_specificTime_win];
386         [o_specificTime_win close];
387     }
388     else if( sender == o_specificTime_ok_btn )
389     {
390         input_thread_t * p_input = pl_CurrentInput( VLCIntf );
391         if( p_input )
392         {
393             int64_t timeInSec = 0;
394             NSString * fieldContent = [o_specificTime_enter_fld stringValue];
395             if( [[fieldContent componentsSeparatedByString: @":"] count] > 1 &&
396                 [[fieldContent componentsSeparatedByString: @":"] count] <= 3 )
397             {
398                 NSArray * ourTempArray = \
399                     [fieldContent componentsSeparatedByString: @":"];
400
401                 if( [[fieldContent componentsSeparatedByString: @":"] count] == 3 )
402                 {
403                     timeInSec += ([[ourTempArray objectAtIndex: 0] intValue] * 3600); //h
404                     timeInSec += ([[ourTempArray objectAtIndex: 1] intValue] * 60); //m
405                     timeInSec += [[ourTempArray objectAtIndex: 2] intValue];        //s
406                 }
407                 else
408                 {
409                     timeInSec += ([[ourTempArray objectAtIndex: 0] intValue] * 60); //m
410                     timeInSec += [[ourTempArray objectAtIndex: 1] intValue]; //s
411                 }
412             }
413             else
414                 timeInSec = [fieldContent intValue];
415
416             input_Control( p_input, INPUT_SET_TIME, (int64_t)(timeInSec * 1000000));
417             vlc_object_release( p_input );
418         }
419
420         [NSApp endSheet: o_specificTime_win];
421         [o_specificTime_win close];
422     }
423     else
424     {
425         input_thread_t * p_input = pl_CurrentInput( VLCIntf );
426         if( p_input )
427         {
428             /* we can obviously only do that if an input is available */
429             vlc_value_t pos, length;
430             var_Get( p_input, "time", &pos );
431             [o_specificTime_enter_fld setIntValue: (pos.i_time / 1000000)];
432             var_Get( p_input, "length", &length );
433             [o_specificTime_stepper setMaxValue: (length.i_time / 1000000)];
434
435             [NSApp beginSheet: o_specificTime_win modalForWindow: \
436                 [NSApp mainWindow] modalDelegate: self didEndSelector: nil \
437                 contextInfo: nil];
438             [o_specificTime_win makeKeyWindow];
439             vlc_object_release( p_input );
440         }
441     }
442 }
443
444 @end
445
446 @implementation VLCControls (NSMenuValidation)
447
448 - (BOOL)validateMenuItem:(NSMenuItem *)o_mi
449 {
450     return [[VLCMainMenu sharedInstance] validateMenuItem:o_mi];
451 }
452
453 @end