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