82240ac28dec85ea60536931f7a663d1c4cf0e43
[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.13 2003/05/12 17:33:19 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
80 private:
81     /* Event handlers (these functions should _not_ be virtual) */
82     void OnSelectTreeItem( wxTreeEvent& event );
83
84     DECLARE_EVENT_TABLE()
85
86     intf_thread_t *p_intf;
87     PrefsDialog *p_prefs_dialog;
88     wxBoxSizer *p_sizer;
89     wxWindow *p_parent;
90
91     wxTreeItemId root_item;
92     wxTreeItemId plugins_item;
93 };
94
95 struct ConfigData
96 {
97     ConfigData( wxPanel *_panel, int _i_conf_type,
98                 vlc_bool_t _b_advanced, char *psz_name )
99     { panel = _panel; b_advanced = _b_advanced; b_config_list = VLC_FALSE;
100       i_config_type = _i_conf_type; option_name = wxU(psz_name); }
101
102     vlc_bool_t b_advanced;
103     int i_config_type;
104     vlc_bool_t b_config_list;
105
106     union control
107     {
108         wxComboBox *combobox;
109         wxRadioButton *radio;
110         wxSpinCtrl *spinctrl;
111         wxCheckBox *checkbox;
112         wxTextCtrl *textctrl;
113
114     } control;
115
116     wxPanel *panel;
117     wxString option_name;
118 };
119
120 WX_DEFINE_ARRAY(ConfigData *, ArrayOfConfigData);
121
122 class PrefsPanel : public wxPanel
123 {
124 public:
125
126     PrefsPanel() { }
127     PrefsPanel( wxWindow *parent, intf_thread_t *_p_intf,
128                 PrefsDialog *_p_prefs_dialog,
129                 module_t *p_module, 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; }
154     virtual ~ConfigTreeData() { if( panel ) delete panel; }
155
156     PrefsPanel *panel;
157     wxBoxSizer *sizer;
158 };
159
160 class ConfigEvtHandler : public wxEvtHandler
161 {
162 public:
163     ConfigEvtHandler( intf_thread_t *p_intf, PrefsDialog *p_prefs_dialog );
164     virtual ~ConfigEvtHandler();
165
166     void ConfigEvtHandler::OnCommandEvent( wxCommandEvent& event );
167
168 private:
169
170     DECLARE_EVENT_TABLE()
171
172     intf_thread_t *p_intf;
173     PrefsDialog *p_prefs_dialog;
174 };
175
176 /*****************************************************************************
177  * Event Table.
178  *****************************************************************************/
179
180 /* IDs for the controls and the menu commands */
181 enum
182 {
183     Notebook_Event = wxID_HIGHEST,
184     MRL_Event,
185     ResetAll_Event,
186     Advanced_Event,
187 };
188
189 BEGIN_EVENT_TABLE(PrefsDialog, wxFrame)
190     /* Button events */
191     EVT_BUTTON(wxID_OK, PrefsDialog::OnOk)
192     EVT_BUTTON(wxID_CANCEL, PrefsDialog::OnCancel)
193     EVT_BUTTON(wxID_SAVE, PrefsDialog::OnSave)
194     EVT_BUTTON(ResetAll_Event, PrefsDialog::OnResetAll)
195
196     /* Don't destroy the window when the user closes it */
197     EVT_CLOSE(PrefsDialog::OnCancel)
198 END_EVENT_TABLE()
199
200 // menu and control ids
201 enum
202 {
203     PrefsTree_Ctrl = wxID_HIGHEST
204 };
205
206 BEGIN_EVENT_TABLE(PrefsTreeCtrl, wxTreeCtrl)
207     EVT_TREE_SEL_CHANGED(PrefsTree_Ctrl, PrefsTreeCtrl::OnSelectTreeItem)
208 END_EVENT_TABLE()
209
210 BEGIN_EVENT_TABLE(PrefsPanel, wxPanel)
211     /* Button events */
212     EVT_BUTTON(Advanced_Event, PrefsPanel::OnAdvanced)
213
214 END_EVENT_TABLE()
215
216 BEGIN_EVENT_TABLE(ConfigEvtHandler, wxEvtHandler)
217     EVT_BUTTON(-1, ConfigEvtHandler::OnCommandEvent)
218     EVT_TEXT(-1, ConfigEvtHandler::OnCommandEvent)
219     EVT_RADIOBOX(-1, ConfigEvtHandler::OnCommandEvent)
220     EVT_SPINCTRL(-1, ConfigEvtHandler::OnCommandEvent)
221 END_EVENT_TABLE()
222
223 /*****************************************************************************
224  * Constructor.
225  *****************************************************************************/
226 PrefsDialog::PrefsDialog( intf_thread_t *_p_intf, Interface *_p_main_interface)
227   :  wxFrame( _p_main_interface, -1, wxU(_("Preferences")), wxDefaultPosition,
228               wxSize(650,450), wxDEFAULT_FRAME_STYLE )
229 {
230     /* Initializations */
231     p_intf = _p_intf;
232     p_main_interface = _p_main_interface;
233     SetIcon( *p_intf->p_sys->p_icon );
234
235     /* Create a panel to put everything in */
236     wxPanel *panel = new wxPanel( this, -1 );
237     panel->SetAutoLayout( TRUE );
238
239     /* Create the preferences tree control */
240     wxBoxSizer *controls_sizer = new wxBoxSizer( wxHORIZONTAL );
241     prefs_tree =
242         new PrefsTreeCtrl( panel, p_intf, this, controls_sizer );
243
244     /* Separation */
245     wxStaticLine *static_line = new wxStaticLine( panel, wxID_OK );
246
247     /* Create the buttons */
248     wxButton *ok_button = new wxButton( panel, wxID_OK, wxU(_("OK")) );
249     ok_button->SetDefault();
250     wxButton *cancel_button = new wxButton( panel, wxID_CANCEL,
251                                             wxU(_("Cancel")) );
252     wxButton *save_button = new wxButton( panel, wxID_SAVE, wxU(_("Save")) );
253     wxButton *reset_button = new wxButton( panel, ResetAll_Event,
254                                            wxU(_("Reset All")) );
255
256     /* Place everything in sizers */
257     wxBoxSizer *button_sizer = new wxBoxSizer( wxHORIZONTAL );
258     button_sizer->Add( ok_button, 0, wxALL, 5 );
259     button_sizer->Add( cancel_button, 0, wxALL, 5 );
260     button_sizer->Add( save_button, 0, wxALL, 5 );
261     button_sizer->Add( reset_button, 0, wxALL, 5 );
262     button_sizer->Layout();
263
264     wxBoxSizer *main_sizer = new wxBoxSizer( wxVERTICAL );
265     wxBoxSizer *panel_sizer = new wxBoxSizer( wxVERTICAL );
266     panel_sizer->Add( controls_sizer, 1, wxEXPAND | wxALL, 5 );
267     panel_sizer->Add( static_line, 0, wxEXPAND | wxALL, 5 );
268     panel_sizer->Add( button_sizer, 0, wxALIGN_LEFT | wxALIGN_BOTTOM |
269                       wxALL, 5 );
270     panel_sizer->Layout();
271     panel->SetSizer( panel_sizer );
272     main_sizer->Add( panel, 1, wxEXPAND, 0 );
273     main_sizer->Layout();
274     SetSizer( main_sizer );
275 }
276
277 PrefsDialog::~PrefsDialog()
278 {
279 }
280
281 /*****************************************************************************
282  * Private methods.
283  *****************************************************************************/
284
285
286 /*****************************************************************************
287  * Events methods.
288  *****************************************************************************/
289 void PrefsDialog::OnOk( wxCommandEvent& WXUNUSED(event) )
290 {
291     prefs_tree->ApplyChanges();
292
293     this->Hide();
294 }
295
296 void PrefsDialog::OnCancel( wxCommandEvent& WXUNUSED(event) )
297 {
298     this->Hide();
299 }
300
301 void PrefsDialog::OnSave( wxCommandEvent& WXUNUSED(event) )
302 {
303     prefs_tree->ApplyChanges();
304
305     config_SaveConfigFile( p_intf, NULL );
306 }
307
308 void PrefsDialog::OnResetAll( wxCommandEvent& WXUNUSED(event) )
309 {
310     wxMessageDialog dlg( this,
311         wxU(_("Beware this will reset your VLC Media Player config file.\n"
312               "Are you sure you want to continue?")),
313         wxU(_("Reset config file")), wxYES_NO|wxNO_DEFAULT|wxCENTRE );
314
315     if ( dlg.ShowModal() == wxID_YES )
316     {
317         /* TODO: need to reset all the controls */
318         config_ResetAll( p_intf );
319         config_SaveConfigFile( p_intf, NULL );
320     }
321 }
322
323 /*****************************************************************************
324  * PrefsTreeCtrl class definition.
325  *****************************************************************************/
326 PrefsTreeCtrl::PrefsTreeCtrl( wxWindow *_p_parent, intf_thread_t *_p_intf,
327                               PrefsDialog *_p_prefs_dialog,
328                               wxBoxSizer *_p_sizer )
329   : wxTreeCtrl( _p_parent, PrefsTree_Ctrl, wxDefaultPosition, wxDefaultSize,
330                 wxTR_NO_LINES | wxTR_FULL_ROW_HIGHLIGHT |
331                 wxTR_LINES_AT_ROOT | wxTR_HIDE_ROOT |
332                 wxTR_HAS_BUTTONS | wxTR_TWIST_BUTTONS | wxSUNKEN_BORDER )
333 {
334     vlc_list_t      *p_list;
335     module_t        *p_module;
336     module_config_t *p_item;
337     int i_index;
338
339     /* Initializations */
340     p_intf = _p_intf;
341     p_prefs_dialog = _p_prefs_dialog;
342     p_sizer = _p_sizer;
343     p_parent = _p_parent;
344
345     root_item = AddRoot( wxT("") );
346
347     /* List the plugins */
348     p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
349     if( !p_list ) return;
350
351     /*
352      * Build a tree of the main options
353      */
354     for( i_index = 0; i_index < p_list->i_count; i_index++ )
355     {
356         p_module = (module_t *)p_list->p_values[i_index].p_object;
357         if( !strcmp( p_module->psz_object_name, "main" ) )
358             break;
359     }
360     if( i_index < p_list->i_count )
361     {
362         /* We found the main module */
363
364         /* Enumerate config options and add corresponding config boxes */
365         p_item = p_module->p_config;
366
367         if( p_item ) do
368         {
369             switch( p_item->i_type )
370             {
371             case CONFIG_HINT_CATEGORY:
372                 ConfigTreeData *config_data = new ConfigTreeData;
373                 config_data->panel =
374                     new PrefsPanel( p_parent, p_intf, p_prefs_dialog,
375                                     p_module, p_item->psz_text );
376                 config_data->panel->Hide();
377
378                 /* Add the category to the tree */
379                 AppendItem( root_item, wxU(p_item->psz_text),
380                             -1, -1, config_data );
381                 break;
382             }
383         }
384         while( p_item->i_type != CONFIG_HINT_END && p_item++ );
385
386         SortChildren( root_item );
387     }
388
389
390     /*
391      * Build a tree of all the plugins
392      */
393     plugins_item = AppendItem( root_item, wxU(_("Plugins")) );
394
395     for( i_index = 0; i_index < p_list->i_count; i_index++ )
396     {
397         p_module = (module_t *)p_list->p_values[i_index].p_object;
398
399         /* Exclude the main module */
400         if( !strcmp( p_module->psz_object_name, "main" ) )
401             continue;
402
403         /* Exclude empty plugins */
404         p_item = p_module->p_config;
405         if( !p_item ) continue;
406         do
407         {
408             if( p_item->i_type & CONFIG_ITEM )
409                 break;
410         }
411         while( p_item->i_type != CONFIG_HINT_END && p_item++ );
412         if( p_item->i_type == CONFIG_HINT_END ) continue;
413
414         /* Find the capability child item */
415         long cookie; size_t i_child_index;
416         wxTreeItemId capability_item = GetFirstChild( plugins_item, cookie);
417         for( i_child_index = 0;
418              i_child_index < GetChildrenCount( plugins_item, FALSE );
419              i_child_index++ )
420         {
421             if( !GetItemText(capability_item).Cmp(
422                     wxU(p_module->psz_capability ) ) )
423             {
424                 break;
425             }
426             capability_item = GetNextChild( plugins_item, cookie );
427         }
428
429         if( i_child_index == GetChildrenCount( plugins_item, FALSE ) &&
430             p_module->psz_capability && *p_module->psz_capability )
431         {
432             /* We didn't find it, add it */
433             capability_item = AppendItem( plugins_item,
434                                           wxU(p_module->psz_capability) );
435         }
436
437         /* Add the plugin to the tree */
438         ConfigTreeData *config_data = new ConfigTreeData;
439         config_data->panel =
440             new PrefsPanel( p_parent, p_intf, p_prefs_dialog, p_module, NULL );
441         config_data->panel->Hide();
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 )
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 )
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::OnSelectTreeItem( wxTreeEvent& event )
519 {
520     ConfigTreeData *config_data;
521
522     config_data = (ConfigTreeData *)GetItemData( event.GetOldItem() );
523     if( config_data && config_data->panel )
524     {
525         config_data->panel->Hide();
526         p_sizer->Remove( config_data->panel );
527     }
528
529     config_data = (ConfigTreeData *)GetItemData( event.GetItem() );
530     if( config_data && config_data->panel )
531     {
532         config_data->panel->Show();
533         p_sizer->Add( config_data->panel, 2, wxEXPAND | wxALL, 0 );
534         p_sizer->Layout();
535     }
536 }
537
538 /*****************************************************************************
539  * PrefsPanel class definition.
540  *****************************************************************************/
541 PrefsPanel::PrefsPanel( wxWindow* parent, intf_thread_t *_p_intf,
542                         PrefsDialog *_p_prefs_dialog,
543                         module_t *p_module, char *psz_section )
544   :  wxPanel( parent, -1, wxDefaultPosition, wxDefaultSize )
545 {
546     module_config_t *p_item;
547     vlc_list_t      *p_list;
548     module_t        *p_parser;
549
550     wxStaticText *label;
551     wxComboBox *combo;
552     wxSpinCtrl *spin;
553     wxCheckBox *checkbox;
554     wxTextCtrl *textctrl;
555     wxButton *button;
556     wxArrayString array;
557
558     /* Initializations */
559     p_intf = _p_intf;
560     p_prefs_dialog =_p_prefs_dialog,
561
562     b_advanced = VLC_TRUE;
563     SetAutoLayout( TRUE );
564
565     wxBoxSizer *sizer = new wxBoxSizer( wxVERTICAL );
566
567     /* Enumerate config options and add corresponding config boxes */
568     p_item = p_module->p_config;
569
570     /* Find the category if it has been specified */
571     if( psz_section && p_item->i_type == CONFIG_HINT_CATEGORY )
572     {
573         while( !p_item->i_type == CONFIG_HINT_CATEGORY ||
574                strcmp( psz_section, p_item->psz_text ) )
575         {
576             if( p_item->i_type == CONFIG_HINT_END )
577                 break;
578             p_item++;
579         }
580     }
581
582     /* Add a head title to the panel */
583     wxStaticBox *static_box = new wxStaticBox( this, -1, wxT("") );
584     wxStaticBoxSizer *box_sizer = new wxStaticBoxSizer( static_box,
585                                                         wxHORIZONTAL );
586     label = new wxStaticText( this, -1,
587                               wxU(psz_section ? p_item->psz_text :
588                               p_module->psz_longname) );
589
590     box_sizer->Add( label, 1, wxALL, 5 );
591     sizer->Add( box_sizer, 0, wxEXPAND | wxALL, 5 );
592
593     /* Now put all the config options into a scrolled window */
594     config_sizer = new wxBoxSizer( wxVERTICAL );
595     config_window = new wxScrolledWindow( this, -1, wxDefaultPosition,
596                                           wxDefaultSize );
597     config_window->SetAutoLayout( TRUE );
598     config_window->SetScrollRate( 5, 5 );
599
600     if( p_item ) do
601     {
602         /* If a category has been specified, check we finished the job */
603         if( psz_section && p_item->i_type == CONFIG_HINT_CATEGORY &&
604             strcmp( psz_section, p_item->psz_text ) )
605             break;
606
607         /* put each config option in a separate panel so we can hide advanced
608          * options easily */
609         wxPanel *panel = new wxPanel( config_window, -1, wxDefaultPosition,
610                                       wxDefaultSize );
611         wxBoxSizer *panel_sizer = new wxBoxSizer( wxHORIZONTAL );
612         ConfigData *config_data =
613             new ConfigData( panel, p_item->i_type,
614                             p_item->b_advanced, p_item->psz_name );
615
616         switch( p_item->i_type )
617         {
618         case CONFIG_ITEM_MODULE:
619             label = new wxStaticText(panel, -1, wxU(p_item->psz_text));
620             combo = new wxComboBox( panel, -1, wxU(p_item->psz_value),
621                                     wxDefaultPosition, wxDefaultSize,
622                                     0, NULL, wxCB_READONLY | wxCB_SORT );
623
624             /* build a list of available modules */
625             p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
626             combo->Append( wxU(_("Default")), (void *)NULL );
627             combo->SetSelection( 0 );
628             for( int i_index = 0; i_index < p_list->i_count; i_index++ )
629             {
630                 p_parser = (module_t *)p_list->p_values[i_index].p_object ;
631
632                 if( !strcmp( p_parser->psz_capability,
633                              p_item->psz_type ) )
634                 {
635                     combo->Append( wxU(p_parser->psz_longname),
636                                    p_parser->psz_object_name );
637                     if( p_item->psz_value &&
638                         !strcmp(p_item->psz_value, p_parser->psz_object_name) )
639                         combo->SetValue( wxU(p_parser->psz_longname) );
640                 }
641             }
642
643             combo->SetToolTip( wxU(p_item->psz_longtext) );
644             config_data->control.combobox = combo;
645             panel_sizer->Add( label, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
646             panel_sizer->Add( combo, 1, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
647             break;
648
649         case CONFIG_ITEM_STRING:
650         case CONFIG_ITEM_FILE:
651         case CONFIG_ITEM_DIRECTORY:
652             label = new wxStaticText(panel, -1, wxU(p_item->psz_text));
653             panel_sizer->Add( label, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
654
655             if( !p_item->ppsz_list )
656             {
657                 textctrl = new wxTextCtrl( panel, -1, wxU(p_item->psz_value),
658                                            wxDefaultPosition, wxDefaultSize,
659                                            wxTE_PROCESS_ENTER);
660                 textctrl->SetToolTip( wxU(p_item->psz_longtext) );
661                 config_data->control.textctrl = textctrl;
662                 panel_sizer->Add( textctrl, 1, wxALL, 5 );
663             }
664             else
665             {
666                 combo = new wxComboBox( panel, -1, wxU(p_item->psz_value),
667                                         wxDefaultPosition, wxDefaultSize,
668                                         0, NULL, wxCB_READONLY | wxCB_SORT );
669
670                 /* build a list of available options */
671                 for( int i_index = 0; p_item->ppsz_list[i_index]; i_index++ )
672                 {
673                     combo->Append( wxU(p_item->ppsz_list[i_index]) );
674                 }
675
676                 if( p_item->psz_value )
677                     combo->SetValue( wxU(p_item->psz_value) );
678                 combo->SetToolTip( wxU(p_item->psz_longtext) );
679                 config_data->control.combobox = combo;
680                 config_data->b_config_list = VLC_TRUE;
681                 panel_sizer->Add( combo, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
682             }
683
684             if( p_item->i_type == CONFIG_ITEM_FILE )
685             {
686                 button = new wxButton( panel, -1, wxU(_("Browse...")) );
687                 panel_sizer->Add( button, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
688                 button->SetClientData((void *)config_data);
689             }
690             break;
691
692         case CONFIG_ITEM_INTEGER:
693             label = new wxStaticText(panel, -1, wxU(p_item->psz_text));
694             spin = new wxSpinCtrl( panel, -1,
695                                    wxString::Format(wxT("%d"),p_item->i_value),
696                                    wxDefaultPosition, wxDefaultSize,
697                                    wxSP_ARROW_KEYS,
698                                    0, 16000, p_item->i_value);
699             spin->SetToolTip( wxU(p_item->psz_longtext) );
700             config_data->control.spinctrl = spin;
701             panel_sizer->Add( label, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
702             panel_sizer->Add( spin, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
703
704             spin->SetClientData((void *)config_data);
705             break;
706
707         case CONFIG_ITEM_FLOAT:
708             label = new wxStaticText(panel, -1, wxU(p_item->psz_text));
709             spin = new wxSpinCtrl( panel, -1,
710                                    wxString::Format(wxT("%f"),p_item->f_value),
711                                    wxDefaultPosition, wxDefaultSize,
712                                    wxSP_ARROW_KEYS,
713                                    0, 16000, (int)p_item->f_value);
714             spin->SetToolTip( wxU(p_item->psz_longtext) );
715             config_data->control.spinctrl = spin;
716             panel_sizer->Add( label, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
717             panel_sizer->Add( spin, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
718             break;
719
720         case CONFIG_ITEM_BOOL:
721             checkbox = new wxCheckBox( panel, -1, wxU(p_item->psz_text) );
722             if( p_item->i_value ) checkbox->SetValue(TRUE);
723             checkbox->SetToolTip( wxU(p_item->psz_longtext) );
724             config_data->control.checkbox = checkbox;
725             panel_sizer->Add( checkbox, 0, wxALL, 5 );
726             break;
727
728         default:
729             delete panel; panel = NULL;
730             delete panel_sizer;
731             delete config_data;
732             break;
733         }
734
735         /* Don't add items that were not recognized */
736         if( panel == NULL ) continue;
737
738         panel_sizer->Layout();
739         panel->SetSizerAndFit( panel_sizer );
740
741         /* Add the config data to our array so we can keep a trace of it */
742         config_array.Add( config_data );
743
744         config_sizer->Add( panel, 0, wxEXPAND | wxALL, 2 );
745     }
746     while( p_item->i_type != CONFIG_HINT_END && p_item++ );
747
748     /* Display a nice message if no configuration options are available */
749     if( !config_array.GetCount() )
750     {
751         config_sizer->Add( new wxStaticText( config_window, -1,
752                            wxU(_("No configuration options available")) ), 1,
753                            wxALIGN_CENTER_VERTICAL | wxALIGN_CENTER, 2 );
754     }
755
756     config_sizer->Layout();
757     config_window->SetSizer( config_sizer );
758     sizer->Add( config_window, 1, wxEXPAND | wxALL, 5 );
759
760     /* Intercept all menu events in our custom event handler */
761     config_window->PushEventHandler(
762         new ConfigEvtHandler( p_intf, p_prefs_dialog ) );
763
764     /* Update panel */
765     wxCommandEvent dummy_event;
766     b_advanced = !config_GetInt( p_intf, "advanced" );
767     OnAdvanced( dummy_event );
768
769     /* Create advanced button */
770     if( config_array.GetCount() )
771     {
772         wxButton *advanced_button = new wxButton( this, Advanced_Event,
773                                                   wxU(_("Advanced...")) );
774         sizer->Add( advanced_button, 0, wxALL, 5 );
775     }
776
777     sizer->Layout();
778     SetSizer( sizer );
779 }
780
781 void PrefsPanel::ApplyChanges()
782 {
783     for( size_t i = 0; i < config_array.GetCount(); i++ )
784     {
785         ConfigData *config_data = config_array.Item(i);
786
787         switch( config_data->i_config_type )
788         {
789         case CONFIG_ITEM_MODULE:
790             config_PutPsz( p_intf, config_data->option_name.mb_str(), (char *)
791                            config_data->control.combobox->GetClientData(
792                            config_data->control.combobox->GetSelection() ) );
793             break;
794         case CONFIG_ITEM_STRING:
795         case CONFIG_ITEM_FILE:
796         case CONFIG_ITEM_DIRECTORY:
797             if( !config_data->b_config_list )
798                 config_PutPsz( p_intf, config_data->option_name.mb_str(),
799                                config_data->control.textctrl->GetValue().mb_str() );
800             else
801                 config_PutPsz( p_intf, config_data->option_name.mb_str(),
802                                config_data->control.combobox->GetValue().mb_str() );
803             break;
804         case CONFIG_ITEM_BOOL:
805             config_PutInt( p_intf, config_data->option_name.mb_str(),
806                            config_data->control.checkbox->IsChecked() );
807             break;
808         case CONFIG_ITEM_INTEGER:
809             config_PutInt( p_intf, config_data->option_name.mb_str(),
810                            config_data->control.spinctrl->GetValue() );
811             break;
812         case CONFIG_ITEM_FLOAT:
813             config_PutFloat( p_intf, config_data->option_name.mb_str(),
814                              config_data->control.spinctrl->GetValue() );
815             break;
816         }
817     }
818 }
819
820 void PrefsPanel::OnAdvanced( wxCommandEvent& WXUNUSED(event) )
821 {
822     b_advanced = !b_advanced;
823
824     for( size_t i = 0; i < config_array.GetCount(); i++ )
825     {
826         ConfigData *config_data = config_array.Item(i);
827         if( config_data->b_advanced )
828         {
829             config_data->panel->Show( b_advanced );
830             config_sizer->Show( config_data->panel, b_advanced );
831         }
832     }
833
834     config_sizer->Layout();
835     config_window->FitInside();
836 }
837
838 /*****************************************************************************
839  * A small helper class which intercepts all events
840  *****************************************************************************/
841 ConfigEvtHandler::ConfigEvtHandler( intf_thread_t *_p_intf,
842                                     PrefsDialog *_p_prefs_dialog )
843 {
844     /* Initializations */
845     p_intf = _p_intf;
846     p_prefs_dialog = _p_prefs_dialog;
847 }
848
849 ConfigEvtHandler::~ConfigEvtHandler()
850 {
851 }
852
853 void ConfigEvtHandler::OnCommandEvent( wxCommandEvent& event )
854 {
855     if( !event.GetEventObject() )
856     {
857         event.Skip();
858         return;
859     }
860
861     ConfigData *config_data = (ConfigData *)
862         ((wxEvtHandler *)event.GetEventObject())->GetClientData();
863
864     if( !config_data )
865     {
866         event.Skip();
867         return;
868     }
869
870     if( config_data->i_config_type == CONFIG_ITEM_FILE )
871     {
872         wxFileDialog dialog( p_prefs_dialog, wxU(_("Open file")),
873                              wxT(""), wxT(""), wxT("*.*"), wxOPEN | wxSAVE );
874
875         if( dialog.ShowModal() == wxID_OK )
876         {
877             config_data->control.textctrl->SetValue( dialog.GetPath() );      
878         }
879     }
880
881     switch( config_data->i_config_type )
882     {
883     case CONFIG_ITEM_MODULE:
884         break;
885     case CONFIG_ITEM_STRING:
886         break;
887     case CONFIG_ITEM_FILE:
888         break;
889     case CONFIG_ITEM_INTEGER:
890         break;
891     case CONFIG_ITEM_FLOAT:
892         break;
893     case CONFIG_ITEM_BOOL:
894         break;
895     }
896
897     event.Skip();
898 }