226d667f353e1d2d07e963f5131cade89d5567bc
[vlc.git] / modules / gui / macosx / controls.m
1 /*****************************************************************************
2  * controls.m: MacOS X interface module
3  *****************************************************************************
4  * Copyright (C) 2002-2011 the VideoLAN team
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 "vout.h"
37 #import "open.h"
38 #import "controls.h"
39 #import "playlist.h"
40 #import "CoreInteraction.h"
41 #import <vlc_keys.h>
42
43 #pragma mark -
44 /*****************************************************************************
45  * VLCControls implementation
46  *****************************************************************************/
47 @implementation VLCControls
48
49 - (id)init
50 {
51     [super init];
52     o_fs_panel = [[VLCFSPanel alloc] init];
53     return self;
54 }
55
56 - (void)awakeFromNib
57 {
58     [o_specificTime_mi setTitle: _NS("Jump To Time")];
59     [o_specificTime_cancel_btn setTitle: _NS("Cancel")];
60     [o_specificTime_ok_btn setTitle: _NS("OK")];
61     [o_specificTime_sec_lbl setStringValue: _NS("sec.")];
62     [o_specificTime_goTo_lbl setStringValue: _NS("Jump to time")];
63 }
64
65
66 - (void)dealloc
67 {
68     [[NSNotificationCenter defaultCenter] removeObserver: self];
69
70     [super dealloc];
71 }
72
73 - (IBAction)play:(id)sender
74 {
75     [[VLCCoreInteraction sharedInstance] play];
76 }
77
78 - (IBAction)stop:(id)sender
79 {
80     [[VLCCoreInteraction sharedInstance] stop];
81 }
82
83 - (IBAction)prev:(id)sender
84 {
85     [[VLCCoreInteraction sharedInstance] previous];
86 }
87
88 - (IBAction)next:(id)sender
89 {
90     [[VLCCoreInteraction sharedInstance] next];
91 }
92
93 - (IBAction)random:(id)sender
94 {
95     [[VLCCoreInteraction sharedInstance] shuffle];
96 }
97
98 - (IBAction)repeat:(id)sender
99 {
100     vlc_value_t val;
101     intf_thread_t * p_intf = VLCIntf;
102     playlist_t * p_playlist = pl_Get( p_intf );
103
104     var_Get( p_playlist, "repeat", &val );
105     if(! val.b_bool )
106         [[VLCCoreInteraction sharedInstance] repeatOne];
107     else
108         [[VLCCoreInteraction sharedInstance] repeatOff];
109 }
110
111 - (IBAction)loop:(id)sender
112 {
113     vlc_value_t val;
114     intf_thread_t * p_intf = VLCIntf;
115     playlist_t * p_playlist = pl_Get( p_intf );
116
117     var_Get( p_playlist, "loop", &val );
118     if(! val.b_bool )
119         [[VLCCoreInteraction sharedInstance] repeatAll];
120     else
121         [[VLCCoreInteraction sharedInstance] repeatOff];
122 }
123
124 - (IBAction)quitAfterPlayback:(id)sender
125 {
126     vlc_value_t val;
127     playlist_t * p_playlist = pl_Get( VLCIntf );
128     var_ToggleBool( p_playlist, "play-and-exit" );
129 }
130
131 - (IBAction)forward:(id)sender
132 {
133     [[VLCCoreInteraction sharedInstance] forward];
134 }
135
136 - (IBAction)backward:(id)sender
137 {
138     [[VLCCoreInteraction sharedInstance] backward];
139 }
140
141 - (IBAction)volumeUp:(id)sender
142 {
143     [[VLCCoreInteraction sharedInstance] volumeUp];
144 }
145
146 - (IBAction)volumeDown:(id)sender
147 {
148     [[VLCCoreInteraction sharedInstance] volumeDown];
149 }
150
151 - (IBAction)mute:(id)sender
152 {
153     [[VLCCoreInteraction sharedInstance] mute];
154 }
155
156 - (IBAction)volumeSliderUpdated:(id)sender
157 {
158     [[VLCCoreInteraction sharedInstance] setVolume: [sender intValue]];
159 }
160
161 - (IBAction)showPosition: (id)sender
162 {
163     input_thread_t * p_input = pl_CurrentInput( VLCIntf );
164     if( p_input != NULL )
165     {
166         vout_thread_t *p_vout = input_GetVout( p_input );
167         if( p_vout != NULL )
168         {
169             var_SetInteger( VLCIntf->p_libvlc, "key-action", ACTIONID_POSITION );
170             vlc_object_release( (vlc_object_t *)p_vout );
171         }
172         vlc_object_release( p_input );
173     }
174 }
175
176 - (IBAction)toogleFullscreen:(id)sender {
177     [[VLCCoreInteraction sharedInstance] toggleFullscreen];
178 }
179
180 - (BOOL) isFullscreen {
181     id o_vout_view = [[VLCCoreInteraction sharedInstance] voutView];
182     if( o_vout_view )
183     {
184         return [o_vout_view isFullscreen];
185     }
186     return NO;
187 }
188
189 - (IBAction)telxTransparent:(id)sender
190 {
191     vlc_object_t *p_vbi;
192     p_vbi = (vlc_object_t *) vlc_object_find_name( pl_Get( VLCIntf ), "zvbi" );
193     if( p_vbi )
194     {
195         var_SetBool( p_vbi, "vbi-opaque", [sender state] );
196         [sender setState: ![sender state]];
197         vlc_object_release( p_vbi );
198     }
199 }
200
201 - (IBAction)telxNavLink:(id)sender
202 {
203     intf_thread_t * p_intf = VLCIntf;
204     vlc_object_t *p_vbi;
205     int i_page = 0;
206
207     if( [[sender title] isEqualToString: _NS("Index")] )
208         i_page = 'i' << 16;
209     else if( [[sender title] isEqualToString: _NS("Red")] )
210         i_page = 'r' << 16;
211     else if( [[sender title] isEqualToString: _NS("Green")] )
212         i_page = 'g' << 16;
213     else if( [[sender title] isEqualToString: _NS("Yellow")] )
214         i_page = 'y' << 16;
215     else if( [[sender title] isEqualToString: _NS("Blue")] )
216         i_page = 'b' << 16;
217     if( i_page == 0 ) return;
218
219     p_vbi = (vlc_object_t *) vlc_object_find_name( pl_Get( VLCIntf ), "zvbi" );
220     if( p_vbi )
221     {
222         var_SetInteger( p_vbi, "vbi-page", i_page );
223         vlc_object_release( p_vbi );
224     }
225 }
226
227 - (IBAction)lockVideosAspectRatio:(id)sender
228 {
229     [[VLCCoreInteraction sharedInstance] setAspectRatioLocked: [sender state]];
230     [sender setState: [[VLCCoreInteraction sharedInstance] aspectRatioIsLocked]];
231 }
232
233 - (IBAction)addSubtitleFile:(id)sender
234 {
235     NSInteger i_returnValue = 0;
236     input_thread_t * p_input = pl_CurrentInput( VLCIntf );
237     if( !p_input ) return;
238
239     input_item_t *p_item = input_GetItem( p_input );
240     if( !p_item ) return;
241
242     char *path = input_item_GetURI( p_item );
243     if( !path ) path = strdup( "" );
244
245     NSOpenPanel * openPanel = [NSOpenPanel openPanel];
246     [openPanel setCanChooseFiles: YES];
247     [openPanel setCanChooseDirectories: NO];
248     [openPanel setAllowsMultipleSelection: YES];
249     [openPanel setAllowedFileTypes: [NSArray arrayWithObjects: @"cdg",@"@idx",@"srt",@"sub",@"utf",@"ass",@"ssa",@"aqt",@"jss",@"psb",@"rt",@"smi",@"txt",@"smil", nil]];
250     [openPanel setDirectoryURL:[NSURL fileURLWithPath:[[NSString stringWithUTF8String:path] stringByExpandingTildeInPath]]];
251     i_returnValue = [openPanel runModal];
252     free( path );
253
254     if( i_returnValue == NSOKButton )
255     {
256         NSUInteger c = 0;
257         if( !p_input ) return;
258
259         c = [[openPanel URLs] count];
260
261         for (int i = 0; i < c ; i++)
262         {
263             msg_Dbg( VLCIntf, "loading subs from %s", [[[[openPanel URLs] objectAtIndex: i] path] UTF8String] );
264             if( input_AddSubtitle( p_input, [[[[openPanel URLs] objectAtIndex: i] path] UTF8String], TRUE ) )
265                 msg_Warn( VLCIntf, "unable to load subtitles from '%s'",
266                          [[[[openPanel URLs] objectAtIndex: i] path] UTF8String] );
267         }
268     }
269 }
270
271 - (id)fspanel
272 {
273     if( o_fs_panel )
274         return o_fs_panel;
275     else
276     {
277         msg_Err( VLCIntf, "FSPanel is nil" );
278         return NULL;
279     }
280 }
281
282 - (void)scrollWheel:(NSEvent *)theEvent
283 {
284     intf_thread_t * p_intf = VLCIntf;
285     BOOL b_invertedEventFromDevice = NO;
286     if ([theEvent respondsToSelector:@selector(isDirectionInvertedFromDevice)])
287     {
288         if ([theEvent isDirectionInvertedFromDevice])
289             b_invertedEventFromDevice = YES;
290     }
291
292     float f_yabsvalue = [theEvent deltaY] > 0.0f ? [theEvent deltaY] : -[theEvent deltaY];
293     float f_xabsvalue = [theEvent deltaX] > 0.0f ? [theEvent deltaX] : -[theEvent deltaX];
294     int i, i_yvlckey, i_xvlckey;
295
296     if (b_invertedEventFromDevice)
297     {
298         if ([theEvent deltaY] > 0.0f)
299             i_yvlckey = KEY_MOUSEWHEELDOWN;
300         else
301             i_yvlckey = KEY_MOUSEWHEELUP;
302
303         if ([theEvent deltaX] > 0.0f)
304             i_xvlckey = KEY_MOUSEWHEELRIGHT;
305         else
306             i_xvlckey = KEY_MOUSEWHEELLEFT;
307     }
308     else
309     {
310         if ([theEvent deltaY] < 0.0f)
311             i_yvlckey = KEY_MOUSEWHEELDOWN;
312         else
313             i_yvlckey = KEY_MOUSEWHEELUP;
314
315         if ([theEvent deltaX] < 0.0f)
316             i_xvlckey = KEY_MOUSEWHEELRIGHT;
317         else
318             i_xvlckey = KEY_MOUSEWHEELLEFT;
319     }
320
321     /* Send multiple key event, depending on the intensity of the event */
322     for (i = 0; i < (int)(f_yabsvalue/4.+1.) && f_yabsvalue > 0.05 ; i++)
323         var_SetInteger( p_intf->p_libvlc, "key-pressed", i_yvlckey );
324
325     /* Prioritize Y event (sound volume) over X event */
326     if (f_yabsvalue < 0.05)
327     {
328         for (i = 0; i < (int)(f_xabsvalue/6.+1.) && f_xabsvalue > 0.05; i++)
329          var_SetInteger( p_intf->p_libvlc, "key-pressed", i_xvlckey );
330     }
331 }
332
333 - (BOOL)keyEvent:(NSEvent *)o_event
334 {
335     BOOL eventHandled = NO;
336     unichar key = [[o_event charactersIgnoringModifiers] characterAtIndex: 0];
337
338     if( key )
339     {
340         input_thread_t * p_input = pl_CurrentInput( VLCIntf );
341         if( p_input != NULL )
342         {
343             vout_thread_t *p_vout = input_GetVout( p_input );
344
345             if( p_vout != NULL )
346             {
347                 /* Escape */
348                 if( key == (unichar) 0x1b )
349                 {
350                     id o_vout_view = [[VLCCoreInteraction sharedInstance] voutView];
351                     if( o_vout_view && [o_vout_view isFullscreen] )
352                     {
353                         [o_vout_view toggleFullscreen];
354                         eventHandled = YES;
355                     }
356                 }
357                 else if( key == ' ' )
358                 {
359                     [self play:self];
360                     eventHandled = YES;
361                 }
362                 vlc_object_release( (vlc_object_t *)p_vout );
363             }
364             vlc_object_release( p_input );
365         }
366     }
367     return eventHandled;
368 }
369
370 - (IBAction)goToSpecificTime:(id)sender
371 {
372     if( sender == o_specificTime_cancel_btn )
373     {
374         [NSApp endSheet: o_specificTime_win];
375         [o_specificTime_win close];
376     }
377     else if( sender == o_specificTime_ok_btn )
378     {
379         input_thread_t * p_input = pl_CurrentInput( VLCIntf );
380         if( p_input )
381         {
382             int64_t timeInSec = 0;
383             NSString * fieldContent = [o_specificTime_enter_fld stringValue];
384             if( [[fieldContent componentsSeparatedByString: @":"] count] > 1 &&
385                 [[fieldContent componentsSeparatedByString: @":"] count] <= 3 )
386             {
387                 NSArray * ourTempArray = \
388                     [fieldContent componentsSeparatedByString: @":"];
389
390                 if( [[fieldContent componentsSeparatedByString: @":"] count] == 3 )
391                 {
392                     timeInSec += ([[ourTempArray objectAtIndex: 0] intValue] * 3600); //h
393                     timeInSec += ([[ourTempArray objectAtIndex: 1] intValue] * 60); //m
394                     timeInSec += [[ourTempArray objectAtIndex: 2] intValue];        //s
395                 }
396                 else
397                 {
398                     timeInSec += ([[ourTempArray objectAtIndex: 0] intValue] * 60); //m
399                     timeInSec += [[ourTempArray objectAtIndex: 1] intValue]; //s
400                 }
401             }
402             else
403                 timeInSec = [fieldContent intValue];
404
405             input_Control( p_input, INPUT_SET_TIME, (int64_t)(timeInSec * 1000000));
406             vlc_object_release( p_input );
407         }
408
409         [NSApp endSheet: o_specificTime_win];
410         [o_specificTime_win close];
411     }
412     else
413     {
414         input_thread_t * p_input = pl_CurrentInput( VLCIntf );
415         if( p_input )
416         {
417             /* we can obviously only do that if an input is available */
418             vlc_value_t pos, length;
419             var_Get( p_input, "time", &pos );
420             [o_specificTime_enter_fld setIntValue: (pos.i_time / 1000000)];
421             var_Get( p_input, "length", &length );
422             [o_specificTime_stepper setMaxValue: (length.i_time / 1000000)];
423
424             [NSApp beginSheet: o_specificTime_win modalForWindow: \
425                 [NSApp mainWindow] modalDelegate: self didEndSelector: nil \
426                 contextInfo: nil];
427             [o_specificTime_win makeKeyWindow];
428             vlc_object_release( p_input );
429         }
430     }
431 }
432
433 @end