]> git.sesse.net Git - vlc/blob - modules/gui/macosx/simple_prefs.m
macosx: saved various objc selector dispatches when iterating, additionally fixes...
[vlc] / modules / gui / macosx / simple_prefs.m
1 /*****************************************************************************
2 * simple_prefs.m: Simple Preferences for Mac OS X
3 *****************************************************************************
4 * Copyright (C) 2008-2011 the VideoLAN team
5 * $Id$
6 *
7 * Authors: Felix Paul Kühne <fkuehne at videolan dot org>
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 #import "simple_prefs.h"
25 #import "prefs.h"
26 #import <vlc_keys.h>
27 #import <vlc_interface.h>
28 #import <vlc_dialog.h>
29 #import <vlc_modules.h>
30 #import "misc.h"
31 #import "intf.h"
32 #import "AppleRemote.h"
33 #import <Sparkle/Sparkle.h>                        //for o_intf_last_update_lbl
34
35 static NSString* VLCSPrefsToolbarIdentifier = @"Our Simple Preferences Toolbar Identifier";
36 static NSString* VLCIntfSettingToolbarIdentifier = @"Intf Settings Item Identifier";
37 static NSString* VLCAudioSettingToolbarIdentifier = @"Audio Settings Item Identifier";
38 static NSString* VLCVideoSettingToolbarIdentifier = @"Video Settings Item Identifier";
39 static NSString* VLCOSDSettingToolbarIdentifier = @"Subtitles Settings Item Identifier";
40 static NSString* VLCInputSettingToolbarIdentifier = @"Input Settings Item Identifier";
41 static NSString* VLCHotkeysSettingToolbarIdentifier = @"Hotkeys Settings Item Identifier";
42
43 @implementation VLCSimplePrefs
44
45 static VLCSimplePrefs *_o_sharedInstance = nil;
46
47 + (VLCSimplePrefs *)sharedInstance
48 {
49     return _o_sharedInstance ? _o_sharedInstance : [[self alloc] init];
50 }
51
52 - (id)init
53 {
54     if (_o_sharedInstance) {
55         [self dealloc];
56     } else {
57         _o_sharedInstance = [super init];
58         p_intf = VLCIntf;
59     }
60
61     return _o_sharedInstance;
62 }
63
64 - (void)dealloc
65 {
66     [o_currentlyShownCategoryView release];
67
68     [o_hotkeySettings release];
69     [o_hotkeyDescriptions release];
70     [o_hotkeyNames release];
71     [o_hotkeysNonUseableKeys release];
72
73     [o_keyInTransition release];
74
75     [super dealloc];
76 }
77
78 - (NSString *)OSXStringKeyToString:(NSString *)theString
79 {
80     if (![theString isEqualToString:@""]) {
81         theString = [theString stringByReplacingOccurrencesOfString:@"Command" withString: [NSString stringWithUTF8String: "\xE2\x8C\x98"]];
82         theString = [theString stringByReplacingOccurrencesOfString:@"Alt" withString: [NSString stringWithUTF8String: "\xE2\x8C\xA5"]];
83         theString = [theString stringByReplacingOccurrencesOfString:@"Shift" withString: [NSString stringWithUTF8String: "\xE2\x87\xA7"]];
84         theString = [theString stringByReplacingOccurrencesOfString:@"Ctrl" withString: [NSString stringWithUTF8String: "\xE2\x8C\x83"]];
85         theString = [theString stringByReplacingOccurrencesOfString:@"+" withString:@""];
86         theString = [theString stringByReplacingOccurrencesOfString:@"-" withString:@""];
87         theString = [theString capitalizedString];
88     }
89     else
90         theString = [NSString stringWithString:_NS("Not Set")];
91     return theString;
92 }
93
94 - (void)awakeFromNib
95 {
96     [self initStrings];
97
98     /* setup the toolbar */
99     NSToolbar * o_sprefs_toolbar = [[[NSToolbar alloc] initWithIdentifier: VLCSPrefsToolbarIdentifier] autorelease];
100     [o_sprefs_toolbar setAllowsUserCustomization: NO];
101     [o_sprefs_toolbar setAutosavesConfiguration: NO];
102     [o_sprefs_toolbar setDisplayMode: NSToolbarDisplayModeIconAndLabel];
103     [o_sprefs_toolbar setSizeMode: NSToolbarSizeModeRegular];
104     [o_sprefs_toolbar setDelegate: self];
105     [o_sprefs_win setToolbar: o_sprefs_toolbar];
106
107     /* setup useful stuff */
108     o_hotkeysNonUseableKeys = [[NSArray arrayWithObjects: @"Command-c", @"Command-x", @"Command-v", @"Command-a", @"Command-," , @"Command-h", @"Command-Alt-h", @"Command-Shift-o", @"Command-o", @"Command-d", @"Command-n", @"Command-s", @"Command-z", @"Command-l", @"Command-r", @"Command-3", @"Command-m", @"Command-w", @"Command-Shift-w", @"Command-Shift-c", @"Command-Shift-p", @"Command-i", @"Command-e", @"Command-Shift-e", @"Command-b", @"Command-Shift-m", @"Command-Ctrl-m", @"Command-?", @"Command-Alt-?", nil] retain];
109 }
110
111 #define CreateToolbarItem( o_name, o_desc, o_img, sel ) \
112     o_toolbarItem = create_toolbar_item(o_itemIdent, o_name, o_desc, o_img, self, @selector(sel));
113 static inline NSToolbarItem *
114 create_toolbar_item( NSString * o_itemIdent, NSString * o_name, NSString * o_desc, NSString * o_img, id target, SEL selector )
115 {
116     NSToolbarItem *o_toolbarItem = [[[NSToolbarItem alloc] initWithItemIdentifier: o_itemIdent] autorelease]; \
117
118     [o_toolbarItem setLabel: o_name];
119     [o_toolbarItem setPaletteLabel: o_desc];
120
121     [o_toolbarItem setToolTip: o_desc];
122     [o_toolbarItem setImage: [NSImage imageNamed: o_img]];
123
124     [o_toolbarItem setTarget: target];
125     [o_toolbarItem setAction: selector];
126
127     [o_toolbarItem setEnabled: YES];
128     [o_toolbarItem setAutovalidates: YES];
129
130     return o_toolbarItem;
131 }
132
133 - (NSToolbarItem *) toolbar: (NSToolbar *)o_sprefs_toolbar
134       itemForItemIdentifier: (NSString *)o_itemIdent
135   willBeInsertedIntoToolbar: (BOOL)b_willBeInserted
136 {
137     NSToolbarItem *o_toolbarItem = nil;
138
139     if( [o_itemIdent isEqual: VLCIntfSettingToolbarIdentifier] )
140     {
141         CreateToolbarItem( _NS("Interface"), _NS("Interface Settings"), @"spref_cone_Interface_64", showInterfaceSettings );
142     }
143     else if( [o_itemIdent isEqual: VLCAudioSettingToolbarIdentifier] )
144     {
145         CreateToolbarItem( _NS("Audio"), _NS("General Audio Settings"), @"spref_cone_Audio_64", showAudioSettings );
146     }
147     else if( [o_itemIdent isEqual: VLCVideoSettingToolbarIdentifier] )
148     {
149         CreateToolbarItem( _NS("Video"), _NS("General Video Settings"), @"spref_cone_Video_64", showVideoSettings );
150     }
151     else if( [o_itemIdent isEqual: VLCOSDSettingToolbarIdentifier] )
152     {
153         CreateToolbarItem( _NS("Subtitles & OSD"), _NS("Subtitles & On Screen Display Settings"), @"spref_cone_Subtitles_64", showOSDSettings );
154     }
155     else if( [o_itemIdent isEqual: VLCInputSettingToolbarIdentifier] )
156     {
157         CreateToolbarItem( _NS("Input & Codecs"), _NS("Input & Codec settings"), @"spref_cone_Input_64", showInputSettings );
158     }
159     else if( [o_itemIdent isEqual: VLCHotkeysSettingToolbarIdentifier] )
160     {
161         CreateToolbarItem( _NS("Hotkeys"), _NS("Hotkeys settings"), @"spref_cone_Hotkeys_64", showHotkeySettings );
162     }
163
164     return o_toolbarItem;
165 }
166
167 - (NSArray *)toolbarDefaultItemIdentifiers: (NSToolbar *)toolbar
168 {
169     return [NSArray arrayWithObjects: VLCIntfSettingToolbarIdentifier, VLCAudioSettingToolbarIdentifier, VLCVideoSettingToolbarIdentifier,
170         VLCOSDSettingToolbarIdentifier, VLCInputSettingToolbarIdentifier, VLCHotkeysSettingToolbarIdentifier, NSToolbarFlexibleSpaceItemIdentifier, nil];
171 }
172
173 - (NSArray *)toolbarAllowedItemIdentifiers: (NSToolbar *)toolbar
174 {
175     return [NSArray arrayWithObjects: VLCIntfSettingToolbarIdentifier, VLCAudioSettingToolbarIdentifier, VLCVideoSettingToolbarIdentifier,
176         VLCOSDSettingToolbarIdentifier, VLCInputSettingToolbarIdentifier, VLCHotkeysSettingToolbarIdentifier, NSToolbarFlexibleSpaceItemIdentifier, nil];
177 }
178
179 - (NSArray *)toolbarSelectableItemIdentifiers:(NSToolbar *)toolbar
180 {
181     return [NSArray arrayWithObjects: VLCIntfSettingToolbarIdentifier, VLCAudioSettingToolbarIdentifier, VLCVideoSettingToolbarIdentifier,
182         VLCOSDSettingToolbarIdentifier, VLCInputSettingToolbarIdentifier, VLCHotkeysSettingToolbarIdentifier, nil];
183 }
184
185 - (void)initStrings
186 {
187     /* audio */
188     [o_audio_dolby_txt setStringValue: _NS("Force detection of Dolby Surround")];
189     [o_audio_effects_box setTitle: _NS("Effects")];
190     [o_audio_enable_ckb setTitle: _NS("Enable Audio")];
191     [o_audio_general_box setTitle: _NS("General Audio")];
192     [o_audio_lang_txt setStringValue: _NS("Preferred Audio language")];
193     [o_audio_last_ckb setTitle: _NS("Enable Last.fm submissions")];
194     [o_audio_lastpwd_txt setStringValue: _NS("Password")];
195     [o_audio_lastuser_txt setStringValue: _NS("User name")];
196     [o_audio_spdif_ckb setTitle: _NS("Use S/PDIF when available")];
197     [o_audio_visual_txt setStringValue: _NS("Visualization")];
198     [o_audio_vol_txt setStringValue: _NS("Default Volume")];
199
200     /* hotkeys */
201     [o_hotkeys_change_btn setTitle: _NS("Change")];
202     [o_hotkeys_change_win setTitle: _NS("Change Hotkey")];
203     [o_hotkeys_change_cancel_btn setTitle: _NS("Cancel")];
204     [o_hotkeys_change_ok_btn setTitle: _NS("OK")];
205     [o_hotkeys_clear_btn setTitle: _NS("Clear")];
206     [o_hotkeys_lbl setStringValue: _NS("Select an action to change the associated hotkey:")];
207     [[[o_hotkeys_listbox tableColumnWithIdentifier: @"action"] headerCell] setStringValue: _NS("Action")];
208     [[[o_hotkeys_listbox tableColumnWithIdentifier: @"shortcut"] headerCell] setStringValue: _NS("Shortcut")];
209
210     /* input */
211     [o_input_avi_txt setStringValue: _NS("Repair AVI Files")];
212     [o_input_cachelevel_txt setStringValue: _NS("Default Caching Level")];
213     [o_input_caching_box setTitle: _NS("Caching")];
214     [o_input_cachelevel_custom_txt setStringValue: _NS("Use the complete preferences to configure custom caching values for each access module.")];
215     [o_input_httpproxy_txt setStringValue: _NS("HTTP Proxy")];
216     [o_input_httpproxypwd_txt setStringValue: _NS("Password for HTTP Proxy")];
217     [o_input_mux_box setTitle: _NS("Codecs / Muxers")];
218     [o_input_net_box setTitle: _NS("Network")];
219     [o_input_postproc_txt setStringValue: _NS("Post-Processing Quality")];
220     [o_input_rtsp_ckb setTitle: _NS("Use RTP over RTSP (TCP)")];
221     [o_input_skipLoop_txt setStringValue: _NS("Skip the loop filter for H.264 decoding")];
222
223     /* interface */
224     [o_intf_style_txt setStringValue: _NS("Interface style")];
225     [o_intf_style_dark_bcell setTitle: _NS("Dark")];
226     [o_intf_style_bright_bcell setTitle: _NS("Bright")];
227     [o_intf_art_txt setStringValue: _NS("Album art download policy")];
228     [o_intf_embedded_ckb setTitle: _NS("Show video within the main window")];
229     [o_intf_fspanel_ckb setTitle: _NS("Show Fullscreen Controller")];
230     [o_intf_lang_txt setStringValue: _NS("Language")];
231     [o_intf_network_box setTitle: _NS("Privacy / Network Interaction")];
232         [o_intf_appleremote_ckb setTitle: _NS("Control playback with the Apple Remote")];
233         [o_intf_mediakeys_ckb setTitle: _NS("Control playback with media keys")];
234     [o_intf_update_ckb setTitle: _NS("Automatically check for updates")];
235     [o_intf_last_update_lbl setStringValue: @""];
236     [o_intf_enableGrowl_ckb setStringValue: _NS("Enable Growl notifications (on playlist item change)")];
237
238     /* Subtitles and OSD */
239     [o_osd_encoding_txt setStringValue: _NS("Default Encoding")];
240     [o_osd_font_box setTitle: _NS("Display Settings")];
241     [o_osd_font_btn setTitle: _NS("Choose...")];
242     [o_osd_font_color_txt setStringValue: _NS("Font Color")];
243     [o_osd_font_size_txt setStringValue: _NS("Font Size")];
244     [o_osd_font_txt setStringValue: _NS("Font")];
245     [o_osd_lang_box setTitle: _NS("Subtitle Languages")];
246     [o_osd_lang_txt setStringValue: _NS("Preferred Subtitle Language")];
247     [o_osd_osd_box setTitle: _NS("On Screen Display")];
248     [o_osd_osd_ckb setTitle: _NS("Enable OSD")];
249     [o_osd_opacity_txt setStringValue: _NS("Opacity")];
250     [o_osd_forcebold_ckb setTitle: _NS("Force Bold")];
251     [o_osd_moreoptions_txt setStringValue: _NS("More options on background, shadow and outline are available in the advanced preferences.")];
252
253     /* video */
254     [o_video_black_ckb setTitle: _NS("Black screens in Fullscreen mode")];
255     [o_video_device_txt setStringValue: _NS("Fullscreen Video Device")];
256     [o_video_display_box setTitle: _NS("Display")];
257     [o_video_enable_ckb setTitle: _NS("Enable Video")];
258     [o_video_fullscreen_ckb setTitle: _NS("Fullscreen")];
259     [o_video_onTop_ckb setTitle: _NS("Always on top")];
260     [o_video_output_txt setStringValue: _NS("Output module")];
261     [o_video_skipFrames_ckb setTitle: _NS("Skip frames")];
262     [o_video_snap_box setTitle: _NS("Video snapshots")];
263     [o_video_snap_folder_btn setTitle: _NS("Browse...")];
264     [o_video_snap_folder_txt setStringValue: _NS("Folder")];
265     [o_video_snap_format_txt setStringValue: _NS("Format")];
266     [o_video_snap_prefix_txt setStringValue: _NS("Prefix")];
267     [o_video_snap_seqnum_ckb setTitle: _NS("Sequential numbering")];
268
269     /* generic stuff */
270     [[o_sprefs_basicFull_matrix cellAtRow: 0 column: 0] setTitle: _NS("Basic")];
271     [[o_sprefs_basicFull_matrix cellAtRow: 0 column: 1] setTitle: _NS("All")];
272     [o_sprefs_cancel_btn setTitle: _NS("Cancel")];
273     [o_sprefs_reset_btn setTitle: _NS("Reset All")];
274     [o_sprefs_save_btn setTitle: _NS("Save")];
275     [o_sprefs_win setTitle: _NS("Preferences")];
276 }
277
278 /* TODO: move this part to core */
279 #define config_GetLabel(a,b) __config_GetLabel(VLC_OBJECT(a),b)
280 static inline char * __config_GetLabel( vlc_object_t *p_this, const char *psz_name )
281 {
282     module_config_t *p_config;
283
284     p_config = config_FindConfig( p_this, psz_name );
285
286     /* sanity checks */
287     if( !p_config )
288     {
289         msg_Err( p_this, "option %s does not exist", psz_name );
290         return NULL;
291     }
292
293     if ( p_config->psz_longtext )
294         return p_config->psz_longtext;
295     else if( p_config->psz_text )
296         return p_config->psz_text;
297     else
298         msg_Warn( p_this, "option %s does not include any help", psz_name );
299
300     return NULL;
301 }
302
303 - (void)setupButton: (NSPopUpButton *)object forStringList: (const char *)name
304 {
305     module_config_t *p_item;
306
307     [object removeAllItems];
308     p_item = config_FindConfig( VLC_OBJECT(p_intf), name );
309
310     /* serious problem, if no item found */
311     assert( p_item );
312
313     for( int i = 0; i < p_item->i_list; i++ )
314     {
315         NSMenuItem *mi;
316         if( p_item->ppsz_list_text != NULL )
317             mi = [[NSMenuItem alloc] initWithTitle: _NS( p_item->ppsz_list_text[i] ) action:NULL keyEquivalent: @""];
318         else if( p_item->ppsz_list[i] && strcmp(p_item->ppsz_list[i],"") == 0 )
319         {
320             [[object menu] addItem: [NSMenuItem separatorItem]];
321             continue;
322         }
323         else if( p_item->ppsz_list[i] )
324             mi = [[NSMenuItem alloc] initWithTitle: [NSString stringWithUTF8String: p_item->ppsz_list[i]] action:NULL keyEquivalent: @""];
325         else
326             msg_Err( p_intf, "item %d of pref %s failed to be created", i, name );
327         [mi setRepresentedObject:[NSString stringWithUTF8String: p_item->ppsz_list[i]]];
328         [[object menu] addItem: [mi autorelease]];
329         if( p_item->value.psz && !strcmp( p_item->value.psz, p_item->ppsz_list[i] ) )
330             [object selectItem:[object lastItem]];
331     }
332     [object setToolTip: _NS( p_item->psz_longtext )];
333 }
334
335 - (void)setupButton: (NSPopUpButton *)object forIntList: (const char *)name
336 {
337     module_config_t *p_item;
338
339     [object removeAllItems];
340     p_item = config_FindConfig( VLC_OBJECT(p_intf), name );
341
342     /* serious problem, if no item found */
343     assert( p_item );
344
345     for( int i = 0; i < p_item->i_list; i++ )
346     {
347         NSMenuItem *mi;
348         if( p_item->ppsz_list_text != NULL)
349             mi = [[NSMenuItem alloc] initWithTitle: _NS( p_item->ppsz_list_text[i] ) action:NULL keyEquivalent: @""];
350         else if( p_item->pi_list[i] )
351             mi = [[NSMenuItem alloc] initWithTitle: [NSString stringWithFormat: @"%d", p_item->pi_list[i]] action:NULL keyEquivalent: @""];
352         else
353             msg_Err( p_intf, "item %d of pref %s failed to be created", i, name);
354         [mi setRepresentedObject:[NSNumber numberWithInt: p_item->pi_list[i]]];
355         [[object menu] addItem: [mi autorelease]];
356         if( p_item->value.i == p_item->pi_list[i] )
357             [object selectItem:[object lastItem]];
358     }
359     [object setToolTip: _NS( p_item->psz_longtext )];
360 }
361
362 - (void)setupButton: (NSPopUpButton *)object forModuleList: (const char *)name
363 {
364     module_config_t *p_item;
365     module_t *p_parser, **p_list;
366     int y = 0;
367
368     [object removeAllItems];
369
370     p_item = config_FindConfig( VLC_OBJECT(p_intf), name );
371     p_list = module_list_get( NULL );
372     if( !p_item ||!p_list )
373     {
374         if( p_list ) module_list_free(p_list);
375         msg_Err( p_intf, "serious problem, item or list not found" );
376         return;
377     }
378
379     [object addItemWithTitle: _NS("Default")];
380     for( size_t i_index = 0; p_list[i_index]; i_index++ )
381     {
382         p_parser = p_list[i_index];
383         if( module_provides( p_parser, p_item->psz_type ) )
384         {
385             [object addItemWithTitle: [NSString stringWithUTF8String: module_GetLongName( p_parser ) ?: ""]];
386             if( p_item->value.psz && !strcmp( p_item->value.psz, module_get_object( p_parser ) ) )
387                 [object selectItem: [object lastItem]];
388         }
389     }
390     module_list_free( p_list );
391     [object setToolTip: _NS(p_item->psz_longtext)];
392 }
393
394 - (void)setupButton: (NSButton *)object forBoolValue: (const char *)name
395 {
396     [object setState: config_GetInt( p_intf, name )];
397     [object setToolTip: [NSString stringWithUTF8String: config_GetLabel( p_intf, name )]];
398 }
399
400 - (void)setupField:(NSTextField *)o_object forOption:(const char *)psz_option
401 {
402     char *psz_tmp = config_GetPsz( p_intf, psz_option );
403     [o_object setStringValue: [NSString stringWithUTF8String: psz_tmp ?: ""]];
404     [o_object setToolTip: [NSString stringWithUTF8String: config_GetLabel( p_intf, psz_option )]];
405     free( psz_tmp );
406 }
407
408 - (void)resetControls
409 {
410     module_config_t *p_item;
411     int i, y = 0;
412     char *psz_tmp;
413
414     [[o_sprefs_basicFull_matrix cellAtRow:0 column:0] setState: NSOnState];
415     [[o_sprefs_basicFull_matrix cellAtRow:0 column:1] setState: NSOffState];
416
417     /**********************
418      * interface settings *
419      **********************/
420     [self setupButton: o_intf_lang_pop forStringList: "language"];
421     [self setupButton: o_intf_art_pop forIntList: "album-art"];
422
423     [self setupButton: o_intf_fspanel_ckb forBoolValue: "macosx-fspanel"];
424     [self setupButton: o_intf_embedded_ckb forBoolValue: "embedded-video"];
425         [self setupButton: o_intf_appleremote_ckb forBoolValue: "macosx-appleremote"];
426         [self setupButton: o_intf_mediakeys_ckb forBoolValue: "macosx-mediakeys"];
427     if( [[SUUpdater sharedUpdater] lastUpdateCheckDate] != NULL )
428         [o_intf_last_update_lbl setStringValue: [NSString stringWithFormat: _NS("Last check on: %@"), [[[SUUpdater sharedUpdater] lastUpdateCheckDate] descriptionWithLocale: [[NSUserDefaults standardUserDefaults] dictionaryRepresentation]]]];
429     else
430         [o_intf_last_update_lbl setStringValue: _NS("No check was performed yet.")];
431     psz_tmp = config_GetPsz( p_intf, "control" );
432     if (psz_tmp) {
433         [o_intf_enableGrowl_ckb setState: (NSInteger)strstr( psz_tmp, "growl")];
434         free( psz_tmp );
435     }
436     else
437         [o_intf_enableGrowl_ckb setState: NSOffState];
438     if (config_GetInt( p_intf, "macosx-interfacestyle" ))
439     {
440         [o_intf_style_dark_bcell setState: YES];
441         [o_intf_style_bright_bcell setState: NO];
442     }
443     else
444     {
445         [o_intf_style_dark_bcell setState: NO];
446         [o_intf_style_bright_bcell setState: YES];
447     }
448
449     /******************
450      * audio settings *
451      ******************/
452     [self setupButton: o_audio_enable_ckb forBoolValue: "audio"];
453     i = (config_GetInt( p_intf, "volume" ) * 0.390625);
454     [o_audio_vol_fld setToolTip: [NSString stringWithUTF8String: config_GetLabel( p_intf, "volume")]];
455     [o_audio_vol_fld setIntValue: i];
456     [o_audio_vol_sld setToolTip: [o_audio_vol_fld toolTip]];
457     [o_audio_vol_sld setIntValue: i];
458
459     [self setupButton: o_audio_spdif_ckb forBoolValue: "spdif"];
460
461     [self setupButton: o_audio_dolby_pop forIntList: "force-dolby-surround"];
462     [self setupField: o_audio_lang_fld forOption: "audio-language"];
463
464     [self setupButton: o_audio_visual_pop forModuleList: "audio-visual"];
465
466     /* Last.FM is optional */
467     if( module_exists( "audioscrobbler" ) )
468     {
469         [self setupField: o_audio_lastuser_fld forOption:"lastfm-username"];
470         [self setupField: o_audio_lastpwd_sfld forOption:"lastfm-password"];
471
472         if( config_ExistIntf( VLC_OBJECT( p_intf ), "audioscrobbler" ) )
473         {
474             [o_audio_last_ckb setState: NSOnState];
475             [o_audio_lastuser_fld setEnabled: YES];
476             [o_audio_lastpwd_sfld setEnabled: YES];
477         }
478         else
479         {
480             [o_audio_last_ckb setState: NSOffState];
481             [o_audio_lastuser_fld setEnabled: NO];
482             [o_audio_lastpwd_sfld setEnabled: NO];
483         }
484     }
485     else
486         [o_audio_last_ckb setEnabled: NO];
487
488     /******************
489      * video settings *
490      ******************/
491     [self setupButton: o_video_enable_ckb forBoolValue: "video"];
492     [self setupButton: o_video_fullscreen_ckb forBoolValue: "fullscreen"];
493     [self setupButton: o_video_onTop_ckb forBoolValue: "video-on-top"];
494     [self setupButton: o_video_skipFrames_ckb forBoolValue: "skip-frames"];
495     [self setupButton: o_video_black_ckb forBoolValue: "macosx-black"];
496
497     [self setupButton: o_video_output_pop forModuleList: "vout"];
498
499     [o_video_device_pop removeAllItems];
500     i = 0;
501     y = [[NSScreen screens] count];
502     [o_video_device_pop addItemWithTitle: _NS("Default")];
503     [[o_video_device_pop lastItem] setTag: 0];
504     while( i < y )
505     {
506         NSRect s_rect = [[[NSScreen screens] objectAtIndex: i] frame];
507         [o_video_device_pop addItemWithTitle:
508          [NSString stringWithFormat: @"%@ %i (%ix%i)", _NS("Screen"), i+1,
509                    (int)s_rect.size.width, (int)s_rect.size.height]];
510         [[o_video_device_pop lastItem] setTag: (int)[[[NSScreen screens] objectAtIndex: i] displayID]];
511         i++;
512     }
513     [o_video_device_pop selectItemAtIndex: 0];
514     [o_video_device_pop selectItemWithTag: config_GetInt( p_intf, "macosx-vdev" )];
515
516     [self setupField: o_video_snap_folder_fld forOption:"snapshot-path"];
517     [self setupField: o_video_snap_prefix_fld forOption:"snapshot-prefix"];
518     [self setupButton: o_video_snap_seqnum_ckb forBoolValue: "snapshot-sequential"];
519     [self setupButton: o_video_snap_format_pop forStringList: "snapshot-format"];
520
521     /***************************
522      * input & codecs settings *
523      ***************************/
524     [self setupField: o_input_httpproxy_fld forOption:"http-proxy"];
525     [self setupField: o_input_httpproxypwd_sfld forOption:"http-proxy-pwd"];
526     [o_input_postproc_fld setIntValue: config_GetInt( p_intf, "postproc-q")];
527     [o_input_postproc_fld setToolTip: [NSString stringWithUTF8String: config_GetLabel( p_intf, "postproc-q")]];
528
529     [self setupButton: o_input_avi_pop forIntList: "avi-index"];
530
531     [self setupButton: o_input_rtsp_ckb forBoolValue: "rtsp-tcp"];
532     [self setupButton: o_input_skipLoop_pop forIntList: "ffmpeg-skiploopfilter"];
533
534     [o_input_cachelevel_pop removeAllItems];
535     [o_input_cachelevel_pop addItemsWithTitles:
536         [NSArray arrayWithObjects: _NS("Custom"), _NS("Lowest latency"), _NS("Low latency"), _NS("Normal"),
537             _NS("High latency"), _NS("Higher latency"), nil]];
538     [[o_input_cachelevel_pop itemAtIndex: 0] setTag: 0];
539     [[o_input_cachelevel_pop itemAtIndex: 1] setTag: 100];
540     [[o_input_cachelevel_pop itemAtIndex: 2] setTag: 200];
541     [[o_input_cachelevel_pop itemAtIndex: 3] setTag: 300];
542     [[o_input_cachelevel_pop itemAtIndex: 4] setTag: 400];
543     [[o_input_cachelevel_pop itemAtIndex: 5] setTag: 500];
544
545 #define TestCaC( name ) \
546     b_cache_equal =  b_cache_equal && \
547         ( i_cache == config_GetInt( p_intf, name ) )
548
549 #define TestCaCi( name, int ) \
550         b_cache_equal = b_cache_equal &&  \
551         ( ( i_cache * int ) == config_GetInt( p_intf, name ) )
552
553     /* Select the accurate value of the PopupButton */
554     bool b_cache_equal = true;
555     int i_cache = config_GetInt( p_intf, "file-caching");
556
557     TestCaC( "udp-caching" );
558     if( module_exists ("dvdread") )
559         TestCaC( "dvdread-caching" );
560     if( module_exists ("dvdnav") )
561         TestCaC( "dvdnav-caching" );
562     TestCaC( "tcp-caching" );
563     TestCaC( "cdda-caching" );
564     TestCaC( "screen-caching" );
565     TestCaC( "vcd-caching" );
566     TestCaCi( "rtsp-caching", 4 );
567     TestCaCi( "ftp-caching", 2 );
568     TestCaCi( "http-caching", 4 );
569     if(module_exists ("access_realrtsp"))
570         TestCaCi( "realrtsp-caching", 10 );
571     TestCaCi( "mms-caching", 19 );
572     if( b_cache_equal )
573     {
574         [o_input_cachelevel_pop selectItemWithTag: i_cache];
575         [o_input_cachelevel_custom_txt setHidden: YES];
576     }
577     else
578     {
579         [o_input_cachelevel_pop selectItemWithTitle: _NS("Custom")];
580         [o_input_cachelevel_custom_txt setHidden: NO];
581     }
582
583     /*********************
584      * subtitle settings *
585      *********************/
586     [self setupButton: o_osd_osd_ckb forBoolValue: "osd"];
587
588     [self setupButton: o_osd_encoding_pop forStringList: "subsdec-encoding"];
589     [self setupField: o_osd_lang_fld forOption: "sub-language" ];
590
591     [self setupField: o_osd_font_fld forOption: "freetype-font"];
592     [self setupButton: o_osd_font_color_pop forIntList: "freetype-color"];
593     [self setupButton: o_osd_font_size_pop forIntList: "freetype-rel-fontsize"];
594     i = config_GetInt( p_intf, "freetype-opacity" );
595     [o_osd_opacity_fld setIntValue: i];
596     [o_osd_opacity_sld setIntValue: i];
597     [o_osd_opacity_sld setToolTip: [NSString stringWithUTF8String: config_GetLabel( p_intf, "freetype-opacity")]];
598     [o_osd_opacity_fld setToolTip: [o_osd_opacity_sld toolTip]];
599     [self setupButton: o_osd_forcebold_ckb forBoolValue: "freetype-bold"];
600
601     /********************
602      * hotkeys settings *
603      ********************/
604     const struct hotkey *p_hotkeys = p_intf->p_libvlc->p_hotkeys;
605     [o_hotkeySettings release];
606     o_hotkeySettings = [[NSMutableArray alloc] init];
607     NSMutableArray *o_tempArray_desc = [[NSMutableArray alloc] init];
608     NSMutableArray *o_tempArray_names = [[NSMutableArray alloc] init];
609
610     /* Get the main Module */
611     module_t *p_main = module_get_main();
612     assert( p_main );
613     unsigned confsize;
614     module_config_t *p_config;
615     
616     p_config = module_config_get (p_main, &confsize);
617     
618     for (size_t i = 0; i < confsize; i++)
619     {
620         module_config_t *p_item = p_config + i;
621
622         if( CONFIG_ITEM(p_item->i_type) && p_item->psz_name != NULL
623            && !strncmp( p_item->psz_name , "key-", 4 )
624            && !EMPTY_STR( p_item->psz_text ) )
625         {
626             [o_tempArray_desc addObject: _NS( p_item->psz_text )];
627             [o_tempArray_names addObject: [NSString stringWithUTF8String:p_item->psz_name]];
628             if (p_item->value.psz)
629                 [o_hotkeySettings addObject: [NSString stringWithUTF8String:p_item->value.psz]];
630             else
631                 [o_hotkeySettings addObject: [NSString string]];
632         }
633     }
634     module_config_free (p_config);
635     module_release (p_main);
636                   
637     [o_hotkeyDescriptions release];
638     o_hotkeyDescriptions = [[NSArray alloc] initWithArray: o_tempArray_desc copyItems: YES];
639     [o_tempArray_desc release];
640     [o_hotkeyNames release];
641     o_hotkeyNames = [[NSArray alloc] initWithArray: o_tempArray_names copyItems: YES];
642     [o_tempArray_names release];
643     [o_hotkeys_listbox reloadData];
644 }
645
646 - (void)showSimplePrefs
647 {
648     /* we want to show the interface settings, if no category was chosen */
649     if( [[o_sprefs_win toolbar] selectedItemIdentifier] == nil )
650     {
651         [[o_sprefs_win toolbar] setSelectedItemIdentifier: VLCIntfSettingToolbarIdentifier];
652         [self showInterfaceSettings];
653     }
654
655     [self resetControls];
656
657     [o_sprefs_win center];
658     [o_sprefs_win makeKeyAndOrderFront: self];
659 }
660
661 - (IBAction)buttonAction:(id)sender
662 {
663     if( sender == o_sprefs_cancel_btn )
664         [o_sprefs_win orderOut: sender];
665     else if( sender == o_sprefs_save_btn )
666     {
667         [self saveChangedSettings];
668         [o_sprefs_win orderOut: sender];
669     }
670     else if( sender == o_sprefs_reset_btn )
671         NSBeginInformationalAlertSheet( _NS("Reset Preferences"), _NS("Cancel"),
672                                         _NS("Continue"), nil, o_sprefs_win, self,
673                                         @selector(sheetDidEnd: returnCode: contextInfo:), NULL, nil,
674                                         _NS("Beware this will reset the VLC media player preferences.\n"
675                                             "Are you sure you want to continue?") );
676     else if( sender == o_sprefs_basicFull_matrix )
677     {
678         [o_sprefs_win orderOut: self];
679         [[o_sprefs_basicFull_matrix cellAtRow:0 column:0] setState: NSOffState];
680         [[o_sprefs_basicFull_matrix cellAtRow:0 column:1] setState: NSOnState];
681         [[[VLCMain sharedInstance] preferences] showPrefs];
682     }
683     else
684         msg_Warn( p_intf, "unknown buttonAction sender" );
685 }
686
687 - (void)sheetDidEnd:(NSWindow *)o_sheet
688          returnCode:(int)i_return
689         contextInfo:(void *)o_context
690 {
691     if( i_return == NSAlertAlternateReturn )
692     {
693         config_ResetAll( p_intf );
694         [self resetControls];
695         config_SaveConfigFile( p_intf );
696     }
697 }
698
699 static inline void save_int_list( intf_thread_t * p_intf, id object, const char * name )
700 {
701     NSNumber *p_valueobject;
702     module_config_t *p_item;
703     p_item = config_FindConfig( VLC_OBJECT(p_intf), name );
704     p_valueobject = (NSNumber *)[[object selectedItem] representedObject];
705     assert([p_valueobject isKindOfClass:[NSNumber class]]);
706     if( p_valueobject) config_PutInt( p_intf, name, [p_valueobject intValue] );
707 }
708
709 static inline void save_string_list( intf_thread_t * p_intf, id object, const char * name )
710 {
711     NSString *p_stringobject;
712     module_config_t *p_item;
713     p_item = config_FindConfig( VLC_OBJECT(p_intf), name );
714     p_stringobject = (NSString *)[[object selectedItem] representedObject];
715     assert([p_stringobject isKindOfClass:[NSString class]]);
716     if( p_stringobject )
717     {
718         config_PutPsz( p_intf, name, [p_stringobject UTF8String] );
719     }
720 }
721
722 static inline void save_module_list( intf_thread_t * p_intf, id object, const char * name )
723 {
724     module_config_t *p_item;
725     module_t *p_parser, **p_list;
726
727     p_item = config_FindConfig( VLC_OBJECT(p_intf), name );
728
729     p_list = module_list_get( NULL );
730     for( size_t i_module_index = 0; p_list[i_module_index]; i_module_index++ )
731     {
732         p_parser = p_list[i_module_index];
733
734         if( p_item->i_type == CONFIG_ITEM_MODULE && module_provides( p_parser, p_item->psz_type ) )
735         {
736             if( [[[object selectedItem] title] isEqualToString: _NS( module_GetLongName( p_parser ) )] )
737             {
738                 config_PutPsz( p_intf, name, strdup( module_get_object( p_parser )));
739                 break;
740             }
741         }
742     }
743     module_list_free( p_list );
744     if( [[[object selectedItem] title] isEqualToString: _NS( "Default" )] )
745         config_PutPsz( p_intf, name, "" );
746 }
747
748 - (void)saveChangedSettings
749 {
750     NSString *tmpString;
751     NSRange tmpRange;
752
753 #define SaveIntList( object, name ) save_int_list( p_intf, object, name )
754
755 #define SaveStringList( object, name ) save_string_list( p_intf, object, name )
756
757 #define SaveModuleList( object, name ) save_module_list( p_intf, object, name )
758
759 #define getString( name ) [NSString stringWithFormat:@"%s", config_GetPsz( p_intf, name )]
760
761     /**********************
762      * interface settings *
763      **********************/
764     if( b_intfSettingChanged )
765     {
766         SaveStringList( o_intf_lang_pop, "language" );
767         SaveIntList( o_intf_art_pop, "album-art" );
768
769         config_PutInt( p_intf, "macosx-fspanel", [o_intf_fspanel_ckb state] );
770         config_PutInt( p_intf, "embedded-video", [o_intf_embedded_ckb state] );
771                 config_PutInt( p_intf, "macosx-appleremote", [o_intf_appleremote_ckb state] );
772         config_PutInt( p_intf, "macosx-mediakeys", [o_intf_mediakeys_ckb state] );
773         config_PutInt( p_intf, "macosx-interfacestyle", [o_intf_style_dark_bcell state] );
774         if( [o_intf_enableGrowl_ckb state] == NSOnState )
775         {
776             tmpString = getString( "control" );
777             tmpRange = [tmpString rangeOfString:@"growl"];
778             if( [tmpString length] > 0 && tmpRange.location == NSNotFound )
779             {
780                 tmpString = [tmpString stringByAppendingString: @":growl"];
781                 config_PutPsz( p_intf, "control", [tmpString UTF8String] );
782             }
783             else
784                 config_PutPsz( p_intf, "control", "growl" );
785         }
786         else
787         {
788             tmpString = getString( "control" );
789             if(! [tmpString isEqualToString:@""] )
790             {
791                 tmpString = [tmpString stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:@":growl"]];
792                 tmpString = [tmpString stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:@"growl:"]];
793                 tmpString = [tmpString stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString:@"growl"]];
794                 config_PutPsz( p_intf, "control", [tmpString UTF8String] );
795             }
796         }
797
798                 /* activate stuff without restart */
799                 if( [o_intf_appleremote_ckb state] == YES )
800                         [[[VLCMain sharedInstance] appleRemoteController] startListening: [VLCMain sharedInstance]];
801                 else
802                         [[[VLCMain sharedInstance] appleRemoteController] stopListening: [VLCMain sharedInstance]];
803         b_intfSettingChanged = NO;
804     }
805
806     /******************
807      * audio settings *
808      ******************/
809     if( b_audioSettingChanged )
810     {
811         config_PutInt( p_intf, "audio", [o_audio_enable_ckb state] );
812         config_PutInt( p_intf, "volume", ([o_audio_vol_sld intValue] * 2.56));
813         config_PutInt( p_intf, "spdif", [o_audio_spdif_ckb state] );
814
815         SaveIntList( o_audio_dolby_pop, "force-dolby-surround" );
816
817         config_PutPsz( p_intf, "audio-language", [[o_audio_lang_fld stringValue] UTF8String] );
818
819         SaveModuleList( o_audio_visual_pop, "audio-visual" );
820
821         /* Last.FM is optional */
822         if( module_exists( "audioscrobbler" ) )
823         {
824             [o_audio_last_ckb setEnabled: YES];
825             if( [o_audio_last_ckb state] == NSOnState )
826                 config_AddIntf( p_intf, "audioscrobbler" );
827             else
828                 config_RemoveIntf( p_intf, "audioscrobbler" );
829
830             config_PutPsz( p_intf, "lastfm-username", [[o_audio_lastuser_fld stringValue] UTF8String] );
831             config_PutPsz( p_intf, "lastfm-password", [[o_audio_lastpwd_sfld stringValue] UTF8String] );
832         }
833         else
834             [o_audio_last_ckb setEnabled: NO];
835         b_audioSettingChanged = NO;
836     }
837
838     /******************
839      * video settings *
840      ******************/
841     if( b_videoSettingChanged )
842     {
843         config_PutInt( p_intf, "video", [o_video_enable_ckb state] );
844         config_PutInt( p_intf, "fullscreen", [o_video_fullscreen_ckb state] );
845         config_PutInt( p_intf, "video-on-top", [o_video_onTop_ckb state] );
846         config_PutInt( p_intf, "skip-frames", [o_video_skipFrames_ckb state] );
847         config_PutInt( p_intf, "macosx-black", [o_video_black_ckb state] );
848
849         SaveModuleList( o_video_output_pop, "vout" );
850         config_PutInt( p_intf, "macosx-vdev", [[o_video_device_pop selectedItem] tag] );
851
852         config_PutPsz( p_intf, "snapshot-path", [[o_video_snap_folder_fld stringValue] UTF8String] );
853         config_PutPsz( p_intf, "snapshot-prefix", [[o_video_snap_prefix_fld stringValue] UTF8String] );
854         config_PutInt( p_intf, "snapshot-sequential", [o_video_snap_seqnum_ckb state] );
855         SaveStringList( o_video_snap_format_pop, "snapshot-format" );
856         b_videoSettingChanged = NO;
857     }
858
859     /***************************
860      * input & codecs settings *
861      ***************************/
862     if( b_inputSettingChanged )
863     {
864         config_PutPsz( p_intf, "http-proxy", [[o_input_httpproxy_fld stringValue] UTF8String] );
865         config_PutPsz( p_intf, "http-proxy-pwd", [[o_input_httpproxypwd_sfld stringValue] UTF8String] );
866         config_PutInt( p_intf, "postproc-q", [o_input_postproc_fld intValue] );
867
868         SaveIntList( o_input_avi_pop, "avi-index" );
869
870         config_PutInt( p_intf, "rtsp-tcp", [o_input_rtsp_ckb state] );
871         SaveIntList( o_input_skipLoop_pop, "ffmpeg-skiploopfilter" );
872
873         #define CaCi( name, int ) config_PutInt( p_intf, name, int * [[o_input_cachelevel_pop selectedItem] tag] )
874         #define CaC( name ) CaCi( name, 1 )
875         msg_Dbg( p_intf, "Adjusting all cache values to: %i", (int)[[o_input_cachelevel_pop selectedItem] tag] );
876         CaC( "udp-caching" );
877         if( module_exists ( "dvdread" ) )
878             CaC( "dvdread-caching" );
879         if( module_exists ( "dvdnav" ) )
880             CaC( "dvdnav-caching" );
881         CaC( "tcp-caching" ); CaC( "vcd-caching" );
882         CaC( "cdda-caching" ); CaC( "file-caching" );
883         CaC( "screen-caching" );
884         CaCi( "rtsp-caching", 4 ); CaCi( "ftp-caching", 2 );
885         CaCi( "http-caching", 4 );
886         if( module_exists ( "access_realrtsp" ) )
887             CaCi( "realrtsp-caching", 10 );
888         CaCi( "mms-caching", 19 );
889         b_inputSettingChanged = NO;
890     }
891
892     /**********************
893      * subtitles settings *
894      **********************/
895     if( b_osdSettingChanged )
896     {
897         config_PutInt( p_intf, "osd", [o_osd_osd_ckb state] );
898
899         if( [o_osd_encoding_pop indexOfSelectedItem] >= 0 )
900             SaveStringList( o_osd_encoding_pop, "subsdec-encoding" );
901         else
902             config_PutPsz( p_intf, "subsdec-encoding", "" );
903
904         config_PutPsz( p_intf, "sub-language", [[o_osd_lang_fld stringValue] UTF8String] );
905
906         config_PutPsz( p_intf, "freetype-font", [[o_osd_font_fld stringValue] UTF8String] );
907         SaveIntList( o_osd_font_color_pop, "freetype-color" );
908         SaveIntList( o_osd_font_size_pop, "freetype-rel-fontsize" );
909         config_PutInt( p_intf, "freetype-opacity", [o_osd_opacity_sld intValue] );
910         config_PutInt( p_intf, "freetype-bold", [o_osd_forcebold_ckb state] );
911         b_osdSettingChanged = NO;
912     }
913
914     /********************
915      * hotkeys settings *
916      ********************/
917     if( b_hotkeyChanged )
918     {
919         NSUInteger hotKeyCount = [o_hotkeySettings count];
920         for( NSUInteger i = 0; i < hotKeyCount; i++ )
921             config_PutPsz( p_intf, [[o_hotkeyNames objectAtIndex:i] UTF8String], [[o_hotkeySettings objectAtIndex:i]UTF8String] );
922         b_hotkeyChanged = NO;
923     }
924
925     /* okay, let's save our changes to vlcrc */
926     config_SaveConfigFile( p_intf );
927
928     [[NSNotificationCenter defaultCenter] postNotificationName: @"VLCMediaKeySupportSettingChanged"
929                                                             object: nil
930                                                           userInfo: nil];
931 }
932
933 - (void)showSettingsForCategory: (id)o_new_category_view
934 {
935     NSRect o_win_rect, o_view_rect, o_old_view_rect;
936     o_win_rect = [o_sprefs_win frame];
937     o_view_rect = [o_new_category_view frame];
938
939     if( o_currentlyShownCategoryView != nil )
940     {
941         /* restore our window's height, if we've shown another category previously */
942         o_old_view_rect = [o_currentlyShownCategoryView frame];
943         o_win_rect.size.height = o_win_rect.size.height - o_old_view_rect.size.height;
944         o_win_rect.origin.y = ( o_win_rect.origin.y + o_old_view_rect.size.height ) - o_view_rect.size.height;
945     }
946
947     o_win_rect.size.height = o_win_rect.size.height + o_view_rect.size.height;
948
949     [o_new_category_view setFrame: NSMakeRect( 0,
950                                                [o_sprefs_controls_box frame].size.height,
951                                                o_view_rect.size.width,
952                                                o_view_rect.size.height )];
953     [o_new_category_view setAutoresizesSubviews: YES];
954     if (o_currentlyShownCategoryView)
955     {
956         [[[o_sprefs_win contentView] animator] replaceSubview: o_currentlyShownCategoryView with: o_new_category_view];
957         [o_currentlyShownCategoryView release];
958         [[o_sprefs_win animator] setFrame: o_win_rect display:YES];
959     }
960     else
961     {
962         [[o_sprefs_win contentView] addSubview: o_new_category_view];
963         [o_sprefs_win setFrame: o_win_rect display:YES animate:NO];
964     }
965
966     /* keep our current category for further reference */
967     o_currentlyShownCategoryView = o_new_category_view;
968     [o_currentlyShownCategoryView retain];
969 }
970
971 - (IBAction)interfaceSettingChanged:(id)sender
972 {
973     b_intfSettingChanged = YES;
974 }
975
976 - (void)showInterfaceSettings
977 {
978     [self showSettingsForCategory: o_intf_view];
979 }
980
981 - (IBAction)audioSettingChanged:(id)sender
982 {
983     if( sender == o_audio_vol_sld )
984         [o_audio_vol_fld setIntValue: [o_audio_vol_sld intValue]];
985
986     if( sender == o_audio_vol_fld )
987         [o_audio_vol_sld setIntValue: [o_audio_vol_fld intValue]];
988
989     if( sender == o_audio_last_ckb )
990     {
991         if( [o_audio_last_ckb state] == NSOnState )
992         {
993             [o_audio_lastpwd_sfld setEnabled: YES];
994             [o_audio_lastuser_fld setEnabled: YES];
995         }
996         else
997         {
998             [o_audio_lastpwd_sfld setEnabled: NO];
999             [o_audio_lastuser_fld setEnabled: NO];
1000         }
1001     }
1002
1003     b_audioSettingChanged = YES;
1004 }
1005
1006 - (void)showAudioSettings
1007 {
1008     [self showSettingsForCategory: o_audio_view];
1009 }
1010
1011 - (IBAction)videoSettingChanged:(id)sender
1012 {
1013     if( sender == o_video_snap_folder_btn )
1014     {
1015         o_selectFolderPanel = [[NSOpenPanel alloc] init];
1016         [o_selectFolderPanel setCanChooseDirectories: YES];
1017         [o_selectFolderPanel setCanChooseFiles: NO];
1018         [o_selectFolderPanel setResolvesAliases: YES];
1019         [o_selectFolderPanel setAllowsMultipleSelection: NO];
1020         [o_selectFolderPanel setMessage: _NS("Choose the folder to save your video snapshots to.")];
1021         [o_selectFolderPanel setCanCreateDirectories: YES];
1022         [o_selectFolderPanel setPrompt: _NS("Choose")];
1023         [o_selectFolderPanel beginSheetForDirectory: nil file: nil modalForWindow: o_sprefs_win
1024                                       modalDelegate: self
1025                                      didEndSelector: @selector(savePanelDidEnd:returnCode:contextInfo:)
1026                                         contextInfo: o_video_snap_folder_btn];
1027     }
1028     else
1029         b_videoSettingChanged = YES;
1030 }
1031
1032 - (void)savePanelDidEnd:(NSOpenPanel * )panel returnCode: (int)returnCode contextInfo: (void *)contextInfo
1033 {
1034     if( returnCode == NSOKButton )
1035     {
1036         if( contextInfo == o_video_snap_folder_btn )
1037         {
1038             [o_video_snap_folder_fld setStringValue: [[o_selectFolderPanel URL] path]];
1039             b_videoSettingChanged = YES;
1040         }
1041     }
1042
1043     [o_selectFolderPanel release];
1044 }
1045
1046 - (void)showVideoSettings
1047 {
1048     [self showSettingsForCategory: o_video_view];
1049 }
1050
1051 - (IBAction)osdSettingChanged:(id)sender
1052 {
1053     if( sender == o_osd_opacity_fld )
1054         [o_osd_opacity_sld setIntValue: [o_osd_opacity_fld intValue]];
1055
1056     if( sender == o_osd_opacity_sld )
1057         [o_osd_opacity_fld setIntValue: [o_osd_opacity_sld intValue]];
1058
1059     b_osdSettingChanged = YES;
1060 }
1061
1062 - (void)showOSDSettings
1063 {
1064     [self showSettingsForCategory: o_osd_view];
1065 }
1066
1067 - (IBAction)showFontPicker:(id)sender
1068 {
1069     char * font = config_GetPsz( p_intf, "freetype-font" );
1070     NSString * fontFamilyName = font ? [NSString stringWithUTF8String: font] : nil;
1071     free(font);
1072     if( fontFamilyName )
1073     {
1074         NSFontDescriptor * fd = [NSFontDescriptor fontDescriptorWithFontAttributes:nil];
1075         NSFont * font = [NSFont fontWithDescriptor:[fd fontDescriptorWithFamily:fontFamilyName] textTransform:nil];
1076         [[NSFontManager sharedFontManager] setSelectedFont:font isMultiple:NO];
1077     }
1078     [[NSFontManager sharedFontManager] setTarget: self];
1079     [[NSFontPanel sharedFontPanel] orderFront:self];
1080 }
1081
1082 - (void)changeFont:(id)sender
1083 {
1084     NSFont * font = [sender convertFont:[[NSFontManager sharedFontManager] selectedFont]];
1085     [o_osd_font_fld setStringValue:[font familyName]];
1086     [self osdSettingChanged:self];
1087 }
1088
1089 - (IBAction)inputSettingChanged:(id)sender
1090 {
1091     if( sender == o_input_cachelevel_pop )
1092     {
1093         if( [[[o_input_cachelevel_pop selectedItem] title] isEqualToString: _NS("Custom")] )
1094             [o_input_cachelevel_custom_txt setHidden: NO];
1095         else
1096             [o_input_cachelevel_custom_txt setHidden: YES];
1097     }
1098
1099     b_inputSettingChanged = YES;
1100 }
1101
1102 - (void)showInputSettings
1103 {
1104     [self showSettingsForCategory: o_input_view];
1105 }
1106
1107 - (IBAction)hotkeySettingChanged:(id)sender
1108 {
1109     if( sender == o_hotkeys_change_btn || sender == o_hotkeys_listbox )
1110     {
1111         [o_hotkeys_change_lbl setStringValue: [NSString stringWithFormat: _NS("Press new keys for\n\"%@\""),
1112                                                [o_hotkeyDescriptions objectAtIndex: [o_hotkeys_listbox selectedRow]]]];
1113         [o_hotkeys_change_keys_lbl setStringValue: [self OSXStringKeyToString:[o_hotkeySettings objectAtIndex: [o_hotkeys_listbox selectedRow]]]];
1114         [o_hotkeys_change_taken_lbl setStringValue: @""];
1115         [o_hotkeys_change_win setInitialFirstResponder: [o_hotkeys_change_win contentView]];
1116         [o_hotkeys_change_win makeFirstResponder: [o_hotkeys_change_win contentView]];
1117         [NSApp runModalForWindow: o_hotkeys_change_win];
1118     }
1119     else if( sender == o_hotkeys_change_cancel_btn )
1120     {
1121         [NSApp stopModal];
1122         [o_hotkeys_change_win close];
1123     }
1124     else if( sender == o_hotkeys_change_ok_btn )
1125     {
1126         NSInteger i_returnValue;
1127         if(! o_keyInTransition )
1128         {
1129             [NSApp stopModal];
1130             [o_hotkeys_change_win close];
1131             msg_Err( p_intf, "internal error prevented the hotkey switch" );
1132             return;
1133         }
1134
1135         b_hotkeyChanged = YES;
1136
1137         i_returnValue = [o_hotkeySettings indexOfObject: o_keyInTransition];
1138         if( i_returnValue != NSNotFound )
1139             [o_hotkeySettings replaceObjectAtIndex: i_returnValue withObject: [NSString string]];
1140         NSString *tempString;
1141         tempString = [o_keyInTransition stringByReplacingOccurrencesOfString:@"-" withString:@"+"];
1142         i_returnValue = [o_hotkeySettings indexOfObject: tempString];
1143         if( i_returnValue != NSNotFound )
1144             [o_hotkeySettings replaceObjectAtIndex: i_returnValue withObject: [NSString string]];
1145
1146         [o_hotkeySettings replaceObjectAtIndex: [o_hotkeys_listbox selectedRow] withObject: [o_keyInTransition retain]];
1147
1148         [NSApp stopModal];
1149         [o_hotkeys_change_win close];
1150
1151         [o_hotkeys_listbox reloadData];
1152     }
1153     else if( sender == o_hotkeys_clear_btn )
1154     {
1155         [o_hotkeySettings replaceObjectAtIndex: [o_hotkeys_listbox selectedRow] withObject: [NSString string]];
1156         [o_hotkeys_listbox reloadData];
1157         b_hotkeyChanged = YES;
1158     }
1159
1160     [[NSNotificationCenter defaultCenter] postNotificationName: @"VLCMediaKeySupportSettingChanged"
1161                                                         object: nil
1162                                                       userInfo: nil];
1163 }
1164
1165 - (void)showHotkeySettings
1166 {
1167     [self showSettingsForCategory: o_hotkeys_view];
1168 }
1169
1170 - (int)numberOfRowsInTableView:(NSTableView *)aTableView
1171 {
1172     return [o_hotkeySettings count];
1173 }
1174
1175 - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex
1176 {
1177     if( [[aTableColumn identifier] isEqualToString: @"action"] )
1178         return [o_hotkeyDescriptions objectAtIndex: rowIndex];
1179     else if( [[aTableColumn identifier] isEqualToString: @"shortcut"] )
1180         return [self OSXStringKeyToString:[o_hotkeySettings objectAtIndex: rowIndex]];
1181     else
1182     {
1183         msg_Err( p_intf, "unknown TableColumn identifier (%s)!", [[aTableColumn identifier] UTF8String] );
1184         return NULL;
1185     }
1186 }
1187
1188 - (BOOL)changeHotkeyTo: (NSString *)theKey
1189 {
1190     NSInteger i_returnValue, i_returnValue2;
1191     i_returnValue = [o_hotkeysNonUseableKeys indexOfObject: theKey];
1192
1193     if( i_returnValue != NSNotFound || [theKey isEqualToString:@""] )
1194     {
1195         [o_hotkeys_change_keys_lbl setStringValue: _NS("Invalid combination")];
1196         [o_hotkeys_change_taken_lbl setStringValue: _NS("Regrettably, these keys cannot be assigned as hotkey shortcuts.")];
1197         [o_hotkeys_change_ok_btn setEnabled: NO];
1198         return NO;
1199     }
1200     else
1201     {
1202         [o_hotkeys_change_keys_lbl setStringValue: [self OSXStringKeyToString:theKey]];
1203
1204         i_returnValue = [o_hotkeySettings indexOfObject: theKey];
1205         i_returnValue2 = [o_hotkeySettings indexOfObject: [theKey stringByReplacingOccurrencesOfString:@"-" withString:@"+"]];
1206         if( i_returnValue != NSNotFound )
1207             [o_hotkeys_change_taken_lbl setStringValue: [NSString stringWithFormat:
1208                                                          _NS("This combination is already taken by \"%@\"."),
1209                                                          [o_hotkeyDescriptions objectAtIndex: i_returnValue]]];
1210         else if( i_returnValue2 != NSNotFound )
1211             [o_hotkeys_change_taken_lbl setStringValue: [NSString stringWithFormat:
1212                                                          _NS("This combination is already taken by \"%@\"."),
1213                                                          [o_hotkeyDescriptions objectAtIndex: i_returnValue2]]];
1214         
1215         else
1216             [o_hotkeys_change_taken_lbl setStringValue: @""];
1217
1218         [o_hotkeys_change_ok_btn setEnabled: YES];
1219         [o_keyInTransition release];
1220         o_keyInTransition = theKey;
1221         [o_keyInTransition retain];
1222         return YES;
1223     }
1224 }
1225
1226 @end
1227
1228 /********************
1229  * hotkeys settings *
1230  ********************/
1231
1232 @implementation VLCHotkeyChangeWindow
1233
1234 - (BOOL)acceptsFirstResponder
1235 {
1236     return YES;
1237 }
1238
1239 - (BOOL)becomeFirstResponder
1240 {
1241     return YES;
1242 }
1243
1244 - (BOOL)resignFirstResponder
1245 {
1246     /* We need to stay the first responder or we'll miss the user's input */
1247     return NO;
1248 }
1249
1250 - (BOOL)performKeyEquivalent:(NSEvent *)o_theEvent
1251 {
1252     NSMutableString *tempString = [[[NSMutableString alloc] init] autorelease];
1253     if( [o_theEvent modifierFlags] & NSControlKeyMask )
1254         [tempString appendString:@"Ctrl-"];
1255     
1256     if( [o_theEvent modifierFlags] & NSAlternateKeyMask  )
1257         [tempString appendString:@"Alt-"];
1258     
1259     if( [o_theEvent modifierFlags] & NSShiftKeyMask )
1260         [tempString appendString:@"Shift-"];
1261     
1262     if( [o_theEvent modifierFlags] & NSCommandKeyMask )
1263         [tempString appendString:@"Command-"];
1264
1265     if (![[[o_theEvent charactersIgnoringModifiers] lowercaseString] isEqualToString:@""]) {
1266         [tempString appendString:[[o_theEvent charactersIgnoringModifiers] lowercaseString]];
1267             return [[[VLCMain sharedInstance] simplePreferences] changeHotkeyTo: tempString];
1268     }
1269     return NO;
1270 }
1271
1272 @end
1273
1274 @implementation VLCSimplePrefsWindow
1275
1276 - (BOOL)acceptsFirstResponder
1277 {
1278     return YES;
1279 }
1280
1281 - (void)changeFont:(id)sender
1282 {
1283     [[[VLCMain sharedInstance] simplePreferences] changeFont: sender];
1284 }
1285 @end