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