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