]> git.sesse.net Git - vlc/blob - modules/gui/wxwindows/preferences.cpp
* modules/gui/wxwindows/preferences.cpp: fixes some alignment issues in the config...
[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.35 2003/10/17 16:40:09 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 #include <vlc/intf.h>
34
35 #include <vlc_help.h>
36
37 #include "wxwindows.h"
38 #include <wx/notebook.h>
39 #include <wx/textctrl.h>
40 #include <wx/combobox.h>
41 #include <wx/spinctrl.h>
42 #include <wx/statline.h>
43 #include <wx/treectrl.h>
44 #include <wx/clntdata.h>
45 #include <wx/dynarray.h>
46
47 #ifndef wxRB_SINGLE
48 #   define wxRB_SINGLE 0
49 #endif
50
51 #define GENERAL_ID 1242
52 #define PLUGIN_ID 1243
53 #define CAPABILITY_ID 1244
54
55 /*****************************************************************************
56  * Classes declarations.
57  *****************************************************************************/
58 class ConfigTreeData;
59 class PrefsTreeCtrl : public wxTreeCtrl
60 {
61 public:
62
63     PrefsTreeCtrl() { }
64     PrefsTreeCtrl( wxWindow *parent, intf_thread_t *_p_intf,
65                    PrefsDialog *p_prefs_dialog, wxBoxSizer *_p_sizer );
66     virtual ~PrefsTreeCtrl();
67
68     void ApplyChanges();
69     void CleanChanges();
70
71 private:
72     /* Event handlers (these functions should _not_ be virtual) */
73     void OnSelectTreeItem( wxTreeEvent& event );
74     void OnAdvanced( wxCommandEvent& event );
75
76     ConfigTreeData *FindModuleConfig( ConfigTreeData *config_data );
77
78     DECLARE_EVENT_TABLE()
79
80     intf_thread_t *p_intf;
81     PrefsDialog *p_prefs_dialog;
82     wxBoxSizer *p_sizer;
83     wxWindow *p_parent;
84     vlc_bool_t b_advanced;
85
86     wxTreeItemId root_item;
87     wxTreeItemId general_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 = wxU(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 *, int i_object_id, char *, char * );
125     virtual ~PrefsPanel() {}
126
127     void ApplyChanges();
128     void SwitchAdvanced( vlc_bool_t );
129
130 private:
131     intf_thread_t *p_intf;
132     PrefsDialog *p_prefs_dialog;
133
134     vlc_bool_t b_advanced;
135
136     wxBoxSizer *config_sizer;
137     wxScrolledWindow *config_window;
138
139     ArrayOfConfigData config_array;
140 };
141
142 class ConfigTreeData : public wxTreeItemData
143 {
144 public:
145
146     ConfigTreeData() { b_submodule = 0; panel = NULL; psz_section = NULL; }
147     virtual ~ConfigTreeData() { if( panel ) delete panel; }
148
149     vlc_bool_t b_submodule;
150
151     char *psz_help;
152
153     PrefsPanel *panel;
154     wxBoxSizer *sizer;
155     int i_object_id;
156     char *psz_section;
157 };
158
159 class ConfigEvtHandler : public wxEvtHandler
160 {
161 public:
162     ConfigEvtHandler( intf_thread_t *p_intf, PrefsDialog *p_prefs_dialog );
163     virtual ~ConfigEvtHandler();
164
165     void ConfigEvtHandler::OnCommandEvent( wxCommandEvent& event );
166
167 private:
168
169     DECLARE_EVENT_TABLE()
170
171     intf_thread_t *p_intf;
172     PrefsDialog *p_prefs_dialog;
173 };
174
175 /*****************************************************************************
176  * Event Table.
177  *****************************************************************************/
178
179 /* IDs for the controls and the menu commands */
180 enum
181 {
182     Notebook_Event = wxID_HIGHEST,
183     MRL_Event,
184     ResetAll_Event,
185     Advanced_Event,
186 };
187
188 BEGIN_EVENT_TABLE(PrefsDialog, wxFrame)
189     /* Button events */
190     EVT_BUTTON(wxID_OK, PrefsDialog::OnOk)
191     EVT_BUTTON(wxID_CANCEL, PrefsDialog::OnCancel)
192     EVT_BUTTON(wxID_SAVE, PrefsDialog::OnSave)
193     EVT_BUTTON(ResetAll_Event, PrefsDialog::OnResetAll)
194     EVT_CHECKBOX(Advanced_Event, PrefsDialog::OnAdvanced)
195
196     /* Don't destroy the window when the user closes it */
197     EVT_CLOSE(PrefsDialog::OnCancel)
198 END_EVENT_TABLE()
199
200 // menu and control ids
201 enum
202 {
203     PrefsTree_Ctrl = wxID_HIGHEST
204 };
205
206 BEGIN_EVENT_TABLE(PrefsTreeCtrl, wxTreeCtrl)
207     EVT_TREE_SEL_CHANGED(PrefsTree_Ctrl, PrefsTreeCtrl::OnSelectTreeItem)
208     EVT_COMMAND(Advanced_Event, wxEVT_USER_FIRST, PrefsTreeCtrl::OnAdvanced)
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, wxWindow *p_parent)
222   :  wxFrame( p_parent, -1, wxU(_("Preferences")), wxDefaultPosition,
223               wxSize(700,450), wxDEFAULT_FRAME_STYLE )
224 {
225     /* Initializations */
226     p_intf = _p_intf;
227     SetIcon( *p_intf->p_sys->p_icon );
228
229     /* Create a panel to put everything in */
230     wxPanel *panel = new wxPanel( this, -1 );
231     panel->SetAutoLayout( TRUE );
232
233     /* Create the preferences tree control */
234     wxBoxSizer *controls_sizer = new wxBoxSizer( wxHORIZONTAL );
235     prefs_tree =
236         new PrefsTreeCtrl( panel, p_intf, this, controls_sizer );
237
238     /* Separation */
239     wxStaticLine *static_line = new wxStaticLine( panel, wxID_OK );
240
241     /* Create the buttons */
242     wxButton *ok_button = new wxButton( panel, wxID_OK, wxU(_("OK")) );
243     ok_button->SetDefault();
244     wxButton *cancel_button = new wxButton( panel, wxID_CANCEL,
245                                             wxU(_("Cancel")) );
246     wxButton *save_button = new wxButton( panel, wxID_SAVE, wxU(_("Save")) );
247     wxButton *reset_button = new wxButton( panel, ResetAll_Event,
248                                            wxU(_("Reset All")) );
249
250     wxPanel *dummy_panel = new wxPanel( this, -1 );
251     wxCheckBox *advanced_checkbox =
252         new wxCheckBox( panel, Advanced_Event, wxU(_("Advanced options")) );
253
254     if( config_GetInt( p_intf, "advanced" ) )
255     {
256         advanced_checkbox->SetValue(TRUE);
257         wxCommandEvent dummy_event;
258         dummy_event.SetInt(TRUE);
259         OnAdvanced( dummy_event );
260     }
261
262     /* Place everything in sizers */
263     wxBoxSizer *button_sizer = new wxBoxSizer( wxHORIZONTAL );
264     button_sizer->Add( ok_button, 0, wxALL, 5 );
265     button_sizer->Add( cancel_button, 0, wxALL, 5 );
266     button_sizer->Add( save_button, 0, wxALL, 5 );
267     button_sizer->Add( reset_button, 0, wxALL, 5 );
268     button_sizer->Add( dummy_panel, 1, wxALL, 5 );
269     button_sizer->Add( advanced_checkbox, 0, wxALL | wxALIGN_RIGHT |
270                        wxALIGN_CENTER_VERTICAL, 0 );
271     button_sizer->Layout();
272
273     wxBoxSizer *main_sizer = new wxBoxSizer( wxVERTICAL );
274     wxBoxSizer *panel_sizer = new wxBoxSizer( wxVERTICAL );
275     panel_sizer->Add( controls_sizer, 1, wxEXPAND | wxALL, 5 );
276     panel_sizer->Add( static_line, 0, wxEXPAND | wxALL, 5 );
277     panel_sizer->Add( button_sizer, 0, wxALIGN_LEFT | wxALIGN_BOTTOM |
278                       wxALL | wxEXPAND, 5 );
279     panel_sizer->Layout();
280     panel->SetSizer( panel_sizer );
281     main_sizer->Add( panel, 1, wxEXPAND, 0 );
282     main_sizer->Layout();
283     SetSizer( main_sizer );
284 }
285
286 PrefsDialog::~PrefsDialog()
287 {
288 }
289
290 /*****************************************************************************
291  * Private methods.
292  *****************************************************************************/
293
294
295 /*****************************************************************************
296  * Events methods.
297  *****************************************************************************/
298 void PrefsDialog::OnOk( wxCommandEvent& WXUNUSED(event) )
299 {
300     prefs_tree->ApplyChanges();
301     this->Hide();
302     prefs_tree->CleanChanges();
303 }
304
305 void PrefsDialog::OnCancel( wxCommandEvent& WXUNUSED(event) )
306 {
307     this->Hide();
308     prefs_tree->CleanChanges();
309 }
310
311 void PrefsDialog::OnSave( wxCommandEvent& WXUNUSED(event) )
312 {
313     prefs_tree->ApplyChanges();
314     config_SaveConfigFile( p_intf, NULL );
315     this->Hide();
316 }
317
318 void PrefsDialog::OnResetAll( wxCommandEvent& WXUNUSED(event) )
319 {
320     wxMessageDialog dlg( this,
321         wxU(_("Beware this will reset your VLC Media Player config file.\n"
322               "Are you sure you want to continue?")),
323         wxU(_("Reset config file")), wxYES_NO|wxNO_DEFAULT|wxCENTRE );
324
325     if ( dlg.ShowModal() == wxID_YES )
326     {
327         /* TODO: need to reset all the controls */
328         config_ResetAll( p_intf );
329         prefs_tree->CleanChanges();
330         config_SaveConfigFile( p_intf, NULL );
331     }
332 }
333
334 void PrefsDialog::OnAdvanced( wxCommandEvent& event )
335 {
336     wxCommandEvent newevent( wxEVT_USER_FIRST, Advanced_Event );
337     newevent.SetInt( event.GetInt() );
338
339     prefs_tree->AddPendingEvent( newevent );
340 }
341
342 /*****************************************************************************
343  * GetCapabilityHelp: Display the help for one capability.
344  *****************************************************************************/
345 static char * GetCapabilityHelp( char *psz_capability, int i_type)
346 {
347     if( psz_capability == NULL) return "";
348
349     if( !strcasecmp(psz_capability,"access") )
350         return i_type == 1 ? ACCESS_TITLE : ACCESS_HELP;
351     if( !strcasecmp(psz_capability,"audio filter") )
352         return i_type == 1 ? AUDIO_FILTER_TITLE : AUDIO_FILTER_HELP;
353     if( !strcasecmp(psz_capability,"audio output") )
354         return i_type == 1 ? AOUT_TITLE : AOUT_HELP;
355     if( !strcasecmp(psz_capability,"chroma") )
356         return i_type == 1 ? CHROMA_TITLE : CHROMA_HELP;
357     if( !strcasecmp(psz_capability,"decoder") )
358         return i_type == 1 ? DECODER_TITLE : DECODER_HELP;
359     if( !strcasecmp(psz_capability,"demux") )
360         return i_type == 1 ? DEMUX_TITLE : DEMUX_HELP;
361     if( !strcasecmp(psz_capability,"interface") )
362         return i_type == 1 ? INTERFACE_TITLE : INTERFACE_HELP;
363     if( !strcasecmp(psz_capability,"sout access") )
364         return i_type == 1 ? SOUT_TITLE : SOUT_HELP;
365     if( !strcasecmp(psz_capability,"subtitle demux") )
366         return i_type == 1 ? SUBTITLE_DEMUX_TITLE : SUBTITLE_DEMUX_HELP;
367     if( !strcasecmp(psz_capability,"text renderer") )
368         return i_type == 1 ? TEXT_TITLE : TEXT_HELP;
369     if( !strcasecmp(psz_capability,"video output") )
370         return i_type == 1 ? VOUT__TITLE : VOUT_HELP;
371     if( !strcasecmp(psz_capability,"video filter") )
372         return i_type == 1 ? VIDEO_FILTER_TITLE : VIDEO_FILTER_HELP;
373
374     return "";
375 }
376
377 /*****************************************************************************
378  * PrefsTreeCtrl class definition.
379  *****************************************************************************/
380 PrefsTreeCtrl::PrefsTreeCtrl( wxWindow *_p_parent, intf_thread_t *_p_intf,
381                               PrefsDialog *_p_prefs_dialog,
382                               wxBoxSizer *_p_sizer )
383   : wxTreeCtrl( _p_parent, PrefsTree_Ctrl, wxDefaultPosition, wxDefaultSize,
384                 wxTR_NO_LINES | wxTR_FULL_ROW_HIGHLIGHT |
385                 wxTR_LINES_AT_ROOT | wxTR_HIDE_ROOT |
386                 wxTR_HAS_BUTTONS | wxTR_TWIST_BUTTONS | wxSUNKEN_BORDER )
387 {
388     vlc_list_t      *p_list;
389     module_t        *p_module;
390     module_config_t *p_item;
391     int i_index;
392
393     /* Initializations */
394     p_intf = _p_intf;
395     p_prefs_dialog = _p_prefs_dialog;
396     p_sizer = _p_sizer;
397     p_parent = _p_parent;
398     b_advanced = VLC_FALSE;
399
400     root_item = AddRoot( wxT("") );
401
402     /* List the plugins */
403     p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
404     if( !p_list ) return;
405
406     /*
407      * Build a tree of the main options
408      */
409     ConfigTreeData *config_data = new ConfigTreeData;
410     config_data->psz_section = NULL;
411     config_data->i_object_id = GENERAL_ID;
412     config_data->psz_help = wraptext( GENERAL_HELP, WRAPCOUNT, ISUTF8 );
413     config_data->psz_section = strdup( GENERAL_TITLE );
414     general_item = AppendItem( root_item, wxU(_("General Settings")),
415                                 -1, -1, config_data );
416
417     for( i_index = 0; i_index < p_list->i_count; i_index++ )
418     {
419         p_module = (module_t *)p_list->p_values[i_index].p_object;
420         if( !strcmp( p_module->psz_object_name, "main" ) )
421             break;
422     }
423     if( i_index < p_list->i_count )
424     {
425         /* We found the main module */
426
427         /* Enumerate config categories and store a reference so we can
428          * generate their config panel them when it is asked by the user. */
429         p_item = p_module->p_config;
430
431         if( p_item ) do
432         {
433             switch( p_item->i_type )
434             {
435             case CONFIG_HINT_CATEGORY:
436                 ConfigTreeData *config_data = new ConfigTreeData;
437                 config_data->psz_section = strdup(p_item->psz_text);
438                 if( p_item->psz_longtext )
439                 {
440                     config_data->psz_help =
441                         wraptext( p_item->psz_longtext, WRAPCOUNT, ISUTF8 );
442                 }
443                 else
444                 {
445                     config_data->psz_help = NULL;
446                 }
447                 config_data->i_object_id = p_module->i_object_id;
448
449                 /* Add the category to the tree */
450                 AppendItem( general_item, wxU(p_item->psz_text),
451                             -1, -1, config_data );
452                 break;
453             }
454         }
455         while( p_item->i_type != CONFIG_HINT_END && p_item++ );
456
457         SortChildren( general_item );
458     }
459
460
461     /*
462      * Build a tree of all the plugins
463      */
464     config_data = new ConfigTreeData;
465     config_data->psz_section = NULL;
466     config_data->i_object_id = PLUGIN_ID;
467     config_data->psz_help = wraptext( PLUGIN_HELP, WRAPCOUNT, ISUTF8 );
468     config_data->psz_section = strdup( PLUGIN_TITLE );
469     plugins_item = AppendItem( root_item, wxU(_("Plugins")),
470                         -1,-1,config_data );
471
472     for( i_index = 0; i_index < p_list->i_count; i_index++ )
473     {
474         p_module = (module_t *)p_list->p_values[i_index].p_object;
475
476         /* Exclude the main module */
477         if( !strcmp( p_module->psz_object_name, "main" ) )
478             continue;
479
480         /* Exclude empty plugins (submodules don't have config options, they
481          * are stored in the parent module) */
482         if( p_module->b_submodule )
483             p_item = ((module_t *)p_module->p_parent)->p_config;
484         else
485             p_item = p_module->p_config;
486
487         if( !p_item ) continue;
488         do
489         {
490             if( p_item->i_type & CONFIG_ITEM )
491                 break;
492         }
493         while( p_item->i_type != CONFIG_HINT_END && p_item++ );
494         if( p_item->i_type == CONFIG_HINT_END ) continue;
495
496         /* Find the capability child item */
497         long cookie; size_t i_child_index;
498         wxTreeItemId capability_item = GetFirstChild( plugins_item, cookie);
499         for( i_child_index = 0;
500              i_child_index < GetChildrenCount( plugins_item, FALSE );
501              i_child_index++ )
502         {
503             if( !GetItemText(capability_item).Cmp(
504                     wxU(p_module->psz_capability ) ) )
505             {
506                 break;
507             }
508             capability_item = GetNextChild( plugins_item, cookie );
509         }
510
511         if( i_child_index == GetChildrenCount( plugins_item, FALSE ) &&
512             p_module->psz_capability && *p_module->psz_capability )
513         {
514             /* We didn't find it, add it */
515             ConfigTreeData *config_data = new ConfigTreeData;
516             config_data->psz_section =
517                 wraptext( GetCapabilityHelp( p_module->psz_capability , 1 ),
518                           WRAPCOUNT, ISUTF8 );
519             config_data->psz_help =
520                 wraptext( GetCapabilityHelp( p_module->psz_capability , 2 ),
521                           WRAPCOUNT, ISUTF8 );
522             config_data->i_object_id = CAPABILITY_ID;
523             capability_item = AppendItem( plugins_item,
524                                           wxU(p_module->psz_capability),
525                                           -1,-1,config_data );
526         }
527
528         /* Add the plugin to the tree */
529         ConfigTreeData *config_data = new ConfigTreeData;
530         config_data->b_submodule = p_module->b_submodule;
531         config_data->i_object_id = p_module->b_submodule ?
532             ((module_t *)p_module->p_parent)->i_object_id :
533             p_module->i_object_id;
534         config_data->psz_help = NULL;
535         AppendItem( capability_item, wxU(p_module->psz_object_name), -1, -1,
536                     config_data );
537     }
538
539     /* Sort all this mess */
540     long cookie; size_t i_child_index;
541     SortChildren( plugins_item );
542     wxTreeItemId capability_item = GetFirstChild( plugins_item, cookie);
543     for( i_child_index = 0;
544          i_child_index < GetChildrenCount( plugins_item, FALSE );
545          i_child_index++ )
546     {
547         capability_item = GetNextChild( plugins_item, cookie );
548         SortChildren( capability_item );
549     }
550
551     /* Clean-up everything */
552     vlc_list_release( p_list );
553
554     p_sizer->Add( this, 1, wxEXPAND | wxALL, 0 );
555     p_sizer->Layout();
556
557     /* Update Tree Ctrl */
558 #ifndef WIN32 /* Workaround a bug in win32 implementation */
559     SelectItem( GetFirstChild( root_item, cookie ) );
560 #endif
561
562     Expand( general_item );
563 }
564
565 PrefsTreeCtrl::~PrefsTreeCtrl()
566 {
567 }
568
569 void PrefsTreeCtrl::ApplyChanges()
570 {
571     long cookie, cookie2;
572     ConfigTreeData *config_data;
573
574     /* Apply changes to the main module */
575     wxTreeItemId item = GetFirstChild( general_item, cookie );
576     for( size_t i_child_index = 0;
577          i_child_index < GetChildrenCount( general_item, FALSE );
578          i_child_index++ )
579     {
580         config_data = (ConfigTreeData *)GetItemData( item );
581         if( config_data && config_data->panel )
582         {
583             config_data->panel->ApplyChanges();
584         }
585
586         item = GetNextChild( general_item, cookie );
587     }
588
589     /* Apply changes to the plugins */
590     item = GetFirstChild( plugins_item, cookie );
591     for( size_t i_child_index = 0;
592          i_child_index < GetChildrenCount( plugins_item, FALSE );
593          i_child_index++ )
594     {
595         wxTreeItemId item2 = GetFirstChild( item, cookie2 );
596         for( size_t i_child_index = 0;
597              i_child_index < GetChildrenCount( item, FALSE );
598              i_child_index++ )
599         {
600             config_data = (ConfigTreeData *)GetItemData( item2 );
601             if( config_data && config_data->panel )
602             {
603                 config_data->panel->ApplyChanges();
604             }
605
606             item2 = GetNextChild( item, cookie2 );
607         }
608
609         item = GetNextChild( plugins_item, cookie );
610     }
611 }
612
613 void PrefsTreeCtrl::CleanChanges()
614 {
615     long cookie, cookie2;
616     ConfigTreeData *config_data;
617
618     config_data = !GetSelection() ? NULL :
619         FindModuleConfig( (ConfigTreeData *)GetItemData( GetSelection() ) );
620     if( config_data  )
621     {
622         config_data->panel->Hide();
623         p_sizer->Remove( config_data->panel );
624     }
625
626     /* Clean changes for the main module */
627     wxTreeItemId item = GetFirstChild( general_item, cookie );
628     for( size_t i_child_index = 0;
629          i_child_index < GetChildrenCount( general_item, FALSE );
630          i_child_index++ )
631     {
632         config_data = (ConfigTreeData *)GetItemData( item );
633         if( config_data && config_data->panel )
634         {
635             delete config_data->panel;
636             config_data->panel = NULL;
637         }
638
639         item = GetNextChild( general_item, cookie );
640     }
641
642     /* Clean changes for the plugins */
643     item = GetFirstChild( plugins_item, cookie );
644     for( size_t i_child_index = 0;
645          i_child_index < GetChildrenCount( plugins_item, FALSE );
646          i_child_index++ )
647     {
648         wxTreeItemId item2 = GetFirstChild( item, cookie2 );
649         for( size_t i_child_index = 0;
650              i_child_index < GetChildrenCount( item, FALSE );
651              i_child_index++ )
652         {
653             config_data = (ConfigTreeData *)GetItemData( item2 );
654
655             if( config_data && config_data->panel )
656             {
657                 delete config_data->panel;
658                 config_data->panel = NULL;
659             }
660
661             item2 = GetNextChild( item, cookie2 );
662         }
663
664         item = GetNextChild( plugins_item, cookie );
665     }
666
667     if( GetSelection() )
668     {
669         wxTreeEvent event;
670         OnSelectTreeItem( event );
671     }
672 }
673
674 ConfigTreeData *PrefsTreeCtrl::FindModuleConfig( ConfigTreeData *config_data )
675 {
676     /* We need this complexity because submodules don't have their own config
677      * options. They use the parent module ones. */
678
679     if( !config_data || !config_data->b_submodule )
680     {
681         return config_data;
682     }
683
684     long cookie, cookie2;
685     ConfigTreeData *config_new;
686     wxTreeItemId item = GetFirstChild( plugins_item, cookie );
687     for( size_t i_child_index = 0;
688          i_child_index < GetChildrenCount( plugins_item, FALSE );
689          i_child_index++ )
690     {
691         wxTreeItemId item2 = GetFirstChild( item, cookie2 );
692         for( size_t i_child_index = 0;
693              i_child_index < GetChildrenCount( item, FALSE );
694              i_child_index++ )
695         {
696             config_new = (ConfigTreeData *)GetItemData( item2 );
697             if( config_new && !config_new->b_submodule &&
698                 config_new->i_object_id == config_data->i_object_id )
699             {
700                 return config_new;
701             }
702
703             item2 = GetNextChild( item, cookie2 );
704         }
705
706         item = GetNextChild( plugins_item, cookie );
707     }
708
709     /* Found nothing */
710     return NULL;
711 }
712
713 void PrefsTreeCtrl::OnSelectTreeItem( wxTreeEvent& event )
714 {
715     ConfigTreeData *config_data;
716
717     config_data = FindModuleConfig( (ConfigTreeData *)GetItemData(
718                                     event.GetOldItem() ) );
719     if( config_data && config_data->panel )
720     {
721         config_data->panel->Hide();
722         p_sizer->Remove( config_data->panel );
723     }
724
725     /* Don't use event.GetItem() because we also send fake events */
726     config_data = FindModuleConfig( (ConfigTreeData *)GetItemData(
727                                     GetSelection() ) );
728     if( config_data )
729     {
730         if( !config_data->panel )
731         {
732             /* The panel hasn't been created yet. Let's do it. */
733             config_data->panel =
734                 new PrefsPanel( p_parent, p_intf, p_prefs_dialog,
735                                 config_data->i_object_id,
736                                 config_data->psz_section,
737                                 config_data->psz_help );
738             config_data->panel->SwitchAdvanced( b_advanced );
739         }
740         else
741         {
742             config_data->panel->SwitchAdvanced( b_advanced );
743             config_data->panel->Show();
744         }
745
746         p_sizer->Add( config_data->panel, 3, wxEXPAND | wxALL, 0 );
747         p_sizer->Layout();
748     }
749 }
750
751 void PrefsTreeCtrl::OnAdvanced( wxCommandEvent& event )
752 {
753     b_advanced = event.GetInt();
754
755     ConfigTreeData *config_data = !GetSelection() ? NULL :
756         FindModuleConfig( (ConfigTreeData *)GetItemData( GetSelection() ) );
757     if( config_data  )
758     {
759         config_data->panel->Hide();
760         p_sizer->Remove( config_data->panel );
761     }
762
763     if( GetSelection() )
764     {
765         wxTreeEvent event;
766         OnSelectTreeItem( event );
767     }
768 }
769
770 /*****************************************************************************
771  * PrefsPanel class definition.
772  *****************************************************************************/
773 PrefsPanel::PrefsPanel( wxWindow* parent, intf_thread_t *_p_intf,
774                         PrefsDialog *_p_prefs_dialog,
775                         int i_object_id, char *psz_section, char *psz_help )
776   :  wxPanel( parent, -1, wxDefaultPosition, wxDefaultSize )
777 {
778     module_config_t *p_item;
779     vlc_list_t      *p_list;
780     module_t        *p_parser;
781
782     wxStaticText *label;
783     wxStaticText *help;
784     wxComboBox *combo;
785     wxSpinCtrl *spin;
786     wxCheckBox *checkbox;
787     wxTextCtrl *textctrl;
788     wxButton *button;
789     wxArrayString array;
790
791     vlc_bool_t b_has_advanced = VLC_FALSE;
792     module_t *p_module = NULL;
793     
794     /* Initializations */
795     p_intf = _p_intf;
796     p_prefs_dialog =_p_prefs_dialog,
797
798     b_advanced = VLC_TRUE;
799     SetAutoLayout( TRUE );
800
801     wxBoxSizer *sizer = new wxBoxSizer( wxVERTICAL );
802
803
804     if( i_object_id == PLUGIN_ID || i_object_id == GENERAL_ID ||
805         i_object_id == CAPABILITY_ID )
806     {
807         label = new wxStaticText( this, -1,wxU(_( psz_section )));
808         wxFont heading_font = label->GetFont();
809         heading_font.SetPointSize( heading_font.GetPointSize() + 5 );
810         label->SetFont( heading_font );
811         sizer->Add( label, 0, wxEXPAND | wxLEFT, 10 );
812         sizer->Add( new wxStaticLine( this, 0 ), 0,
813                     wxEXPAND | wxLEFT | wxRIGHT, 2 );
814
815         help = new wxStaticText( this, -1, wxU(_( psz_help ) ) );
816         sizer->Add( help ,0 ,wxEXPAND | wxALL, 5 );
817
818         config_sizer = NULL; config_window = NULL;
819     }
820     else
821     {
822         /* Get a pointer to the module */
823         p_module = (module_t *)vlc_object_get( p_intf,  i_object_id );
824         if( p_module->i_object_type != VLC_OBJECT_MODULE )
825         {
826             /* 0OOoo something went really bad */
827             return;
828         }
829
830         /* Enumerate config options and add corresponding config boxes
831          * (submodules don't have config options, they are stored in the
832          *  parent module) */
833         if( p_module->b_submodule )
834             p_item = ((module_t *)p_module->p_parent)->p_config;
835         else
836             p_item = p_module->p_config;
837
838         /* Find the category if it has been specified */
839         if( psz_section && p_item->i_type == CONFIG_HINT_CATEGORY )
840         {
841             while( !p_item->i_type == CONFIG_HINT_CATEGORY ||
842                    strcmp( psz_section, p_item->psz_text ) )
843             {
844                 if( p_item->i_type == CONFIG_HINT_END )
845                     break;
846                 p_item++;
847             }
848         }
849
850         /* Add a head title to the panel */
851         label = new wxStaticText( this, -1,
852                                   wxU(_(psz_section ? p_item->psz_text :
853                                   p_module->psz_longname )));
854         wxFont heading_font = label->GetFont();
855         heading_font.SetPointSize( heading_font.GetPointSize() + 5 );
856         label->SetFont( heading_font );
857         sizer->Add( label, 0, wxEXPAND | wxLEFT, 10 );
858         sizer->Add( new wxStaticLine( this, 0 ), 0,
859                     wxEXPAND | wxLEFT | wxRIGHT, 2 );
860
861         /* Now put all the config options into a scrolled window */
862         config_sizer = new wxBoxSizer( wxVERTICAL );
863         config_window = new wxScrolledWindow( this, -1, wxDefaultPosition,
864             wxDefaultSize, wxSTATIC_BORDER | wxHSCROLL | wxVSCROLL );
865         config_window->SetAutoLayout( TRUE );
866         config_window->SetScrollRate( 5, 5 );
867
868         if( p_item ) do
869         {
870             /* If a category has been specified, check we finished the job */
871             if( psz_section && p_item->i_type == CONFIG_HINT_CATEGORY &&
872                 strcmp( psz_section, p_item->psz_text ) )
873                 break;
874
875             /* put each config option in a separate panel so we can hide
876              * advanced options easily */
877             wxPanel *panel = new wxPanel( config_window, -1, wxDefaultPosition,
878                                           wxDefaultSize );
879             wxBoxSizer *panel_sizer = new wxBoxSizer( wxHORIZONTAL );
880             ConfigData *config_data =
881                 new ConfigData( panel, p_item->i_type,
882                                 p_item->b_advanced, p_item->psz_name );
883
884             switch( p_item->i_type )
885             {
886             case CONFIG_ITEM_MODULE:
887                 label = new wxStaticText(panel, -1, wxU(p_item->psz_text));
888                 combo = new wxComboBox( panel, -1, wxU(p_item->psz_value),
889                                         wxDefaultPosition, wxDefaultSize,
890                                         0, NULL, wxCB_READONLY | wxCB_SORT );
891
892                 /* build a list of available modules */
893                 p_list = vlc_list_find( p_intf,
894                                         VLC_OBJECT_MODULE, FIND_ANYWHERE );
895                 combo->Append( wxU(_("Default")), (void *)NULL );
896                 combo->SetSelection( 0 );
897                 for( int i_index = 0; i_index < p_list->i_count; i_index++ )
898                 {
899                     p_parser = (module_t *)p_list->p_values[i_index].p_object ;
900
901                     if( !strcmp( p_parser->psz_capability, p_item->psz_type ) )
902                     {
903                         combo->Append( wxU(p_parser->psz_longname),
904                                        p_parser->psz_object_name );
905                         if( p_item->psz_value && !strcmp(p_item->psz_value, 
906                             p_parser->psz_object_name) )
907                             combo->SetValue( wxU(p_parser->psz_longname) );
908                     }
909                 }
910                 vlc_list_release( p_list );
911
912                 combo->SetToolTip( wxU(p_item->psz_longtext) );
913                 config_data->control.combobox = combo;
914                 panel_sizer->Add( label, 1, wxALIGN_CENTER_VERTICAL
915                                   | wxALL, 5 );
916                 panel_sizer->Add( combo, 1, wxALIGN_CENTER_VERTICAL 
917                                   | wxALL, 5 );
918                 break;
919
920             case CONFIG_ITEM_STRING:
921             case CONFIG_ITEM_FILE:
922             case CONFIG_ITEM_DIRECTORY:
923                 label = new wxStaticText(panel, -1, wxU(p_item->psz_text));
924                 panel_sizer->Add( label, 1, wxALIGN_CENTER_VERTICAL 
925                                   | wxALL, 5 );
926
927                 if( !p_item->ppsz_list )
928                 {
929                     textctrl = new wxTextCtrl( panel, -1, 
930                                                wxU(p_item->psz_value),
931                                                wxDefaultPosition,
932                                                wxDefaultSize,
933                                                wxTE_PROCESS_ENTER);
934                     textctrl->SetToolTip( wxU(p_item->psz_longtext) );
935                     config_data->control.textctrl = textctrl;
936                     panel_sizer->Add( textctrl, 1, wxALL, 5 );
937                 }
938                 else
939                 {
940                     combo = new wxComboBox( panel, -1, wxU(p_item->psz_value),
941                                             wxDefaultPosition, wxDefaultSize,
942                                             0, NULL, wxCB_READONLY|wxCB_SORT );
943
944                     /* build a list of available options */
945                     for( int i_index = 0; p_item->ppsz_list[i_index];
946                          i_index++ )
947                     {
948                         combo->Append( wxU(p_item->ppsz_list[i_index]) );
949                         if( p_item->psz_value && !strcmp( p_item->psz_value,
950                             p_item->ppsz_list[i_index] ) )
951                             combo->SetSelection( i_index );
952                     }
953
954                     if( p_item->psz_value )
955                         combo->SetValue( wxU(p_item->psz_value) );
956                     combo->SetToolTip( wxU(p_item->psz_longtext) );
957                     config_data->control.combobox = combo;
958                     config_data->b_config_list = VLC_TRUE;
959                     panel_sizer->Add( combo, 1, wxALIGN_CENTER_VERTICAL
960                                       |wxALL, 5 );
961                 }
962
963                 if( p_item->i_type == CONFIG_ITEM_FILE )
964                 {
965                     button = new wxButton( panel, -1, wxU(_("Browse...")) );
966                     panel_sizer->Add( button, 0, wxALIGN_CENTER_VERTICAL
967                                       |wxALL, 5);
968                     button->SetClientData((void *)config_data);
969                 }
970                 if( p_item->b_advanced ) b_has_advanced = VLC_TRUE;
971                 break;
972
973             case CONFIG_ITEM_INTEGER:
974                 label = new wxStaticText(panel, -1, wxU(p_item->psz_text));
975                 spin = new wxSpinCtrl( panel, -1,
976                                        wxString::Format(wxT("%d"),
977                                                         p_item->i_value),
978                                        wxDefaultPosition, wxDefaultSize,
979                                        wxSP_ARROW_KEYS,
980                                        -16000, 16000, p_item->i_value);
981                 spin->SetToolTip( wxU(p_item->psz_longtext) );
982                 config_data->control.spinctrl = spin;
983                 panel_sizer->Add( label, 1, wxALIGN_CENTER_VERTICAL 
984                                   | wxALL, 5 );
985                 panel_sizer->Add( spin, 0, wxALIGN_CENTER_VERTICAL 
986                                   | wxALL, 5 );
987
988                 spin->SetClientData((void *)config_data);
989                 if( p_item->b_advanced ) b_has_advanced = VLC_TRUE;
990                 break;
991
992             case CONFIG_ITEM_KEY:
993             {
994                 label = new wxStaticText(panel, -1, wxU(p_item->psz_text));
995                 wxCheckBox *alt = new wxCheckBox( panel, -1, wxU(_("Alt")) );
996                 alt->SetValue( p_item->i_value & KEY_MODIFIER_ALT );
997                 wxCheckBox *ctrl = new wxCheckBox( panel, -1, wxU(_("Ctrl")) );
998                 ctrl->SetValue( p_item->i_value & KEY_MODIFIER_CTRL );
999                 wxCheckBox *shift = new wxCheckBox( panel, -1, 
1000                                                     wxU(_("Shift")) );
1001                 shift->SetValue( p_item->i_value & KEY_MODIFIER_SHIFT );
1002                 combo = new wxComboBox( panel, -1, wxU("f"), 
1003                                         wxDefaultPosition, wxDefaultSize, 0
1004                                         , NULL, wxCB_READONLY | wxCB_SORT );
1005                 for( int i=0; i < sizeof(keys)/sizeof(key_descriptor_s); i++ )
1006                 {
1007                     combo->Append( wxU(_(keys[i].psz_key_string)),
1008                                    (void*)&keys[i].i_key_code );
1009                 }
1010                 combo->SetValue( wxU( KeyToString( 
1011                                  p_item->i_value&~KEY_MODIFIER )));
1012                 config_data->control.combobox = combo;
1013                 panel_sizer->Add( label, 2, wxALIGN_CENTER_VERTICAL 
1014                                   | wxALL | wxEXPAND, 5 );
1015                 panel_sizer->Add( alt, 1, wxALIGN_CENTER_VERTICAL | wxALL | wxEXPAND, 5 );
1016                 panel_sizer->Add( ctrl, 1, wxALIGN_CENTER_VERTICAL | wxALL | wxEXPAND, 5);
1017                 panel_sizer->Add( shift, 1, wxALIGN_CENTER_VERTICAL | wxALL | wxEXPAND, 5);
1018                 panel_sizer->Add( combo, 2, wxALIGN_CENTER_VERTICAL | wxALL | wxEXPAND, 5);
1019                 break;
1020             }
1021
1022             case CONFIG_ITEM_FLOAT:
1023                 label = new wxStaticText(panel, -1, wxU(p_item->psz_text));
1024                 textctrl = new wxTextCtrl( panel, -1,
1025                                            wxString::Format(wxT("%f"),
1026                                                             p_item->f_value),
1027                                            wxDefaultPosition, wxDefaultSize,
1028                                            wxTE_PROCESS_ENTER );
1029                 textctrl->SetToolTip( wxU(p_item->psz_longtext) );
1030                 config_data->control.textctrl = textctrl;
1031                 panel_sizer->Add( label, 1, wxALIGN_CENTER_VERTICAL 
1032                                   | wxALL, 5 );
1033                 panel_sizer->Add( textctrl, 0, wxALIGN_CENTER_VERTICAL 
1034                                   | wxALL, 5);
1035                 if( p_item->b_advanced ) b_has_advanced = VLC_TRUE;
1036                 break;
1037
1038             case CONFIG_ITEM_BOOL:
1039                 checkbox = new wxCheckBox( panel, -1, wxU(p_item->psz_text) );
1040                 if( p_item->i_value ) checkbox->SetValue(TRUE);
1041                 checkbox->SetToolTip( wxU(p_item->psz_longtext) );
1042                 config_data->control.checkbox = checkbox;
1043                 panel_sizer->Add( checkbox, 0, wxALL, 5 );
1044                 if( p_item->b_advanced ) b_has_advanced = VLC_TRUE;
1045                 break;
1046
1047             default:
1048                 delete panel; panel = NULL;
1049                 delete panel_sizer;
1050                 delete config_data;
1051                 break;
1052             }
1053
1054             /* Don't add items that were not recognized */
1055             if( panel == NULL ) continue;
1056
1057             panel_sizer->Layout();
1058             panel->SetSizerAndFit( panel_sizer );
1059
1060             /* Add the config data to our array so we can keep a trace of it */
1061             config_array.Add( config_data );
1062
1063             config_sizer->Add( panel, 0, wxEXPAND | wxALL, 2 );
1064         }
1065         while( p_item->i_type != CONFIG_HINT_END && p_item++ );
1066
1067         config_sizer->Layout();
1068         config_window->SetSizer( config_sizer );
1069         sizer->Add( config_window, 1, wxEXPAND | wxALL, 5 );
1070
1071         /* And at last put a useful help string if available */
1072         if( psz_help && *psz_help )
1073         {
1074             sizer->Add( new wxStaticLine( this, 0 ), 0,
1075                         wxEXPAND | wxLEFT | wxRIGHT, 2 );
1076             help = new wxStaticText( this, -1, wxU(_(psz_help)),
1077                                      wxDefaultPosition, wxDefaultSize,
1078                                      wxALIGN_LEFT,
1079                                      wxT("") );
1080             sizer->Add( help ,0 ,wxEXPAND | wxALL, 5 );
1081         }
1082
1083
1084         /* Intercept all menu events in our custom event handler */
1085         config_window->PushEventHandler(
1086             new ConfigEvtHandler( p_intf, p_prefs_dialog ) );
1087     } 
1088     sizer->Layout();
1089     SetSizer( sizer );
1090 }
1091
1092 void PrefsPanel::ApplyChanges()
1093 {
1094     for( size_t i = 0; i < config_array.GetCount(); i++ )
1095     {
1096         ConfigData *config_data = config_array.Item(i);
1097
1098         switch( config_data->i_config_type )
1099         {
1100         case CONFIG_ITEM_MODULE:
1101             config_PutPsz( p_intf, config_data->option_name.mb_str(), (char *)
1102                            config_data->control.combobox->GetClientData(
1103                            config_data->control.combobox->GetSelection() ) );
1104             break;
1105         case CONFIG_ITEM_STRING:
1106         case CONFIG_ITEM_FILE:
1107         case CONFIG_ITEM_DIRECTORY:
1108             if( !config_data->b_config_list )
1109                 config_PutPsz( p_intf, config_data->option_name.mb_str(),
1110                                config_data->control.textctrl->GetValue().mb_str() );
1111             else
1112                 config_PutPsz( p_intf, config_data->option_name.mb_str(),
1113                                config_data->control.combobox->GetValue().mb_str() );
1114             break;
1115         case CONFIG_ITEM_BOOL:
1116             config_PutInt( p_intf, config_data->option_name.mb_str(),
1117                            config_data->control.checkbox->IsChecked() );
1118             break;
1119         case CONFIG_ITEM_INTEGER:
1120             config_PutInt( p_intf, config_data->option_name.mb_str(),
1121                            config_data->control.spinctrl->GetValue() );
1122             break;
1123         case CONFIG_ITEM_FLOAT:
1124             {
1125                 float f_value;
1126                 if( (wxSscanf(config_data->control.textctrl->GetValue(),
1127                               wxT("%f"), &f_value) == 1) )
1128                     config_PutFloat( p_intf, config_data->option_name.mb_str(),
1129                                      f_value );
1130             }
1131             break;
1132         }
1133     }
1134 }
1135
1136 void PrefsPanel::SwitchAdvanced( vlc_bool_t b_new_advanced )
1137 {
1138     if( b_advanced == b_new_advanced ) return;
1139
1140     if( config_sizer && config_window )
1141     {
1142         b_advanced = b_new_advanced;
1143
1144         for( size_t i = 0; i < config_array.GetCount(); i++ )
1145         {
1146             ConfigData *config_data = config_array.Item(i);
1147             if( config_data->b_advanced )
1148             {
1149                 config_data->panel->Show( b_advanced );
1150                 config_sizer->Show( config_data->panel, b_advanced );
1151             }
1152         }
1153
1154         config_sizer->Layout();
1155         config_window->FitInside();
1156         config_window->Refresh();
1157     }
1158     return;     
1159 }
1160
1161 /*****************************************************************************
1162  * A small helper class which intercepts all events
1163  *****************************************************************************/
1164 ConfigEvtHandler::ConfigEvtHandler( intf_thread_t *_p_intf,
1165                                     PrefsDialog *_p_prefs_dialog )
1166 {
1167     /* Initializations */
1168     p_intf = _p_intf;
1169     p_prefs_dialog = _p_prefs_dialog;
1170 }
1171
1172 ConfigEvtHandler::~ConfigEvtHandler()
1173 {
1174 }
1175
1176 void ConfigEvtHandler::OnCommandEvent( wxCommandEvent& event )
1177 {
1178     if( !event.GetEventObject() )
1179     {
1180         event.Skip();
1181         return;
1182     }
1183
1184     ConfigData *config_data = (ConfigData *)
1185         ((wxEvtHandler *)event.GetEventObject())->GetClientData();
1186
1187     if( !config_data )
1188     {
1189         event.Skip();
1190         return;
1191     }
1192
1193     if( config_data->i_config_type == CONFIG_ITEM_FILE )
1194     {
1195         wxFileDialog dialog( p_prefs_dialog, wxU(_("Open file")),
1196                              wxT(""), wxT(""), wxT("*.*"),
1197 #if defined( __WXMSW__ )
1198                              wxOPEN );
1199 #else
1200                              wxOPEN | wxSAVE );
1201 #endif
1202
1203         if( dialog.ShowModal() == wxID_OK )
1204         {
1205             config_data->control.textctrl->SetValue( dialog.GetPath() );      
1206         }
1207     }
1208
1209     switch( config_data->i_config_type )
1210     {
1211     case CONFIG_ITEM_MODULE:
1212         break;
1213     case CONFIG_ITEM_STRING:
1214         break;
1215     case CONFIG_ITEM_FILE:
1216         break;
1217     case CONFIG_ITEM_INTEGER:
1218         break;
1219     case CONFIG_ITEM_FLOAT:
1220         break;
1221     case CONFIG_ITEM_BOOL:
1222         break;
1223     }
1224
1225     event.Skip();
1226 }