* modules/gui/wxwindows/preferences.cpp: the config panels are now generated on deman...
[vlc.git] / modules / gui / wxwindows / preferences.cpp
1 /*****************************************************************************
2  * preferences.cpp : wxWindows plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2000-2001 VideoLAN
5  * $Id: preferences.cpp,v 1.14 2003/05/12 21:55:01 gbazin Exp $
6  *
7  * Authors: Gildas Bazin <gbazin@netcourrier.com>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                                      /* malloc(), free() */
28 #include <errno.h>                                                 /* ENOMEM */
29 #include <string.h>                                            /* strerror() */
30 #include <stdio.h>
31
32 #include <vlc/vlc.h>
33
34 #ifdef WIN32                                                 /* mingw32 hack */
35 #undef Yield
36 #undef CreateDialog
37 #endif
38
39 /* Let vlc take care of the i18n stuff */
40 #define WXINTL_NO_GETTEXT_MACRO
41
42 #include <wx/wxprec.h>
43 #include <wx/wx.h>
44 #include <wx/window.h>
45 #include <wx/notebook.h>
46 #include <wx/textctrl.h>
47 #include <wx/combobox.h>
48 #include <wx/spinctrl.h>
49 #include <wx/statline.h>
50 #include <wx/treectrl.h>
51 #include <wx/clntdata.h>
52 #include <wx/dynarray.h>
53
54 #include <vlc/intf.h>
55
56 #if defined MODULE_NAME_IS_skins
57 #   include "../skins/src/skin_common.h"
58 #endif
59
60 #include "wxwindows.h"
61
62 #ifndef wxRB_SINGLE
63 #   define wxRB_SINGLE 0
64 #endif
65
66 /*****************************************************************************
67  * Classes declarations.
68  *****************************************************************************/
69 class PrefsTreeCtrl : public wxTreeCtrl
70 {
71 public:
72
73     PrefsTreeCtrl() { }
74     PrefsTreeCtrl( wxWindow *parent, intf_thread_t *_p_intf,
75                    PrefsDialog *p_prefs_dialog, wxBoxSizer *_p_sizer );
76     virtual ~PrefsTreeCtrl();
77
78     void ApplyChanges();
79     void CleanChanges();
80
81 private:
82     /* Event handlers (these functions should _not_ be virtual) */
83     void OnSelectTreeItem( wxTreeEvent& event );
84
85     DECLARE_EVENT_TABLE()
86
87     intf_thread_t *p_intf;
88     PrefsDialog *p_prefs_dialog;
89     wxBoxSizer *p_sizer;
90     wxWindow *p_parent;
91
92     wxTreeItemId root_item;
93     wxTreeItemId plugins_item;
94 };
95
96 struct ConfigData
97 {
98     ConfigData( wxPanel *_panel, int _i_conf_type,
99                 vlc_bool_t _b_advanced, char *psz_name )
100     { panel = _panel; b_advanced = _b_advanced; b_config_list = VLC_FALSE;
101       i_config_type = _i_conf_type; option_name = wxU(psz_name); }
102
103     vlc_bool_t b_advanced;
104     int i_config_type;
105     vlc_bool_t b_config_list;
106
107     union control
108     {
109         wxComboBox *combobox;
110         wxRadioButton *radio;
111         wxSpinCtrl *spinctrl;
112         wxCheckBox *checkbox;
113         wxTextCtrl *textctrl;
114
115     } control;
116
117     wxPanel *panel;
118     wxString option_name;
119 };
120
121 WX_DEFINE_ARRAY(ConfigData *, ArrayOfConfigData);
122
123 class PrefsPanel : public wxPanel
124 {
125 public:
126
127     PrefsPanel() { }
128     PrefsPanel( wxWindow *parent, intf_thread_t *_p_intf,
129                 PrefsDialog *_p_prefs_dialog, int i_object_id, char * );
130     virtual ~PrefsPanel() {}
131
132     void ApplyChanges();
133
134 private:
135     void OnAdvanced( wxCommandEvent& WXUNUSED(event) );
136     DECLARE_EVENT_TABLE()
137
138     intf_thread_t *p_intf;
139     PrefsDialog *p_prefs_dialog;
140
141     vlc_bool_t b_advanced;
142
143     wxBoxSizer *config_sizer;
144     wxScrolledWindow *config_window;
145
146     ArrayOfConfigData config_array;
147 };
148
149 class ConfigTreeData : public wxTreeItemData
150 {
151 public:
152
153     ConfigTreeData() { panel = NULL; psz_section = NULL; }
154     virtual ~ConfigTreeData() { if( panel ) delete panel; }
155
156     PrefsPanel *panel;
157     wxBoxSizer *sizer;
158     int i_object_id;
159     char *psz_section;
160 };
161
162 class ConfigEvtHandler : public wxEvtHandler
163 {
164 public:
165     ConfigEvtHandler( intf_thread_t *p_intf, PrefsDialog *p_prefs_dialog );
166     virtual ~ConfigEvtHandler();
167
168     void ConfigEvtHandler::OnCommandEvent( wxCommandEvent& event );
169
170 private:
171
172     DECLARE_EVENT_TABLE()
173
174     intf_thread_t *p_intf;
175     PrefsDialog *p_prefs_dialog;
176 };
177
178 /*****************************************************************************
179  * Event Table.
180  *****************************************************************************/
181
182 /* IDs for the controls and the menu commands */
183 enum
184 {
185     Notebook_Event = wxID_HIGHEST,
186     MRL_Event,
187     ResetAll_Event,
188     Advanced_Event,
189 };
190
191 BEGIN_EVENT_TABLE(PrefsDialog, wxFrame)
192     /* Button events */
193     EVT_BUTTON(wxID_OK, PrefsDialog::OnOk)
194     EVT_BUTTON(wxID_CANCEL, PrefsDialog::OnCancel)
195     EVT_BUTTON(wxID_SAVE, PrefsDialog::OnSave)
196     EVT_BUTTON(ResetAll_Event, PrefsDialog::OnResetAll)
197
198     /* Don't destroy the window when the user closes it */
199     EVT_CLOSE(PrefsDialog::OnCancel)
200 END_EVENT_TABLE()
201
202 // menu and control ids
203 enum
204 {
205     PrefsTree_Ctrl = wxID_HIGHEST
206 };
207
208 BEGIN_EVENT_TABLE(PrefsTreeCtrl, wxTreeCtrl)
209     EVT_TREE_SEL_CHANGED(PrefsTree_Ctrl, PrefsTreeCtrl::OnSelectTreeItem)
210 END_EVENT_TABLE()
211
212 BEGIN_EVENT_TABLE(PrefsPanel, wxPanel)
213     /* Button events */
214     EVT_BUTTON(Advanced_Event, PrefsPanel::OnAdvanced)
215
216 END_EVENT_TABLE()
217
218 BEGIN_EVENT_TABLE(ConfigEvtHandler, wxEvtHandler)
219     EVT_BUTTON(-1, ConfigEvtHandler::OnCommandEvent)
220     EVT_TEXT(-1, ConfigEvtHandler::OnCommandEvent)
221     EVT_RADIOBOX(-1, ConfigEvtHandler::OnCommandEvent)
222     EVT_SPINCTRL(-1, ConfigEvtHandler::OnCommandEvent)
223 END_EVENT_TABLE()
224
225 /*****************************************************************************
226  * Constructor.
227  *****************************************************************************/
228 PrefsDialog::PrefsDialog( intf_thread_t *_p_intf, Interface *_p_main_interface)
229   :  wxFrame( _p_main_interface, -1, wxU(_("Preferences")), wxDefaultPosition,
230               wxSize(650,450), wxDEFAULT_FRAME_STYLE )
231 {
232     /* Initializations */
233     p_intf = _p_intf;
234     p_main_interface = _p_main_interface;
235     SetIcon( *p_intf->p_sys->p_icon );
236
237     /* Create a panel to put everything in */
238     wxPanel *panel = new wxPanel( this, -1 );
239     panel->SetAutoLayout( TRUE );
240
241     /* Create the preferences tree control */
242     wxBoxSizer *controls_sizer = new wxBoxSizer( wxHORIZONTAL );
243     prefs_tree =
244         new PrefsTreeCtrl( panel, p_intf, this, controls_sizer );
245
246     /* Separation */
247     wxStaticLine *static_line = new wxStaticLine( panel, wxID_OK );
248
249     /* Create the buttons */
250     wxButton *ok_button = new wxButton( panel, wxID_OK, wxU(_("OK")) );
251     ok_button->SetDefault();
252     wxButton *cancel_button = new wxButton( panel, wxID_CANCEL,
253                                             wxU(_("Cancel")) );
254     wxButton *save_button = new wxButton( panel, wxID_SAVE, wxU(_("Save")) );
255     wxButton *reset_button = new wxButton( panel, ResetAll_Event,
256                                            wxU(_("Reset All")) );
257
258     /* Place everything in sizers */
259     wxBoxSizer *button_sizer = new wxBoxSizer( wxHORIZONTAL );
260     button_sizer->Add( ok_button, 0, wxALL, 5 );
261     button_sizer->Add( cancel_button, 0, wxALL, 5 );
262     button_sizer->Add( save_button, 0, wxALL, 5 );
263     button_sizer->Add( reset_button, 0, wxALL, 5 );
264     button_sizer->Layout();
265
266     wxBoxSizer *main_sizer = new wxBoxSizer( wxVERTICAL );
267     wxBoxSizer *panel_sizer = new wxBoxSizer( wxVERTICAL );
268     panel_sizer->Add( controls_sizer, 1, wxEXPAND | wxALL, 5 );
269     panel_sizer->Add( static_line, 0, wxEXPAND | wxALL, 5 );
270     panel_sizer->Add( button_sizer, 0, wxALIGN_LEFT | wxALIGN_BOTTOM |
271                       wxALL, 5 );
272     panel_sizer->Layout();
273     panel->SetSizer( panel_sizer );
274     main_sizer->Add( panel, 1, wxEXPAND, 0 );
275     main_sizer->Layout();
276     SetSizer( main_sizer );
277 }
278
279 PrefsDialog::~PrefsDialog()
280 {
281 }
282
283 /*****************************************************************************
284  * Private methods.
285  *****************************************************************************/
286
287
288 /*****************************************************************************
289  * Events methods.
290  *****************************************************************************/
291 void PrefsDialog::OnOk( wxCommandEvent& WXUNUSED(event) )
292 {
293     prefs_tree->ApplyChanges();
294     this->Hide();
295     prefs_tree->CleanChanges();
296 }
297
298 void PrefsDialog::OnCancel( wxCommandEvent& WXUNUSED(event) )
299 {
300     this->Hide();
301     prefs_tree->CleanChanges();
302 }
303
304 void PrefsDialog::OnSave( wxCommandEvent& WXUNUSED(event) )
305 {
306     prefs_tree->ApplyChanges();
307     config_SaveConfigFile( p_intf, NULL );
308 }
309
310 void PrefsDialog::OnResetAll( wxCommandEvent& WXUNUSED(event) )
311 {
312     wxMessageDialog dlg( this,
313         wxU(_("Beware this will reset your VLC Media Player config file.\n"
314               "Are you sure you want to continue?")),
315         wxU(_("Reset config file")), wxYES_NO|wxNO_DEFAULT|wxCENTRE );
316
317     if ( dlg.ShowModal() == wxID_YES )
318     {
319         /* TODO: need to reset all the controls */
320         config_ResetAll( p_intf );
321         prefs_tree->CleanChanges();
322         config_SaveConfigFile( p_intf, NULL );
323     }
324 }
325
326 /*****************************************************************************
327  * PrefsTreeCtrl class definition.
328  *****************************************************************************/
329 PrefsTreeCtrl::PrefsTreeCtrl( wxWindow *_p_parent, intf_thread_t *_p_intf,
330                               PrefsDialog *_p_prefs_dialog,
331                               wxBoxSizer *_p_sizer )
332   : wxTreeCtrl( _p_parent, PrefsTree_Ctrl, wxDefaultPosition, wxDefaultSize,
333                 wxTR_NO_LINES | wxTR_FULL_ROW_HIGHLIGHT |
334                 wxTR_LINES_AT_ROOT | wxTR_HIDE_ROOT |
335                 wxTR_HAS_BUTTONS | wxTR_TWIST_BUTTONS | wxSUNKEN_BORDER )
336 {
337     vlc_list_t      *p_list;
338     module_t        *p_module;
339     module_config_t *p_item;
340     int i_index;
341
342     /* Initializations */
343     p_intf = _p_intf;
344     p_prefs_dialog = _p_prefs_dialog;
345     p_sizer = _p_sizer;
346     p_parent = _p_parent;
347
348     root_item = AddRoot( wxT("") );
349
350     /* List the plugins */
351     p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
352     if( !p_list ) return;
353
354     /*
355      * Build a tree of the main options
356      */
357     for( i_index = 0; i_index < p_list->i_count; i_index++ )
358     {
359         p_module = (module_t *)p_list->p_values[i_index].p_object;
360         if( !strcmp( p_module->psz_object_name, "main" ) )
361             break;
362     }
363     if( i_index < p_list->i_count )
364     {
365         /* We found the main module */
366
367         /* Enumerate config categories and store a reference so we can
368          * generate their config panel them when it is asked by the user. */
369         p_item = p_module->p_config;
370
371         if( p_item ) do
372         {
373             switch( p_item->i_type )
374             {
375             case CONFIG_HINT_CATEGORY:
376                 ConfigTreeData *config_data = new ConfigTreeData;
377                 config_data->psz_section = strdup(p_item->psz_text);
378                 config_data->i_object_id = p_module->i_object_id;
379
380                 /* Add the category to the tree */
381                 AppendItem( root_item, wxU(p_item->psz_text),
382                             -1, -1, config_data );
383                 break;
384             }
385         }
386         while( p_item->i_type != CONFIG_HINT_END && p_item++ );
387
388         SortChildren( root_item );
389     }
390
391
392     /*
393      * Build a tree of all the plugins
394      */
395     plugins_item = AppendItem( root_item, wxU(_("Plugins")) );
396
397     for( i_index = 0; i_index < p_list->i_count; i_index++ )
398     {
399         p_module = (module_t *)p_list->p_values[i_index].p_object;
400
401         /* Exclude the main module */
402         if( !strcmp( p_module->psz_object_name, "main" ) )
403             continue;
404
405         /* Exclude empty plugins */
406         p_item = p_module->p_config;
407         if( !p_item ) continue;
408         do
409         {
410             if( p_item->i_type & CONFIG_ITEM )
411                 break;
412         }
413         while( p_item->i_type != CONFIG_HINT_END && p_item++ );
414         if( p_item->i_type == CONFIG_HINT_END ) continue;
415
416         /* Find the capability child item */
417         long cookie; size_t i_child_index;
418         wxTreeItemId capability_item = GetFirstChild( plugins_item, cookie);
419         for( i_child_index = 0;
420              i_child_index < GetChildrenCount( plugins_item, FALSE );
421              i_child_index++ )
422         {
423             if( !GetItemText(capability_item).Cmp(
424                     wxU(p_module->psz_capability ) ) )
425             {
426                 break;
427             }
428             capability_item = GetNextChild( plugins_item, cookie );
429         }
430
431         if( i_child_index == GetChildrenCount( plugins_item, FALSE ) &&
432             p_module->psz_capability && *p_module->psz_capability )
433         {
434             /* We didn't find it, add it */
435             capability_item = AppendItem( plugins_item,
436                                           wxU(p_module->psz_capability) );
437         }
438
439         /* Add the plugin to the tree */
440         ConfigTreeData *config_data = new ConfigTreeData;
441         config_data->i_object_id = p_module->i_object_id;
442         AppendItem( capability_item, wxU(p_module->psz_object_name), -1, -1,
443                     config_data );
444     }
445
446     /* Sort all this mess */
447     long cookie; size_t i_child_index;
448     SortChildren( plugins_item );
449     wxTreeItemId capability_item = GetFirstChild( plugins_item, cookie);
450     for( i_child_index = 0;
451          i_child_index < GetChildrenCount( plugins_item, FALSE );
452          i_child_index++ )
453     {
454         capability_item = GetNextChild( plugins_item, cookie );
455         SortChildren( capability_item );
456     }
457
458     /* Clean-up everything */
459     vlc_list_release( p_list );
460
461     p_sizer->Add( this, 1, wxEXPAND | wxALL, 0 );
462     p_sizer->Layout();
463
464     /* Update Tree Ctrl */
465 #ifndef WIN32 /* Workaround a bug in win32 implementation */
466     SelectItem( GetFirstChild( root_item, cookie ) );
467 #endif
468 }
469
470 PrefsTreeCtrl::~PrefsTreeCtrl()
471 {
472 }
473
474 void PrefsTreeCtrl::ApplyChanges()
475 {
476     long cookie, cookie2;
477     ConfigTreeData *config_data;
478
479     /* Apply changes to the main module */
480     wxTreeItemId item = GetFirstChild( root_item, cookie );
481     for( size_t i_child_index = 0;
482          i_child_index < GetChildrenCount( root_item, FALSE );
483          i_child_index++ )
484     {
485         config_data = (ConfigTreeData *)GetItemData( item );
486         if( config_data && config_data->panel )
487         {
488             config_data->panel->ApplyChanges();
489         }
490
491         item = GetNextChild( root_item, cookie );
492     }
493
494     /* Apply changes to the plugins */
495     item = GetFirstChild( plugins_item, cookie );
496     for( size_t i_child_index = 0;
497          i_child_index < GetChildrenCount( plugins_item, FALSE );
498          i_child_index++ )
499     {
500         wxTreeItemId item2 = GetFirstChild( item, cookie2 );
501         for( size_t i_child_index = 0;
502              i_child_index < GetChildrenCount( item, FALSE );
503              i_child_index++ )
504         {
505             config_data = (ConfigTreeData *)GetItemData( item2 );
506             if( config_data && config_data->panel )
507             {
508                 config_data->panel->ApplyChanges();
509             }
510
511             item2 = GetNextChild( item, cookie2 );
512         }
513
514         item = GetNextChild( plugins_item, cookie );
515     }
516 }
517
518 void PrefsTreeCtrl::CleanChanges()
519 {
520     long cookie, cookie2;
521     ConfigTreeData *config_data;
522
523     /* Clean changes for the main module */
524     wxTreeItemId item = GetFirstChild( root_item, cookie );
525     for( size_t i_child_index = 0;
526          i_child_index < GetChildrenCount( root_item, FALSE );
527          i_child_index++ )
528     {
529         config_data = (ConfigTreeData *)GetItemData( item );
530         if( config_data && config_data->panel )
531         {
532             if( item == GetSelection() )
533             {
534                 config_data->panel->Hide();
535                 p_sizer->Remove( config_data->panel );
536             }
537
538             delete config_data->panel;
539             config_data->panel = NULL;
540
541             if( item == GetSelection() )
542             {
543                 wxTreeEvent event;
544                 event.SetItem(item);
545
546                 OnSelectTreeItem( event );
547             }
548         }
549
550         item = GetNextChild( root_item, cookie );
551     }
552
553     /* Clean changes for the plugins */
554     item = GetFirstChild( plugins_item, cookie );
555     for( size_t i_child_index = 0;
556          i_child_index < GetChildrenCount( plugins_item, FALSE );
557          i_child_index++ )
558     {
559         wxTreeItemId item2 = GetFirstChild( item, cookie2 );
560         for( size_t i_child_index = 0;
561              i_child_index < GetChildrenCount( item, FALSE );
562              i_child_index++ )
563         {
564             config_data = (ConfigTreeData *)GetItemData( item2 );
565
566             if( config_data && config_data->panel )
567             {
568                 if( item2 == GetSelection() )
569                 {
570                     config_data->panel->Hide();
571                     p_sizer->Remove( config_data->panel );
572                 }
573
574                 delete config_data->panel;
575                 config_data->panel = NULL;
576
577                 if( item2 == GetSelection() )
578                 {
579                     wxTreeEvent event;
580                     event.SetItem(item2);
581
582                     OnSelectTreeItem( event );
583                 }
584             }
585
586             item2 = GetNextChild( item, cookie2 );
587         }
588
589         item = GetNextChild( plugins_item, cookie );
590     }
591 }
592
593 void PrefsTreeCtrl::OnSelectTreeItem( wxTreeEvent& event )
594 {
595     ConfigTreeData *config_data;
596
597     config_data = (ConfigTreeData *)GetItemData( event.GetOldItem() );
598     if( config_data && config_data->panel )
599     {
600         config_data->panel->Hide();
601         p_sizer->Remove( config_data->panel );
602     }
603
604     config_data = (ConfigTreeData *)GetItemData( event.GetItem() );
605     if( config_data )
606     {
607         if( !config_data->panel )
608         {
609             /* The panel hasn't been created yet. Let's do it. */
610             config_data->panel =
611                 new PrefsPanel( p_parent, p_intf, p_prefs_dialog,
612                                 config_data->i_object_id,
613                                 config_data->psz_section );
614         }
615         else
616         {
617             config_data->panel->Show();
618         }
619
620         p_sizer->Add( config_data->panel, 2, wxEXPAND | wxALL, 0 );
621         p_sizer->Layout();
622     }
623 }
624
625 /*****************************************************************************
626  * PrefsPanel class definition.
627  *****************************************************************************/
628 PrefsPanel::PrefsPanel( wxWindow* parent, intf_thread_t *_p_intf,
629                         PrefsDialog *_p_prefs_dialog,
630                         int i_object_id, char *psz_section )
631   :  wxPanel( parent, -1, wxDefaultPosition, wxDefaultSize )
632 {
633     module_config_t *p_item;
634     vlc_list_t      *p_list;
635     module_t        *p_parser;
636
637     wxStaticText *label;
638     wxComboBox *combo;
639     wxSpinCtrl *spin;
640     wxCheckBox *checkbox;
641     wxTextCtrl *textctrl;
642     wxButton *button;
643     wxArrayString array;
644
645     /* Initializations */
646     p_intf = _p_intf;
647     p_prefs_dialog =_p_prefs_dialog,
648
649     b_advanced = VLC_TRUE;
650     SetAutoLayout( TRUE );
651
652     wxBoxSizer *sizer = new wxBoxSizer( wxVERTICAL );
653
654     /* Get a pointer to the module */
655     module_t *p_module = (module_t *)vlc_object_get( p_intf, i_object_id );
656     if( p_module->i_object_type != VLC_OBJECT_MODULE )
657     {
658         /* 0OOoo something went really bad */
659         return;
660     }
661
662     /* Enumerate config options and add corresponding config boxes */
663     p_item = p_module->p_config;
664
665     /* Find the category if it has been specified */
666     if( psz_section && p_item->i_type == CONFIG_HINT_CATEGORY )
667     {
668         while( !p_item->i_type == CONFIG_HINT_CATEGORY ||
669                strcmp( psz_section, p_item->psz_text ) )
670         {
671             if( p_item->i_type == CONFIG_HINT_END )
672                 break;
673             p_item++;
674         }
675     }
676
677     /* Add a head title to the panel */
678     wxStaticBox *static_box = new wxStaticBox( this, -1, wxT("") );
679     wxStaticBoxSizer *box_sizer = new wxStaticBoxSizer( static_box,
680                                                         wxHORIZONTAL );
681     label = new wxStaticText( this, -1,
682                               wxU(psz_section ? p_item->psz_text :
683                               p_module->psz_longname) );
684
685     box_sizer->Add( label, 1, wxALL, 5 );
686     sizer->Add( box_sizer, 0, wxEXPAND | wxALL, 5 );
687
688     /* Now put all the config options into a scrolled window */
689     config_sizer = new wxBoxSizer( wxVERTICAL );
690     config_window = new wxScrolledWindow( this, -1, wxDefaultPosition,
691                                           wxDefaultSize );
692     config_window->SetAutoLayout( TRUE );
693     config_window->SetScrollRate( 5, 5 );
694
695     if( p_item ) do
696     {
697         /* If a category has been specified, check we finished the job */
698         if( psz_section && p_item->i_type == CONFIG_HINT_CATEGORY &&
699             strcmp( psz_section, p_item->psz_text ) )
700             break;
701
702         /* put each config option in a separate panel so we can hide advanced
703          * options easily */
704         wxPanel *panel = new wxPanel( config_window, -1, wxDefaultPosition,
705                                       wxDefaultSize );
706         wxBoxSizer *panel_sizer = new wxBoxSizer( wxHORIZONTAL );
707         ConfigData *config_data =
708             new ConfigData( panel, p_item->i_type,
709                             p_item->b_advanced, p_item->psz_name );
710
711         switch( p_item->i_type )
712         {
713         case CONFIG_ITEM_MODULE:
714             label = new wxStaticText(panel, -1, wxU(p_item->psz_text));
715             combo = new wxComboBox( panel, -1, wxU(p_item->psz_value),
716                                     wxDefaultPosition, wxDefaultSize,
717                                     0, NULL, wxCB_READONLY | wxCB_SORT );
718
719             /* build a list of available modules */
720             p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
721             combo->Append( wxU(_("Default")), (void *)NULL );
722             combo->SetSelection( 0 );
723             for( int i_index = 0; i_index < p_list->i_count; i_index++ )
724             {
725                 p_parser = (module_t *)p_list->p_values[i_index].p_object ;
726
727                 if( !strcmp( p_parser->psz_capability,
728                              p_item->psz_type ) )
729                 {
730                     combo->Append( wxU(p_parser->psz_longname),
731                                    p_parser->psz_object_name );
732                     if( p_item->psz_value &&
733                         !strcmp(p_item->psz_value, p_parser->psz_object_name) )
734                         combo->SetValue( wxU(p_parser->psz_longname) );
735                 }
736             }
737
738             combo->SetToolTip( wxU(p_item->psz_longtext) );
739             config_data->control.combobox = combo;
740             panel_sizer->Add( label, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
741             panel_sizer->Add( combo, 1, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
742             break;
743
744         case CONFIG_ITEM_STRING:
745         case CONFIG_ITEM_FILE:
746         case CONFIG_ITEM_DIRECTORY:
747             label = new wxStaticText(panel, -1, wxU(p_item->psz_text));
748             panel_sizer->Add( label, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
749
750             if( !p_item->ppsz_list )
751             {
752                 textctrl = new wxTextCtrl( panel, -1, wxU(p_item->psz_value),
753                                            wxDefaultPosition, wxDefaultSize,
754                                            wxTE_PROCESS_ENTER);
755                 textctrl->SetToolTip( wxU(p_item->psz_longtext) );
756                 config_data->control.textctrl = textctrl;
757                 panel_sizer->Add( textctrl, 1, wxALL, 5 );
758             }
759             else
760             {
761                 combo = new wxComboBox( panel, -1, wxU(p_item->psz_value),
762                                         wxDefaultPosition, wxDefaultSize,
763                                         0, NULL, wxCB_READONLY | wxCB_SORT );
764
765                 /* build a list of available options */
766                 for( int i_index = 0; p_item->ppsz_list[i_index]; i_index++ )
767                 {
768                     combo->Append( wxU(p_item->ppsz_list[i_index]) );
769                 }
770
771                 if( p_item->psz_value )
772                     combo->SetValue( wxU(p_item->psz_value) );
773                 combo->SetToolTip( wxU(p_item->psz_longtext) );
774                 config_data->control.combobox = combo;
775                 config_data->b_config_list = VLC_TRUE;
776                 panel_sizer->Add( combo, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
777             }
778
779             if( p_item->i_type == CONFIG_ITEM_FILE )
780             {
781                 button = new wxButton( panel, -1, wxU(_("Browse...")) );
782                 panel_sizer->Add( button, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
783                 button->SetClientData((void *)config_data);
784             }
785             break;
786
787         case CONFIG_ITEM_INTEGER:
788             label = new wxStaticText(panel, -1, wxU(p_item->psz_text));
789             spin = new wxSpinCtrl( panel, -1,
790                                    wxString::Format(wxT("%d"),p_item->i_value),
791                                    wxDefaultPosition, wxDefaultSize,
792                                    wxSP_ARROW_KEYS,
793                                    0, 16000, p_item->i_value);
794             spin->SetToolTip( wxU(p_item->psz_longtext) );
795             config_data->control.spinctrl = spin;
796             panel_sizer->Add( label, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
797             panel_sizer->Add( spin, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
798
799             spin->SetClientData((void *)config_data);
800             break;
801
802         case CONFIG_ITEM_FLOAT:
803             label = new wxStaticText(panel, -1, wxU(p_item->psz_text));
804             spin = new wxSpinCtrl( panel, -1,
805                                    wxString::Format(wxT("%f"),p_item->f_value),
806                                    wxDefaultPosition, wxDefaultSize,
807                                    wxSP_ARROW_KEYS,
808                                    0, 16000, (int)p_item->f_value);
809             spin->SetToolTip( wxU(p_item->psz_longtext) );
810             config_data->control.spinctrl = spin;
811             panel_sizer->Add( label, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
812             panel_sizer->Add( spin, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
813             break;
814
815         case CONFIG_ITEM_BOOL:
816             checkbox = new wxCheckBox( panel, -1, wxU(p_item->psz_text) );
817             if( p_item->i_value ) checkbox->SetValue(TRUE);
818             checkbox->SetToolTip( wxU(p_item->psz_longtext) );
819             config_data->control.checkbox = checkbox;
820             panel_sizer->Add( checkbox, 0, wxALL, 5 );
821             break;
822
823         default:
824             delete panel; panel = NULL;
825             delete panel_sizer;
826             delete config_data;
827             break;
828         }
829
830         /* Don't add items that were not recognized */
831         if( panel == NULL ) continue;
832
833         panel_sizer->Layout();
834         panel->SetSizerAndFit( panel_sizer );
835
836         /* Add the config data to our array so we can keep a trace of it */
837         config_array.Add( config_data );
838
839         config_sizer->Add( panel, 0, wxEXPAND | wxALL, 2 );
840     }
841     while( p_item->i_type != CONFIG_HINT_END && p_item++ );
842
843     /* Display a nice message if no configuration options are available */
844     if( !config_array.GetCount() )
845     {
846         config_sizer->Add( new wxStaticText( config_window, -1,
847                            wxU(_("No configuration options available")) ), 1,
848                            wxALIGN_CENTER_VERTICAL | wxALIGN_CENTER, 2 );
849     }
850
851     config_sizer->Layout();
852     config_window->SetSizer( config_sizer );
853     sizer->Add( config_window, 1, wxEXPAND | wxALL, 5 );
854
855     /* Intercept all menu events in our custom event handler */
856     config_window->PushEventHandler(
857         new ConfigEvtHandler( p_intf, p_prefs_dialog ) );
858
859     /* Update panel */
860     wxCommandEvent dummy_event;
861     b_advanced = !config_GetInt( p_intf, "advanced" );
862     OnAdvanced( dummy_event );
863
864     /* Create advanced button */
865     if( config_array.GetCount() )
866     {
867         wxButton *advanced_button = new wxButton( this, Advanced_Event,
868                                                   wxU(_("Advanced...")) );
869         sizer->Add( advanced_button, 0, wxALL, 5 );
870     }
871
872     sizer->Layout();
873     SetSizer( sizer );
874 }
875
876 void PrefsPanel::ApplyChanges()
877 {
878     for( size_t i = 0; i < config_array.GetCount(); i++ )
879     {
880         ConfigData *config_data = config_array.Item(i);
881
882         switch( config_data->i_config_type )
883         {
884         case CONFIG_ITEM_MODULE:
885             config_PutPsz( p_intf, config_data->option_name.mb_str(), (char *)
886                            config_data->control.combobox->GetClientData(
887                            config_data->control.combobox->GetSelection() ) );
888             break;
889         case CONFIG_ITEM_STRING:
890         case CONFIG_ITEM_FILE:
891         case CONFIG_ITEM_DIRECTORY:
892             if( !config_data->b_config_list )
893                 config_PutPsz( p_intf, config_data->option_name.mb_str(),
894                                config_data->control.textctrl->GetValue().mb_str() );
895             else
896                 config_PutPsz( p_intf, config_data->option_name.mb_str(),
897                                config_data->control.combobox->GetValue().mb_str() );
898             break;
899         case CONFIG_ITEM_BOOL:
900             config_PutInt( p_intf, config_data->option_name.mb_str(),
901                            config_data->control.checkbox->IsChecked() );
902             break;
903         case CONFIG_ITEM_INTEGER:
904             config_PutInt( p_intf, config_data->option_name.mb_str(),
905                            config_data->control.spinctrl->GetValue() );
906             break;
907         case CONFIG_ITEM_FLOAT:
908             config_PutFloat( p_intf, config_data->option_name.mb_str(),
909                              config_data->control.spinctrl->GetValue() );
910             break;
911         }
912     }
913 }
914
915 void PrefsPanel::OnAdvanced( wxCommandEvent& WXUNUSED(event) )
916 {
917     b_advanced = !b_advanced;
918
919     for( size_t i = 0; i < config_array.GetCount(); i++ )
920     {
921         ConfigData *config_data = config_array.Item(i);
922         if( config_data->b_advanced )
923         {
924             config_data->panel->Show( b_advanced );
925             config_sizer->Show( config_data->panel, b_advanced );
926         }
927     }
928
929     config_sizer->Layout();
930     config_window->FitInside();
931 }
932
933 /*****************************************************************************
934  * A small helper class which intercepts all events
935  *****************************************************************************/
936 ConfigEvtHandler::ConfigEvtHandler( intf_thread_t *_p_intf,
937                                     PrefsDialog *_p_prefs_dialog )
938 {
939     /* Initializations */
940     p_intf = _p_intf;
941     p_prefs_dialog = _p_prefs_dialog;
942 }
943
944 ConfigEvtHandler::~ConfigEvtHandler()
945 {
946 }
947
948 void ConfigEvtHandler::OnCommandEvent( wxCommandEvent& event )
949 {
950     if( !event.GetEventObject() )
951     {
952         event.Skip();
953         return;
954     }
955
956     ConfigData *config_data = (ConfigData *)
957         ((wxEvtHandler *)event.GetEventObject())->GetClientData();
958
959     if( !config_data )
960     {
961         event.Skip();
962         return;
963     }
964
965     if( config_data->i_config_type == CONFIG_ITEM_FILE )
966     {
967         wxFileDialog dialog( p_prefs_dialog, wxU(_("Open file")),
968                              wxT(""), wxT(""), wxT("*.*"), wxOPEN | wxSAVE );
969
970         if( dialog.ShowModal() == wxID_OK )
971         {
972             config_data->control.textctrl->SetValue( dialog.GetPath() );      
973         }
974     }
975
976     switch( config_data->i_config_type )
977     {
978     case CONFIG_ITEM_MODULE:
979         break;
980     case CONFIG_ITEM_STRING:
981         break;
982     case CONFIG_ITEM_FILE:
983         break;
984     case CONFIG_ITEM_INTEGER:
985         break;
986     case CONFIG_ITEM_FLOAT:
987         break;
988     case CONFIG_ITEM_BOOL:
989         break;
990     }
991
992     event.Skip();
993 }