]> git.sesse.net Git - vlc/blob - modules/gui/win32/preferences.cpp
f0d987a4f1f0fef8f8a56320084fb752c9c3dbfd
[vlc] / modules / gui / win32 / preferences.cpp
1 /*****************************************************************************\r
2  * preferences.cpp: the "Preferences" dialog box\r
3  *****************************************************************************\r
4  * Copyright (C) 2002 VideoLAN\r
5  *\r
6  * Authors: Olivier Teuliere <ipkiss@via.ecp.fr>\r
7  *\r
8  * This program is free software; you can redistribute it and/or modify\r
9  * it under the terms of the GNU General Public License as published by\r
10  * the Free Software Foundation; either version 2 of the License, or\r
11  * (at your option) any later version.\r
12  *\r
13  * This program is distributed in the hope that it will be useful,\r
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
16  * GNU General Public License for more details.\r
17  *\r
18  * You should have received a copy of the GNU General Public License\r
19  * along with this program; if not, write to the Free Software\r
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.\r
21  *****************************************************************************/\r
22 \r
23 #include <vcl.h>\r
24 #pragma hdrstop\r
25 \r
26 #include <stdlib.h>                                      /* malloc(), free() */\r
27 #include <string.h>                                                /* strcmp */\r
28 \r
29 #include <vlc/vlc.h>\r
30 #include <vlc/intf.h>\r
31 \r
32 #include "preferences.h"\r
33 #include "win32_common.h"\r
34 \r
35 //---------------------------------------------------------------------------\r
36 //#pragma package(smart_init)\r
37 #pragma link "CSPIN"\r
38 #pragma resource "*.dfm"\r
39 \r
40 extern intf_thread_t *p_intfGlobal;\r
41 \r
42 \r
43 /****************************************************************************\r
44  * Functions to help components creation\r
45  ****************************************************************************/\r
46 __fastcall TGroupBoxPref::TGroupBoxPref( TComponent* Owner,\r
47             module_config_t *p_config_arg ) : TGroupBox( Owner )\r
48 {\r
49     p_config = p_config_arg;\r
50     Caption = p_config->psz_text;\r
51 }\r
52 //---------------------------------------------------------------------------\r
53 TCheckListBox * __fastcall TGroupBoxPref::CreateCheckListBox(\r
54     TWinControl *Parent, int Left, int Width, int Top, int Height )\r
55 {\r
56     TCheckListBox *CheckListBox = new TCheckListBox( Parent );\r
57     CheckListBox->Parent = Parent;\r
58     CheckListBox->Left = Left;\r
59     CheckListBox->Width = Width;\r
60     CheckListBox->Top = Top;\r
61     CheckListBox->Height = Height;\r
62     return CheckListBox;\r
63 }\r
64 //---------------------------------------------------------------------------\r
65 TButton * __fastcall TGroupBoxPref::CreateButton( TWinControl *Parent,\r
66             int Left, int Width, int Top, int Height, AnsiString Caption )\r
67 {\r
68     TButton *Button = new TButton( Parent );\r
69     Button->Parent = Parent;\r
70     Button->Left = Left;\r
71     Button->Width = Width;\r
72     Button->Top = Top;\r
73     Button->Height = Height;\r
74     Button->Caption = Caption;\r
75     return Button;\r
76 }\r
77 //---------------------------------------------------------------------------\r
78 TCheckBox * __fastcall TGroupBoxPref::CreateCheckBox( TWinControl *Parent,\r
79             int Left, int Width, int Top, int Height, AnsiString Caption )\r
80 {\r
81     TCheckBox *CheckBox = new TCheckBox( Parent );\r
82     CheckBox->Parent = Parent;\r
83     CheckBox->Left = Left;\r
84     CheckBox->Width = Width;\r
85     CheckBox->Top = Top;\r
86     CheckBox->Height = Height;\r
87     CheckBox->Caption = Caption;\r
88     return CheckBox;\r
89 }\r
90 //---------------------------------------------------------------------------\r
91 TLabel * __fastcall TGroupBoxPref::CreateLabel( TWinControl *Parent,\r
92             int Left, int Width, int Top, int Height, AnsiString Caption,\r
93             bool WordWrap )\r
94 {\r
95     TLabel *Label = new TLabel( Parent );\r
96     Label->Parent = Parent;\r
97     Label->Caption = Caption;\r
98     Label->Left = Left;\r
99     Label->Width = Width;\r
100     Label->Top = Top;\r
101     Label->Height = Height;\r
102     Label->WordWrap = WordWrap;\r
103     return Label;\r
104 }\r
105 //---------------------------------------------------------------------------\r
106 TEdit * __fastcall TGroupBoxPref::CreateEdit( TWinControl *Parent,\r
107             int Left, int Width, int Top, int Height, AnsiString Text )\r
108 {\r
109     TEdit *Edit = new TEdit( Parent );\r
110     Edit->Parent = Parent;\r
111     Edit->Left = Left;\r
112     Edit->Width = Width;\r
113     Edit->Top = Top;\r
114     Edit->Height = Height;\r
115     Edit->Text = Text;\r
116     return Edit;\r
117 }\r
118 //---------------------------------------------------------------------------\r
119 TCSpinEdit * __fastcall TGroupBoxPref::CreateSpinEdit( TWinControl *Parent,\r
120             int Left, int Width, int Top, int Height,\r
121             long Min, long Max, long Value )\r
122 {\r
123     TCSpinEdit *SpinEdit = new TCSpinEdit( Parent );\r
124     SpinEdit->Parent = Parent;\r
125     SpinEdit->Left = Left;\r
126     SpinEdit->Width = Width;\r
127     SpinEdit->Top = Top;\r
128     SpinEdit->Height = Height;\r
129     SpinEdit->MinValue = Min;\r
130     SpinEdit->MaxValue = Max;\r
131     SpinEdit->Value = Value;\r
132     return SpinEdit;\r
133 }\r
134 //---------------------------------------------------------------------------\r
135 void __fastcall TGroupBoxPref::UpdateChanges()\r
136 {\r
137 }\r
138 \r
139 \r
140 /****************************************************************************\r
141  * GroupBox for module management\r
142  ****************************************************************************/\r
143 __fastcall TGroupBoxPlugin::TGroupBoxPlugin( TComponent* Owner,\r
144             module_config_t *p_config ) : TGroupBoxPref( Owner, p_config )\r
145 {\r
146     /* init checklistbox */\r
147     CheckListBox = CreateCheckListBox( this, 16, 164, 24, 160 );\r
148     CheckListBox->OnClick = CheckListBoxClick;\r
149     CheckListBox->OnClickCheck = CheckListBoxClickCheck;\r
150 \r
151     /* init description label */\r
152     LabelDesc = CreateLabel( this, 230, 225, 50, 52,\r
153                              p_config->psz_longtext, true );\r
154 \r
155     /* init hint label */\r
156     LabelHint = CreateLabel( this, 230, 225, 135, 13, "", false );\r
157 \r
158     /* init configure button */\r
159     ButtonConfig = CreateButton( this, 16, 70, 192, 25, "Configure" );\r
160     ButtonConfig->Enabled = false;\r
161     ButtonConfig->OnClick = ButtonConfigClick;\r
162 \r
163     Height = 233;\r
164 };\r
165 //---------------------------------------------------------------------------\r
166 void __fastcall TGroupBoxPlugin::CheckListBoxClick( TObject *Sender )\r
167 {\r
168     module_t **pp_parser;\r
169     vlc_list_t *p_list;\r
170 \r
171     /* check that the click is valid (we are on an item, and the click\r
172      * started on an item */\r
173     if( CheckListBox->ItemIndex == -1 )\r
174         return;\r
175 \r
176     AnsiString Name = CheckListBox->Items->Strings[CheckListBox->ItemIndex];\r
177     if( Name == "" )\r
178         return;\r
179 \r
180     /* look for module 'Name' */\r
181     p_list = vlc_list_find( p_intfGlobal, VLC_OBJECT_MODULE, FIND_ANYWHERE );\r
182 \r
183     for( pp_parser = (module_t **)p_list->pp_objects ;\r
184          *pp_parser ;\r
185          pp_parser++ )\r
186     {\r
187         if( strcmp( (*pp_parser)->psz_object_name, Name.c_str() ) == 0 )\r
188         {\r
189             ModuleSelected = (*pp_parser);\r
190             LabelHint->Caption = (*pp_parser)->psz_longname ?\r
191                                  (*pp_parser)->psz_longname : "";\r
192             ButtonConfig->Enabled =\r
193                 (*pp_parser)->i_config_items ? true : false;\r
194 \r
195             break;\r
196         }\r
197     }\r
198 }\r
199 //---------------------------------------------------------------------------\r
200 void __fastcall TGroupBoxPlugin::CheckListBoxClickCheck( TObject *Sender )\r
201 {\r
202     /* one item maximum must be checked */\r
203     if( CheckListBox->Checked[CheckListBox->ItemIndex] )\r
204     {\r
205         for( int item = 0; item < CheckListBox->Items->Count; item++ )\r
206         {\r
207             if( item != CheckListBox->ItemIndex )\r
208             {\r
209                 CheckListBox->Checked[item] = false;\r
210             }\r
211         }\r
212     }\r
213 }\r
214 //---------------------------------------------------------------------------\r
215 void __fastcall TGroupBoxPlugin::ButtonConfigClick( TObject *Sender )\r
216 {\r
217     p_intfGlobal->p_sys->p_window->\r
218                         CreatePreferences( ModuleSelected->psz_object_name );\r
219 }\r
220 //---------------------------------------------------------------------------\r
221 void __fastcall TGroupBoxPlugin::UpdateChanges()\r
222 {\r
223     AnsiString Name = "";\r
224 \r
225     /* find the selected plugin (if any) */\r
226     for( int item = 0; item < CheckListBox->Items->Count; item++ )\r
227     {\r
228         if( CheckListBox->Checked[item] )\r
229         {\r
230             Name = CheckListBox->Items->Strings[item];\r
231             break;\r
232         }\r
233     }\r
234 \r
235     /* XXX: Necessary, since c_str() returns only a temporary pointer... */\r
236     free( p_config->psz_value );\r
237     p_config->psz_value = (char *)malloc( Name.Length() + 1 );\r
238     strcpy( p_config->psz_value, Name.c_str() );\r
239 }\r
240 \r
241 \r
242 /****************************************************************************\r
243  * GroupBox for string management\r
244  ****************************************************************************/\r
245 __fastcall TGroupBoxString::TGroupBoxString( TComponent* Owner,\r
246             module_config_t *p_config ) : TGroupBoxPref( Owner, p_config )\r
247 {\r
248     /* init description label */\r
249     LabelDesc = CreateLabel( this, 230, 225, 24, 26,\r
250                              p_config->psz_longtext, true );\r
251 \r
252     /* init edit */\r
253     Edit = CreateEdit( this, 16, 164, 24, 21, "" );\r
254     vlc_mutex_lock( p_config->p_lock );\r
255     Edit->Text = p_config->psz_value ? p_config->psz_value : "";\r
256     vlc_mutex_unlock( p_config->p_lock );\r
257 \r
258     /* vertical alignment */\r
259     Height = LabelDesc->Height + 24;\r
260     LabelDesc->Top = Top + ( Height - LabelDesc->Height ) / 2 + 4;\r
261     Edit->Top = Top + ( Height - Edit->Height ) / 2 + 4;\r
262 };\r
263 //---------------------------------------------------------------------------\r
264 void __fastcall TGroupBoxString::UpdateChanges()\r
265 {\r
266     /* XXX: Necessary, since c_str() returns only a temporary pointer... */\r
267     free( p_config->psz_value );\r
268     p_config->psz_value = (char *)malloc( Edit->Text.Length() + 1 );\r
269     strcpy( p_config->psz_value, Edit->Text.c_str() );\r
270 }\r
271 \r
272 \r
273 /****************************************************************************\r
274  * GroupBox for integer management\r
275  ****************************************************************************/\r
276 __fastcall TGroupBoxInteger::TGroupBoxInteger( TComponent* Owner,\r
277             module_config_t *p_config ) : TGroupBoxPref( Owner, p_config )\r
278 {\r
279     /* init description label */\r
280     LabelDesc = CreateLabel( this, 230, 225, 19, 26,\r
281                              p_config->psz_longtext, true );\r
282 \r
283     /* init spinedit */\r
284     SpinEdit = CreateSpinEdit( this, 16, 164, 24, 21,\r
285                                -1, 100000, p_config->i_value );\r
286 \r
287     /* vertical alignment */\r
288     Height = LabelDesc->Height + 24;\r
289     LabelDesc->Top = Top + ( Height - LabelDesc->Height ) / 2 + 4;\r
290     SpinEdit->Top = Top + ( Height - SpinEdit->Height ) / 2 + 4;\r
291 };\r
292 //---------------------------------------------------------------------------\r
293 void __fastcall TGroupBoxInteger::UpdateChanges()\r
294 {\r
295     /* Warning: we're casting from long to int */\r
296     p_config->i_value = (int)SpinEdit->Value;\r
297 }\r
298 \r
299 \r
300 /****************************************************************************\r
301  * GroupBox for boolean management\r
302  ****************************************************************************/\r
303 __fastcall TGroupBoxBool::TGroupBoxBool( TComponent* Owner,\r
304             module_config_t *p_config ) : TGroupBoxPref( Owner, p_config )\r
305 {\r
306     /* init description label */\r
307     LabelDesc = CreateLabel( this, 230, 225, 19, 26,\r
308                              p_config->psz_longtext, true );\r
309 \r
310     /* init checkbox */\r
311     CheckBox = CreateCheckBox( this, 16, 184, 28, 17, p_config->psz_text );\r
312     CheckBox->Checked = p_config->i_value;\r
313 \r
314     /* vertical alignment */\r
315     Height = LabelDesc->Height + 24;\r
316     LabelDesc->Top = Top + ( Height - LabelDesc->Height ) / 2 + 4;\r
317     CheckBox->Top = Top + ( Height - CheckBox->Height ) / 2 + 4;\r
318 };\r
319 //---------------------------------------------------------------------------\r
320 void __fastcall TGroupBoxBool::UpdateChanges()\r
321 {\r
322     p_config->i_value = CheckBox->Checked ? 1 : 0;\r
323 }\r
324 \r
325 \r
326 /****************************************************************************\r
327  * Callbacks for the dialog\r
328  ****************************************************************************/\r
329 __fastcall TPreferencesDlg::TPreferencesDlg( TComponent* Owner )\r
330         : TForm( Owner )\r
331 {\r
332     Icon = p_intfGlobal->p_sys->p_window->Icon;\r
333 }\r
334 //---------------------------------------------------------------------------\r
335 void __fastcall TPreferencesDlg::FormClose( TObject *Sender,\r
336       TCloseAction &Action )\r
337 {\r
338     Action = caHide;\r
339 }\r
340 \r
341 \r
342 /****************************************************************************\r
343  * CreateConfigDialog: dynamically creates the configuration dialog\r
344  * box from all the configuration data provided by the selected module.\r
345  ****************************************************************************/\r
346 #define ADD_PANEL                               \\r
347 {                                               \\r
348             Panel = new TPanel( this );         \\r
349             Panel->Parent = ScrollBox;          \\r
350             Panel->Caption = "";                \\r
351             Panel->BevelOuter = bvNone;         \\r
352             Panel->Height = 12;                 \\r
353 }\r
354 \r
355 void __fastcall TPreferencesDlg::CreateConfigDialog( char *psz_module_name )\r
356 {\r
357     module_t          **pp_parser;\r
358     vlc_list_t         *p_list;\r
359 \r
360     module_config_t    *p_item;\r
361     int                 i_pages, i_ctrl;\r
362 \r
363     TTabSheet          *TabSheet;\r
364     TScrollBox         *ScrollBox;\r
365     TPanel             *Panel;\r
366     TGroupBoxPlugin    *GroupBoxPlugin;\r
367     TGroupBoxString    *GroupBoxString;\r
368     TGroupBoxInteger   *GroupBoxInteger;\r
369     TGroupBoxBool      *GroupBoxBool;\r
370 \r
371     /* Look for the selected module */\r
372     p_list = vlc_list_find( p_intfGlobal, VLC_OBJECT_MODULE, FIND_ANYWHERE );\r
373 \r
374     for( pp_parser = (module_t **)p_list->pp_objects ;\r
375          *pp_parser ;\r
376          pp_parser++ )\r
377     {\r
378         if( psz_module_name\r
379              && !strcmp( psz_module_name, (*pp_parser)->psz_object_name ) )\r
380         {\r
381             break;\r
382         }\r
383     }\r
384     if( !(*pp_parser) )\r
385     {\r
386         vlc_list_release( p_list );\r
387         return;\r
388     }\r
389 \r
390     /*\r
391      * We found it, now we can start building its configuration interface\r
392      */\r
393 \r
394     /* Enumerate config options and add corresponding config boxes */\r
395     p_item = (*pp_parser)->p_config;\r
396     if( p_item ) do\r
397     {\r
398         switch( p_item->i_type )\r
399         {\r
400         case CONFIG_HINT_CATEGORY:\r
401 \r
402             /* create a new tabsheet. */\r
403             TabSheet = new TTabSheet( this );\r
404             TabSheet->PageControl = PageControlPref;\r
405             TabSheet->Caption = p_item->psz_text;\r
406             TabSheet->Visible = true;\r
407 \r
408             /* pack a scrollbox into the tabsheet */\r
409             ScrollBox = new TScrollBox( this );\r
410             ScrollBox->Parent = TabSheet;\r
411             ScrollBox->Align = alClient;\r
412             ScrollBox->BorderStyle = bsNone;\r
413             ScrollBox->HorzScrollBar->Tracking = true;\r
414             ScrollBox->VertScrollBar->Tracking = true;\r
415 \r
416             break;\r
417 \r
418         case CONFIG_ITEM_MODULE:\r
419 \r
420             /* add new groupbox for the config option */\r
421             GroupBoxPlugin = new TGroupBoxPlugin( this, p_item );\r
422             GroupBoxPlugin->Parent = ScrollBox;\r
423 \r
424             /* add panel as separator */\r
425             ADD_PANEL;\r
426 \r
427             /* Look for valid modules */\r
428             pp_parser = (module_t **)p_list->pp_objects;\r
429 \r
430             for( ; *pp_parser ; pp_parser++ )\r
431             {\r
432                 if( !strcmp( (*pp_parser)->psz_capability, p_item->psz_type ) )\r
433                 {\r
434                     int item = GroupBoxPlugin->CheckListBox->Items->Add(\r
435                         (*pp_parser)->psz_object_name );\r
436 \r
437                     /* check the box if it's the default module */\r
438                     AnsiString Name = p_item->psz_value ?\r
439                         p_item->psz_value : "";\r
440                     if( !strcmp( (*pp_parser)->psz_object_name, Name.c_str()) )\r
441                     {\r
442                         GroupBoxPlugin->CheckListBox->Checked[item] = true;\r
443                     }\r
444                 }\r
445             }\r
446 \r
447             break;\r
448 \r
449         case CONFIG_ITEM_FILE:\r
450 \r
451         case CONFIG_ITEM_STRING:\r
452 \r
453             /* add new groupbox for the config option */\r
454             GroupBoxString = new TGroupBoxString( this, p_item );\r
455             GroupBoxString->Parent = ScrollBox;\r
456 \r
457             /* add panel as separator */\r
458             ADD_PANEL;\r
459 \r
460             break;\r
461 \r
462         case CONFIG_ITEM_INTEGER:\r
463 \r
464             /* add new groupbox for the config option */\r
465             GroupBoxInteger = new TGroupBoxInteger( this, p_item );\r
466             GroupBoxInteger->Parent = ScrollBox;\r
467 \r
468             /* add panel as separator */\r
469             ADD_PANEL;\r
470 \r
471             break;\r
472 \r
473         case CONFIG_ITEM_BOOL:\r
474 \r
475             /* add new groupbox for the config option */\r
476             GroupBoxBool = new TGroupBoxBool( this, p_item );\r
477             GroupBoxBool->Parent = ScrollBox;\r
478 \r
479             /* add panel as separator */\r
480             ADD_PANEL;\r
481 \r
482             break;\r
483         }\r
484 \r
485         p_item++;\r
486     }\r
487     while( p_item->i_type != CONFIG_HINT_END );\r
488 \r
489     /* Reorder groupboxes inside the tabsheets */\r
490     for( i_pages = 0; i_pages < PageControlPref->PageCount; i_pages++ )\r
491     {\r
492         /* get scrollbox from the tabsheet */\r
493         ScrollBox = (TScrollBox *)PageControlPref->Pages[i_pages]->Controls[0];\r
494 \r
495         for( i_ctrl = ScrollBox->ControlCount - 1; i_ctrl >= 0 ; i_ctrl-- )\r
496         {\r
497             ScrollBox->Controls[i_ctrl]->Align = alTop;\r
498         }\r
499     }\r
500 \r
501     vlc_list_release( p_list );\r
502 \r
503     /* set active tabsheet\r
504      * FIXME: i don't know why, but both lines are necessary */\r
505     PageControlPref->ActivePageIndex = 1;\r
506     PageControlPref->ActivePageIndex = 0;\r
507 }\r
508 #undef ADD_PANEL\r
509 //---------------------------------------------------------------------------\r
510 void __fastcall TPreferencesDlg::ButtonOkClick( TObject *Sender )\r
511 {\r
512     ButtonApplyClick( Sender );\r
513     Hide();\r
514 }\r
515 //---------------------------------------------------------------------------\r
516 void __fastcall TPreferencesDlg::ButtonApplyClick( TObject *Sender )\r
517 {\r
518     TScrollBox *ScrollBox;\r
519     TGroupBoxPref *GroupBox;\r
520     int i, j;\r
521 \r
522     for( i = 0; i < PageControlPref->PageCount; i++ )\r
523     {\r
524         /* get scrollbox from the tabsheet */\r
525         ScrollBox = (TScrollBox *)PageControlPref->Pages[i]->Controls[0];\r
526 \r
527         for( j = 0; j < ScrollBox->ControlCount ; j++ )\r
528         {\r
529             /* skip the panels */\r
530             if( ScrollBox->Controls[j]->InheritsFrom( __classid( TGroupBoxPref ) ) )\r
531             {\r
532                 GroupBox = (TGroupBoxPref *)ScrollBox->Controls[j];\r
533                 GroupBox->UpdateChanges();\r
534                 SaveValue( GroupBox->p_config );\r
535             }\r
536         }\r
537     }\r
538 }\r
539 //---------------------------------------------------------------------------\r
540 void __fastcall TPreferencesDlg::ButtonSaveClick( TObject *Sender )\r
541 {\r
542     ButtonApplyClick( Sender );\r
543     config_SaveConfigFile( p_intfGlobal, NULL );\r
544 }\r
545 //---------------------------------------------------------------------------\r
546 void __fastcall TPreferencesDlg::ButtonCancelClick( TObject *Sender )\r
547 {\r
548     Hide();\r
549 }\r
550 //---------------------------------------------------------------------------\r
551 void __fastcall TPreferencesDlg::SaveValue( module_config_t *p_config )\r
552 {\r
553     switch( p_config->i_type )\r
554     {\r
555         case CONFIG_ITEM_STRING:\r
556         case CONFIG_ITEM_FILE:\r
557         case CONFIG_ITEM_MODULE:\r
558             config_PutPsz( p_intfGlobal, p_config->psz_name,\r
559                            *p_config->psz_value ? p_config->psz_value : NULL );\r
560             break;\r
561         case CONFIG_ITEM_INTEGER:\r
562         case CONFIG_ITEM_BOOL:\r
563             config_PutInt( p_intfGlobal, p_config->psz_name,\r
564                            p_config->i_value );\r
565             break;\r
566     }\r
567 }\r
568 //---------------------------------------------------------------------------\r
569 \r