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