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