* modules/gui/wxwindows/*: changed the preferences panel to use textctrls for float...
[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.22 2003/06/19 12:21:53 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                 }
818
819                 if( p_item->psz_value )
820                     combo->SetValue( wxU(p_item->psz_value) );
821                 combo->SetToolTip( wxU(p_item->psz_longtext) );
822                 config_data->control.combobox = combo;
823                 config_data->b_config_list = VLC_TRUE;
824                 panel_sizer->Add( combo, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
825             }
826
827             if( p_item->i_type == CONFIG_ITEM_FILE )
828             {
829                 button = new wxButton( panel, -1, wxU(_("Browse...")) );
830                 panel_sizer->Add( button, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
831                 button->SetClientData((void *)config_data);
832             }
833             if( p_item->b_advanced ) b_has_advanced = VLC_TRUE;
834             break;
835
836         case CONFIG_ITEM_INTEGER:
837             label = new wxStaticText(panel, -1, wxU(p_item->psz_text));
838             spin = new wxSpinCtrl( panel, -1,
839                                    wxString::Format(wxT("%d"),p_item->i_value),
840                                    wxDefaultPosition, wxDefaultSize,
841                                    wxSP_ARROW_KEYS,
842                                    -16000, 16000, p_item->i_value);
843             spin->SetToolTip( wxU(p_item->psz_longtext) );
844             config_data->control.spinctrl = spin;
845             panel_sizer->Add( label, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
846             panel_sizer->Add( spin, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
847
848             spin->SetClientData((void *)config_data);
849             if( p_item->b_advanced ) b_has_advanced = VLC_TRUE;
850             break;
851
852         case CONFIG_ITEM_FLOAT:
853             label = new wxStaticText(panel, -1, wxU(p_item->psz_text));
854             textctrl = new wxTextCtrl( panel, -1,
855                              wxString::Format(wxT("%f"),p_item->f_value),
856                              wxDefaultPosition, wxDefaultSize,
857                              wxTE_PROCESS_ENTER );
858             textctrl->SetToolTip( wxU(p_item->psz_longtext) );
859             config_data->control.textctrl = textctrl;
860             panel_sizer->Add( label, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
861             panel_sizer->Add( textctrl, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
862             if( p_item->b_advanced ) b_has_advanced = VLC_TRUE;
863             break;
864
865         case CONFIG_ITEM_BOOL:
866             checkbox = new wxCheckBox( panel, -1, wxU(p_item->psz_text) );
867             if( p_item->i_value ) checkbox->SetValue(TRUE);
868             checkbox->SetToolTip( wxU(p_item->psz_longtext) );
869             config_data->control.checkbox = checkbox;
870             panel_sizer->Add( checkbox, 0, wxALL, 5 );
871             if( p_item->b_advanced ) b_has_advanced = VLC_TRUE;
872             break;
873
874         default:
875             delete panel; panel = NULL;
876             delete panel_sizer;
877             delete config_data;
878             break;
879         }
880
881         /* Don't add items that were not recognized */
882         if( panel == NULL ) continue;
883
884         panel_sizer->Layout();
885         panel->SetSizerAndFit( panel_sizer );
886
887         /* Add the config data to our array so we can keep a trace of it */
888         config_array.Add( config_data );
889
890         config_sizer->Add( panel, 0, wxEXPAND | wxALL, 2 );
891     }
892     while( p_item->i_type != CONFIG_HINT_END && p_item++ );
893
894     /* Display a nice message if no configuration options are available */
895     if( !config_array.GetCount() )
896     {
897         config_sizer->Add( new wxStaticText( config_window, -1,
898                            wxU(_("No configuration options available")) ), 1,
899                            wxALIGN_CENTER_VERTICAL | wxALIGN_CENTER, 2 );
900     }
901
902     config_sizer->Layout();
903     config_window->SetSizer( config_sizer );
904     sizer->Add( config_window, 1, wxEXPAND | wxALL, 5 );
905
906     /* Intercept all menu events in our custom event handler */
907     config_window->PushEventHandler(
908         new ConfigEvtHandler( p_intf, p_prefs_dialog ) );
909
910     /* Update panel */
911     wxCommandEvent dummy_event;
912     b_advanced = !config_GetInt( p_intf, "advanced" );
913     OnAdvanced( dummy_event );
914
915     /* Create advanced checkbox if needed */
916     if( config_array.GetCount() && b_has_advanced )
917     {
918         wxCheckBox *advanced_checkbox =
919            new wxCheckBox( this, Advanced_Event, wxU(_("Advanced options")) );
920
921         if( b_advanced ) advanced_checkbox->SetValue(TRUE);
922         sizer->Add( advanced_checkbox, 0, wxALL|wxALIGN_RIGHT, 0 );
923     }
924
925     sizer->Layout();
926     SetSizer( sizer );
927 }
928
929 void PrefsPanel::ApplyChanges()
930 {
931     for( size_t i = 0; i < config_array.GetCount(); i++ )
932     {
933         ConfigData *config_data = config_array.Item(i);
934
935         switch( config_data->i_config_type )
936         {
937         case CONFIG_ITEM_MODULE:
938             config_PutPsz( p_intf, config_data->option_name.mb_str(), (char *)
939                            config_data->control.combobox->GetClientData(
940                            config_data->control.combobox->GetSelection() ) );
941             break;
942         case CONFIG_ITEM_STRING:
943         case CONFIG_ITEM_FILE:
944         case CONFIG_ITEM_DIRECTORY:
945             if( !config_data->b_config_list )
946                 config_PutPsz( p_intf, config_data->option_name.mb_str(),
947                                config_data->control.textctrl->GetValue().mb_str() );
948             else
949                 config_PutPsz( p_intf, config_data->option_name.mb_str(),
950                                config_data->control.combobox->GetValue().mb_str() );
951             break;
952         case CONFIG_ITEM_BOOL:
953             config_PutInt( p_intf, config_data->option_name.mb_str(),
954                            config_data->control.checkbox->IsChecked() );
955             break;
956         case CONFIG_ITEM_INTEGER:
957             config_PutInt( p_intf, config_data->option_name.mb_str(),
958                            config_data->control.spinctrl->GetValue() );
959             break;
960         case CONFIG_ITEM_FLOAT:
961             {
962                 float f_value;
963                 if( (wxSscanf(config_data->control.textctrl->GetValue(),
964                               wxT("%f"), &f_value) == 1) )
965                     config_PutFloat( p_intf, config_data->option_name.mb_str(),
966                                      f_value );
967             }
968             break;
969         }
970     }
971 }
972
973 void PrefsPanel::OnAdvanced( wxCommandEvent& WXUNUSED(event) )
974 {
975     b_advanced = !b_advanced;
976
977     for( size_t i = 0; i < config_array.GetCount(); i++ )
978     {
979         ConfigData *config_data = config_array.Item(i);
980         if( config_data->b_advanced )
981         {
982             config_data->panel->Show( b_advanced );
983             config_sizer->Show( config_data->panel, b_advanced );
984         }
985     }
986
987     config_sizer->Layout();
988     config_window->FitInside();
989     config_window->Refresh();
990 }
991
992 /*****************************************************************************
993  * A small helper class which intercepts all events
994  *****************************************************************************/
995 ConfigEvtHandler::ConfigEvtHandler( intf_thread_t *_p_intf,
996                                     PrefsDialog *_p_prefs_dialog )
997 {
998     /* Initializations */
999     p_intf = _p_intf;
1000     p_prefs_dialog = _p_prefs_dialog;
1001 }
1002
1003 ConfigEvtHandler::~ConfigEvtHandler()
1004 {
1005 }
1006
1007 void ConfigEvtHandler::OnCommandEvent( wxCommandEvent& event )
1008 {
1009     if( !event.GetEventObject() )
1010     {
1011         event.Skip();
1012         return;
1013     }
1014
1015     ConfigData *config_data = (ConfigData *)
1016         ((wxEvtHandler *)event.GetEventObject())->GetClientData();
1017
1018     if( !config_data )
1019     {
1020         event.Skip();
1021         return;
1022     }
1023
1024     if( config_data->i_config_type == CONFIG_ITEM_FILE )
1025     {
1026         wxFileDialog dialog( p_prefs_dialog, wxU(_("Open file")),
1027                              wxT(""), wxT(""), wxT("*.*"), wxOPEN | wxSAVE );
1028
1029         if( dialog.ShowModal() == wxID_OK )
1030         {
1031             config_data->control.textctrl->SetValue( dialog.GetPath() );      
1032         }
1033     }
1034
1035     switch( config_data->i_config_type )
1036     {
1037     case CONFIG_ITEM_MODULE:
1038         break;
1039     case CONFIG_ITEM_STRING:
1040         break;
1041     case CONFIG_ITEM_FILE:
1042         break;
1043     case CONFIG_ITEM_INTEGER:
1044         break;
1045     case CONFIG_ITEM_FLOAT:
1046         break;
1047     case CONFIG_ITEM_BOOL:
1048         break;
1049     }
1050
1051     event.Skip();
1052 }