]> git.sesse.net Git - vlc/blob - modules/gui/wxwindows/preferences.cpp
* modules/gui/wxwindows/preferences.cpp:
[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.28 2003/09/22 14:40:10 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 <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 *_p_prefs_dialog, 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 }
316
317 void PrefsDialog::OnResetAll( wxCommandEvent& WXUNUSED(event) )
318 {
319     wxMessageDialog dlg( this,
320         wxU(_("Beware this will reset your VLC Media Player config file.\n"
321               "Are you sure you want to continue?")),
322         wxU(_("Reset config file")), wxYES_NO|wxNO_DEFAULT|wxCENTRE );
323
324     if ( dlg.ShowModal() == wxID_YES )
325     {
326         /* TODO: need to reset all the controls */
327         config_ResetAll( p_intf );
328         prefs_tree->CleanChanges();
329         config_SaveConfigFile( p_intf, NULL );
330     }
331 }
332
333 void PrefsDialog::OnAdvanced( wxCommandEvent& event )
334 {
335     wxCommandEvent newevent( wxEVT_USER_FIRST, Advanced_Event );
336     newevent.SetInt( event.GetInt() );
337
338     prefs_tree->AddPendingEvent( newevent );
339 }
340
341 /*****************************************************************************
342  * GetCapabilityHelp: Display the help for one capability.
343  *****************************************************************************/
344 static char * GetCapabilityHelp( char *psz_capability)
345 {
346     if( psz_capability == NULL)
347         return NULL;
348
349     if( !strcasecmp(psz_capability,"access") )
350         return strdup(ACCESS_HELP);
351     if( !strcasecmp(psz_capability,"audio filter") )
352         return strdup(AUDIO_FILTER_HELP);
353     if( !strcasecmp(psz_capability,"audio output") )
354         return strdup(AOUT_HELP);
355     if( !strcasecmp(psz_capability,"chroma") )
356         return strdup(CHROMA_HELP);
357     if( !strcasecmp(psz_capability,"decoder") )
358         return strdup(DECODER_HELP);
359     if( !strcasecmp(psz_capability,"demux") )
360         return strdup(DEMUX_HELP);
361     if( !strcasecmp(psz_capability,"interface") )
362         return strdup(INTERFACE_HELP);
363     if( !strcasecmp(psz_capability,"sout access") )
364         return strdup(SOUT_HELP);
365     if( !strcasecmp(psz_capability,"subtitle demux") )
366         return strdup(SUBTITLE_DEMUX_HELP);
367     if( !strcasecmp(psz_capability,"text renderer") )
368         return strdup(TEXT_HELP);
369     if( !strcasecmp(psz_capability,"video output") )
370         return strdup(VOUT_HELP);
371     if( !strcasecmp(psz_capability,"video filter") )
372         return strdup(VIDEO_FILTER_HELP);
373
374     return strdup(UNKNOWN_HELP);
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 = strdup( GENERAL_HELP );
413 printf("dans pouet: %i\n",config_data->i_object_id);
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 = strdup( p_item->psz_longtext);
441                 }
442                 else
443                 {
444                     config_data->psz_help = NULL;
445                 }
446                 config_data->i_object_id = p_module->i_object_id;
447
448                 /* Add the category to the tree */
449                 AppendItem( general_item, wxU(p_item->psz_text),
450                             -1, -1, config_data );
451                 break;
452             }
453         }
454         while( p_item->i_type != CONFIG_HINT_END && p_item++ );
455
456         SortChildren( general_item );
457     }
458
459
460     /*
461      * Build a tree of all the plugins
462      */
463     config_data = new ConfigTreeData;
464     config_data->psz_section = NULL;
465     config_data->i_object_id = PLUGIN_ID;
466     config_data->psz_help = strdup( PLUGIN_HELP );
467     plugins_item = AppendItem( root_item, wxU(_("Plugins")),
468                         -1,-1,config_data );
469
470     for( i_index = 0; i_index < p_list->i_count; i_index++ )
471     {
472         p_module = (module_t *)p_list->p_values[i_index].p_object;
473
474         /* Exclude the main module */
475         if( !strcmp( p_module->psz_object_name, "main" ) )
476             continue;
477
478         /* Exclude empty plugins (submodules don't have config options, they
479          * are stored in the parent module) */
480         if( p_module->b_submodule )
481             p_item = ((module_t *)p_module->p_parent)->p_config;
482         else
483             p_item = p_module->p_config;
484
485         if( !p_item ) continue;
486         do
487         {
488             if( p_item->i_type & CONFIG_ITEM )
489                 break;
490         }
491         while( p_item->i_type != CONFIG_HINT_END && p_item++ );
492         if( p_item->i_type == CONFIG_HINT_END ) continue;
493
494         /* Find the capability child item */
495         long cookie; size_t i_child_index;
496         wxTreeItemId capability_item = GetFirstChild( plugins_item, cookie);
497         for( i_child_index = 0;
498              i_child_index < GetChildrenCount( plugins_item, FALSE );
499              i_child_index++ )
500         {
501             if( !GetItemText(capability_item).Cmp(
502                     wxU(p_module->psz_capability ) ) )
503             {
504                 break;
505             }
506             capability_item = GetNextChild( plugins_item, cookie );
507         }
508
509         if( i_child_index == GetChildrenCount( plugins_item, FALSE ) &&
510             p_module->psz_capability && *p_module->psz_capability )
511         {
512             /* We didn't find it, add it */
513             ConfigTreeData *config_data = new ConfigTreeData;
514             config_data->psz_section = NULL;
515             config_data->psz_help = 
516                 GetCapabilityHelp( p_module->psz_capability );
517             config_data->i_object_id = CAPABILITY_ID;
518             capability_item = AppendItem( plugins_item,
519                                           wxU(p_module->psz_capability),
520                                           -1,-1,config_data );
521         }
522
523         /* Add the plugin to the tree */
524         ConfigTreeData *config_data = new ConfigTreeData;
525         config_data->b_submodule = p_module->b_submodule;
526         config_data->i_object_id = p_module->b_submodule ?
527             ((module_t *)p_module->p_parent)->i_object_id :
528             p_module->i_object_id;
529         config_data->psz_help = strdup( "" );
530         AppendItem( capability_item, wxU(p_module->psz_object_name), -1, -1,
531                     config_data );
532     }
533
534     /* Sort all this mess */
535     long cookie; size_t i_child_index;
536     SortChildren( plugins_item );
537     wxTreeItemId capability_item = GetFirstChild( plugins_item, cookie);
538     for( i_child_index = 0;
539          i_child_index < GetChildrenCount( plugins_item, FALSE );
540          i_child_index++ )
541     {
542         capability_item = GetNextChild( plugins_item, cookie );
543         SortChildren( capability_item );
544     }
545
546     /* Clean-up everything */
547     vlc_list_release( p_list );
548
549     p_sizer->Add( this, 1, wxEXPAND | wxALL, 0 );
550     p_sizer->Layout();
551
552     /* Update Tree Ctrl */
553 #ifndef WIN32 /* Workaround a bug in win32 implementation */
554     SelectItem( GetFirstChild( root_item, cookie ) );
555 #endif
556 }
557
558 PrefsTreeCtrl::~PrefsTreeCtrl()
559 {
560 }
561
562 void PrefsTreeCtrl::ApplyChanges()
563 {
564     long cookie, cookie2;
565     ConfigTreeData *config_data;
566
567     /* Apply changes to the main module */
568     wxTreeItemId item = GetFirstChild( root_item, cookie );
569     for( size_t i_child_index = 0;
570          i_child_index < GetChildrenCount( root_item, FALSE );
571          i_child_index++ )
572     {
573         config_data = (ConfigTreeData *)GetItemData( item );
574         if( config_data && config_data->panel )
575         {
576             config_data->panel->ApplyChanges();
577         }
578
579         item = GetNextChild( root_item, cookie );
580     }
581
582     /* Apply changes to the plugins */
583     item = GetFirstChild( plugins_item, cookie );
584     for( size_t i_child_index = 0;
585          i_child_index < GetChildrenCount( plugins_item, FALSE );
586          i_child_index++ )
587     {
588         wxTreeItemId item2 = GetFirstChild( item, cookie2 );
589         for( size_t i_child_index = 0;
590              i_child_index < GetChildrenCount( item, FALSE );
591              i_child_index++ )
592         {
593             config_data = (ConfigTreeData *)GetItemData( item2 );
594             if( config_data && config_data->panel )
595             {
596                 config_data->panel->ApplyChanges();
597             }
598
599             item2 = GetNextChild( item, cookie2 );
600         }
601
602         item = GetNextChild( plugins_item, cookie );
603     }
604 }
605
606 void PrefsTreeCtrl::CleanChanges()
607 {
608     long cookie, cookie2;
609     ConfigTreeData *config_data;
610
611     config_data = !GetSelection() ? NULL :
612         FindModuleConfig( (ConfigTreeData *)GetItemData( GetSelection() ) );
613     if( config_data  )
614     {
615         config_data->panel->Hide();
616         p_sizer->Remove( config_data->panel );
617     }
618
619     /* Clean changes for the main module */
620     wxTreeItemId item = GetFirstChild( root_item, cookie );
621     for( size_t i_child_index = 0;
622          i_child_index < GetChildrenCount( root_item, FALSE );
623          i_child_index++ )
624     {
625         config_data = (ConfigTreeData *)GetItemData( item );
626         if( config_data && config_data->panel )
627         {
628             delete config_data->panel;
629             config_data->panel = NULL;
630         }
631
632         item = GetNextChild( root_item, cookie );
633     }
634
635     /* Clean changes for the plugins */
636     item = GetFirstChild( plugins_item, cookie );
637     for( size_t i_child_index = 0;
638          i_child_index < GetChildrenCount( plugins_item, FALSE );
639          i_child_index++ )
640     {
641         wxTreeItemId item2 = GetFirstChild( item, cookie2 );
642         for( size_t i_child_index = 0;
643              i_child_index < GetChildrenCount( item, FALSE );
644              i_child_index++ )
645         {
646             config_data = (ConfigTreeData *)GetItemData( item2 );
647
648             if( config_data && config_data->panel )
649             {
650                 delete config_data->panel;
651                 config_data->panel = NULL;
652             }
653
654             item2 = GetNextChild( item, cookie2 );
655         }
656
657         item = GetNextChild( plugins_item, cookie );
658     }
659
660     if( GetSelection() )
661     {
662         wxTreeEvent event;
663         OnSelectTreeItem( event );
664     }
665 }
666
667 ConfigTreeData *PrefsTreeCtrl::FindModuleConfig( ConfigTreeData *config_data )
668 {
669     /* We need this complexity because submodules don't have their own config
670      * options. They use the parent module ones. */
671
672     if( !config_data || !config_data->b_submodule )
673     {
674         return config_data;
675     }
676
677     long cookie, cookie2;
678     ConfigTreeData *config_new;
679     wxTreeItemId item = GetFirstChild( plugins_item, cookie );
680     for( size_t i_child_index = 0;
681          i_child_index < GetChildrenCount( plugins_item, FALSE );
682          i_child_index++ )
683     {
684         wxTreeItemId item2 = GetFirstChild( item, cookie2 );
685         for( size_t i_child_index = 0;
686              i_child_index < GetChildrenCount( item, FALSE );
687              i_child_index++ )
688         {
689             config_new = (ConfigTreeData *)GetItemData( item2 );
690             if( config_new && !config_new->b_submodule &&
691                 config_new->i_object_id == config_data->i_object_id )
692             {
693                 return config_new;
694             }
695
696             item2 = GetNextChild( item, cookie2 );
697         }
698
699         item = GetNextChild( plugins_item, cookie );
700     }
701
702     /* Found nothing */
703     return NULL;
704 }
705
706 void PrefsTreeCtrl::OnSelectTreeItem( wxTreeEvent& event )
707 {
708     ConfigTreeData *config_data;
709
710     config_data = FindModuleConfig( (ConfigTreeData *)GetItemData(
711                                     event.GetOldItem() ) );
712     if( config_data && config_data->panel )
713     {
714         config_data->panel->Hide();
715         p_sizer->Remove( config_data->panel );
716     }
717
718     /* Don't use event.GetItem() because we also send fake events */
719     config_data = FindModuleConfig( (ConfigTreeData *)GetItemData(
720                                     GetSelection() ) );
721     if( config_data )
722     {
723         if( !config_data->panel )
724         {
725             /* The panel hasn't been created yet. Let's do it. */
726             config_data->panel =
727                 new PrefsPanel( p_parent, p_intf, p_prefs_dialog,
728                                 config_data->i_object_id,
729                                 config_data->psz_section,
730                                 config_data->psz_help);
731             config_data->panel->SwitchAdvanced( b_advanced );
732         }
733         else
734         {
735             config_data->panel->SwitchAdvanced( b_advanced );
736             config_data->panel->Show();
737         }
738
739         p_sizer->Add( config_data->panel, 2, wxEXPAND | wxALL, 0 );
740         p_sizer->Layout();
741     }
742 }
743
744 void PrefsTreeCtrl::OnAdvanced( wxCommandEvent& event )
745 {
746     b_advanced = event.GetInt();
747
748     ConfigTreeData *config_data = !GetSelection() ? NULL :
749         FindModuleConfig( (ConfigTreeData *)GetItemData( GetSelection() ) );
750     if( config_data  )
751     {
752         config_data->panel->Hide();
753         p_sizer->Remove( config_data->panel );
754     }
755
756     if( GetSelection() )
757     {
758         wxTreeEvent event;
759         OnSelectTreeItem( event );
760     }
761 }
762
763 /*****************************************************************************
764  * PrefsPanel class definition.
765  *****************************************************************************/
766 PrefsPanel::PrefsPanel( wxWindow* parent, intf_thread_t *_p_intf,
767                         PrefsDialog *_p_prefs_dialog,
768                         int i_object_id, char *psz_section, char*psz_help )
769   :  wxPanel( parent, -1, wxDefaultPosition, wxDefaultSize )
770 {
771     module_config_t *p_item;
772     vlc_list_t      *p_list;
773     module_t        *p_parser;
774
775     wxStaticText *label;
776     wxStaticText *help;
777     wxComboBox *combo;
778     wxSpinCtrl *spin;
779     wxCheckBox *checkbox;
780     wxTextCtrl *textctrl;
781     wxButton *button;
782     wxArrayString array;
783
784     vlc_bool_t b_has_advanced = VLC_FALSE;
785     module_t *p_module = NULL;
786     
787     /* Initializations */
788     p_intf = _p_intf;
789     p_prefs_dialog =_p_prefs_dialog,
790
791     b_advanced = VLC_TRUE;
792     SetAutoLayout( TRUE );
793
794     wxBoxSizer *sizer = new wxBoxSizer( wxVERTICAL );
795
796
797     if( i_object_id == PLUGIN_ID || i_object_id == GENERAL_ID ||
798         i_object_id == CAPABILITY_ID ) 
799     {
800         wxStaticBox *static_box = new wxStaticBox( this, -1, wxT( "" ) );
801         wxStaticBoxSizer *box_sizer = new wxStaticBoxSizer( static_box,
802                                                             wxVERTICAL );
803         label = new wxStaticText( this, -1,
804                         wxU(_( psz_help) ) );
805
806         box_sizer->Add( label, 1,  wxEXPAND | wxLEFT | wxRIGHT, 5 );
807
808         sizer->Add( box_sizer, 0, wxEXPAND | wxALL , 5 );
809     }   
810     else
811     {
812         /* Get a pointer to the module */
813         p_module = (module_t *)vlc_object_get( p_intf,  i_object_id );
814         if( p_module->i_object_type != VLC_OBJECT_MODULE )
815         {
816             /* 0OOoo something went really bad */
817             return;
818         }
819
820         /* Enumerate config options and add corresponding config boxes
821          * (submodules don't have config options, they are stored in the
822          *  parent module) */
823          if( p_module->b_submodule )
824             p_item = ((module_t *)p_module->p_parent)->p_config;
825          else
826             p_item = p_module->p_config;
827     
828          /* Find the category if it has been specified */
829          if( psz_section && p_item->i_type == CONFIG_HINT_CATEGORY )
830          {
831              while( !p_item->i_type == CONFIG_HINT_CATEGORY ||
832                    strcmp( psz_section, p_item->psz_text ) )
833              {
834                 if( p_item->i_type == CONFIG_HINT_END )
835                      break;
836                 p_item++;
837              }
838          }
839          /* Add a head title to the panel */
840          wxStaticBox *static_box = new wxStaticBox( this, -1, wxT( "" ) );
841          wxStaticBoxSizer *box_sizer = new wxStaticBoxSizer( static_box,
842                                                             wxVERTICAL );
843
844          wxStaticBox *help_box = NULL;
845          wxStaticBoxSizer *help_sizer = NULL; 
846
847          label = new wxStaticText( this, -1,
848                                    wxU(_(psz_section ? p_item->psz_text :
849                                    p_module->psz_longname )));
850         
851          box_sizer->Add( label, 1,  wxEXPAND | wxLEFT | wxRIGHT, 5 );
852
853          sizer->Add( box_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT , 5 );
854
855          if( psz_help && psz_help[1] ) 
856          /* Check that we have at least something */
857          {
858              help_box   = new wxStaticBox( this, -1, wxT( "" ) );
859              help_sizer = new wxStaticBoxSizer( help_box,
860                                                 wxHORIZONTAL ) ;
861              help = new wxStaticText( this, -1,
862                                         wxT(_( psz_help) ),
863                                 wxDefaultPosition, wxDefaultSize,
864                                 wxST_NO_AUTORESIZE | wxALIGN_LEFT,
865                                 wxT("") );
866             
867              help_sizer->Add( help, 1,  wxALL | wxEXPAND , 5 );
868              sizer->Add( help_sizer ,0 ,wxEXPAND | wxALL, 5 );
869          } 
870
871          /* Now put all the config options into a scrolled window */
872          config_sizer = new wxBoxSizer( wxVERTICAL );
873          config_window = new wxScrolledWindow( this, -1, wxDefaultPosition,
874             wxDefaultSize, wxSTATIC_BORDER | wxHSCROLL | wxVSCROLL );
875          config_window->SetAutoLayout( TRUE );
876          config_window->SetScrollRate( 5, 5 );
877
878          if( p_item ) do
879          {
880             /* If a category has been specified, check we finished the job */
881              if( psz_section && p_item->i_type == CONFIG_HINT_CATEGORY &&
882                  strcmp( psz_section, p_item->psz_text ) )
883                  break;
884    
885             /* put each config option in a separate panel so we can hide advanced
886              * options easily */
887              wxPanel *panel = new wxPanel( config_window, -1, wxDefaultPosition,
888                                            wxDefaultSize );
889              wxBoxSizer *panel_sizer = new wxBoxSizer( wxHORIZONTAL );
890              ConfigData *config_data =
891                  new ConfigData( panel, p_item->i_type,
892                                  p_item->b_advanced, p_item->psz_name );
893
894              switch( p_item->i_type )
895              {
896                  case CONFIG_ITEM_MODULE:
897                      label = new wxStaticText(panel, -1, wxU(p_item->psz_text));
898                      combo = new wxComboBox( panel, -1, wxU(p_item->psz_value),
899                                              wxDefaultPosition, wxDefaultSize,
900                                              0, NULL, wxCB_READONLY | wxCB_SORT );
901
902                     /* build a list of available modules */
903                     p_list = vlc_list_find( p_intf, 
904                                 VLC_OBJECT_MODULE, FIND_ANYWHERE );
905                     combo->Append( wxU(_("Default")), (void *)NULL );
906                     combo->SetSelection( 0 );
907                     for( int i_index = 0; i_index < p_list->i_count; i_index++ )
908                     {
909                         p_parser = (module_t *)p_list->p_values[i_index].p_object ;
910
911                         if( !strcmp( p_parser->psz_capability,
912                                  p_item->psz_type ) )
913                         {
914                             combo->Append( wxU(p_parser->psz_longname),
915                                        p_parser->psz_object_name );
916                             if( p_item->psz_value &&
917                                !strcmp(p_item->psz_value, 
918                                         p_parser->psz_object_name) )
919                                  combo->SetValue( wxU(p_parser->psz_longname) );
920                         }
921                     }
922                     vlc_list_release( p_list );
923
924                     combo->SetToolTip( wxU(p_item->psz_longtext) );
925                     config_data->control.combobox = combo;
926                     panel_sizer->Add( label, 0, wxALIGN_CENTER_VERTICAL
927                                                 | wxALL, 5 );
928                     panel_sizer->Add( combo, 1, wxALIGN_CENTER_VERTICAL 
929                                                 | wxALL, 5 );
930                     break;
931
932                 case CONFIG_ITEM_STRING:
933                 case CONFIG_ITEM_FILE:
934                 case CONFIG_ITEM_DIRECTORY:
935                     label = new wxStaticText(panel, -1, wxU(p_item->psz_text));
936                     panel_sizer->Add( label, 0, wxALIGN_CENTER_VERTICAL 
937                                                         | wxALL, 5 );
938  
939                     if( !p_item->ppsz_list )
940                     {
941                         textctrl = new wxTextCtrl( panel, -1, 
942                                 wxU(p_item->psz_value),
943                                 wxDefaultPosition, wxDefaultSize,
944                                 wxTE_PROCESS_ENTER);
945                         textctrl->SetToolTip( wxU(p_item->psz_longtext) );
946                         config_data->control.textctrl = textctrl;
947                         panel_sizer->Add( textctrl, 1, wxALL, 5 );
948                     }
949                     else
950                     {
951                         combo = new wxComboBox( panel, -1, wxU(p_item->psz_value),
952                                         wxDefaultPosition, wxDefaultSize,
953                                         0, NULL, wxCB_READONLY | wxCB_SORT );
954
955                         /* build a list of available options */
956                         for( int i_index = 0; p_item->ppsz_list[i_index];
957                                                  i_index++ )
958                         {
959                             combo->Append( wxU(p_item->ppsz_list[i_index]) );
960                             if( p_item->psz_value && !strcmp( p_item->psz_value,
961                                       p_item->ppsz_list[i_index] ) )
962                                 combo->SetSelection( i_index );
963                         }  
964     
965                         if( p_item->psz_value )
966                             combo->SetValue( wxU(p_item->psz_value) );
967                         combo->SetToolTip( wxU(p_item->psz_longtext) );
968                         config_data->control.combobox = combo;
969                         config_data->b_config_list = VLC_TRUE;
970                         panel_sizer->Add( combo, 1, wxALIGN_CENTER_VERTICAL
971                                                         |wxALL, 5 );
972                     }
973   
974                     if( p_item->i_type == CONFIG_ITEM_FILE )
975                     {
976                          button = new wxButton( panel, -1, wxU(_("Browse...")) );
977                          panel_sizer->Add( button, 0, wxALIGN_CENTER_VERTICAL
978                                                         |wxALL, 5);
979                         button->SetClientData((void *)config_data);
980                     }
981                     if( p_item->b_advanced ) b_has_advanced = VLC_TRUE;
982                     break;
983
984                 case CONFIG_ITEM_INTEGER:
985                     label = new wxStaticText(panel, -1, wxU(p_item->psz_text));
986                     spin = new wxSpinCtrl( panel, -1,
987                                        wxString::Format(wxT("%d"),p_item->i_value),
988                                        wxDefaultPosition, wxDefaultSize,
989                                        wxSP_ARROW_KEYS,
990                                        -16000, 16000, p_item->i_value);
991                     spin->SetToolTip( wxU(p_item->psz_longtext) );
992                     config_data->control.spinctrl = spin;
993                     panel_sizer->Add( label, 0, wxALIGN_CENTER_VERTICAL 
994                                                 | wxALL, 5 );
995                     panel_sizer->Add( spin, 0, wxALIGN_CENTER_VERTICAL 
996                                                 | wxALL, 5 );
997
998                     spin->SetClientData((void *)config_data);
999                     if( p_item->b_advanced ) b_has_advanced = VLC_TRUE;
1000                     break;
1001
1002                 case CONFIG_ITEM_KEY:
1003                 {
1004                     label = new wxStaticText(panel, -1, wxU(p_item->psz_text));
1005                     wxCheckBox *alt = new wxCheckBox( panel, -1, wxU(_("Alt")) );
1006                     alt->SetValue( p_item->i_value & KEY_MODIFIER_ALT );
1007                     wxCheckBox *ctrl = new wxCheckBox( panel, -1, wxU(_("Ctrl")) );
1008                     ctrl->SetValue( p_item->i_value & KEY_MODIFIER_CTRL );
1009                     wxCheckBox *shift = new wxCheckBox( panel, -1, 
1010                                         wxU(_("Shift")) );
1011                     shift->SetValue( p_item->i_value & KEY_MODIFIER_SHIFT );
1012                     combo = new wxComboBox( panel, -1, wxU("f"), 
1013                                 wxDefaultPosition, wxDefaultSize, 0
1014                                 , NULL, wxCB_READONLY | wxCB_SORT );
1015                     for( int i = 0; i < sizeof(keys)/sizeof(key_descriptor_s); 
1016                                         i++ )
1017                     {
1018                         combo->Append( wxU(_(keys[i].psz_key_string)),
1019                                      (void*)&keys[i].i_key_code );
1020                     }
1021                     combo->SetValue( wxU( KeyToString( 
1022                                 p_item->i_value&~KEY_MODIFIER )));
1023                     config_data->control.combobox = combo;
1024                     panel_sizer->Add( label, 0, wxALIGN_CENTER_VERTICAL 
1025                                                 | wxALL, 5 );
1026                     panel_sizer->Add( alt, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
1027                     panel_sizer->Add( ctrl, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5 );
1028                     panel_sizer->Add( shift, 0, wxALIGN_CENTER_VERTICAL |
1029                                                                  wxALL, 5 );
1030                     panel_sizer->Add( combo, 0, wxALIGN_CENTER_VERTICAL 
1031                                                                 | wxALL, 5 );
1032                     break;
1033                 }
1034             
1035                 case CONFIG_ITEM_FLOAT:
1036                     label = new wxStaticText(panel, -1, wxU(p_item->psz_text));
1037                     textctrl = new wxTextCtrl( panel, -1,
1038                                  wxString::Format(wxT("%f"),p_item->f_value),
1039                                  wxDefaultPosition, wxDefaultSize,
1040                                  wxTE_PROCESS_ENTER );
1041                     textctrl->SetToolTip( wxU(p_item->psz_longtext) );
1042                     config_data->control.textctrl = textctrl;
1043                     panel_sizer->Add( label, 0, wxALIGN_CENTER_VERTICAL 
1044                                                 | wxALL, 5 );
1045                     panel_sizer->Add( textctrl, 0, wxALIGN_CENTER_VERTICAL 
1046                                                 | wxALL, 5);
1047                     if( p_item->b_advanced ) b_has_advanced = VLC_TRUE;
1048                     break;
1049
1050                  case CONFIG_ITEM_BOOL:
1051                      checkbox = new wxCheckBox( panel, -1, wxU(p_item->psz_text) );
1052                      if( p_item->i_value ) checkbox->SetValue(TRUE);
1053                      checkbox->SetToolTip( wxU(p_item->psz_longtext) );
1054                      config_data->control.checkbox = checkbox;
1055                      panel_sizer->Add( checkbox, 0, wxALL, 5 );
1056                      if( p_item->b_advanced ) b_has_advanced = VLC_TRUE;
1057                      break;
1058
1059
1060                  default:
1061                     delete panel; panel = NULL;
1062                     delete panel_sizer;
1063                     delete config_data;
1064                     break;
1065             }
1066
1067             /* Don't add items that were not recognized */  
1068             if( panel == NULL ) continue;
1069   
1070             panel_sizer->Layout();
1071             panel->SetSizerAndFit( panel_sizer );
1072
1073             /* Add the config data to our array so we can keep a trace of it */
1074             config_array.Add( config_data );
1075  
1076             config_sizer->Add( panel, 0, wxEXPAND | wxALL, 2 );
1077         }
1078         while( p_item->i_type != CONFIG_HINT_END && p_item++ );
1079         config_sizer->Layout();
1080         config_window->SetSizer( config_sizer );
1081         sizer->Add( config_window, 1, wxEXPAND | wxALL, 5 );
1082
1083         /* Intercept all menu events in our custom event handler */
1084         config_window->PushEventHandler(
1085             new ConfigEvtHandler( p_intf, p_prefs_dialog ) );
1086     } 
1087     sizer->Layout();
1088     SetSizer( sizer );
1089 }
1090
1091 void PrefsPanel::ApplyChanges()
1092 {
1093     for( size_t i = 0; i < config_array.GetCount(); i++ )
1094     {
1095         ConfigData *config_data = config_array.Item(i);
1096
1097         switch( config_data->i_config_type )
1098         {
1099         case CONFIG_ITEM_MODULE:
1100             config_PutPsz( p_intf, config_data->option_name.mb_str(), (char *)
1101                            config_data->control.combobox->GetClientData(
1102                            config_data->control.combobox->GetSelection() ) );
1103             break;
1104         case CONFIG_ITEM_STRING:
1105         case CONFIG_ITEM_FILE:
1106         case CONFIG_ITEM_DIRECTORY:
1107             if( !config_data->b_config_list )
1108                 config_PutPsz( p_intf, config_data->option_name.mb_str(),
1109                                config_data->control.textctrl->GetValue().mb_str() );
1110             else
1111                 config_PutPsz( p_intf, config_data->option_name.mb_str(),
1112                                config_data->control.combobox->GetValue().mb_str() );
1113             break;
1114         case CONFIG_ITEM_BOOL:
1115             config_PutInt( p_intf, config_data->option_name.mb_str(),
1116                            config_data->control.checkbox->IsChecked() );
1117             break;
1118         case CONFIG_ITEM_INTEGER:
1119             config_PutInt( p_intf, config_data->option_name.mb_str(),
1120                            config_data->control.spinctrl->GetValue() );
1121             break;
1122         case CONFIG_ITEM_FLOAT:
1123             {
1124                 float f_value;
1125                 if( (wxSscanf(config_data->control.textctrl->GetValue(),
1126                               wxT("%f"), &f_value) == 1) )
1127                     config_PutFloat( p_intf, config_data->option_name.mb_str(),
1128                                      f_value );
1129             }
1130             break;
1131         }
1132     }
1133 }
1134
1135 void PrefsPanel::SwitchAdvanced( vlc_bool_t b_new_advanced )
1136 {
1137     if( b_advanced == b_new_advanced ) return;
1138
1139     if( config_sizer && config_window )
1140     {
1141         b_advanced = b_new_advanced;
1142
1143         for( size_t i = 0; i < config_array.GetCount(); i++ )
1144         {
1145             ConfigData *config_data = config_array.Item(i);
1146             if( config_data->b_advanced )
1147             {
1148                 config_data->panel->Show( b_advanced );
1149                 config_sizer->Show( config_data->panel, b_advanced );
1150             }
1151         }
1152
1153         config_sizer->Layout();
1154         config_window->FitInside();
1155         config_window->Refresh();
1156     }
1157     return;     
1158 }
1159
1160 /*****************************************************************************
1161  * A small helper class which intercepts all events
1162  *****************************************************************************/
1163 ConfigEvtHandler::ConfigEvtHandler( intf_thread_t *_p_intf,
1164                                     PrefsDialog *_p_prefs_dialog )
1165 {
1166     /* Initializations */
1167     p_intf = _p_intf;
1168     p_prefs_dialog = _p_prefs_dialog;
1169 }
1170
1171 ConfigEvtHandler::~ConfigEvtHandler()
1172 {
1173 }
1174
1175 void ConfigEvtHandler::OnCommandEvent( wxCommandEvent& event )
1176 {
1177     if( !event.GetEventObject() )
1178     {
1179         event.Skip();
1180         return;
1181     }
1182
1183     ConfigData *config_data = (ConfigData *)
1184         ((wxEvtHandler *)event.GetEventObject())->GetClientData();
1185
1186     if( !config_data )
1187     {
1188         event.Skip();
1189         return;
1190     }
1191
1192     if( config_data->i_config_type == CONFIG_ITEM_FILE )
1193     {
1194         wxFileDialog dialog( p_prefs_dialog, wxU(_("Open file")),
1195                              wxT(""), wxT(""), wxT("*.*"),
1196 #if defined( __WXMSW__ )
1197                              wxOPEN );
1198 #else
1199                              wxOPEN | wxSAVE );
1200 #endif
1201
1202         if( dialog.ShowModal() == wxID_OK )
1203         {
1204             config_data->control.textctrl->SetValue( dialog.GetPath() );      
1205         }
1206     }
1207
1208     switch( config_data->i_config_type )
1209     {
1210     case CONFIG_ITEM_MODULE:
1211         break;
1212     case CONFIG_ITEM_STRING:
1213         break;
1214     case CONFIG_ITEM_FILE:
1215         break;
1216     case CONFIG_ITEM_INTEGER:
1217         break;
1218     case CONFIG_ITEM_FLOAT:
1219         break;
1220     case CONFIG_ITEM_BOOL:
1221         break;
1222     }
1223
1224     event.Skip();
1225 }