]> git.sesse.net Git - vlc/blob - modules/gui/wxwindows/preferences.cpp
c3470475685645f9d8d558cdd9d7778ed23f4d41
[vlc] / 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.45 2004/01/11 00:45:06 zorglub 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 #include <vlc/intf.h>
34
35 #include <vlc_help.h>
36
37 #include "wxwindows.h"
38 #include "preferences_widgets.h"
39 #include <wx/notebook.h>
40 #include <wx/textctrl.h>
41 #include <wx/combobox.h>
42 #include <wx/spinctrl.h>
43 #include <wx/statline.h>
44 #include <wx/treectrl.h>
45 #include <wx/clntdata.h>
46 #include <wx/dynarray.h>
47
48 #ifndef wxRB_SINGLE
49 #   define wxRB_SINGLE 0
50 #endif
51
52 #define GENERAL_ID 1242
53 #define PLUGIN_ID 1243
54 #define CAPABILITY_ID 1244
55
56 /*****************************************************************************
57  * Classes declarations.
58  *****************************************************************************/
59 class ConfigTreeData;
60 class PrefsTreeCtrl : public wxTreeCtrl
61 {
62 public:
63
64     PrefsTreeCtrl() { }
65     PrefsTreeCtrl( wxWindow *parent, intf_thread_t *_p_intf,
66                    PrefsDialog *p_prefs_dialog, wxBoxSizer *_p_sizer );
67     virtual ~PrefsTreeCtrl();
68
69     void ApplyChanges();
70     void CleanChanges();
71
72 private:
73     /* Event handlers (these functions should _not_ be virtual) */
74     void OnSelectTreeItem( wxTreeEvent& event );
75     void OnAdvanced( wxCommandEvent& event );
76
77     ConfigTreeData *FindModuleConfig( ConfigTreeData *config_data );
78
79     DECLARE_EVENT_TABLE()
80
81     intf_thread_t *p_intf;
82     PrefsDialog *p_prefs_dialog;
83     wxBoxSizer *p_sizer;
84     wxWindow *p_parent;
85     vlc_bool_t b_advanced;
86
87     wxTreeItemId root_item;
88     wxTreeItemId general_item;
89     wxTreeItemId plugins_item;
90 };
91
92 WX_DEFINE_ARRAY(ConfigControl *, ArrayOfConfigControls);
93
94 class PrefsPanel : public wxPanel
95 {
96 public:
97
98     PrefsPanel() { }
99     PrefsPanel( wxWindow *parent, intf_thread_t *_p_intf,
100                 PrefsDialog *, int i_object_id, char *, char * );
101     virtual ~PrefsPanel() {}
102
103     void ApplyChanges();
104     void SwitchAdvanced( vlc_bool_t );
105
106 private:
107     intf_thread_t *p_intf;
108     PrefsDialog *p_prefs_dialog;
109
110     vlc_bool_t b_advanced;
111
112     wxBoxSizer *config_sizer;
113     wxScrolledWindow *config_window;
114
115     ArrayOfConfigControls config_array;
116 };
117
118 class ConfigTreeData : public wxTreeItemData
119 {
120 public:
121
122     ConfigTreeData() { b_submodule = 0; panel = NULL; psz_section = NULL;
123                        psz_help = NULL; }
124     virtual ~ConfigTreeData() { if( panel ) delete panel;
125                                 if( psz_section) free(psz_section);
126                                 if( psz_help) free(psz_help); }
127
128     vlc_bool_t b_submodule;
129
130     PrefsPanel *panel;
131     wxBoxSizer *sizer;
132     int i_object_id;
133     char *psz_section;
134     char *psz_help;
135 };
136
137 /*****************************************************************************
138  * Event Table.
139  *****************************************************************************/
140
141 /* IDs for the controls and the menu commands */
142 enum
143 {
144     Notebook_Event = wxID_HIGHEST,
145     MRL_Event,
146     ResetAll_Event,
147     Advanced_Event,
148 };
149
150 BEGIN_EVENT_TABLE(PrefsDialog, wxFrame)
151     /* Button events */
152     EVT_BUTTON(wxID_OK, PrefsDialog::OnOk)
153     EVT_BUTTON(wxID_CANCEL, PrefsDialog::OnCancel)
154     EVT_BUTTON(wxID_SAVE, PrefsDialog::OnSave)
155     EVT_BUTTON(ResetAll_Event, PrefsDialog::OnResetAll)
156     EVT_CHECKBOX(Advanced_Event, PrefsDialog::OnAdvanced)
157
158     /* Don't destroy the window when the user closes it */
159     EVT_CLOSE(PrefsDialog::OnCancel)
160 END_EVENT_TABLE()
161
162 // menu and control ids
163 enum
164 {
165     PrefsTree_Ctrl = wxID_HIGHEST
166 };
167
168 BEGIN_EVENT_TABLE(PrefsTreeCtrl, wxTreeCtrl)
169     EVT_TREE_SEL_CHANGED(PrefsTree_Ctrl, PrefsTreeCtrl::OnSelectTreeItem)
170     EVT_COMMAND(Advanced_Event, wxEVT_USER_FIRST, PrefsTreeCtrl::OnAdvanced)
171 END_EVENT_TABLE()
172
173 /*****************************************************************************
174  * Constructor.
175  *****************************************************************************/
176 PrefsDialog::PrefsDialog( intf_thread_t *_p_intf, wxWindow *p_parent)
177   :  wxFrame( p_parent, -1, wxU(_("Preferences")), wxDefaultPosition,
178               wxSize(700,450), wxDEFAULT_FRAME_STYLE )
179 {
180     /* Initializations */
181     p_intf = _p_intf;
182     SetIcon( *p_intf->p_sys->p_icon );
183
184     /* Create a panel to put everything in */
185     wxPanel *panel = new wxPanel( this, -1 );
186     panel->SetAutoLayout( TRUE );
187
188     /* Create the preferences tree control */
189     wxBoxSizer *controls_sizer = new wxBoxSizer( wxHORIZONTAL );
190     prefs_tree =
191         new PrefsTreeCtrl( panel, p_intf, this, controls_sizer );
192
193     /* Separation */
194     wxStaticLine *static_line = new wxStaticLine( panel, wxID_OK );
195
196     /* Create the buttons */
197     wxButton *ok_button = new wxButton( panel, wxID_OK, wxU(_("OK")) );
198     ok_button->SetDefault();
199     wxButton *cancel_button = new wxButton( panel, wxID_CANCEL,
200                                             wxU(_("Cancel")) );
201     wxButton *save_button = new wxButton( panel, wxID_SAVE, wxU(_("Save")) );
202     wxButton *reset_button = new wxButton( panel, ResetAll_Event,
203                                            wxU(_("Reset All")) );
204
205     wxPanel *dummy_panel = new wxPanel( this, -1 );
206     wxCheckBox *advanced_checkbox =
207         new wxCheckBox( panel, Advanced_Event, wxU(_("Advanced options")) );
208
209     if( config_GetInt( p_intf, "advanced" ) )
210     {
211         advanced_checkbox->SetValue(TRUE);
212         wxCommandEvent dummy_event;
213         dummy_event.SetInt(TRUE);
214         OnAdvanced( dummy_event );
215     }
216
217     /* Place everything in sizers */
218     wxBoxSizer *button_sizer = new wxBoxSizer( wxHORIZONTAL );
219     button_sizer->Add( ok_button, 0, wxALL, 5 );
220     button_sizer->Add( cancel_button, 0, wxALL, 5 );
221     button_sizer->Add( save_button, 0, wxALL, 5 );
222     button_sizer->Add( reset_button, 0, wxALL, 5 );
223     button_sizer->Add( dummy_panel, 1, wxALL, 5 );
224     button_sizer->Add( advanced_checkbox, 0, wxALL | wxALIGN_RIGHT |
225                        wxALIGN_CENTER_VERTICAL, 0 );
226     button_sizer->Layout();
227
228     wxBoxSizer *main_sizer = new wxBoxSizer( wxVERTICAL );
229     wxBoxSizer *panel_sizer = new wxBoxSizer( wxVERTICAL );
230     panel_sizer->Add( controls_sizer, 1, wxEXPAND | wxALL, 5 );
231     panel_sizer->Add( static_line, 0, wxEXPAND | wxALL, 5 );
232     panel_sizer->Add( button_sizer, 0, wxALIGN_LEFT | wxALIGN_BOTTOM |
233                       wxALL | wxEXPAND, 5 );
234     panel_sizer->Layout();
235     panel->SetSizer( panel_sizer );
236     main_sizer->Add( panel, 1, wxEXPAND, 0 );
237     main_sizer->Layout();
238     SetSizer( main_sizer );
239 }
240
241 PrefsDialog::~PrefsDialog()
242 {
243 }
244
245 /*****************************************************************************
246  * Private methods.
247  *****************************************************************************/
248
249
250 /*****************************************************************************
251  * Events methods.
252  *****************************************************************************/
253 void PrefsDialog::OnOk( wxCommandEvent& WXUNUSED(event) )
254 {
255     prefs_tree->ApplyChanges();
256     this->Hide();
257     prefs_tree->CleanChanges();
258 }
259
260 void PrefsDialog::OnCancel( wxCommandEvent& WXUNUSED(event) )
261 {
262     this->Hide();
263     prefs_tree->CleanChanges();
264 }
265
266 void PrefsDialog::OnSave( wxCommandEvent& WXUNUSED(event) )
267 {
268     prefs_tree->ApplyChanges();
269     config_SaveConfigFile( p_intf, NULL );
270     this->Hide();
271 }
272
273 void PrefsDialog::OnResetAll( wxCommandEvent& WXUNUSED(event) )
274 {
275     wxMessageDialog dlg( this,
276         wxU(_("Beware this will reset your VLC Media Player config file.\n"
277               "Are you sure you want to continue?")),
278         wxU(_("Reset config file")), wxYES_NO|wxNO_DEFAULT|wxCENTRE );
279
280     if ( dlg.ShowModal() == wxID_YES )
281     {
282         /* TODO: need to reset all the controls */
283         config_ResetAll( p_intf );
284         prefs_tree->CleanChanges();
285         config_SaveConfigFile( p_intf, NULL );
286     }
287 }
288
289 void PrefsDialog::OnAdvanced( wxCommandEvent& event )
290 {
291     wxCommandEvent newevent( wxEVT_USER_FIRST, Advanced_Event );
292     newevent.SetInt( event.GetInt() );
293
294     prefs_tree->AddPendingEvent( newevent );
295 }
296
297 /*****************************************************************************
298  * GetCapabilityHelp: Display the help for one capability.
299  *****************************************************************************/
300 static char * GetCapabilityHelp( char *psz_capability, int i_type)
301 {
302     if( psz_capability == NULL) return "";
303
304     if( !strcasecmp(psz_capability,"access") )
305         return i_type == 1 ? ACCESS_TITLE : ACCESS_HELP;
306     if( !strcasecmp(psz_capability,"audio filter") )
307         return i_type == 1 ? AUDIO_FILTER_TITLE : AUDIO_FILTER_HELP;
308     if( !strcasecmp(psz_capability,"audio output") )
309         return i_type == 1 ? AOUT_TITLE : AOUT_HELP;
310     if( !strcasecmp(psz_capability,"audio encoder") )
311         return i_type == 1 ? AOUT_ENC_TITLE : AOUT_ENC_HELP;
312     if( !strcasecmp(psz_capability,"chroma") )
313         return i_type == 1 ? CHROMA_TITLE : CHROMA_HELP;
314     if( !strcasecmp(psz_capability,"decoder") )
315         return i_type == 1 ? DECODER_TITLE : DECODER_HELP;
316     if( !strcasecmp(psz_capability,"demux") )
317         return i_type == 1 ? DEMUX_TITLE : DEMUX_HELP;
318     if( !strcasecmp(psz_capability,"interface") )
319         return i_type == 1 ? INTERFACE_TITLE : INTERFACE_HELP;
320     if( !strcasecmp(psz_capability,"sout access") )
321         return i_type == 1 ? SOUT_TITLE : SOUT_HELP;
322     if( !strcasecmp(psz_capability,"subtitle demux") )
323         return i_type == 1 ? SUBTITLE_DEMUX_TITLE : SUBTITLE_DEMUX_HELP;
324     if( !strcasecmp(psz_capability,"text renderer") )
325         return i_type == 1 ? TEXT_TITLE : TEXT_HELP;
326     if( !strcasecmp(psz_capability,"video output") )
327         return i_type == 1 ? VOUT__TITLE : VOUT_HELP;
328     if( !strcasecmp(psz_capability,"video filter") )
329         return i_type == 1 ? VIDEO_FILTER_TITLE : VIDEO_FILTER_HELP;
330
331     return " ";
332 }
333
334 /*****************************************************************************
335  * PrefsTreeCtrl class definition.
336  *****************************************************************************/
337 PrefsTreeCtrl::PrefsTreeCtrl( wxWindow *_p_parent, intf_thread_t *_p_intf,
338                               PrefsDialog *_p_prefs_dialog,
339                               wxBoxSizer *_p_sizer )
340   : wxTreeCtrl( _p_parent, PrefsTree_Ctrl, wxDefaultPosition, wxDefaultSize,
341                 wxTR_NO_LINES | wxTR_FULL_ROW_HIGHLIGHT |
342                 wxTR_LINES_AT_ROOT | wxTR_HIDE_ROOT |
343                 wxTR_HAS_BUTTONS | wxTR_TWIST_BUTTONS | wxSUNKEN_BORDER )
344 {
345     vlc_list_t      *p_list;
346     module_t        *p_module;
347     module_config_t *p_item;
348     int i_index;
349
350     /* Initializations */
351     p_intf = _p_intf;
352     p_prefs_dialog = _p_prefs_dialog;
353     p_sizer = _p_sizer;
354     p_parent = _p_parent;
355     b_advanced = VLC_FALSE;
356
357     root_item = AddRoot( wxT("") );
358
359     /* List the plugins */
360     p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
361     if( !p_list ) return;
362
363     /*
364      * Build a tree of the main options
365      */
366     ConfigTreeData *config_data = new ConfigTreeData;
367     config_data->i_object_id = GENERAL_ID;
368     config_data->psz_help = wraptext( GENERAL_HELP, 72 , ISUTF8 );
369     config_data->psz_section = strdup( GENERAL_TITLE );
370     general_item = AppendItem( root_item, wxU(_("General settings")),
371                                 -1, -1, config_data );
372
373     for( i_index = 0; i_index < p_list->i_count; i_index++ )
374     {
375         p_module = (module_t *)p_list->p_values[i_index].p_object;
376         if( !strcmp( p_module->psz_object_name, "main" ) )
377             break;
378     }
379     if( i_index < p_list->i_count )
380     {
381         /* We found the main module */
382
383         /* Enumerate config categories and store a reference so we can
384          * generate their config panel them when it is asked by the user. */
385         p_item = p_module->p_config;
386
387         if( p_item ) do
388         {
389             switch( p_item->i_type )
390             {
391             case CONFIG_HINT_CATEGORY:
392                 ConfigTreeData *config_data = new ConfigTreeData;
393                 config_data->psz_section = strdup(p_item->psz_text);
394                 if( p_item->psz_longtext )
395                 {
396                     config_data->psz_help =
397                         wraptext( p_item->psz_longtext, 72 , ISUTF8 );
398                 }
399                 else
400                 {
401                     config_data->psz_help = NULL;
402                 }
403                 config_data->i_object_id = p_module->i_object_id;
404
405                 /* Add the category to the tree */
406                 AppendItem( general_item, wxU(p_item->psz_text),
407                             -1, -1, config_data );
408                 break;
409             }
410         }
411         while( p_item->i_type != CONFIG_HINT_END && p_item++ );
412
413         SortChildren( general_item );
414     }
415
416
417     /*
418      * Build a tree of all the plugins
419      */
420     config_data = new ConfigTreeData;
421     config_data->i_object_id = PLUGIN_ID;
422     config_data->psz_help = wraptext( PLUGIN_HELP, 72, ISUTF8 );
423     config_data->psz_section = strdup( PLUGIN_TITLE );
424     plugins_item = AppendItem( root_item, wxU(_("Plugins")),
425                         -1,-1,config_data );
426
427     for( i_index = 0; i_index < p_list->i_count; i_index++ )
428     {
429         p_module = (module_t *)p_list->p_values[i_index].p_object;
430
431         /* Exclude the main module */
432         if( !strcmp( p_module->psz_object_name, "main" ) )
433             continue;
434
435         /* Exclude empty plugins (submodules don't have config options, they
436          * are stored in the parent module) */
437         if( p_module->b_submodule )
438             p_item = ((module_t *)p_module->p_parent)->p_config;
439         else
440             p_item = p_module->p_config;
441
442         if( !p_item ) continue;
443         do
444         {
445             if( p_item->i_type & CONFIG_ITEM )
446                 break;
447         }
448         while( p_item->i_type != CONFIG_HINT_END && p_item++ );
449         if( p_item->i_type == CONFIG_HINT_END ) continue;
450
451         /* Find the capability child item */
452         long cookie; size_t i_child_index;
453         wxTreeItemId capability_item = GetFirstChild( plugins_item, cookie);
454         for( i_child_index = 0;
455              i_child_index < GetChildrenCount( plugins_item, FALSE );
456              i_child_index++ )
457         {
458             if( !GetItemText(capability_item).Cmp(
459                     wxU(p_module->psz_capability ) ) )
460             {
461                 break;
462             }
463             capability_item = GetNextChild( plugins_item, cookie );
464         }
465
466         if( i_child_index == GetChildrenCount( plugins_item, FALSE ) &&
467             p_module->psz_capability && *p_module->psz_capability )
468         {
469             /* We didn't find it, add it */
470             ConfigTreeData *config_data = new ConfigTreeData;
471             config_data->psz_section =
472                 wraptext( GetCapabilityHelp( p_module->psz_capability , 1 ),
473                           72, ISUTF8 );
474             config_data->psz_help =
475                 wraptext( GetCapabilityHelp( p_module->psz_capability , 2 ),
476                           72, ISUTF8 );
477             config_data->i_object_id = CAPABILITY_ID;
478             capability_item = AppendItem( plugins_item,
479                                           wxU(p_module->psz_capability),
480                                           -1,-1,config_data );
481         }
482
483         /* Add the plugin to the tree */
484         ConfigTreeData *config_data = new ConfigTreeData;
485         config_data->b_submodule = p_module->b_submodule;
486         config_data->i_object_id = p_module->b_submodule ?
487             ((module_t *)p_module->p_parent)->i_object_id :
488             p_module->i_object_id;
489         config_data->psz_help = NULL;
490         AppendItem( capability_item, wxU(p_module->psz_object_name), -1, -1,
491                     config_data );
492     }
493
494     /* Sort all this mess */
495     long cookie; size_t i_child_index;
496     SortChildren( plugins_item );
497     wxTreeItemId capability_item = GetFirstChild( plugins_item, cookie);
498     for( i_child_index = 0;
499          i_child_index < GetChildrenCount( plugins_item, FALSE );
500          i_child_index++ )
501     {
502         capability_item = GetNextChild( plugins_item, cookie );
503         SortChildren( capability_item );
504     }
505
506     /* Clean-up everything */
507     vlc_list_release( p_list );
508
509     p_sizer->Add( this, 1, wxEXPAND | wxALL, 0 );
510     p_sizer->Layout();
511
512     /* Update Tree Ctrl */
513 #ifndef WIN32 /* Workaround a bug in win32 implementation */
514     SelectItem( GetFirstChild( root_item, cookie ) );
515 #endif
516
517     Expand( general_item );
518 }
519
520 PrefsTreeCtrl::~PrefsTreeCtrl()
521 {
522 }
523
524 void PrefsTreeCtrl::ApplyChanges()
525 {
526     long cookie, cookie2;
527     ConfigTreeData *config_data;
528
529     /* Apply changes to the main module */
530     wxTreeItemId item = GetFirstChild( general_item, cookie );
531     for( size_t i_child_index = 0;
532          i_child_index < GetChildrenCount( general_item, FALSE );
533          i_child_index++ )
534     {
535         config_data = (ConfigTreeData *)GetItemData( item );
536         if( config_data && config_data->panel )
537         {
538             config_data->panel->ApplyChanges();
539         }
540
541         item = GetNextChild( general_item, cookie );
542     }
543
544     /* Apply changes to the plugins */
545     item = GetFirstChild( plugins_item, cookie );
546     for( size_t i_child_index = 0;
547          i_child_index < GetChildrenCount( plugins_item, FALSE );
548          i_child_index++ )
549     {
550         wxTreeItemId item2 = GetFirstChild( item, cookie2 );
551         for( size_t i_child_index = 0;
552              i_child_index < GetChildrenCount( item, FALSE );
553              i_child_index++ )
554         {
555             config_data = (ConfigTreeData *)GetItemData( item2 );
556             if( config_data && config_data->panel )
557             {
558                 config_data->panel->ApplyChanges();
559             }
560
561             item2 = GetNextChild( item, cookie2 );
562         }
563
564         item = GetNextChild( plugins_item, cookie );
565     }
566 }
567
568 void PrefsTreeCtrl::CleanChanges()
569 {
570     long cookie, cookie2;
571     ConfigTreeData *config_data;
572
573     config_data = !GetSelection() ? NULL :
574         FindModuleConfig( (ConfigTreeData *)GetItemData( GetSelection() ) );
575     if( config_data  )
576     {
577         config_data->panel->Hide();
578         p_sizer->Remove( config_data->panel );
579     }
580
581     /* Clean changes for the main module */
582     wxTreeItemId item = GetFirstChild( general_item, cookie );
583     for( size_t i_child_index = 0;
584          i_child_index < GetChildrenCount( general_item, FALSE );
585          i_child_index++ )
586     {
587         config_data = (ConfigTreeData *)GetItemData( item );
588         if( config_data && config_data->panel )
589         {
590             delete config_data->panel;
591             config_data->panel = NULL;
592         }
593
594         item = GetNextChild( general_item, cookie );
595     }
596
597     /* Clean changes for the plugins */
598     item = GetFirstChild( plugins_item, cookie );
599     for( size_t i_child_index = 0;
600          i_child_index < GetChildrenCount( plugins_item, FALSE );
601          i_child_index++ )
602     {
603         wxTreeItemId item2 = GetFirstChild( item, cookie2 );
604         for( size_t i_child_index = 0;
605              i_child_index < GetChildrenCount( item, FALSE );
606              i_child_index++ )
607         {
608             config_data = (ConfigTreeData *)GetItemData( item2 );
609
610             if( config_data && config_data->panel )
611             {
612                 delete config_data->panel;
613                 config_data->panel = NULL;
614             }
615
616             item2 = GetNextChild( item, cookie2 );
617         }
618
619         item = GetNextChild( plugins_item, cookie );
620     }
621
622     if( GetSelection() )
623     {
624         wxTreeEvent event;
625         OnSelectTreeItem( event );
626     }
627 }
628
629 ConfigTreeData *PrefsTreeCtrl::FindModuleConfig( ConfigTreeData *config_data )
630 {
631     /* We need this complexity because submodules don't have their own config
632      * options. They use the parent module ones. */
633
634     if( !config_data || !config_data->b_submodule )
635     {
636         return config_data;
637     }
638
639     long cookie, cookie2;
640     ConfigTreeData *config_new;
641     wxTreeItemId item = GetFirstChild( plugins_item, cookie );
642     for( size_t i_child_index = 0;
643          i_child_index < GetChildrenCount( plugins_item, FALSE );
644          i_child_index++ )
645     {
646         wxTreeItemId item2 = GetFirstChild( item, cookie2 );
647         for( size_t i_child_index = 0;
648              i_child_index < GetChildrenCount( item, FALSE );
649              i_child_index++ )
650         {
651             config_new = (ConfigTreeData *)GetItemData( item2 );
652             if( config_new && !config_new->b_submodule &&
653                 config_new->i_object_id == config_data->i_object_id )
654             {
655                 return config_new;
656             }
657
658             item2 = GetNextChild( item, cookie2 );
659         }
660
661         item = GetNextChild( plugins_item, cookie );
662     }
663
664     /* Found nothing */
665     return NULL;
666 }
667
668 void PrefsTreeCtrl::OnSelectTreeItem( wxTreeEvent& event )
669 {
670     ConfigTreeData *config_data;
671
672     config_data = FindModuleConfig( (ConfigTreeData *)GetItemData(
673                                     event.GetOldItem() ) );
674     if( config_data && config_data->panel )
675     {
676         config_data->panel->Hide();
677         p_sizer->Remove( config_data->panel );
678     }
679
680     /* Don't use event.GetItem() because we also send fake events */
681     config_data = FindModuleConfig( (ConfigTreeData *)GetItemData(
682                                     GetSelection() ) );
683     if( config_data )
684     {
685         if( !config_data->panel )
686         {
687             /* The panel hasn't been created yet. Let's do it. */
688             config_data->panel =
689                 new PrefsPanel( p_parent, p_intf, p_prefs_dialog,
690                                 config_data->i_object_id,
691                                 config_data->psz_section,
692                                 config_data->psz_help );
693             config_data->panel->SwitchAdvanced( b_advanced );
694         }
695         else
696         {
697             config_data->panel->SwitchAdvanced( b_advanced );
698             config_data->panel->Show();
699         }
700
701         p_sizer->Add( config_data->panel, 3, wxEXPAND | wxALL, 0 );
702         p_sizer->Layout();
703     }
704 }
705
706 void PrefsTreeCtrl::OnAdvanced( wxCommandEvent& event )
707 {
708     b_advanced = event.GetInt();
709
710     ConfigTreeData *config_data = !GetSelection() ? NULL :
711         FindModuleConfig( (ConfigTreeData *)GetItemData( GetSelection() ) );
712     if( config_data  )
713     {
714         config_data->panel->Hide();
715         p_sizer->Remove( config_data->panel );
716     }
717
718     if( GetSelection() )
719     {
720         wxTreeEvent event;
721         OnSelectTreeItem( event );
722     }
723 }
724
725 /*****************************************************************************
726  * PrefsPanel class definition.
727  *****************************************************************************/
728 PrefsPanel::PrefsPanel( wxWindow* parent, intf_thread_t *_p_intf,
729                         PrefsDialog *_p_prefs_dialog,
730                         int i_object_id, char *psz_section, char *psz_help )
731   :  wxPanel( parent, -1, wxDefaultPosition, wxDefaultSize )
732 {
733     module_config_t *p_item;
734
735     wxStaticText *label;
736     wxStaticText *help;
737     wxArrayString array;
738
739     module_t *p_module = NULL;
740
741     /* Initializations */
742     p_intf = _p_intf;
743     p_prefs_dialog =_p_prefs_dialog,
744
745     b_advanced = VLC_TRUE;
746     SetAutoLayout( TRUE );
747
748     wxBoxSizer *sizer = new wxBoxSizer( wxVERTICAL );
749
750
751     if( i_object_id == PLUGIN_ID || i_object_id == GENERAL_ID ||
752         i_object_id == CAPABILITY_ID )
753     {
754         label = new wxStaticText( this, -1,wxU(_( psz_section )));
755         wxFont heading_font = label->GetFont();
756         heading_font.SetPointSize( heading_font.GetPointSize() + 5 );
757         label->SetFont( heading_font );
758         sizer->Add( label, 0, wxEXPAND | wxLEFT, 10 );
759         sizer->Add( new wxStaticLine( this, 0 ), 0,
760                     wxEXPAND | wxLEFT | wxRIGHT, 2 );
761
762         help = new wxStaticText( this, -1, wxU(_( psz_help ) ) );
763         sizer->Add( help ,0 ,wxEXPAND | wxALL, 5 );
764
765         config_sizer = NULL; config_window = NULL;
766     }
767     else
768     {
769         /* Get a pointer to the module */
770         p_module = (module_t *)vlc_object_get( p_intf,  i_object_id );
771         if( p_module->i_object_type != VLC_OBJECT_MODULE )
772         {
773             /* 0OOoo something went really bad */
774             return;
775         }
776
777         /* Enumerate config options and add corresponding config boxes
778          * (submodules don't have config options, they are stored in the
779          *  parent module) */
780         if( p_module->b_submodule )
781             p_item = ((module_t *)p_module->p_parent)->p_config;
782         else
783             p_item = p_module->p_config;
784
785         /* Find the category if it has been specified */
786         if( psz_section && p_item->i_type == CONFIG_HINT_CATEGORY )
787         {
788             while( !p_item->i_type == CONFIG_HINT_CATEGORY ||
789                    strcmp( psz_section, p_item->psz_text ) )
790             {
791                 if( p_item->i_type == CONFIG_HINT_END )
792                     break;
793                 p_item++;
794             }
795         }
796
797         /* Add a head title to the panel */
798         label = new wxStaticText( this, -1,
799                                   wxU(_(psz_section ? p_item->psz_text :
800                                   p_module->psz_longname )));
801         wxFont heading_font = label->GetFont();
802         heading_font.SetPointSize( heading_font.GetPointSize() + 5 );
803         label->SetFont( heading_font );
804         sizer->Add( label, 0, wxEXPAND | wxLEFT, 10 );
805         sizer->Add( new wxStaticLine( this, 0 ), 0,
806                     wxEXPAND | wxLEFT | wxRIGHT, 2 );
807
808         /* Now put all the config options into a scrolled window */
809         config_sizer = new wxBoxSizer( wxVERTICAL );
810         config_window = new wxScrolledWindow( this, -1, wxDefaultPosition,
811             wxDefaultSize, wxSTATIC_BORDER | wxHSCROLL | wxVSCROLL );
812         config_window->SetAutoLayout( TRUE );
813         config_window->SetScrollRate( 5, 5 );
814
815         if( p_item ) do
816         {
817             /* If a category has been specified, check we finished the job */
818             if( psz_section && p_item->i_type == CONFIG_HINT_CATEGORY &&
819                 strcmp( psz_section, p_item->psz_text ) )
820                 break;
821
822             ConfigControl *control =
823                 CreateConfigControl( VLC_OBJECT(p_intf),
824                                      p_item, config_window );
825
826             /* Don't add items that were not recognized */
827             if( control == NULL ) continue;
828
829             /* Add the config data to our array so we can keep a trace of it */
830             config_array.Add( control );
831
832             config_sizer->Add( control, 0, wxEXPAND | wxALL, 2 );
833         }
834         while( p_item->i_type != CONFIG_HINT_END && p_item++ );
835
836         config_sizer->Layout();
837         config_window->SetSizer( config_sizer );
838         sizer->Add( config_window, 1, wxEXPAND | wxALL, 5 );
839
840         /* And at last put a useful help string if available */
841         if( psz_help && *psz_help )
842         {
843             sizer->Add( new wxStaticLine( this, 0 ), 0,
844                         wxEXPAND | wxLEFT | wxRIGHT, 2 );
845             help = new wxStaticText( this, -1, wxU(_(psz_help)),
846                                      wxDefaultPosition, wxDefaultSize,
847                                      wxALIGN_LEFT,
848                                      wxT("") );
849             sizer->Add( help ,0 ,wxEXPAND | wxALL, 5 );
850         }
851
852     }
853     sizer->Layout();
854     SetSizer( sizer );
855 }
856
857 void PrefsPanel::ApplyChanges()
858 {
859     vlc_value_t val;
860
861     for( size_t i = 0; i < config_array.GetCount(); i++ )
862     {
863         ConfigControl *control = config_array.Item(i);
864
865         switch( control->GetType() )
866         {
867         case CONFIG_ITEM_STRING:
868         case CONFIG_ITEM_FILE:
869         case CONFIG_ITEM_DIRECTORY:
870         case CONFIG_ITEM_MODULE:
871             config_PutPsz( p_intf, control->GetName().mb_str(),
872                            control->GetPszValue().mb_str() );
873             break;
874         case CONFIG_ITEM_KEY:
875             /* So you don't need to restart to have the changes take effect */
876             val.i_int = control->GetIntValue();
877             var_Set( p_intf->p_vlc, control->GetName().mb_str(), val );
878         case CONFIG_ITEM_INTEGER:
879         case CONFIG_ITEM_BOOL:
880             config_PutInt( p_intf, control->GetName().mb_str(),
881                            control->GetIntValue() );
882             break;
883         case CONFIG_ITEM_FLOAT:
884             config_PutFloat( p_intf, control->GetName().mb_str(),
885                              control->GetFloatValue() );
886             break;
887         }
888     }
889 }
890
891 void PrefsPanel::SwitchAdvanced( vlc_bool_t b_new_advanced )
892 {
893     if( b_advanced == b_new_advanced ) return;
894
895     if( config_sizer && config_window )
896     {
897         b_advanced = b_new_advanced;
898
899         for( size_t i = 0; i < config_array.GetCount(); i++ )
900         {
901             ConfigControl *control = config_array.Item(i);
902             if( control->IsAdvanced() )
903             {
904                 control->Show( b_advanced );
905                 config_sizer->Show( control, b_advanced );
906             }
907         }
908
909         config_sizer->Layout();
910         config_window->FitInside();
911         config_window->Refresh();
912     }
913     return;
914 }