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