]> git.sesse.net Git - vlc/blob - modules/gui/macosx/prefs_widgets.m
macosx: robustify media key trap handling
[vlc] / modules / gui / macosx / prefs_widgets.m
1 /*****************************************************************************
2  * prefs_widgets.m: Preferences controls
3  *****************************************************************************
4  * Copyright (C) 2002-2012 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Derk-Jan Hartman <hartman at videolan.org>
8  *          Jérôme Decoodt <djc at videolan.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <stdlib.h>                                      /* malloc(), free() */
29 #include <string.h>
30
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
34
35 #include <vlc_common.h>
36 #include <vlc_modules.h>
37 #include <vlc_plugin.h>
38 #include <vlc_keys.h>
39
40 #include "intf.h"
41 #include "prefs_widgets.h"
42
43 #define PREFS_WRAP 300
44 #define OFFSET_RIGHT 20
45 #define OFFSET_BETWEEN 2
46
47 #define UPWARDS_WHITE_ARROW                 "\xE2\x87\xA7"
48 #define OPTION_KEY                          "\xE2\x8C\xA5"
49 #define UP_ARROWHEAD                        "\xE2\x8C\x83"
50 #define PLACE_OF_INTEREST_SIGN              "\xE2\x8C\x98"
51
52 #define POPULATE_A_KEY(o_menu, string, value)                               \
53 {                                                                           \
54     NSMenuItem *o_mi;                                                       \
55 /*  Normal */                                                               \
56     o_mi = [[NSMenuItem alloc] initWithTitle:string                         \
57         action:nil keyEquivalent:@""];                                      \
58     [o_mi setKeyEquivalentModifierMask:                                     \
59         0];                                                                 \
60     [o_mi setAlternate: NO];                                                \
61     [o_mi setTag:                                                           \
62         (value)];                                                           \
63     [o_menu addItem: o_mi];                                                 \
64 /*  Ctrl */                                                                 \
65     o_mi = [[NSMenuItem alloc] initWithTitle:                               \
66         [[NSString stringWithUTF8String:UP_ARROWHEAD]                       \
67           stringByAppendingString: string]                                  \
68         action:nil keyEquivalent:@""];                                      \
69     [o_mi setKeyEquivalentModifierMask:                                     \
70         NSControlKeyMask];                                                  \
71     [o_mi setAlternate: YES];                                               \
72     [o_mi setTag:                                                           \
73         KEY_MODIFIER_CTRL | (value)];                                       \
74     [o_menu addItem: o_mi];                                                 \
75 /* Ctrl+Alt */                                                              \
76     o_mi = [[NSMenuItem alloc] initWithTitle:                               \
77         [[NSString stringWithUTF8String:UP_ARROWHEAD OPTION_KEY]            \
78           stringByAppendingString: string]                                  \
79         action:nil keyEquivalent:@""];                                      \
80     [o_mi setKeyEquivalentModifierMask:                                     \
81         NSControlKeyMask | NSAlternateKeyMask];                             \
82     [o_mi setAlternate: YES];                                               \
83     [o_mi setTag:                                                           \
84         (KEY_MODIFIER_CTRL | KEY_MODIFIER_ALT) | (value)];                  \
85     [o_menu addItem: o_mi];                                                 \
86 /* Ctrl+Shift */                                                            \
87     o_mi = [[NSMenuItem alloc] initWithTitle:                               \
88         [[NSString stringWithUTF8String:UP_ARROWHEAD UPWARDS_WHITE_ARROW]   \
89           stringByAppendingString: string]                                  \
90         action:nil keyEquivalent:@""];                                      \
91     [o_mi setKeyEquivalentModifierMask:                                     \
92        NSControlKeyMask | NSShiftKeyMask];                                  \
93     [o_mi setAlternate: YES];                                               \
94     [o_mi setTag:                                                           \
95         (KEY_MODIFIER_CTRL | KEY_MODIFIER_SHIFT) | (value)];                \
96     [o_menu addItem: o_mi];                                                 \
97 /* Ctrl+Apple */                                                            \
98     o_mi = [[NSMenuItem alloc] initWithTitle:                               \
99         [[NSString stringWithUTF8String:UP_ARROWHEAD PLACE_OF_INTEREST_SIGN]\
100           stringByAppendingString: string]                                  \
101         action:nil keyEquivalent:@""];                                      \
102     [o_mi setKeyEquivalentModifierMask:                                     \
103         NSControlKeyMask | NSCommandKeyMask];                               \
104     [o_mi setAlternate: YES];                                               \
105     [o_mi setTag:                                                           \
106         (KEY_MODIFIER_CTRL | KEY_MODIFIER_COMMAND) | (value)];              \
107     [o_menu addItem: o_mi];                                                 \
108 /* Ctrl+Alt+Shift */                                                        \
109     o_mi = [[NSMenuItem alloc] initWithTitle:                               \
110         [[NSString stringWithUTF8String:UP_ARROWHEAD OPTION_KEY UPWARDS_WHITE_ARROW] \
111           stringByAppendingString: string]                                  \
112         action:nil keyEquivalent:@""];                                      \
113     [o_mi setKeyEquivalentModifierMask:                                     \
114         NSControlKeyMask | NSAlternateKeyMask | NSShiftKeyMask];            \
115     [o_mi setAlternate: YES];                                               \
116     [o_mi setTag:                                                           \
117         (KEY_MODIFIER_CTRL | KEY_MODIFIER_ALT | KEY_MODIFIER_SHIFT) |       \
118              (value)];                                                      \
119     [o_menu addItem: o_mi];                                                 \
120 /* Ctrl+Alt+Apple */                                                        \
121     o_mi = [[NSMenuItem alloc] initWithTitle:                               \
122         [[NSString stringWithUTF8String:UP_ARROWHEAD OPTION_KEY PLACE_OF_INTEREST_SIGN] \
123           stringByAppendingString: string]                                  \
124         action:nil keyEquivalent:@""];                                      \
125     [o_mi setKeyEquivalentModifierMask:                                     \
126         NSControlKeyMask | NSAlternateKeyMask | NSCommandKeyMask];          \
127     [o_mi setAlternate: YES];                                               \
128     [o_mi setTag:                                                           \
129         (KEY_MODIFIER_CTRL | KEY_MODIFIER_ALT | KEY_MODIFIER_COMMAND) |     \
130             (value)];                                                       \
131     [o_menu addItem: o_mi];                                                 \
132 /* Ctrl+Shift+Apple */                                                      \
133     o_mi = [[NSMenuItem alloc] initWithTitle:                               \
134         [[NSString stringWithUTF8String:UP_ARROWHEAD UPWARDS_WHITE_ARROW PLACE_OF_INTEREST_SIGN] \
135           stringByAppendingString: string]                                  \
136         action:nil keyEquivalent:@""];                                      \
137     [o_mi setKeyEquivalentModifierMask:                                     \
138         NSControlKeyMask | NSShiftKeyMask | NSCommandKeyMask];              \
139     [o_mi setAlternate: YES];                                               \
140     [o_mi setTag:                                                           \
141         (KEY_MODIFIER_CTRL | KEY_MODIFIER_SHIFT | KEY_MODIFIER_COMMAND) |   \
142             (value)];                                                       \
143     [o_menu addItem: o_mi];                                                 \
144 /* Ctrl+Alt+Shift+Apple */                                                  \
145     o_mi = [[NSMenuItem alloc] initWithTitle:                               \
146         [[NSString stringWithUTF8String:UP_ARROWHEAD OPTION_KEY UPWARDS_WHITE_ARROW PLACE_OF_INTEREST_SIGN] \
147          stringByAppendingString: string]                                  \
148         action:nil keyEquivalent:@""];                                      \
149     [o_mi setKeyEquivalentModifierMask:                                     \
150         NSControlKeyMask | NSAlternateKeyMask | NSShiftKeyMask |            \
151             NSCommandKeyMask];                                              \
152     [o_mi setAlternate: YES];                                               \
153     [o_mi setTag:                                                           \
154         (KEY_MODIFIER_CTRL | KEY_MODIFIER_ALT | KEY_MODIFIER_SHIFT |        \
155             KEY_MODIFIER_COMMAND) | (value)];                               \
156     [o_menu addItem: o_mi];                                                 \
157 /* Alt */                                                                   \
158     o_mi = [[NSMenuItem alloc] initWithTitle:                               \
159         [[NSString stringWithUTF8String:OPTION_KEY] stringByAppendingString: string] \
160         action:nil keyEquivalent:@""];                                      \
161     [o_mi setKeyEquivalentModifierMask:                                     \
162         NSAlternateKeyMask];                                                \
163     [o_mi setAlternate: YES];                                               \
164     [o_mi setTag:                                                           \
165         KEY_MODIFIER_ALT | (value)];                                        \
166     [o_menu addItem: o_mi];                                                 \
167 /* Alt+Shift */                                                             \
168     o_mi = [[NSMenuItem alloc] initWithTitle:                               \
169         [[NSString stringWithUTF8String:OPTION_KEY UPWARDS_WHITE_ARROW] stringByAppendingString: string] \
170         action:nil keyEquivalent:@""];                                      \
171     [o_mi setKeyEquivalentModifierMask:                                     \
172         NSAlternateKeyMask | NSShiftKeyMask];                               \
173     [o_mi setAlternate: YES];                                               \
174     [o_mi setTag:                                                           \
175         (KEY_MODIFIER_ALT | KEY_MODIFIER_SHIFT) | (value)];                 \
176     [o_menu addItem: o_mi];                                                 \
177 /* Alt+Apple */                                                             \
178     o_mi = [[NSMenuItem alloc] initWithTitle:                               \
179         [[NSString stringWithUTF8String:OPTION_KEY PLACE_OF_INTEREST_SIGN]  \
180          stringByAppendingString: string] action:nil keyEquivalent:@""];    \
181     [o_mi setKeyEquivalentModifierMask:                                     \
182         NSAlternateKeyMask | NSCommandKeyMask];                             \
183     [o_mi setAlternate: YES];                                               \
184     [o_mi setTag:                                                           \
185         (KEY_MODIFIER_ALT | KEY_MODIFIER_COMMAND) | (value)];               \
186     [o_menu addItem: o_mi];                                                 \
187 /* Alt+Shift+Apple */                                                       \
188     o_mi = [[NSMenuItem alloc] initWithTitle:                               \
189         [[NSString stringWithUTF8String:OPTION_KEY UPWARDS_WHITE_ARROW PLACE_OF_INTEREST_SIGN] \
190           stringByAppendingString: string]                                  \
191         action:nil keyEquivalent:@""];                                      \
192     [o_mi setKeyEquivalentModifierMask:                                     \
193         NSAlternateKeyMask | NSShiftKeyMask | NSCommandKeyMask];            \
194     [o_mi setAlternate: YES];                                               \
195     [o_mi setTag:                                                           \
196         (KEY_MODIFIER_ALT | KEY_MODIFIER_SHIFT | KEY_MODIFIER_COMMAND) |    \
197             (value)];                                                       \
198     [o_menu addItem: o_mi];                                                 \
199 /* Shift */                                                                 \
200     o_mi = [[NSMenuItem alloc] initWithTitle:                               \
201         [[NSString stringWithUTF8String:UPWARDS_WHITE_ARROW]                \
202           stringByAppendingString: string]                                  \
203         action:nil keyEquivalent:@""];                                      \
204     [o_mi setKeyEquivalentModifierMask:                                     \
205         NSShiftKeyMask];                                                    \
206     [o_mi setAlternate: YES];                                               \
207     [o_mi setTag:                                                           \
208         KEY_MODIFIER_SHIFT | (value)];                                      \
209     [o_menu addItem: o_mi];                                                 \
210 /* Shift+Apple */                                                           \
211     o_mi = [[NSMenuItem alloc] initWithTitle:                               \
212         [[NSString stringWithUTF8String:UPWARDS_WHITE_ARROW PLACE_OF_INTEREST_SIGN] \
213          stringByAppendingString: string]                                   \
214         action:nil keyEquivalent:@""];                                      \
215     [o_mi setKeyEquivalentModifierMask:                                     \
216         NSShiftKeyMask | NSCommandKeyMask];                                 \
217     [o_mi setAlternate: YES];                                               \
218     [o_mi setTag:                                                           \
219         (KEY_MODIFIER_SHIFT | KEY_MODIFIER_COMMAND) | (value)];             \
220     [o_menu addItem: o_mi];                                                 \
221 /* Apple */                                                                 \
222     o_mi = [[NSMenuItem alloc] initWithTitle:                               \
223         [[NSString stringWithUTF8String:PLACE_OF_INTEREST_SIGN]             \
224           stringByAppendingString: string]                                  \
225         action:nil keyEquivalent:@""];                                      \
226     [o_mi setKeyEquivalentModifierMask:                                     \
227         NSCommandKeyMask];                                                  \
228     [o_mi setAlternate: YES];                                               \
229     [o_mi setTag:                                                           \
230         KEY_MODIFIER_COMMAND | (value)];                                    \
231     [o_menu addItem: o_mi];                                                 \
232 }
233
234 #define ADD_LABEL(o_label, superFrame, x_offset, my_y_offset, label,        \
235     tooltip)                                                                \
236 {                                                                           \
237     NSRect s_rc = superFrame;                                               \
238     s_rc.size.height = 17;                                                  \
239     s_rc.origin.x = x_offset - 3;                                           \
240     s_rc.origin.y = superFrame.size.height - 17 + my_y_offset;              \
241     o_label = [[[NSTextField alloc] initWithFrame: s_rc] retain];           \
242     [o_label setDrawsBackground: NO];                                       \
243     [o_label setBordered: NO];                                              \
244     [o_label setEditable: NO];                                              \
245     [o_label setSelectable: NO];                                            \
246     [o_label setStringValue: label];                                        \
247     [o_label setToolTip: tooltip];                                          \
248     [o_label setFont:[NSFont systemFontOfSize:0]];                          \
249     [o_label sizeToFit];                                                    \
250 }
251
252 #define ADD_TEXTFIELD(o_textfield, superFrame, x_offset, my_y_offset,       \
253     my_width, tooltip, init_value)                                          \
254 {                                                                           \
255     NSRect s_rc = superFrame;                                               \
256     s_rc.origin.x = x_offset;                                               \
257     s_rc.origin.y = my_y_offset;                                            \
258     s_rc.size.height = 22;                                                  \
259     s_rc.size.width = my_width;                                             \
260     o_textfield = [[[NSTextField alloc] initWithFrame: s_rc] retain];       \
261     [o_textfield setFont:[NSFont systemFontOfSize:0]];                      \
262     [o_textfield setToolTip: tooltip];                                      \
263     [o_textfield setStringValue: init_value];                               \
264 }
265
266 #define ADD_SECURETEXTFIELD(o_textfield, superFrame, x_offset, my_y_offset, \
267 my_width, tooltip, init_value)                                              \
268 {                                                                           \
269 NSRect s_rc = superFrame;                                                   \
270 s_rc.origin.x = x_offset;                                                   \
271 s_rc.origin.y = my_y_offset;                                                \
272 s_rc.size.height = 22;                                                      \
273 s_rc.size.width = my_width;                                                 \
274 o_textfield = [[[NSSecureTextField alloc] initWithFrame: s_rc] retain];     \
275 [o_textfield setFont:[NSFont systemFontOfSize:0]];                          \
276 [o_textfield setToolTip: tooltip];                                          \
277 [o_textfield setStringValue: init_value];                                   \
278 }
279
280 #define ADD_COMBO(o_combo, superFrame, x_offset, my_y_offset, x2_offset,    \
281     tooltip)                                                                \
282 {                                                                           \
283     NSRect s_rc = superFrame;                                               \
284     s_rc.origin.x = x_offset + 2;                                           \
285     s_rc.origin.y = my_y_offset;                                            \
286     s_rc.size.height = 26;                                                  \
287     s_rc.size.width = superFrame.size.width + 2 - s_rc.origin.x -           \
288         (x2_offset);                                                        \
289     o_combo = [[[NSComboBox alloc] initWithFrame: s_rc] retain];            \
290     [o_combo setFont:[NSFont systemFontOfSize:0]];                          \
291     [o_combo setToolTip: tooltip];                                          \
292     [o_combo setUsesDataSource:TRUE];                                       \
293     [o_combo setDataSource:self];                                           \
294     [o_combo setNumberOfVisibleItems:10];                                   \
295     [o_combo setCompletes:YES];                                             \
296 }
297
298 #define ADD_RIGHT_BUTTON(o_button, superFrame, x_offset, my_y_offset,       \
299     tooltip, title)                                                         \
300 {                                                                           \
301     NSRect s_rc = superFrame;                                               \
302     o_button = [[[NSButton alloc] initWithFrame: s_rc] retain];             \
303     [o_button setButtonType: NSMomentaryPushInButton];                      \
304     [o_button setBezelStyle: NSRoundedBezelStyle];                          \
305     [o_button setTitle: title];                                             \
306     [o_button setFont:[NSFont systemFontOfSize:0]];                         \
307     [o_button sizeToFit];                                                   \
308     s_rc = [o_button frame];                                                \
309     s_rc.origin.x = superFrame.size.width - [o_button frame].size.width - 6;\
310     s_rc.origin.y = my_y_offset - 6;                                        \
311     s_rc.size.width += 12;                                                  \
312     [o_button setFrame: s_rc];                                              \
313     [o_button setToolTip: tooltip];                                         \
314     [o_button setTarget: self];                                             \
315     [o_button setAction: @selector(openFileDialog:)];                       \
316 }
317
318 #define ADD_POPUP(o_popup, superFrame, x_offset, my_y_offset, x2_offset,    \
319     tooltip)                                                                \
320 {                                                                           \
321     NSRect s_rc = superFrame;                                               \
322     s_rc.origin.x = x_offset - 1;                                           \
323     s_rc.origin.y = my_y_offset;                                            \
324     s_rc.size.height = 26;                                                  \
325     s_rc.size.width = superFrame.size.width + 2 - s_rc.origin.x -           \
326         (x2_offset);                                                        \
327     o_popup = [[[NSPopUpButton alloc] initWithFrame: s_rc] retain];         \
328     [o_popup setFont:[NSFont systemFontOfSize:0]];                          \
329     [o_popup setToolTip: tooltip];                                          \
330 }
331
332 #define ADD_STEPPER(o_stepper, superFrame, x_offset, my_y_offset, tooltip,  \
333     lower, higher)                                                          \
334 {                                                                           \
335     NSRect s_rc = superFrame;                                               \
336     s_rc.origin.x = x_offset;                                               \
337     s_rc.origin.y = my_y_offset;                                            \
338     s_rc.size.height = 23;                                                  \
339     s_rc.size.width = 23;                                                   \
340     o_stepper = [[[NSStepper alloc] initWithFrame: s_rc] retain];           \
341     [o_stepper setFont:[NSFont systemFontOfSize:0]];                        \
342     [o_stepper setToolTip: tooltip];                                        \
343     [o_stepper setMaxValue: higher];                                        \
344     [o_stepper setMinValue: lower];                                         \
345     [o_stepper setTarget: self];                                            \
346     [o_stepper setAction: @selector(stepperChanged:)];                      \
347     [o_stepper sendActionOn:NSLeftMouseUpMask | NSLeftMouseDownMask |       \
348         NSLeftMouseDraggedMask];                                            \
349 }
350
351 #define ADD_SLIDER(o_slider, superFrame, x_offset, my_y_offset, my_width,   \
352     tooltip, lower, higher)                                                 \
353 {                                                                           \
354     NSRect s_rc = superFrame;                                               \
355     s_rc.origin.x = x_offset;                                               \
356     s_rc.origin.y = my_y_offset;                                            \
357     s_rc.size.height = 21;                                                  \
358     s_rc.size.width = my_width;                                             \
359     o_slider = [[[NSSlider alloc] initWithFrame: s_rc] retain];             \
360     [o_slider setFont:[NSFont systemFontOfSize:0]];                         \
361     [o_slider setToolTip: tooltip];                                         \
362     [o_slider setMaxValue: higher];                                         \
363     [o_slider setMinValue: lower];                                          \
364 }
365
366 #define ADD_CHECKBOX(o_checkbox, superFrame, x_offset, my_y_offset, label,  \
367     tooltip, init_value, position)                                          \
368 {                                                                           \
369     NSRect s_rc = superFrame;                                               \
370     s_rc.size.height = 18;                                                  \
371     s_rc.origin.x = x_offset - 2;                                           \
372     s_rc.origin.y = superFrame.size.height - 18 + my_y_offset;              \
373     o_checkbox = [[[NSButton alloc] initWithFrame: s_rc] retain];           \
374     [o_checkbox setFont:[NSFont systemFontOfSize:0]];                       \
375     [o_checkbox setButtonType: NSSwitchButton];                             \
376     [o_checkbox setImagePosition: position];                                \
377     [o_checkbox setIntValue: init_value];                                   \
378     [o_checkbox setTitle: label];                                           \
379     [o_checkbox setToolTip: tooltip];                                       \
380     [o_checkbox sizeToFit];                                                 \
381 }
382
383 @implementation VLCConfigControl
384 @synthesize type = i_type, viewType = i_view_type, advanced = b_advanced;
385
386 - (id)initWithFrame: (NSRect)frame
387 {
388     return [self initWithFrame: frame
389                     item: nil];
390 }
391
392 - (id)initWithFrame: (NSRect)frame
393         item: (module_config_t *)_p_item
394 {
395     self = [super initWithFrame: frame];
396
397     if (self != nil) {
398         p_item = _p_item;
399         psz_name = p_item->psz_name;
400         o_label = NULL;
401         i_type = p_item->i_type;
402         i_view_type = 0;
403         b_advanced = p_item->b_advanced;
404         [self setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin ];
405     }
406     return (self);
407 }
408
409 - (void)setYPos:(int)i_yPos
410 {
411     NSRect frame = [self frame];
412     frame.origin.y = i_yPos;
413     [self setFrame:frame];
414 }
415
416 - (void)dealloc
417 {
418     if (o_label) [o_label release];
419     free(psz_name);
420     [super dealloc];
421 }
422
423 + (int)calcVerticalMargin: (int)i_curItem lastItem: (int)i_lastItem
424 {
425     int i_margin;
426     switch(i_curItem) {
427     case CONFIG_ITEM_STRING:
428     case CONFIG_ITEM_PASSWORD:
429         switch(i_lastItem) {
430         case CONFIG_ITEM_STRING:
431         case CONFIG_ITEM_PASSWORD:
432             i_margin = 8;
433             break;
434         case CONFIG_ITEM_STRING_LIST:
435             i_margin = 7;
436             break;
437         case CONFIG_ITEM_LOADFILE:
438         case CONFIG_ITEM_SAVEFILE:
439             i_margin = 8;
440             break;
441         case CONFIG_ITEM_MODULE:
442             i_margin = 4;
443             break;
444         case CONFIG_ITEM_INTEGER:
445             i_margin = 7;
446             break;
447         case CONFIG_ITEM_RANGED_INTEGER:
448             i_margin = 5;
449             break;
450         case CONFIG_ITEM_BOOL:
451             i_margin = 7;
452             break;
453         case CONFIG_ITEM_KEY:
454             i_margin = 6;
455             break;
456         case CONFIG_ITEM_MODULE_LIST:
457             i_margin = 8;
458             break;
459         default:
460             i_margin = 20;
461             break;
462         }
463         break;
464     case CONFIG_ITEM_STRING_LIST:
465         switch(i_lastItem) {
466         case CONFIG_ITEM_STRING:
467         case CONFIG_ITEM_PASSWORD:
468             i_margin = 8;
469             break;
470         case CONFIG_ITEM_STRING_LIST:
471             i_margin = 7;
472             break;
473         case CONFIG_ITEM_LOADFILE:
474         case CONFIG_ITEM_SAVEFILE:
475             i_margin = 6;
476             break;
477         case CONFIG_ITEM_MODULE:
478             i_margin = 4;
479             break;
480         case CONFIG_ITEM_INTEGER:
481             i_margin = 7;
482             break;
483         case CONFIG_ITEM_RANGED_INTEGER:
484             i_margin = 5;
485             break;
486         case CONFIG_ITEM_BOOL:
487             i_margin = 7;
488             break;
489         case CONFIG_ITEM_KEY:
490             i_margin = 6;
491             break;
492         case CONFIG_ITEM_MODULE_LIST:
493             i_margin = 8;
494             break;
495         default:
496             i_margin = 20;
497             break;
498         }
499         break;
500     case CONFIG_ITEM_LOADFILE:
501     case CONFIG_ITEM_SAVEFILE:
502         switch(i_lastItem) {
503         case CONFIG_ITEM_STRING:
504         case CONFIG_ITEM_PASSWORD:
505             i_margin = 13;
506             break;
507         case CONFIG_ITEM_STRING_LIST:
508             i_margin = 10;
509             break;
510         case CONFIG_ITEM_LOADFILE:
511         case CONFIG_ITEM_SAVEFILE:
512             i_margin = 9;
513             break;
514         case CONFIG_ITEM_MODULE:
515             i_margin = 9;
516             break;
517         case CONFIG_ITEM_INTEGER:
518             i_margin = 10;
519             break;
520         case CONFIG_ITEM_RANGED_INTEGER:
521             i_margin = 8;
522             break;
523         case CONFIG_ITEM_BOOL:
524             i_margin = 10;
525             break;
526         case CONFIG_ITEM_KEY:
527             i_margin = 9;
528             break;
529         case CONFIG_ITEM_MODULE_LIST:
530             i_margin = 11;
531             break;
532         default:
533             i_margin = 23;
534             break;
535         }
536         break;
537     case CONFIG_ITEM_MODULE:
538         switch(i_lastItem) {
539         case CONFIG_ITEM_STRING:
540         case CONFIG_ITEM_PASSWORD:
541             i_margin = 8;
542             break;
543         case CONFIG_ITEM_STRING_LIST:
544             i_margin = 7;
545             break;
546         case CONFIG_ITEM_LOADFILE:
547         case CONFIG_ITEM_SAVEFILE:
548             i_margin = 6;
549             break;
550         case CONFIG_ITEM_MODULE:
551             i_margin = 5;
552             break;
553         case CONFIG_ITEM_INTEGER:
554             i_margin = 7;
555             break;
556         case CONFIG_ITEM_RANGED_INTEGER:
557             i_margin = 6;
558             break;
559         case CONFIG_ITEM_BOOL:
560             i_margin = 8;
561             break;
562         case CONFIG_ITEM_KEY:
563             i_margin = 7;
564             break;
565         case CONFIG_ITEM_MODULE_LIST:
566             i_margin = 9;
567             break;
568         default:
569             i_margin = 20;
570             break;
571         }
572         break;
573     case CONFIG_ITEM_INTEGER:
574         switch(i_lastItem) {
575         case CONFIG_ITEM_STRING:
576         case CONFIG_ITEM_PASSWORD:
577             i_margin = 8;
578             break;
579         case CONFIG_ITEM_STRING_LIST:
580             i_margin = 7;
581             break;
582         case CONFIG_ITEM_LOADFILE:
583         case CONFIG_ITEM_SAVEFILE:
584             i_margin = 6;
585             break;
586         case CONFIG_ITEM_MODULE:
587             i_margin = 4;
588             break;
589         case CONFIG_ITEM_INTEGER:
590             i_margin = 7;
591             break;
592         case CONFIG_ITEM_RANGED_INTEGER:
593             i_margin = 5;
594             break;
595         case CONFIG_ITEM_BOOL:
596             i_margin = 7;
597             break;
598         case CONFIG_ITEM_KEY:
599             i_margin = 6;
600             break;
601         case CONFIG_ITEM_MODULE_LIST:
602             i_margin = 8;
603             break;
604         default:
605             i_margin = 20;
606             break;
607         }
608         break;
609     case CONFIG_ITEM_RANGED_INTEGER:
610         switch(i_lastItem) {
611         case CONFIG_ITEM_STRING:
612         case CONFIG_ITEM_PASSWORD:
613             i_margin = 8;
614             break;
615         case CONFIG_ITEM_STRING_LIST:
616             i_margin = 7;
617             break;
618         case CONFIG_ITEM_LOADFILE:
619         case CONFIG_ITEM_SAVEFILE:
620             i_margin = 8;
621             break;
622         case CONFIG_ITEM_MODULE:
623             i_margin = 4;
624             break;
625         case CONFIG_ITEM_INTEGER:
626             i_margin = 7;
627             break;
628         case CONFIG_ITEM_RANGED_INTEGER:
629             i_margin = 5;
630             break;
631         case CONFIG_ITEM_BOOL:
632             i_margin = 7;
633             break;
634         case CONFIG_ITEM_KEY:
635             i_margin = 6;
636             break;
637         case CONFIG_ITEM_MODULE_LIST:
638             i_margin = 8;
639             break;
640         default:
641             i_margin = 20;
642             break;
643         }
644         break;
645     case CONFIG_ITEM_BOOL:
646         switch(i_lastItem) {
647         case CONFIG_ITEM_STRING:
648         case CONFIG_ITEM_PASSWORD:
649             i_margin = 10;
650             break;
651         case CONFIG_ITEM_STRING_LIST:
652             i_margin = 9;
653             break;
654         case CONFIG_ITEM_LOADFILE:
655         case CONFIG_ITEM_SAVEFILE:
656             i_margin = 8;
657             break;
658         case CONFIG_ITEM_MODULE:
659             i_margin = 6;
660             break;
661         case CONFIG_ITEM_INTEGER:
662             i_margin = 9;
663             break;
664         case CONFIG_ITEM_RANGED_INTEGER:
665             i_margin = 7;
666             break;
667         case CONFIG_ITEM_BOOL:
668             i_margin = 7;
669             break;
670         case CONFIG_ITEM_KEY:
671             i_margin = 5;
672             break;
673         case CONFIG_ITEM_MODULE_LIST:
674             i_margin = 10;
675             break;
676         default:
677             i_margin = 20;
678             break;
679         }
680         break;
681     case CONFIG_ITEM_KEY:
682         switch(i_lastItem) {
683         case CONFIG_ITEM_STRING:
684         case CONFIG_ITEM_PASSWORD:
685             i_margin = 8;
686             break;
687         case CONFIG_ITEM_STRING_LIST:
688             i_margin = 7;
689             break;
690         case CONFIG_ITEM_LOADFILE:
691         case CONFIG_ITEM_SAVEFILE:
692             i_margin = 6;
693             break;
694         case CONFIG_ITEM_MODULE:
695             i_margin = 6;
696             break;
697         case CONFIG_ITEM_INTEGER:
698             i_margin = 7;
699             break;
700         case CONFIG_ITEM_RANGED_INTEGER:
701             i_margin = 5;
702             break;
703         case CONFIG_ITEM_BOOL:
704             i_margin = 7;
705             break;
706         case CONFIG_ITEM_KEY:
707             i_margin = 8;
708             break;
709         case CONFIG_ITEM_MODULE_LIST:
710             i_margin = 10;
711             break;
712         default:
713             i_margin = 20;
714             break;
715         }
716         break;
717     case CONFIG_ITEM_MODULE_LIST:
718         switch(i_lastItem) {
719         case CONFIG_ITEM_STRING:
720         case CONFIG_ITEM_PASSWORD:
721             i_margin = 10;
722             break;
723         case CONFIG_ITEM_STRING_LIST:
724             i_margin = 7;
725             break;
726         case CONFIG_ITEM_LOADFILE:
727         case CONFIG_ITEM_SAVEFILE:
728             i_margin = 6;
729             break;
730         case CONFIG_ITEM_MODULE:
731             i_margin = 6;
732             break;
733         case CONFIG_ITEM_INTEGER:
734             i_margin = 9;
735             break;
736         case CONFIG_ITEM_RANGED_INTEGER:
737             i_margin = 5;
738             break;
739         case CONFIG_ITEM_BOOL:
740             i_margin = 7;
741             break;
742         case CONFIG_ITEM_KEY:
743             i_margin = 5;
744             break;
745         case CONFIG_ITEM_MODULE_LIST:
746             i_margin = 8;
747             break;
748         default:
749             i_margin = 20;
750             break;
751         }
752         break;
753     default:
754         i_margin = 20;
755         break;
756     }
757     return i_margin;
758 }
759
760 + (VLCConfigControl *)newControl: (module_config_t *)_p_item
761                       withView: (NSView *)o_parent_view
762 {
763     VLCConfigControl *p_control = NULL;
764
765     switch(_p_item->i_type) {
766     case CONFIG_ITEM_STRING:
767     case CONFIG_ITEM_PASSWORD:
768         if (!_p_item->list_count) {
769             p_control = [[StringConfigControl alloc]
770                     initWithItem: _p_item
771                     withView: o_parent_view];
772         } else {
773             p_control = [[StringListConfigControl alloc]
774                     initWithItem: _p_item
775                     withView: o_parent_view];
776         }
777         break;
778     case CONFIG_ITEM_LOADFILE:
779     case CONFIG_ITEM_SAVEFILE:
780     case CONFIG_ITEM_DIRECTORY:
781         p_control = [[FileConfigControl alloc]
782                     initWithItem: _p_item
783                     withView: o_parent_view];
784         break;
785     case CONFIG_ITEM_MODULE:
786             p_control = [[StringListConfigControl alloc]
787                          initWithItem: _p_item
788                          withView: o_parent_view];
789             break;
790     case CONFIG_ITEM_MODULE_CAT:
791         p_control = [[ModuleConfigControl alloc]
792                     initWithItem: _p_item
793                     withView: o_parent_view];
794         break;
795     case CONFIG_ITEM_INTEGER:
796         if (_p_item->list_count)
797             p_control = [[IntegerListConfigControl alloc] initWithItem: _p_item withView: o_parent_view];
798         else if ((_p_item->min.i != 0 || _p_item->max.i != 0) && (_p_item->min.i != INT_MIN || _p_item->max.i != INT_MAX))
799             p_control = [[RangedIntegerConfigControl alloc] initWithItem: _p_item withView: o_parent_view];
800         else
801             p_control = [[IntegerConfigControl alloc] initWithItem: _p_item withView: o_parent_view];
802         break;
803     case CONFIG_ITEM_BOOL:
804         p_control = [[BoolConfigControl alloc]
805                     initWithItem: _p_item
806                     withView: o_parent_view];
807         break;
808     case CONFIG_ITEM_FLOAT:
809         if ((_p_item->min.i != 0 || _p_item->max.i != 0) && (_p_item->min.i != INT_MIN || _p_item->max.i != INT_MAX))
810             p_control = [[RangedFloatConfigControl alloc] initWithItem: _p_item withView: o_parent_view];
811         else
812             p_control = [[FloatConfigControl alloc] initWithItem: _p_item withView: o_parent_view];
813         break;
814     /* don't display keys in the advanced settings, since the current controls
815     are broken by design. The user is required to change hotkeys in the sprefs
816     and can only change really advanced stuff here..
817     case CONFIG_ITEM_KEY:
818         p_control = [[KeyConfigControl alloc]
819                         initWithItem: _p_item
820                         withView: o_parent_view];
821         break; */
822     case CONFIG_ITEM_MODULE_LIST:
823     case CONFIG_ITEM_MODULE_LIST_CAT:
824         p_control = [[ModuleListConfigControl alloc] initWithItem: _p_item withView: o_parent_view];
825         break;
826     case CONFIG_SECTION:
827         p_control = [[SectionControl alloc] initWithItem: _p_item withView: o_parent_view];
828         break;
829     default:
830         break;
831     }
832     return p_control;
833 }
834
835 - (NSString *)name
836 {
837     return _NS(psz_name);
838 }
839
840 - (int)intValue
841 {
842     return 0;
843 }
844
845 - (float)floatValue
846 {
847     return 0;
848 }
849
850 - (char *)stringValue
851 {
852     return NULL;
853 }
854
855 - (void)applyChanges
856 {
857     vlc_value_t val;
858     switch(p_item->i_type) {
859     case CONFIG_ITEM_STRING:
860     case CONFIG_ITEM_PASSWORD:
861     case CONFIG_ITEM_LOADFILE:
862     case CONFIG_ITEM_SAVEFILE:
863     case CONFIG_ITEM_DIRECTORY:
864     case CONFIG_ITEM_MODULE:
865     case CONFIG_ITEM_MODULE_LIST:
866     case CONFIG_ITEM_MODULE_LIST_CAT: {
867         char *psz_val = [self stringValue];
868         config_PutPsz(VLCIntf, psz_name, psz_val);
869         free(psz_val);
870         break;
871     }
872     case CONFIG_ITEM_KEY:
873         /* So you don't need to restart to have the changes take effect */
874         val.i_int = [self intValue];
875         var_Set(VLCIntf->p_libvlc, psz_name, val);
876     case CONFIG_ITEM_INTEGER:
877     case CONFIG_ITEM_BOOL:
878         config_PutInt(VLCIntf, psz_name, [self intValue]);
879         break;
880     case CONFIG_ITEM_FLOAT:
881         config_PutFloat(VLCIntf, psz_name, [self floatValue]);
882         break;
883     }
884 }
885
886 - (void)resetValues
887 {
888 }
889
890 - (int)labelSize
891 {
892     return [o_label frame].size.width;
893 }
894
895 - (void) alignWithXPosition:(int)i_xPos;
896 {
897     /* FIXME: not implemented atm, but created to shut up the warning
898      * about "method definition not found" -- FK @ 7/24/05 */
899 }
900 @end
901
902 @implementation StringConfigControl
903 - (id) initWithItem: (module_config_t *)_p_item
904            withView: (NSView *)o_parent_view
905 {
906     NSRect mainFrame = [o_parent_view frame];
907     NSString *o_labelString, *o_textfieldString, *o_textfieldTooltip;
908     mainFrame.size.height = 22;
909     mainFrame.size.width = mainFrame.size.width - LEFTMARGIN - RIGHTMARGIN;
910     mainFrame.origin.x = LEFTMARGIN;
911     mainFrame.origin.y = 0;
912
913     if ([super initWithFrame: mainFrame item: _p_item] != nil) {
914         if (p_item->i_type == CONFIG_ITEM_PASSWORD)
915             i_view_type = CONFIG_ITEM_PASSWORD;
916         else
917             i_view_type = CONFIG_ITEM_STRING;
918
919         o_textfieldTooltip = [[VLCStringUtility sharedInstance] wrapString: _NS((char *)p_item->psz_longtext) toWidth: PREFS_WRAP];
920
921         /* add the label */
922         if (p_item->psz_text)
923             o_labelString = _NS((char *)p_item->psz_text);
924         else
925             o_labelString = @"";
926         ADD_LABEL(o_label, mainFrame, 0, -3, o_labelString, o_textfieldTooltip)
927         [o_label setAutoresizingMask:NSViewNotSizable ];
928         [self addSubview: o_label];
929
930         /* build the textfield */
931         if (p_item->value.psz)
932             o_textfieldString = [NSString stringWithCString:p_item->value.psz encoding:NSUTF8StringEncoding];
933         else
934             o_textfieldString = @"";
935         if (p_item->i_type == CONFIG_ITEM_PASSWORD) {
936             ADD_SECURETEXTFIELD(o_textfield, mainFrame, [o_label frame].size.width + 2,
937                           0, mainFrame.size.width - [o_label frame].size.width -
938                           2, o_textfieldTooltip, o_textfieldString)
939         } else {
940             ADD_TEXTFIELD(o_textfield, mainFrame, [o_label frame].size.width + 2,
941                             0, mainFrame.size.width - [o_label frame].size.width -
942                             2, o_textfieldTooltip, o_textfieldString)
943         }
944         [o_textfield setAutoresizingMask:NSViewWidthSizable ];
945
946         [self addSubview: o_textfield];
947     }
948     return self;
949 }
950
951 - (void) alignWithXPosition:(int)i_xPos
952 {
953     NSRect frame;
954     NSRect superFrame = [self frame];
955     frame = [o_label frame];
956     frame.origin.x = i_xPos - frame.size.width - 3;
957     [o_label setFrame:frame];
958
959     frame = [o_textfield frame];
960     frame.origin.x = i_xPos + 2;
961     frame.size.width = superFrame.size.width - frame.origin.x - 1;
962     [o_textfield setFrame:frame];
963 }
964
965 - (void)dealloc
966 {
967     [o_textfield release];
968     [super dealloc];
969 }
970
971 - (char *)stringValue
972 {
973     return strdup([[o_textfield stringValue] UTF8String]);
974 }
975
976 - (void)resetValues
977 {
978     NSString *o_textfieldString;
979     char *psz_value = config_GetPsz(VLCIntf, p_item->psz_name);
980     if (psz_value)
981         o_textfieldString = _NS(psz_value);
982     else
983         o_textfieldString = @"";
984     free(psz_value);
985     [super resetValues];
986 }
987 @end
988
989 @implementation StringListConfigControl
990 - (id) initWithItem: (module_config_t *)_p_item
991            withView: (NSView *)o_parent_view
992 {
993     NSRect mainFrame = [o_parent_view frame];
994     NSString *o_labelString, *o_textfieldTooltip;
995     mainFrame.size.height = 22;
996     mainFrame.size.width = mainFrame.size.width - LEFTMARGIN - RIGHTMARGIN + 1;
997     mainFrame.origin.x = LEFTMARGIN;
998     mainFrame.origin.y = 0;
999
1000     if ([super initWithFrame: mainFrame item: _p_item] != nil) {
1001         if (p_item->i_type == CONFIG_ITEM_STRING)
1002             i_view_type = CONFIG_ITEM_STRING_LIST;
1003         else
1004             i_view_type = CONFIG_ITEM_MODULE;
1005
1006         o_textfieldTooltip = [[VLCStringUtility sharedInstance] wrapString: _NS(p_item->psz_longtext) toWidth: PREFS_WRAP];
1007
1008         /* add the label */
1009         if (p_item->psz_text)
1010             o_labelString = _NS((char *)p_item->psz_text);
1011         else
1012             o_labelString = @"";
1013         ADD_LABEL(o_label, mainFrame, 0, -3, o_labelString, o_textfieldTooltip)
1014         [o_label setAutoresizingMask:NSViewNotSizable ];
1015         [self addSubview: o_label];
1016
1017         /* build the textfield */
1018         ADD_POPUP(o_popup, mainFrame, [o_label frame].size.width,
1019             -2, 0, o_textfieldTooltip)
1020         [o_popup setAutoresizingMask:NSViewWidthSizable];
1021
1022         /* add items */
1023         [self resetValues];
1024
1025         [self addSubview: o_popup];
1026     }
1027     return self;
1028 }
1029
1030 - (void) alignWithXPosition:(int)i_xPos
1031 {
1032     NSRect frame;
1033     NSRect superFrame = [self frame];
1034     frame = [o_label frame];
1035     frame.origin.x = i_xPos - frame.size.width - 3;
1036     [o_label setFrame:frame];
1037
1038     frame = [o_popup frame];
1039     frame.origin.x = i_xPos + 2;
1040     frame.size.width = superFrame.size.width - frame.origin.x + 2;
1041     [o_popup setFrame:frame];
1042 }
1043
1044 - (void)dealloc
1045 {
1046     [o_popup release];
1047     [super dealloc];
1048 }
1049
1050 - (char *)stringValue
1051 {
1052     if ([o_popup indexOfSelectedItem] < 0)
1053         return NULL;
1054
1055     NSString *o_data = [[o_popup selectedItem] representedObject];
1056     return strdup([o_data UTF8String]);
1057 }
1058
1059 - (void)resetValues
1060 {
1061     [o_popup removeAllItems];
1062
1063     char *psz_value = config_GetPsz(VLCIntf, p_item->psz_name);
1064
1065     char **values, **texts;
1066     ssize_t count = config_GetPszChoices(VLC_OBJECT(VLCIntf), p_item->psz_name,
1067                                          &values, &texts);
1068     for (ssize_t i = 0; i < count && texts; i++) {
1069         if (texts[i] == NULL || values[i] == NULL)
1070             continue;
1071
1072         [o_popup addItemWithTitle: toNSStr(texts[i])];
1073         NSMenuItem *lastItem = [o_popup lastItem];
1074         [lastItem setRepresentedObject: toNSStr(values[i])];
1075
1076         if (!strcmp(psz_value ? psz_value : "", values[i]))
1077             [o_popup selectItem: [o_popup lastItem]];
1078
1079         free(texts[i]);
1080         free(values[i]);
1081     }
1082     free(texts);
1083     free(values);
1084
1085     free(psz_value);
1086
1087     [super resetValues];
1088 }
1089 @end
1090
1091 @implementation FileConfigControl
1092 - (id) initWithItem: (module_config_t *)_p_item
1093            withView: (NSView *)o_parent_view
1094 {
1095     NSRect mainFrame = [o_parent_view frame];
1096     NSString *o_labelString, *o_itemTooltip, *o_textfieldString;
1097     mainFrame.size.height = 46;
1098     mainFrame.size.width = mainFrame.size.width - LEFTMARGIN - RIGHTMARGIN;
1099     mainFrame.origin.x = LEFTMARGIN;
1100     mainFrame.origin.y = 0;
1101
1102     if ([super initWithFrame: mainFrame item: _p_item] != nil) {
1103         i_view_type = CONFIG_ITEM_LOADFILE;
1104
1105         o_itemTooltip = [[VLCStringUtility sharedInstance] wrapString: _NS((char *)p_item->psz_longtext) toWidth: PREFS_WRAP];
1106
1107         /* is it a directory */
1108         b_directory = ([self type] == CONFIG_ITEM_DIRECTORY) ? YES : NO;
1109
1110         /* add the label */
1111         if (p_item->psz_text)
1112             o_labelString = _NS((char *)p_item->psz_text);
1113         else
1114             o_labelString = @"";
1115         ADD_LABEL(o_label, mainFrame, 0, 3, o_labelString, o_itemTooltip)
1116         [o_label setAutoresizingMask:NSViewNotSizable ];
1117         [self addSubview: o_label];
1118
1119         /* build the button */
1120         ADD_RIGHT_BUTTON(o_button, mainFrame, 0, 0, o_itemTooltip,
1121                             _NS("Browse..."))
1122         [o_button setAutoresizingMask:NSViewMinXMargin ];
1123         [self addSubview: o_button];
1124
1125         /* build the textfield */
1126         if (p_item->value.psz)
1127             o_textfieldString = [NSString stringWithFormat: @"%s", (char *)p_item->value.psz];
1128         else
1129             o_textfieldString = @"";
1130         ADD_TEXTFIELD(o_textfield, mainFrame, 12, 2, mainFrame.size.width -
1131                         8 - [o_button frame].size.width,
1132                         o_itemTooltip, o_textfieldString)
1133         [o_textfield setAutoresizingMask:NSViewWidthSizable ];
1134         [self addSubview: o_textfield];
1135     }
1136     return self;
1137 }
1138
1139 - (void) alignWithXPosition:(int)i_xPos
1140 {
1141     ;
1142 }
1143
1144 - (void)dealloc
1145 {
1146     [o_textfield release];
1147     [o_button release];
1148     [super dealloc];
1149 }
1150
1151 - (IBAction)openFileDialog: (id)sender
1152 {
1153     NSOpenPanel *o_open_panel = [NSOpenPanel openPanel];
1154
1155     [o_open_panel setTitle: (b_directory)?
1156         _NS("Select a directory"):_NS("Select a file")];
1157     [o_open_panel setPrompt: _NS("Select")];
1158     [o_open_panel setAllowsMultipleSelection: NO];
1159     [o_open_panel setCanChooseFiles: !b_directory];
1160     [o_open_panel setCanChooseDirectories: b_directory];
1161     [o_open_panel beginSheetModalForWindow:[sender window] completionHandler:^(NSInteger returnCode) {
1162         if (returnCode == NSOKButton) {
1163             NSString *o_path = [[[o_open_panel URLs] objectAtIndex:0] path];
1164             [o_textfield setStringValue: o_path];
1165         }        
1166     }];
1167 }
1168
1169 - (char *)stringValue
1170 {
1171     if ([[o_textfield stringValue] length] != 0)
1172         return strdup([[o_textfield stringValue] fileSystemRepresentation]);
1173     else
1174         return NULL;
1175 }
1176
1177 -(void)resetValues
1178 {
1179     NSString *o_textfieldString;
1180     char *psz_value = config_GetPsz(VLCIntf, p_item->psz_name);
1181     if (psz_value)
1182         o_textfieldString = [NSString stringWithFormat: @"%s", psz_value];
1183     else
1184         o_textfieldString = @"";
1185
1186     free(psz_value);
1187     [super resetValues];
1188 }
1189 @end
1190
1191 @implementation ModuleConfigControl
1192 - (id) initWithItem: (module_config_t *)_p_item
1193            withView: (NSView *)o_parent_view
1194 {
1195     NSRect mainFrame = [o_parent_view frame];
1196     NSString *o_labelString, *o_popupTooltip;
1197     mainFrame.size.height = 22;
1198     mainFrame.size.width = mainFrame.size.width - LEFTMARGIN - RIGHTMARGIN + 1;
1199     mainFrame.origin.x = LEFTMARGIN;
1200     mainFrame.origin.y = 0;
1201
1202     if ([super initWithFrame: mainFrame item: _p_item] != nil) {
1203         i_view_type = CONFIG_ITEM_MODULE;
1204
1205         o_popupTooltip = [[VLCStringUtility sharedInstance] wrapString: _NS((char *)p_item->psz_longtext) toWidth: PREFS_WRAP];
1206
1207         /* add the label */
1208         if (p_item->psz_text)
1209             o_labelString = _NS((char *)p_item->psz_text);
1210         else
1211             o_labelString = @"";
1212
1213         ADD_LABEL(o_label, mainFrame, 0, -1, o_labelString, o_popupTooltip)
1214         [o_label setAutoresizingMask:NSViewNotSizable ];
1215         [self addSubview: o_label];
1216
1217         /* build the popup */
1218         ADD_POPUP(o_popup, mainFrame, [o_label frame].size.width,
1219             -2, 0, o_popupTooltip)
1220         [o_popup setAutoresizingMask:NSViewWidthSizable ];
1221         [o_popup addItemWithTitle: _NS("Default")];
1222         [[o_popup lastItem] setTag: -1];
1223         [o_popup selectItem: [o_popup lastItem]];
1224
1225         [self resetValues];
1226         [self addSubview: o_popup];
1227     }
1228     return self;
1229 }
1230
1231 - (void) alignWithXPosition:(int)i_xPos
1232 {
1233     NSRect frame;
1234     NSRect superFrame = [self frame];
1235     frame = [o_label frame];
1236     frame.origin.x = i_xPos - frame.size.width - 3;
1237     [o_label setFrame:frame];
1238
1239     frame = [o_popup frame];
1240     frame.origin.x = i_xPos - 1;
1241     frame.size.width = superFrame.size.width - frame.origin.x + 2;
1242     [o_popup setFrame:frame];
1243 }
1244
1245 - (void)dealloc
1246 {
1247     [o_popup release];
1248     [super dealloc];
1249 }
1250
1251 - (char *)stringValue
1252 {
1253     NSString *newval = [o_popup titleOfSelectedItem];
1254     char *returnval = NULL;
1255     size_t i_module_index;
1256     module_t *p_parser, **p_list;
1257
1258     size_t count;
1259     p_list = module_list_get(&count);
1260     for (i_module_index = 0; i_module_index < count; i_module_index++) {
1261         p_parser = p_list[i_module_index];
1262
1263         if (module_is_main(p_parser))
1264             continue;
1265
1266         unsigned int confsize;
1267         module_config_t *p_config = module_config_get(p_parser, &confsize);
1268         for (size_t i = 0; i < confsize; i++) {
1269             module_config_t *p_cfg = p_config + i;
1270             /* Hack: required subcategory is stored in i_min */
1271             if (p_cfg->i_type == CONFIG_SUBCATEGORY &&
1272                 p_cfg->value.i == p_cfg->min.i) {
1273                 NSString *o_description = _NS(module_get_name(p_parser, TRUE));
1274                 if ([newval isEqualToString: o_description]) {
1275                     returnval = strdup(module_get_object(p_parser));
1276                     break;
1277                 }
1278             }
1279             module_config_free(p_config);
1280         }
1281     }
1282     module_list_free(p_list);
1283
1284     if(returnval == NULL && [newval isEqualToString: _NS("Default")] && p_item->orig.psz != NULL) {
1285         returnval = strdup(p_item->orig.psz);
1286     }
1287     return returnval;
1288 }
1289
1290 -(void)resetValues
1291 {
1292     /* build a list of available modules */
1293     module_t *p_parser, **p_list;
1294
1295     size_t count;
1296     p_list = module_list_get(&count);
1297     for (size_t i_index = 0; i_index < count; i_index++) {
1298         p_parser = p_list[i_index];
1299
1300         if (module_is_main(p_parser))
1301             continue;
1302         unsigned int confsize;
1303
1304         module_config_t *p_configlist = module_config_get(p_parser, &confsize);
1305         for (size_t i = 0; i < confsize; i++) {
1306             module_config_t *p_config = &p_configlist[i];
1307             /* Hack: required subcategory is stored in i_min */
1308             if (p_config->i_type == CONFIG_SUBCATEGORY &&
1309                 p_config->value.i == p_item->min.i) {
1310                 NSString *o_description = _NS(module_get_name(p_parser, TRUE));
1311                 [o_popup addItemWithTitle: o_description];
1312
1313                 if (p_item->value.psz && !strcmp(p_item->value.psz,
1314                                                  module_get_object(p_parser)))
1315                     [o_popup selectItem:[o_popup lastItem]];
1316             }
1317         }
1318         module_config_free(p_configlist);
1319     }
1320     module_list_free(p_list);
1321     [super resetValues];
1322 }
1323 @end
1324
1325 @implementation IntegerConfigControl
1326 - (id) initWithItem: (module_config_t *)_p_item
1327            withView: (NSView *)o_parent_view
1328 {
1329     NSRect mainFrame = [o_parent_view frame];
1330     NSString *o_labelString, *o_tooltip;
1331     mainFrame.size.height = 23;
1332     mainFrame.size.width = mainFrame.size.width - LEFTMARGIN - RIGHTMARGIN + 1;
1333     mainFrame.origin.x = LEFTMARGIN;
1334     mainFrame.origin.y = 0;
1335
1336     if ([super initWithFrame: mainFrame item: _p_item] != nil) {
1337         i_view_type = CONFIG_ITEM_INTEGER;
1338
1339         o_tooltip = [[VLCStringUtility sharedInstance] wrapString: _NS((char *)p_item->psz_longtext) toWidth: PREFS_WRAP];
1340
1341         /* add the label */
1342         if (p_item->psz_text)
1343             o_labelString = _NS((char *)p_item->psz_text);
1344         else
1345             o_labelString = @"";
1346         ADD_LABEL(o_label, mainFrame, 0, -3, o_labelString, o_tooltip)
1347         [o_label setAutoresizingMask:NSViewNotSizable ];
1348         [self addSubview: o_label];
1349
1350         /* build the stepper */
1351         ADD_STEPPER(o_stepper, mainFrame, mainFrame.size.width - 19,
1352             0, o_tooltip, -100000, 100000)
1353         [o_stepper setIntValue: p_item->value.i];
1354         [o_stepper setAutoresizingMask:NSViewMaxXMargin ];
1355         [self addSubview: o_stepper];
1356
1357         ADD_TEXTFIELD(o_textfield, mainFrame, mainFrame.size.width - 19 - 52,
1358             1, 49, o_tooltip, @"")
1359         [o_textfield setIntValue: p_item->value.i];
1360         [o_textfield setDelegate: self];
1361         [[NSNotificationCenter defaultCenter] addObserver: self
1362             selector: @selector(textfieldChanged:)
1363             name: NSControlTextDidChangeNotification
1364             object: o_textfield];
1365         [o_textfield setAutoresizingMask:NSViewMaxXMargin ];
1366         [self addSubview: o_textfield];
1367     }
1368     return self;
1369 }
1370
1371 - (void) alignWithXPosition:(int)i_xPos
1372 {
1373     NSRect frame;
1374     frame = [o_label frame];
1375     frame.origin.x = i_xPos - frame.size.width - 3;
1376     [o_label setFrame:frame];
1377
1378     frame = [o_textfield frame];
1379     frame.origin.x = i_xPos + 2;
1380     [o_textfield setFrame:frame];
1381
1382     frame = [o_stepper frame];
1383     frame.origin.x = i_xPos + [o_textfield frame].size.width + 5;
1384     [o_stepper setFrame:frame];
1385 }
1386
1387 - (void)dealloc
1388 {
1389     [o_stepper release];
1390     [o_textfield release];
1391     [super dealloc];
1392 }
1393
1394 - (IBAction)stepperChanged:(id)sender
1395 {
1396     [o_textfield setIntValue: [o_stepper intValue]];
1397 }
1398
1399 - (void)textfieldChanged:(NSNotification *)o_notification
1400 {
1401     [o_stepper setIntValue: [o_textfield intValue]];
1402 }
1403
1404 - (int)intValue
1405 {
1406     return [o_textfield intValue];
1407 }
1408
1409 -(void)resetValues
1410 {
1411     [o_textfield setIntValue: config_GetInt(VLCIntf, p_item->psz_name)];
1412     [super resetValues];
1413 }
1414
1415 @end
1416
1417 @implementation IntegerListConfigControl
1418
1419 - (id) initWithItem: (module_config_t *)_p_item
1420            withView: (NSView *)o_parent_view
1421 {
1422     NSRect mainFrame = [o_parent_view frame];
1423     NSString *o_labelString, *o_textfieldTooltip;
1424     mainFrame.size.height = 22;
1425     mainFrame.size.width = mainFrame.size.width - LEFTMARGIN - RIGHTMARGIN + 1;
1426     mainFrame.origin.x = LEFTMARGIN;
1427     mainFrame.origin.y = 0;
1428
1429     if ([super initWithFrame: mainFrame item: _p_item] != nil) {
1430         i_view_type = CONFIG_ITEM_STRING_LIST;
1431
1432         o_textfieldTooltip = [[VLCStringUtility sharedInstance] wrapString: _NS((char *)p_item->psz_longtext) toWidth: PREFS_WRAP];
1433
1434         /* add the label */
1435         if (p_item->psz_text)
1436             o_labelString = _NS((char *)p_item->psz_text);
1437         else
1438             o_labelString = @"";
1439         ADD_LABEL(o_label, mainFrame, 0, -3, o_labelString, o_textfieldTooltip)
1440         [o_label setAutoresizingMask:NSViewNotSizable ];
1441         [self addSubview: o_label];
1442
1443         /* build the textfield */
1444         ADD_POPUP(o_popup, mainFrame, [o_label frame].size.width,
1445             -2, 0, o_textfieldTooltip)
1446         [o_popup setAutoresizingMask:NSViewWidthSizable ];
1447
1448         /* add items */
1449         [self resetValues];
1450         
1451         [self addSubview: o_popup];
1452     }
1453     return self;
1454 }
1455
1456 - (void) alignWithXPosition:(int)i_xPos
1457 {
1458     NSRect frame;
1459     NSRect superFrame = [self frame];
1460     frame = [o_label frame];
1461     frame.origin.x = i_xPos - frame.size.width - 3;
1462     [o_label setFrame:frame];
1463
1464     frame = [o_popup frame];
1465     frame.origin.x = i_xPos + 2;
1466     frame.size.width = superFrame.size.width - frame.origin.x + 2;
1467     [o_popup setFrame:frame];
1468 }
1469
1470 - (void)dealloc
1471 {
1472     [o_popup release];
1473     [super dealloc];
1474 }
1475
1476 - (int)intValue
1477 {
1478     NSNumber *p_valueobject = (NSNumber *)[[o_popup selectedItem] representedObject];
1479     if (p_valueobject) {
1480         assert([p_valueobject isKindOfClass:[NSNumber class]]);
1481         return [p_valueobject intValue];
1482     } else
1483         return 0;
1484 }
1485
1486 -(void)resetValues
1487 {
1488     [o_popup removeAllItems];
1489
1490     int i_current_selection = config_GetInt(VLCIntf, p_item->psz_name);
1491     int64_t *values;
1492     char **texts;
1493     ssize_t count = config_GetIntChoices(VLC_OBJECT(VLCIntf), p_item->psz_name, &values, &texts);
1494     for (ssize_t i = 0; i < count; i++) {
1495         NSMenuItem *mi = [[NSMenuItem alloc] initWithTitle: toNSStr(texts[i]) action: NULL keyEquivalent: @""];
1496         [mi setRepresentedObject:[NSNumber numberWithInt:values[i]]];
1497         [[o_popup menu] addItem: [mi autorelease]];
1498
1499         if (i_current_selection == values[i])
1500             [o_popup selectItem:[o_popup lastItem]];
1501
1502         free(texts[i]);
1503     }
1504     free(texts);
1505 }
1506 @end
1507
1508 @implementation RangedIntegerConfigControl
1509 - (id) initWithItem: (module_config_t *)_p_item
1510            withView: (NSView *)o_parent_view
1511 {
1512     NSRect mainFrame = [o_parent_view frame];
1513     NSString *o_labelString, *o_tooltip;
1514     mainFrame.size.height = 50;
1515     mainFrame.size.width = mainFrame.size.width - LEFTMARGIN - RIGHTMARGIN;
1516     mainFrame.origin.x = LEFTMARGIN;
1517     mainFrame.origin.y = 0;
1518
1519     if ([super initWithFrame: mainFrame item: _p_item] != nil) {
1520         i_view_type = CONFIG_ITEM_RANGED_INTEGER;
1521
1522         o_tooltip = [[VLCStringUtility sharedInstance] wrapString: _NS((char *)p_item->psz_longtext) toWidth: PREFS_WRAP];
1523
1524         /* add the label */
1525         if (p_item->psz_text)
1526             o_labelString = _NS((char *)p_item->psz_text);
1527         else
1528             o_labelString = @"";
1529         ADD_LABEL(o_label, mainFrame, 0, -3, o_labelString, o_tooltip)
1530         [o_label setAutoresizingMask:NSViewNotSizable ];
1531         [self addSubview: o_label];
1532
1533         /* build the textfield */
1534         ADD_TEXTFIELD(o_textfield, mainFrame, [o_label frame].size.width + 2,
1535             28, 49, o_tooltip, @"")
1536         [o_textfield setIntValue: p_item->value.i];
1537         [o_textfield setAutoresizingMask:NSViewMaxXMargin ];
1538         [o_textfield setDelegate: self];
1539         [[NSNotificationCenter defaultCenter] addObserver: self
1540             selector: @selector(textfieldChanged:)
1541             name: NSControlTextDidChangeNotification
1542             object: o_textfield];
1543         [self addSubview: o_textfield];
1544
1545         /* build the mintextfield */
1546         ADD_LABEL(o_textfield_min, mainFrame, 12, -30, @"-8888", @"")
1547         [o_textfield_min setIntValue: p_item->min.i];
1548         [o_textfield_min setAutoresizingMask:NSViewMaxXMargin ];
1549         [o_textfield_min setAlignment:NSRightTextAlignment];
1550         [self addSubview: o_textfield_min];
1551
1552         /* build the maxtextfield */
1553         ADD_LABEL(o_textfield_max, mainFrame,
1554                     mainFrame.size.width - 31, -30, @"8888", @"")
1555         [o_textfield_max setIntValue: p_item->max.i];
1556         [o_textfield_max setAutoresizingMask:NSViewMinXMargin ];
1557         [self addSubview: o_textfield_max];
1558
1559         /* build the slider */
1560         ADD_SLIDER(o_slider, mainFrame, [o_textfield_min frame].origin.x +
1561             [o_textfield_min frame].size.width + 6, -1, mainFrame.size.width -
1562             [o_textfield_max frame].size.width -
1563             [o_textfield_max frame].size.width - 14 -
1564             [o_textfield_min frame].origin.x, o_tooltip,
1565             p_item->min.i, p_item->max.i)
1566         [o_slider setIntValue: p_item->value.i];
1567         [o_slider setAutoresizingMask:NSViewWidthSizable ];
1568         [o_slider setTarget: self];
1569         [o_slider setAction: @selector(sliderChanged:)];
1570         [o_slider sendActionOn:NSLeftMouseUpMask | NSLeftMouseDownMask |
1571             NSLeftMouseDraggedMask];
1572         [self addSubview: o_slider];
1573
1574     }
1575     return self;
1576 }
1577
1578 - (void) alignWithXPosition:(int)i_xPos
1579 {
1580     NSRect frame;
1581     frame = [o_label frame];
1582     frame.origin.x = i_xPos - frame.size.width - 3;
1583     [o_label setFrame:frame];
1584
1585     frame = [o_textfield frame];
1586     frame.origin.x = i_xPos + 2;
1587     [o_textfield setFrame:frame];
1588 }
1589
1590 - (void)dealloc
1591 {
1592     [o_textfield release];
1593     [o_textfield_min release];
1594     [o_textfield_max release];
1595     [o_slider release];
1596     [super dealloc];
1597 }
1598
1599 - (IBAction)sliderChanged:(id)sender
1600 {
1601     [o_textfield setIntValue: [o_slider intValue]];
1602 }
1603
1604 - (void)textfieldChanged:(NSNotification *)o_notification
1605 {
1606     [o_slider setIntValue: [o_textfield intValue]];
1607 }
1608
1609 - (int)intValue
1610 {
1611     return [o_slider intValue];
1612 }
1613
1614 - (void)resetValues
1615 {
1616     int value = config_GetInt(VLCIntf, p_item->psz_name);
1617     [o_textfield setIntValue:value];
1618     [o_slider setIntValue:value];
1619     [super resetValues];
1620 }
1621 @end
1622
1623 @implementation FloatConfigControl
1624 - (id) initWithItem: (module_config_t *)_p_item
1625            withView: (NSView *)o_parent_view
1626 {
1627     NSRect mainFrame = [o_parent_view frame];
1628     NSString *o_labelString, *o_tooltip;
1629     mainFrame.size.height = 23;
1630     mainFrame.size.width = mainFrame.size.width - LEFTMARGIN - RIGHTMARGIN + 1;
1631     mainFrame.origin.x = LEFTMARGIN;
1632     mainFrame.origin.y = 0;
1633
1634     if ([super initWithFrame: mainFrame item: _p_item] != nil) {
1635         i_view_type = CONFIG_ITEM_INTEGER;
1636
1637         o_tooltip = [[VLCStringUtility sharedInstance] wrapString: _NS((char *)p_item->psz_longtext) toWidth: PREFS_WRAP];
1638
1639         /* add the label */
1640         if (p_item->psz_text)
1641             o_labelString = _NS((char *)p_item->psz_text);
1642         else
1643             o_labelString = @"";
1644         ADD_LABEL(o_label, mainFrame, 0, -2, o_labelString, o_tooltip)
1645         [o_label setAutoresizingMask:NSViewNotSizable ];
1646         [self addSubview: o_label];
1647
1648         /* build the stepper */
1649         ADD_STEPPER(o_stepper, mainFrame, mainFrame.size.width - 19,
1650             0, o_tooltip, -100000, 100000)
1651         [o_stepper setFloatValue: p_item->value.f];
1652         [o_stepper setAutoresizingMask:NSViewMaxXMargin ];
1653         [self addSubview: o_stepper];
1654
1655         /* build the textfield */
1656         ADD_TEXTFIELD(o_textfield, mainFrame, mainFrame.size.width - 19 - 52,
1657             1, 49, o_tooltip, @"")
1658         [o_textfield setFloatValue: p_item->value.f];
1659         [o_textfield setDelegate: self];
1660         [[NSNotificationCenter defaultCenter] addObserver: self
1661             selector: @selector(textfieldChanged:)
1662             name: NSControlTextDidChangeNotification
1663             object: o_textfield];
1664         [o_textfield setAutoresizingMask:NSViewMaxXMargin ];
1665         [self addSubview: o_textfield];
1666     }
1667     return self;
1668 }
1669
1670 - (void) alignWithXPosition:(int)i_xPos
1671 {
1672     NSRect frame;
1673     frame = [o_label frame];
1674     frame.origin.x = i_xPos - frame.size.width - 3;
1675     [o_label setFrame:frame];
1676
1677     frame = [o_textfield frame];
1678     frame.origin.x = i_xPos + 2;
1679     [o_textfield setFrame:frame];
1680
1681     frame = [o_stepper frame];
1682     frame.origin.x = i_xPos + [o_textfield frame].size.width + 5;
1683     [o_stepper setFrame:frame];
1684 }
1685
1686 - (void)dealloc
1687 {
1688     [o_stepper release];
1689     [o_textfield release];
1690     [super dealloc];
1691 }
1692
1693 - (IBAction)stepperChanged:(id)sender
1694 {
1695     [o_textfield setFloatValue: [o_stepper floatValue]];
1696 }
1697
1698 - (void)textfieldChanged:(NSNotification *)o_notification
1699 {
1700     [o_stepper setFloatValue: [o_textfield floatValue]];
1701 }
1702
1703 - (float)floatValue
1704 {
1705     return [o_stepper floatValue];
1706 }
1707
1708 - (void)resetValues
1709 {
1710     [o_textfield setFloatValue: config_GetFloat(VLCIntf, p_item->psz_name)];
1711     [super resetValues];
1712 }
1713 @end
1714
1715 @implementation RangedFloatConfigControl
1716 - (id) initWithItem: (module_config_t *)_p_item
1717            withView: (NSView *)o_parent_view
1718 {
1719     NSRect mainFrame = [o_parent_view frame];
1720     NSString *o_labelString, *o_tooltip;
1721     mainFrame.size.height = 50;
1722     mainFrame.size.width = mainFrame.size.width - LEFTMARGIN - RIGHTMARGIN;
1723     mainFrame.origin.x = LEFTMARGIN;
1724     mainFrame.origin.y = 0;
1725
1726     if ([super initWithFrame: mainFrame item: _p_item] != nil) {
1727         i_view_type = CONFIG_ITEM_RANGED_INTEGER;
1728
1729         o_tooltip = [[VLCStringUtility sharedInstance] wrapString: _NS((char *)p_item->psz_longtext) toWidth: PREFS_WRAP];
1730
1731         /* add the label */
1732         if (p_item->psz_text)
1733             o_labelString = _NS((char *)p_item->psz_text);
1734         else
1735             o_labelString = @"";
1736         ADD_LABEL(o_label, mainFrame, 0, -3, o_labelString, o_tooltip)
1737         [o_label setAutoresizingMask:NSViewNotSizable ];
1738         [self addSubview: o_label];
1739
1740         /* build the textfield */
1741         ADD_TEXTFIELD(o_textfield, mainFrame, [o_label frame].size.width + 2,
1742             28, 49, o_tooltip, @"")
1743         [o_textfield setFloatValue: p_item->value.f];
1744         [o_textfield setAutoresizingMask:NSViewMaxXMargin ];
1745         [o_textfield setDelegate: self];
1746         [[NSNotificationCenter defaultCenter] addObserver: self
1747             selector: @selector(textfieldChanged:)
1748             name: NSControlTextDidChangeNotification
1749             object: o_textfield];
1750         [self addSubview: o_textfield];
1751
1752         /* build the mintextfield */
1753         ADD_LABEL(o_textfield_min, mainFrame, 12, -30, @"-8888", @"")
1754         [o_textfield_min setFloatValue: p_item->min.f];
1755         [o_textfield_min setAutoresizingMask:NSViewMaxXMargin ];
1756         [o_textfield_min setAlignment:NSRightTextAlignment];
1757         [self addSubview: o_textfield_min];
1758
1759         /* build the maxtextfield */
1760         ADD_LABEL(o_textfield_max, mainFrame, mainFrame.size.width - 31,
1761             -30, @"8888", @"")
1762         [o_textfield_max setFloatValue: p_item->max.f];
1763         [o_textfield_max setAutoresizingMask:NSViewMinXMargin ];
1764         [self addSubview: o_textfield_max];
1765
1766         /* build the slider */
1767         ADD_SLIDER(o_slider, mainFrame, [o_textfield_min frame].origin.x +
1768             [o_textfield_min frame].size.width + 6, -1, mainFrame.size.width -
1769             [o_textfield_max frame].size.width -
1770             [o_textfield_max frame].size.width - 14 -
1771             [o_textfield_min frame].origin.x, o_tooltip, p_item->min.f,
1772             p_item->max.f)
1773         [o_slider setFloatValue: p_item->value.f];
1774         [o_slider setAutoresizingMask:NSViewWidthSizable ];
1775         [o_slider setTarget: self];
1776         [o_slider setAction: @selector(sliderChanged:)];
1777         [o_slider sendActionOn:NSLeftMouseUpMask | NSLeftMouseDownMask |
1778             NSLeftMouseDraggedMask];
1779         [self addSubview: o_slider];
1780
1781     }
1782     return self;
1783 }
1784
1785 - (void) alignWithXPosition:(int)i_xPos
1786 {
1787     NSRect frame;
1788     frame = [o_label frame];
1789     frame.origin.x = i_xPos - frame.size.width - 3;
1790     [o_label setFrame:frame];
1791
1792     frame = [o_textfield frame];
1793     frame.origin.x = i_xPos + 2;
1794     [o_textfield setFrame:frame];
1795 }
1796
1797 - (void)dealloc
1798 {
1799     [o_textfield release];
1800     [o_textfield_min release];
1801     [o_textfield_max release];
1802     [o_slider release];
1803     [super dealloc];
1804 }
1805
1806 - (IBAction)sliderChanged:(id)sender
1807 {
1808     [o_textfield setFloatValue: [o_slider floatValue]];
1809 }
1810
1811 - (void)textfieldChanged:(NSNotification *)o_notification
1812 {
1813     [o_slider setFloatValue: [o_textfield floatValue]];
1814 }
1815
1816 - (float)floatValue
1817 {
1818     return [o_slider floatValue];
1819 }
1820
1821 - (void)resetValues
1822 {
1823     [o_textfield setFloatValue: config_GetFloat(VLCIntf, p_item->psz_name)];
1824     [o_slider setFloatValue: config_GetFloat(VLCIntf, p_item->psz_name)];
1825     [super resetValues];
1826 }
1827 @end
1828
1829 @implementation BoolConfigControl
1830
1831 - (id) initWithItem: (module_config_t *)_p_item
1832            withView: (NSView *)o_parent_view
1833 {
1834     NSRect mainFrame = [o_parent_view frame];
1835     NSString *o_labelString, *o_tooltip;
1836     mainFrame.size.height = 17;
1837     mainFrame.size.width = mainFrame.size.width - LEFTMARGIN - RIGHTMARGIN;
1838     mainFrame.origin.x = LEFTMARGIN;
1839     mainFrame.origin.y = 0;
1840
1841     if ([super initWithFrame: mainFrame item: _p_item] != nil) {
1842         i_view_type = CONFIG_ITEM_BOOL;
1843
1844         if (p_item->psz_text)
1845             o_labelString = _NS((char *)p_item->psz_text);
1846         else
1847             o_labelString = @"";
1848
1849         o_tooltip = [[VLCStringUtility sharedInstance] wrapString: _NS((char *)p_item->psz_longtext) toWidth: PREFS_WRAP];
1850
1851         /* add the checkbox */
1852         ADD_CHECKBOX(o_checkbox, mainFrame, 0,
1853                         0, o_labelString, o_tooltip, p_item->value.i, NSImageLeft)
1854         [o_checkbox setAutoresizingMask:NSViewNotSizable ];
1855         [self addSubview: o_checkbox];
1856     }
1857     return self;
1858 }
1859
1860 - (void)dealloc
1861 {
1862     [o_checkbox release];
1863     [super dealloc];
1864 }
1865
1866 - (int)intValue
1867 {
1868     return [o_checkbox intValue];
1869 }
1870
1871 - (void)resetValues
1872 {
1873     [o_checkbox setState: config_GetInt(VLCIntf, p_item->psz_name)];
1874     [super resetValues];
1875 }
1876 @end
1877
1878 @implementation KeyConfigControl
1879 - (id) initWithItem: (module_config_t *)_p_item
1880            withView: (NSView *)o_parent_view
1881 {
1882     NSRect mainFrame = [o_parent_view frame];
1883     NSString *o_labelString, *o_tooltip;
1884     mainFrame.size.height = 22;
1885     mainFrame.size.width = mainFrame.size.width - LEFTMARGIN - RIGHTMARGIN + 1;
1886     mainFrame.origin.x = LEFTMARGIN;
1887     mainFrame.origin.y = 0;
1888
1889     if ([super initWithFrame: mainFrame item: _p_item] != nil) {
1890         i_view_type = CONFIG_ITEM_KEY;
1891
1892         o_tooltip = [[VLCStringUtility sharedInstance] wrapString: _NS((char *)p_item->psz_longtext) toWidth: PREFS_WRAP];
1893
1894         /* add the label */
1895         if (p_item->psz_text)
1896             o_labelString = _NS((char *)p_item->psz_text);
1897         else
1898             o_labelString = @"";
1899         ADD_LABEL(o_label, mainFrame, 0, -1, o_labelString, o_tooltip)
1900         [o_label setAutoresizingMask:NSViewNotSizable ];
1901         [self addSubview: o_label];
1902
1903         /* build the popup */
1904         ADD_POPUP(o_popup, mainFrame, [o_label frame].origin.x +
1905             [o_label frame].size.width + 3,
1906             -2, 0, o_tooltip)
1907         [o_popup setAutoresizingMask:NSViewWidthSizable ];
1908
1909         if (o_keys_menu == nil) {
1910             unsigned int i;
1911             o_keys_menu = [[NSMenu alloc] initWithTitle: @"Keys Menu"];
1912 #warning This does not work anymore. FIXME.
1913 #if 0
1914             for (i = 0; i < sizeof(vlc_key) / sizeof(key_descriptor_t); i++)
1915                 if (vlc_key[i].psz_key_string)
1916                     POPULATE_A_KEY(o_keys_menu,
1917                         [NSString stringWithUTF8String:vlc_key[i].psz_key_string],
1918                                    vlc_key[i].i_key_code)
1919 #endif
1920         }
1921         [o_popup setMenu:[o_keys_menu copyWithZone:nil]];
1922         [o_popup selectItem:[[o_popup menu] itemWithTag:p_item->value.i]];
1923         [self addSubview: o_popup];
1924
1925     }
1926     return self;
1927 }
1928
1929 - (void) alignWithXPosition:(int)i_xPos
1930 {
1931     NSRect frame;
1932     NSRect superFrame = [self frame];
1933     frame = [o_label frame];
1934     frame.origin.x = i_xPos - frame.size.width - 3;
1935     [o_label setFrame:frame];
1936
1937     frame = [o_popup frame];
1938     frame.origin.x = i_xPos - 1;
1939     frame.size.width = superFrame.size.width - frame.origin.x + 2;
1940     [o_popup setFrame:frame];
1941 }
1942
1943 - (void)dealloc
1944 {
1945     [o_popup release];
1946     [super dealloc];
1947 }
1948
1949 - (int)intValue
1950 {
1951     return [o_popup selectedTag];
1952 }
1953
1954 - (void)resetValues
1955 {
1956     [o_popup selectItem:[[o_popup menu] itemWithTag:config_GetInt(VLCIntf, p_item->psz_name)]];
1957     [super resetValues];
1958 }
1959 @end
1960
1961 @implementation ModuleListConfigControl
1962 - (id) initWithItem: (module_config_t *)_p_item
1963            withView: (NSView *)o_parent_view
1964 {
1965     BOOL b_by_cat = _p_item->i_type == CONFIG_ITEM_MODULE_LIST_CAT;
1966
1967     //Fill our array to know how may items we have...
1968     module_t *p_parser, **p_list;
1969     size_t i_module_index;
1970     NSRect mainFrame = [o_parent_view frame];
1971     NSString *o_labelString, *o_textfieldString, *o_tooltip;
1972
1973     o_modulearray = [[NSMutableArray alloc] initWithCapacity:10];
1974     /* build a list of available modules */
1975     size_t count;
1976     p_list = module_list_get(&count);
1977     for (i_module_index = 0; i_module_index < count; i_module_index++) {
1978         int i;
1979         p_parser = p_list[i_module_index];
1980
1981         if (module_is_main(p_parser))
1982             continue;
1983
1984         if (b_by_cat) {
1985             unsigned int confsize;
1986             module_config_t *p_configlist = module_config_get(p_parser, &confsize);
1987
1988             for (i = 0; i < confsize; i++) {
1989                 unsigned int unused;
1990                 module_config_t *p_config = &p_configlist[i];
1991                 NSString *o_modulelongname, *o_modulename;
1992                 NSNumber *o_moduleenabled = nil;
1993
1994                 /* Hack: required subcategory is stored in i_min */
1995                 if (p_config->i_type == CONFIG_SUBCATEGORY &&
1996                     p_config->value.i == _p_item->min.i) {
1997
1998                     o_modulelongname = [NSString stringWithUTF8String:module_get_name(p_parser, TRUE)];
1999                     o_modulename = [NSString stringWithUTF8String:module_get_object(p_parser)];
2000
2001                     if (_p_item->value.psz &&
2002                         strstr(_p_item->value.psz, module_get_object(p_parser)))
2003                         o_moduleenabled = [NSNumber numberWithBool:YES];
2004                     else
2005                         o_moduleenabled = [NSNumber numberWithBool:NO];
2006
2007                     [o_modulearray addObject:[NSMutableArray
2008                                               arrayWithObjects: o_modulename, o_modulelongname,
2009                                               o_moduleenabled, nil]];
2010                 }
2011
2012                 /* Parental Advisory HACK:
2013                  * Selecting HTTP, RC and Telnet interfaces is difficult now
2014                  * since they are just the lua interface module */
2015                 if (p_config->i_type == CONFIG_SUBCATEGORY &&
2016                     !strcmp(module_get_object(p_parser), "lua") &&
2017                     !strcmp(_p_item->psz_name, "extraintf") &&
2018                     p_config->value.i == _p_item->min.i) {
2019
2020 #define addLuaIntf(shortname, longname) \
2021 if (_p_item->value.psz && strstr(_p_item->value.psz, shortname))\
2022     o_moduleenabled = [NSNumber numberWithBool:YES];\
2023 else\
2024     o_moduleenabled = [NSNumber numberWithBool:NO];\
2025     [o_modulearray addObject:[NSMutableArray arrayWithObjects: @shortname, _NS(longname), o_moduleenabled, nil]]
2026
2027                     addLuaIntf("http", "Web");
2028                     addLuaIntf("telnet", "Telnet");
2029                     addLuaIntf("cli", "Console");
2030 #undef addLuaIntf
2031                 }
2032
2033             }
2034             module_config_free(p_configlist);
2035
2036
2037         } else if (module_provides(p_parser, _p_item->psz_type)) {
2038
2039             NSString *o_modulelongname = toNSStr(module_get_name(p_parser, TRUE));
2040             NSString *o_modulename = toNSStr(module_get_object(p_parser));
2041
2042             NSNumber *o_moduleenabled = nil;
2043             if (_p_item->value.psz &&
2044                 strstr(_p_item->value.psz, module_get_object(p_parser)))
2045                 o_moduleenabled = [NSNumber numberWithBool:YES];
2046             else
2047                 o_moduleenabled = [NSNumber numberWithBool:NO];
2048
2049             [o_modulearray addObject:[NSMutableArray
2050                                       arrayWithObjects: o_modulename, o_modulelongname,
2051                                       o_moduleenabled, nil]];
2052         }
2053
2054     } /* FOR i_module_index */
2055     module_list_free(p_list);
2056
2057     // First, initialize and draw the table view to get its height
2058     // width is increased a little to fix horizontal auto-sizing
2059     NSRect s_rc = NSMakeRect(12, 10, mainFrame.size.width - LEFTMARGIN - RIGHTMARGIN + 18, 50);
2060     // height is automatically increased as needed
2061     o_tableview = [[NSTableView alloc] initWithFrame : s_rc];
2062     [o_tableview setUsesAlternatingRowBackgroundColors:YES];
2063     [o_tableview setHeaderView:nil];
2064     /* FIXME: support for multiple selection... */
2065     //    [o_tableview setAllowsMultipleSelection:YES];
2066
2067     NSCell *o_headerCell = [[NSCell alloc] initTextCell:@"Enabled"];
2068     NSCell *o_dataCell = [[NSButtonCell alloc] init];
2069     [(NSButtonCell*)o_dataCell setButtonType:NSSwitchButton];
2070     [o_dataCell setTitle:@""];
2071     [o_dataCell setFont:[NSFont systemFontOfSize:0]];
2072     NSTableColumn *o_tableColumn = [[NSTableColumn alloc]
2073                                     initWithIdentifier:@"Enabled"];
2074     [o_tableColumn setHeaderCell: o_headerCell];
2075     [o_tableColumn setDataCell: o_dataCell];
2076     [o_tableColumn setWidth:17];
2077     [o_tableview addTableColumn: o_tableColumn];
2078
2079     o_headerCell = [[NSCell alloc] initTextCell:@"Module Name"];
2080     o_dataCell = [[NSTextFieldCell alloc] init];
2081     [o_dataCell setFont:[NSFont systemFontOfSize:12]];
2082     o_tableColumn = [[NSTableColumn alloc]
2083                      initWithIdentifier:@"Module"];
2084     [o_tableColumn setHeaderCell: o_headerCell];
2085     [o_tableColumn setDataCell: o_dataCell];
2086     [o_tableColumn setWidth:s_rc.size.width - 34];
2087     [o_tableview addTableColumn: o_tableColumn];
2088     [o_tableview registerForDraggedTypes:[NSArray arrayWithObject:@"VLC media player module"]];
2089
2090     [o_tableview setDataSource:self];
2091     [o_tableview setTarget: self];
2092     [o_tableview setAction: @selector(tableChanged:)];
2093     [o_tableview sendActionOn:NSLeftMouseUpMask | NSLeftMouseDownMask |
2094      NSLeftMouseDraggedMask];
2095
2096     [o_tableview reloadData];
2097     [o_tableview setAutoresizingMask: NSViewWidthSizable];
2098
2099     CGFloat tableview_height = [o_tableview frame].size.height;
2100
2101     mainFrame.size.height = 40 + tableview_height;
2102     mainFrame.size.width = mainFrame.size.width - LEFTMARGIN - RIGHTMARGIN;
2103     mainFrame.origin.x = LEFTMARGIN;
2104     mainFrame.origin.y = 0;
2105     if ([super initWithFrame: mainFrame item: _p_item] != nil) {
2106         i_view_type = CONFIG_ITEM_MODULE_LIST;
2107
2108         o_tooltip = [[VLCStringUtility sharedInstance] wrapString: _NS((char *)p_item->psz_longtext) toWidth: PREFS_WRAP];
2109
2110         /* add the label */
2111         if (p_item->psz_text)
2112             o_labelString = _NS((char *)p_item->psz_text);
2113         else
2114             o_labelString = @"";
2115         ADD_LABEL(o_label, mainFrame, 0, -3, o_labelString, o_tooltip)
2116         [o_label setAutoresizingMask:NSViewNotSizable ];
2117         [self addSubview: o_label];
2118
2119         /* build the textfield */
2120         if (p_item->value.psz)
2121             o_textfieldString = _NS((char *)p_item->value.psz);
2122         else
2123             o_textfieldString = @"";
2124         ADD_TEXTFIELD(o_textfield, mainFrame, [o_label frame].size.width + 2,
2125                       mainFrame.size.height - 22, mainFrame.size.width -
2126                       [o_label frame].size.width - 2, o_tooltip, o_textfieldString)
2127         [o_textfield setAutoresizingMask:NSViewWidthSizable ];
2128         [self addSubview: o_textfield];
2129
2130         [self addSubview: o_tableview];
2131     }
2132     return self;
2133 }
2134
2135 - (void) alignWithXPosition:(int)i_xPos
2136 {
2137     ;
2138 }
2139
2140 - (IBAction)tableChanged:(id)sender
2141 {
2142     NSString *o_newstring = @"";
2143     NSUInteger count = [o_modulearray count];
2144     for (NSUInteger i = 0 ; i < count ; i++)
2145         if ([[[o_modulearray objectAtIndex:i] objectAtIndex:2]
2146             boolValue] != NO) {
2147             o_newstring = [o_newstring stringByAppendingString:
2148                 [[o_modulearray objectAtIndex:i] objectAtIndex:0]];
2149             o_newstring = [o_newstring stringByAppendingString:@":"];
2150         }
2151
2152     [o_textfield setStringValue: [o_newstring
2153         substringToIndex: ([o_newstring length])?[o_newstring length] - 1:0]];
2154 }
2155
2156 - (void)dealloc
2157 {
2158     [o_tableview release];
2159     [super dealloc];
2160 }
2161
2162
2163 - (char *)stringValue
2164 {
2165     return strdup([[o_textfield stringValue] UTF8String]);
2166 }
2167
2168 -(void)resetValues
2169 {
2170 #warning Reset prefs of the module selector is broken atm.
2171     msg_Err(VLCIntf, "don't forget about modulelistconfig");
2172     [super resetValues];
2173 }
2174
2175 @end
2176
2177 @implementation ModuleListConfigControl (NSTableDataSource)
2178
2179 - (BOOL)tableView:(NSTableView*)table writeRows:(NSArray*)rows
2180     toPasteboard:(NSPasteboard*)pb
2181 {
2182     // We only want to allow dragging of selected rows.
2183     NSEnumerator    *iter = [rows objectEnumerator];
2184     NSNumber        *row;
2185     while ((row = [iter nextObject]) != nil) {
2186         if (![table isRowSelected:[row intValue]])
2187             return NO;
2188     }
2189
2190     [pb declareTypes:[NSArray arrayWithObject:@"VLC media player module"] owner:nil];
2191     [pb setPropertyList:rows forType:@"VLC media player module"];
2192     return YES;
2193 }
2194
2195 - (NSDragOperation)tableView:(NSTableView*)table
2196     validateDrop:(id <NSDraggingInfo>)info proposedRow:(NSInteger)row
2197     proposedDropOperation:(NSTableViewDropOperation)op
2198 {
2199     // Make drops at the end of the table go to the end.
2200     if (row == -1) {
2201         row = [table numberOfRows];
2202         op = NSTableViewDropAbove;
2203         [table setDropRow:row dropOperation:op];
2204     }
2205
2206     // We don't ever want to drop onto a row, only between rows.
2207     if (op == NSTableViewDropOn)
2208         [table setDropRow:(row+1) dropOperation:NSTableViewDropAbove];
2209     return NSTableViewDropAbove;
2210 }
2211
2212 - (BOOL)tableView:(NSTableView*)table acceptDrop:(id <NSDraggingInfo>)info
2213     row:(NSInteger)dropRow dropOperation:(NSTableViewDropOperation)op;
2214 {
2215     NSPasteboard    *pb = [info draggingPasteboard];
2216     NSDragOperation srcMask = [info draggingSourceOperationMask];
2217     BOOL accepted = NO;
2218
2219     NS_DURING
2220
2221         NSArray *array;
2222
2223         // Intra-table drag - data is the array of rows.
2224         if (!accepted && (array =
2225             [pb propertyListForType:@"VLC media player module"]) != NULL) {
2226             NSEnumerator *iter = nil;
2227             id val;
2228             BOOL isCopy = (srcMask & NSDragOperationMove) ? NO:YES;
2229             // Move the modules
2230             iter = [array objectEnumerator];
2231             while ((val = [iter nextObject]) != NULL) {
2232                 NSArray *o_tmp = [[o_modulearray objectAtIndex:
2233                     [val intValue]] mutableCopyWithZone:nil];
2234                 [o_modulearray removeObject:o_tmp];
2235                 [o_modulearray insertObject:o_tmp
2236                     atIndex:(dropRow>[val intValue]) ? dropRow - 1 : dropRow];
2237                 dropRow++;
2238             }
2239
2240             // Select the newly-dragged items.
2241             iter = [array objectEnumerator];
2242 //TODO...
2243             [table deselectAll:self];
2244
2245             [self tableChanged:self];
2246             [table setNeedsDisplay:YES];
2247             // Indicate that we finished the drag.
2248             accepted = YES;
2249         }
2250         [table reloadData];
2251         [table setNeedsDisplay:YES];
2252
2253         NS_HANDLER
2254
2255             // An exception occurred. Uh-oh. Update the track table so that
2256             // it stays consistent, and re-raise the exception.
2257             [table reloadData];
2258             [localException raise];
2259             [table setNeedsDisplay:YES];
2260     NS_ENDHANDLER
2261
2262     return accepted;
2263 }
2264
2265 - (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView
2266 {
2267     return [o_modulearray count];
2268 }
2269
2270 - (id)tableView:(NSTableView *)aTableView
2271     objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
2272 {
2273     if ([[aTableColumn identifier] isEqualToString: @"Enabled"])
2274         return [[o_modulearray objectAtIndex:rowIndex] objectAtIndex:2];
2275     if ([[aTableColumn identifier] isEqualToString: @"Module"])
2276         return [[o_modulearray objectAtIndex:rowIndex] objectAtIndex:1];
2277
2278     return nil;
2279 }
2280
2281 - (void)tableView:(NSTableView *)aTableView setObjectValue:(id)anObject
2282     forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
2283 {
2284     [[o_modulearray objectAtIndex:rowIndex] replaceObjectAtIndex:2
2285         withObject: anObject];
2286 }
2287 @end
2288
2289 @implementation SectionControl
2290
2291 - (id) initWithItem: (module_config_t *)_p_item
2292            withView: (NSView *)o_parent_view
2293 {
2294     NSRect mainFrame = [o_parent_view frame];
2295     NSString *o_labelString, *o_tooltip;
2296     mainFrame.size.height = 17;
2297     mainFrame.size.width = mainFrame.size.width - LEFTMARGIN - RIGHTMARGIN;
2298     mainFrame.origin.x = LEFTMARGIN;
2299     mainFrame.origin.y = 0;
2300
2301     if ([super initWithFrame: mainFrame item: _p_item] != nil) {
2302         
2303         /* add the label */
2304         if (p_item->psz_text)
2305             o_labelString = _NS((char *)p_item->psz_text);
2306         else
2307             o_labelString = @"";
2308
2309         NSDictionary *boldAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
2310                         [NSFont boldSystemFontOfSize:[NSFont systemFontSize]],
2311                         NSFontAttributeName,
2312                         nil];
2313         NSAttributedString *o_bold_string = [[NSAttributedString alloc] initWithString: o_labelString attributes: boldAttributes];
2314
2315         ADD_LABEL(o_label, mainFrame, 1, 0, @"", @"")
2316         [o_label setAttributedStringValue: o_bold_string];
2317         [o_label sizeToFit];
2318
2319         [o_bold_string release];
2320         
2321         [o_label setAutoresizingMask:NSViewNotSizable];
2322         [self addSubview: o_label];
2323     }
2324     return self;
2325 }
2326
2327 @end
2328