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