1 /*****************************************************************************
2 * preferences.cpp : wxWindows plugin for vlc
3 *****************************************************************************
4 * Copyright (C) 2000-2001 VideoLAN
5 * $Id: preferences.cpp,v 1.3 2003/03/30 02:58:36 gbazin Exp $
7 * Authors: Gildas Bazin <gbazin@netcourrier.com>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
27 #include <stdlib.h> /* malloc(), free() */
28 #include <errno.h> /* ENOMEM */
29 #include <string.h> /* strerror() */
34 #ifdef WIN32 /* mingw32 hack */
39 /* Let vlc take care of the i18n stuff */
40 #define WXINTL_NO_GETTEXT_MACRO
42 #include <wx/wxprec.h>
44 #include <wx/window.h>
45 #include <wx/notebook.h>
46 #include <wx/textctrl.h>
47 #include <wx/combobox.h>
48 #include <wx/spinctrl.h>
49 #include <wx/statline.h>
50 #include <wx/treectrl.h>
51 #include <wx/clntdata.h>
52 #include <wx/dynarray.h>
56 #include "wxwindows.h"
59 # define wxRB_SINGLE 0
62 /*****************************************************************************
63 * Classes declarations.
64 *****************************************************************************/
65 class PrefsTreeCtrl : public wxTreeCtrl
70 PrefsTreeCtrl( wxWindow *parent, intf_thread_t *_p_intf,
71 PrefsDialog *p_prefs_dialog, wxBoxSizer *_p_sizer );
72 virtual ~PrefsTreeCtrl();
77 /* Event handlers (these functions should _not_ be virtual) */
78 void OnSelectTreeItem( wxTreeEvent& event );
82 intf_thread_t *p_intf;
83 PrefsDialog *p_prefs_dialog;
87 wxTreeItemId root_item;
92 ConfigData( wxPanel *_panel, int _i_conf_type,
93 vlc_bool_t _b_advanced, char *psz_name )
94 { panel = _panel; b_advanced = _b_advanced;
95 i_config_type = _i_conf_type; option_name = psz_name; }
97 vlc_bool_t b_advanced;
102 wxComboBox *combobox;
103 wxRadioButton *radio;
104 wxSpinCtrl *spinctrl;
105 wxCheckBox *checkbox;
106 wxTextCtrl *textctrl;
111 wxString option_name;
114 WX_DEFINE_ARRAY(ConfigData *, ArrayOfConfigData);
116 class PrefsPanel : public wxPanel
121 PrefsPanel( wxWindow *parent, intf_thread_t *_p_intf,
122 module_t *p_module, char * );
123 virtual ~PrefsPanel() {}
128 void OnFileBrowse( wxCommandEvent& WXUNUSED(event) );
129 void OnDirectoryBrowse( wxCommandEvent& WXUNUSED(event) );
130 void OnAdvanced( wxCommandEvent& WXUNUSED(event) );
131 DECLARE_EVENT_TABLE()
133 intf_thread_t *p_intf;
134 vlc_bool_t b_advanced;
136 wxBoxSizer *config_sizer;
137 wxScrolledWindow *config_window;
139 ArrayOfConfigData config_array;
142 class ConfigTreeData : public wxTreeItemData
146 ConfigTreeData() { panel == NULL; }
147 virtual ~ConfigTreeData() { if( panel ) delete panel; }
153 class ConfigEvtHandler : public wxEvtHandler
156 ConfigEvtHandler( intf_thread_t *p_intf );
157 virtual ~ConfigEvtHandler();
159 void ConfigEvtHandler::OnCommandEvent( wxCommandEvent& event );
163 DECLARE_EVENT_TABLE()
165 intf_thread_t *p_intf;
168 /*****************************************************************************
170 *****************************************************************************/
172 /* IDs for the controls and the menu commands */
175 Notebook_Event = wxID_HIGHEST,
181 BEGIN_EVENT_TABLE(PrefsDialog, wxDialog)
183 EVT_BUTTON(wxID_OK, PrefsDialog::OnOk)
184 EVT_BUTTON(wxID_CANCEL, PrefsDialog::OnCancel)
185 EVT_BUTTON(wxID_SAVE, PrefsDialog::OnSave)
189 // menu and control ids
192 PrefsTree_Ctrl = wxID_HIGHEST
195 BEGIN_EVENT_TABLE(PrefsTreeCtrl, wxTreeCtrl)
196 EVT_TREE_SEL_CHANGED(PrefsTree_Ctrl, PrefsTreeCtrl::OnSelectTreeItem)
201 FileBrowse_Event = wxID_HIGHEST,
202 DirectoryBrowse_Event,
206 BEGIN_EVENT_TABLE(PrefsPanel, wxPanel)
208 EVT_BUTTON(Advanced_Event, PrefsPanel::OnAdvanced)
209 EVT_BUTTON(FileBrowse_Event, PrefsPanel::OnFileBrowse)
210 EVT_BUTTON(DirectoryBrowse_Event, PrefsPanel::OnDirectoryBrowse)
214 BEGIN_EVENT_TABLE(ConfigEvtHandler, wxEvtHandler)
215 EVT_BUTTON(-1, ConfigEvtHandler::OnCommandEvent)
216 EVT_TEXT(-1, ConfigEvtHandler::OnCommandEvent)
217 EVT_RADIOBOX(-1, ConfigEvtHandler::OnCommandEvent)
218 EVT_SPINCTRL(-1, ConfigEvtHandler::OnCommandEvent)
221 /*****************************************************************************
223 *****************************************************************************/
224 PrefsDialog::PrefsDialog( intf_thread_t *_p_intf, Interface *_p_main_interface)
225 : wxDialog( _p_main_interface, -1, _("Preferences"), wxDefaultPosition,
226 wxSize(650,450), wxDEFAULT_FRAME_STYLE )
228 /* Initializations */
230 p_main_interface = _p_main_interface;
232 /* Create a panel to put everything in */
233 wxPanel *panel = new wxPanel( this, -1 );
234 panel->SetAutoLayout( TRUE );
236 /* Create the preferences tree control */
237 wxBoxSizer *controls_sizer = new wxBoxSizer( wxHORIZONTAL );
239 new PrefsTreeCtrl( panel, p_intf, this, controls_sizer );
242 wxStaticLine *static_line = new wxStaticLine( panel, wxID_OK );
244 /* Create the buttons */
245 wxButton *ok_button = new wxButton( panel, wxID_OK, _("OK") );
246 ok_button->SetDefault();
247 wxButton *cancel_button = new wxButton( panel, wxID_CANCEL, _("Cancel") );
248 wxButton *save_button = new wxButton( panel, wxID_SAVE, _("Save") );
249 //wxButton *reset_button = new wxButton( panel, Reset_Event, _("Reset") );
251 /* Place everything in sizers */
252 wxBoxSizer *button_sizer = new wxBoxSizer( wxHORIZONTAL );
253 button_sizer->Add( ok_button, 0, wxALL, 5 );
254 button_sizer->Add( cancel_button, 0, wxALL, 5 );
255 button_sizer->Add( save_button, 0, wxALL, 5 );
256 //button_sizer->Add( reset_button, 0, wxALL, 5 );
257 button_sizer->Layout();
259 wxBoxSizer *main_sizer = new wxBoxSizer( wxVERTICAL );
260 wxBoxSizer *panel_sizer = new wxBoxSizer( wxVERTICAL );
261 panel_sizer->Add( controls_sizer, 1, wxEXPAND | wxALL, 5 );
262 panel_sizer->Add( static_line, 0, wxEXPAND | wxALL, 5 );
263 panel_sizer->Add( button_sizer, 0, wxALIGN_LEFT | wxALIGN_BOTTOM |
265 panel_sizer->Layout();
266 panel->SetSizer( panel_sizer );
267 main_sizer->Add( panel, 1, wxEXPAND, 0 );
268 main_sizer->Layout();
269 SetSizer( main_sizer );
272 PrefsDialog::~PrefsDialog()
276 /*****************************************************************************
278 *****************************************************************************/
281 /*****************************************************************************
283 *****************************************************************************/
284 void PrefsDialog::OnOk( wxCommandEvent& WXUNUSED(event) )
286 prefs_tree->ApplyChanges();
291 void PrefsDialog::OnCancel( wxCommandEvent& WXUNUSED(event) )
296 void PrefsDialog::OnSave( wxCommandEvent& WXUNUSED(event) )
298 prefs_tree->ApplyChanges();
300 config_SaveConfigFile( p_intf, NULL );
303 /*****************************************************************************
304 * PrefsTreeCtrl class definition.
305 *****************************************************************************/
306 PrefsTreeCtrl::PrefsTreeCtrl( wxWindow *_p_parent, intf_thread_t *_p_intf,
307 PrefsDialog *_p_prefs_dialog,
308 wxBoxSizer *_p_sizer )
309 : wxTreeCtrl( _p_parent, PrefsTree_Ctrl, wxDefaultPosition, wxDefaultSize,
310 wxTR_NO_LINES | wxTR_FULL_ROW_HIGHLIGHT |
311 wxTR_LINES_AT_ROOT | wxTR_HIDE_ROOT |
312 wxTR_HAS_BUTTONS | wxTR_TWIST_BUTTONS | wxSUNKEN_BORDER )
316 module_config_t *p_item;
319 /* Initializations */
321 p_prefs_dialog = _p_prefs_dialog;
323 p_parent = _p_parent;
325 root_item = AddRoot( "" );
327 /* List the plugins */
328 p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
329 if( !p_list ) return;
332 * Build a tree of the main options
334 for( i_index = 0; i_index < p_list->i_count; i_index++ )
336 p_module = (module_t *)p_list->p_values[i_index].p_object;
337 if( !strcmp( p_module->psz_object_name, "main" ) )
340 if( i_index < p_list->i_count )
342 /* We found the main module */
344 /* Enumerate config options and add corresponding config boxes */
345 p_item = p_module->p_config;
349 switch( p_item->i_type )
351 case CONFIG_HINT_CATEGORY:
352 ConfigTreeData *config_data = new ConfigTreeData;
354 new PrefsPanel( p_parent, p_intf,
355 p_module, p_item->psz_text );
356 config_data->panel->Hide();
358 /* Add the category to the tree */
359 AppendItem( root_item, p_item->psz_text, -1, -1, config_data );
363 while( p_item->i_type != CONFIG_HINT_END && p_item++ );
365 SortChildren( root_item );
370 * Build a tree of all the plugins
372 wxTreeItemId plugins_item = AppendItem( root_item, _("Plugins") );
374 for( i_index = 0; i_index < p_list->i_count; i_index++ )
376 p_module = (module_t *)p_list->p_values[i_index].p_object;
378 /* Find the capabiltiy child item */
379 long cookie; size_t i_child_index;
380 wxTreeItemId capability_item = GetFirstChild( plugins_item, cookie);
381 for( i_child_index = 0;
382 i_child_index < GetChildrenCount( plugins_item, FALSE );
385 if( !GetItemText(capability_item).Cmp(p_module->psz_capability) )
389 capability_item = GetNextChild( plugins_item, cookie );
392 if( i_child_index == GetChildrenCount( plugins_item, FALSE ) &&
393 p_module->psz_capability && *p_module->psz_capability )
395 /* We didn't find it, add it */
396 capability_item = AppendItem( plugins_item,
397 p_module->psz_capability );
400 /* Add the plugin to the tree */
401 ConfigTreeData *config_data = new ConfigTreeData;
403 new PrefsPanel( p_parent, p_intf, p_module, NULL );
404 config_data->panel->Hide();
405 AppendItem( capability_item, p_module->psz_object_name, -1, -1,
409 /* Sort all this mess */
410 long cookie; size_t i_child_index;
411 SortChildren( plugins_item );
412 wxTreeItemId capability_item = GetFirstChild( plugins_item, cookie);
413 for( i_child_index = 0;
414 i_child_index < GetChildrenCount( plugins_item, FALSE );
417 capability_item = GetNextChild( plugins_item, cookie );
418 SortChildren( capability_item );
421 /* Clean-up everything */
422 vlc_list_release( p_list );
424 p_sizer->Add( this, 1, wxEXPAND | wxALL, 0 );
427 /* Update Tree Ctrl */
428 SelectItem( GetFirstChild( root_item, cookie ) );
431 PrefsTreeCtrl::~PrefsTreeCtrl()
435 void PrefsTreeCtrl::ApplyChanges()
437 long cookie; size_t i_child_index;
438 ConfigTreeData *config_data;
440 wxTreeItemId item = GetFirstChild( root_item, cookie);
441 for( i_child_index = 0;
442 i_child_index < GetChildrenCount( root_item, TRUE );
445 config_data = (ConfigTreeData *)GetItemData( item );
448 config_data->panel->ApplyChanges();
451 item = GetNextChild( root_item, cookie );
455 void PrefsTreeCtrl::OnSelectTreeItem( wxTreeEvent& event )
457 ConfigTreeData *config_data;
459 config_data = (ConfigTreeData *)GetItemData( event.GetOldItem() );
460 if( config_data && config_data->panel )
462 config_data->panel->Hide();
463 p_sizer->Remove( config_data->panel );
466 config_data = (ConfigTreeData *)GetItemData( event.GetItem() );
467 if( config_data && config_data->panel )
469 config_data->panel->Show();
470 p_sizer->Add( config_data->panel, 2, wxEXPAND | wxALL, 0 );
475 /*****************************************************************************
476 * PrefsPanel class definition.
477 *****************************************************************************/
478 PrefsPanel::PrefsPanel( wxWindow* parent, intf_thread_t *_p_intf,
479 module_t *p_module, char *psz_section )
480 : wxPanel( parent, -1, wxDefaultPosition, wxDefaultSize )
482 module_config_t *p_item;
489 wxCheckBox *checkbox;
490 wxTextCtrl *textctrl;
494 /* Initializations */
496 b_advanced = VLC_TRUE;
497 SetAutoLayout( TRUE );
499 wxBoxSizer *sizer = new wxBoxSizer( wxVERTICAL );
501 /* Enumerate config options and add corresponding config boxes */
502 p_item = p_module->p_config;
504 /* Find the category if it has been specified */
505 if( psz_section && p_item->i_type == CONFIG_HINT_CATEGORY )
507 while( !p_item->i_type == CONFIG_HINT_CATEGORY ||
508 strcmp( psz_section, p_item->psz_text ) )
510 if( p_item->i_type == CONFIG_HINT_END )
516 /* Add a head title to the panel */
517 wxStaticBox *static_box = new wxStaticBox( this, -1, "" );
518 wxStaticBoxSizer *box_sizer = new wxStaticBoxSizer( static_box,
520 label = new wxStaticText( this, -1,
521 psz_section ? p_item->psz_text :
522 p_module->psz_longname );
524 box_sizer->Add( label, 1, wxALL, 5 );
525 sizer->Add( box_sizer, 0, wxEXPAND | wxALL, 5 );
527 /* Now put all the config options into a scrolled window */
528 config_sizer = new wxBoxSizer( wxVERTICAL );
529 config_window = new wxScrolledWindow( this, -1, wxDefaultPosition,
531 config_window->SetAutoLayout( TRUE );
532 config_window->SetScrollRate( 5, 5 );
536 /* If a category has been specified, check we finished the job */
537 if( psz_section && p_item->i_type == CONFIG_HINT_CATEGORY &&
538 strcmp( psz_section, p_item->psz_text ) )
541 /* put each config option in a separate panel so we can hide advanced
543 wxPanel *panel = new wxPanel( config_window, -1, wxDefaultPosition,
545 wxBoxSizer *panel_sizer = new wxBoxSizer( wxHORIZONTAL );
546 ConfigData *config_data =
547 new ConfigData( panel, p_item->i_type,
548 p_item->b_advanced, p_item->psz_name );
550 switch( p_item->i_type )
552 case CONFIG_ITEM_MODULE:
553 label = new wxStaticText(panel, -1, p_item->psz_text);
554 combo = new wxComboBox( panel, -1, p_item->psz_value,
555 wxDefaultPosition, wxDefaultSize,
556 0, NULL, wxCB_READONLY | wxCB_SORT );
558 /* build a list of available modules */
559 p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
560 combo->Append( _("Default"), (void *)NULL );
561 combo->SetSelection( 0 );
562 for( int i_index = 0; i_index < p_list->i_count; i_index++ )
564 p_parser = (module_t *)p_list->p_values[i_index].p_object ;
566 if( !strcmp( p_parser->psz_capability,
569 combo->Append( p_parser->psz_longname,
570 p_parser->psz_object_name );
571 if( p_item->psz_value &&
572 !strcmp(p_item->psz_value, p_parser->psz_object_name) )
573 combo->SetSelection( combo->GetCount() - 1 );
577 combo->SetToolTip( p_item->psz_longtext );
578 config_data->control.combobox = combo;
579 panel_sizer->Add( label, 0, wxALL, 5 );
580 panel_sizer->Add( combo, 1, wxALL, 5 );
583 case CONFIG_ITEM_STRING:
584 case CONFIG_ITEM_FILE:
585 label = new wxStaticText(panel, -1, p_item->psz_text);
586 textctrl = new wxTextCtrl( panel, -1, p_item->psz_value,
587 wxDefaultPosition, wxDefaultSize,
589 textctrl->SetToolTip( p_item->psz_longtext );
590 config_data->control.textctrl = textctrl;
591 panel_sizer->Add( label, 0, wxALL, 5 );
592 panel_sizer->Add( textctrl, 1, wxALL, 5 );
593 if( p_item->i_type == CONFIG_ITEM_FILE )
595 button = new wxButton( panel, -1, _("Browse...") );
596 panel_sizer->Add( button, 0, wxALL, 5 );
600 case CONFIG_ITEM_INTEGER:
601 label = new wxStaticText(panel, -1, p_item->psz_text);
602 spin = new wxSpinCtrl( panel, -1,
603 wxString::Format(_("%d"), p_item->i_value),
604 wxDefaultPosition, wxDefaultSize,
606 0, 16000, p_item->i_value);
607 spin->SetToolTip( p_item->psz_longtext );
608 config_data->control.spinctrl = spin;
609 panel_sizer->Add( label, 0, wxALL, 5 );
610 panel_sizer->Add( spin, 0, wxALL, 5 );
612 spin->SetClientData((void *)config_data);
615 case CONFIG_ITEM_FLOAT:
616 label = new wxStaticText(panel, -1, p_item->psz_text);
617 spin = new wxSpinCtrl( panel, -1,
618 wxString::Format(_("%d"), p_item->i_value),
619 wxDefaultPosition, wxDefaultSize,
621 0, 16000, p_item->i_value);
622 spin->SetToolTip( p_item->psz_longtext );
623 config_data->control.spinctrl = spin;
624 panel_sizer->Add( label, 0, wxALL, 5 );
625 panel_sizer->Add( spin, 0, wxALL, 5 );
628 case CONFIG_ITEM_BOOL:
629 checkbox = new wxCheckBox( panel, -1, p_item->psz_text );
630 if( p_item->i_value ) checkbox->SetValue(TRUE);
631 checkbox->SetToolTip( p_item->psz_longtext );
632 config_data->control.checkbox = checkbox;
633 panel_sizer->Add( checkbox, 0, wxALL, 5 );
637 delete panel; panel = NULL;
643 /* Don't add items that were not recognized */
644 if( panel == NULL ) continue;
646 panel_sizer->Layout();
647 panel->SetSizerAndFit( panel_sizer );
649 /* Add the config data to our array so we can keep a trace of it */
650 config_array.Add( config_data );
652 config_sizer->Add( panel, 0, wxEXPAND | wxALL, 2 );
654 while( p_item->i_type != CONFIG_HINT_END && p_item++ );
656 /* Display a nice message if no configuration options are available */
657 if( !config_array.GetCount() )
659 config_sizer->Add( new wxStaticText( config_window, -1,
660 _("No configuration options available") ), 1,
661 wxALIGN_CENTER_VERTICAL | wxALIGN_CENTER, 2 );
664 config_sizer->Layout();
665 config_window->SetSizer( config_sizer );
666 sizer->Add( config_window, 1, wxEXPAND | wxALL, 5 );
668 /* Intercept all menu events in our custom event handler */
669 config_window->PushEventHandler(
670 new ConfigEvtHandler( p_intf ) );
673 wxCommandEvent dummy_event;
674 b_advanced = !config_GetInt( p_intf, "advanced" );
675 OnAdvanced( dummy_event );
677 /* Create advanced button */
678 if( config_array.GetCount() )
680 wxButton *advanced_button = new wxButton( this, Advanced_Event,
682 sizer->Add( advanced_button, 0, wxALL, 5 );
689 void PrefsPanel::ApplyChanges()
691 for( size_t i = 0; i < config_array.GetCount(); i++ )
693 ConfigData *config_data = config_array.Item(i);
695 msg_Err( p_intf, "ApplyChanges %s", config_data->option_name.c_str() );
696 switch( config_data->i_config_type )
698 case CONFIG_ITEM_MODULE:
699 config_PutPsz( p_intf, config_data->option_name.c_str(), (char *)
700 config_data->control.combobox->GetClientData(
701 config_data->control.combobox->GetSelection() ) );
703 case CONFIG_ITEM_STRING:
704 case CONFIG_ITEM_FILE:
705 config_PutPsz( p_intf, config_data->option_name.c_str(),
706 config_data->control.textctrl->GetValue() );
708 case CONFIG_ITEM_BOOL:
709 config_PutInt( p_intf, config_data->option_name.c_str(),
710 config_data->control.checkbox->GetValue() );
712 case CONFIG_ITEM_INTEGER:
713 config_PutInt( p_intf, config_data->option_name.c_str(),
714 config_data->control.spinctrl->GetValue() );
716 case CONFIG_ITEM_FLOAT:
717 config_PutFloat( p_intf, config_data->option_name.c_str(),
718 config_data->control.spinctrl->GetValue() );
724 void PrefsPanel::OnAdvanced( wxCommandEvent& WXUNUSED(event) )
726 b_advanced = !b_advanced;
728 for( size_t i = 0; i < config_array.GetCount(); i++ )
730 ConfigData *config_data = config_array.Item(i);
731 if( config_data->b_advanced )
733 config_data->panel->Show( b_advanced );
734 config_sizer->Show( config_data->panel, b_advanced );
738 config_sizer->Layout();
739 config_window->FitInside();
742 void PrefsPanel::OnFileBrowse( wxCommandEvent& WXUNUSED(event) )
744 wxFileDialog dialog( this, _("Open file"), "", "", "*.*",
747 if( dialog.ShowModal() == wxID_OK )
750 file_combo->SetValue( dialog.GetPath() );
755 void PrefsPanel::OnDirectoryBrowse( wxCommandEvent& WXUNUSED(event) )
757 wxFileDialog dialog( this, _("Open file"), "", "", "*.*",
760 if( dialog.ShowModal() == wxID_OK )
763 file_combo->SetValue( dialog.GetPath() );
768 /*****************************************************************************
769 * A small helper class which intercepts all events
770 *****************************************************************************/
771 ConfigEvtHandler::ConfigEvtHandler( intf_thread_t *_p_intf )
773 /* Initializations */
777 ConfigEvtHandler::~ConfigEvtHandler()
781 void ConfigEvtHandler::OnCommandEvent( wxCommandEvent& event )
783 if( !event.GetEventObject() )
789 ConfigData *config_data = (ConfigData *)
790 ((wxEvtHandler *)event.GetEventObject())->GetClientData();
798 msg_Err( p_intf, "%s", config_data->option_name.c_str() );
800 switch( config_data->i_config_type )
802 case CONFIG_ITEM_MODULE:
804 case CONFIG_ITEM_STRING:
805 case CONFIG_ITEM_FILE:
807 case CONFIG_ITEM_INTEGER:
809 case CONFIG_ITEM_FLOAT:
811 case CONFIG_ITEM_BOOL: