]> git.sesse.net Git - vlc/blob - modules/gui/beos/PreferencesWindow.cpp
Avoid \r\n problems between platforms
[vlc] / modules / gui / beos / PreferencesWindow.cpp
1 /*****************************************************************************
2  * PreferencesWindow.cpp: beos interface
3  *****************************************************************************
4  * Copyright (C) 1999, 2000, 2001 VideoLAN
5  * $Id$
6  *
7  * Authors: Eric Petit <titer@videolan.org>
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 #include <stdlib.h> /* atoi(), strtod() */
25
26 #include <String.h>
27
28 #include <vlc/vlc.h>
29 #include <vlc/intf.h>
30 #include <vlc_keys.h>
31
32 #include "PreferencesWindow.h"
33
34 /* TODO:
35     - add the needed LockLooper()s
36     - fix window resizing */
37
38 /* We use this function to order the items of the BOutlineView */
39 static int compare_func( const BListItem * _first,
40                          const BListItem * _second )
41 {
42     StringItemWithView * first = (StringItemWithView*) _first;
43     StringItemWithView * second = (StringItemWithView*) _second;
44
45     /* The Modules tree at last */
46     if( !strcmp( first->Text(), _( "Modules" ) ) )
47         return 1;
48     if( !strcmp( second->Text(), _( "Modules" ) ) )
49         return -1;
50
51     /* alphabetic order */
52     return( strcmp( first->Text(), second->Text() ) );
53 }
54
55 /*****************************************************************************
56  * PreferencesWindow::PreferencesWindow
57  *****************************************************************************/
58 PreferencesWindow::PreferencesWindow( intf_thread_t * p_interface,
59                                       BRect frame, const char * name )
60     : BWindow( frame, name, B_FLOATING_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
61                B_NOT_ZOOMABLE | B_NOT_RESIZABLE ),
62       fConfigScroll( NULL ),
63       p_intf( p_interface )
64 {
65     SetSizeLimits( PREFS_WINDOW_WIDTH, PREFS_WINDOW_WIDTH,
66                    200, 2000 );
67
68     BRect rect;
69
70     /* The "background" view */
71     fPrefsView = new BView( Bounds(), NULL, B_FOLLOW_ALL, B_WILL_DRAW );
72     fPrefsView->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
73     AddChild( fPrefsView );
74
75     /* Create the preferences tree */
76     rect = Bounds();
77     rect.InsetBy( 10, 10 );
78     rect.right = rect.left + 150;
79     fOutline = new BOutlineListView( rect, "preferences tree",
80                                      B_SINGLE_SELECTION_LIST,
81                                      B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM );
82     BScrollView * scrollview =
83         new BScrollView( "scrollview", fOutline,
84                          B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM,
85                          0, false, true );
86     fPrefsView->AddChild( scrollview );
87
88     /* We need to be informed if the user selects an item */
89     fOutline->SetSelectionMessage( new BMessage( PREFS_ITEM_SELECTED ) );
90
91     /* Create a dummy view so we can correctly place the real config
92        views later */
93     rect.bottom -= 40;
94     rect.left = rect.right + 15 + B_V_SCROLL_BAR_WIDTH;
95     rect.right = Bounds().right - 15;
96     fDummyView = new BView( rect, "", B_FOLLOW_ALL_SIDES, B_WILL_DRAW );
97     fDummyView->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
98     fPrefsView->AddChild( fDummyView );
99
100     /* Add a category for modules configuration */
101     StringItemWithView * modulesItem;
102     modulesItem = new StringItemWithView( _("Modules") );
103     fOutline->AddItem( modulesItem );
104
105     /* Fill the tree */
106     vlc_list_t * p_list;
107     p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
108     if( !p_list )
109     {
110         msg_Warn( p_intf, "couldn't find any module !" );
111         return;
112     }
113
114     /* First, handle the main module */
115     module_t * p_module = NULL;
116     module_config_t * p_item;
117     for( int i = 0; i < p_list->i_count; i++ )
118     {
119         p_module = (module_t*) p_list->p_values[i].p_object;
120
121         if( !strcmp( p_module->psz_object_name, "main" ) &&
122             ( p_item = p_module->p_config ) )
123             break;
124         else
125             p_module = NULL;
126     }
127
128     if( p_module )
129     {
130         /* We found the main module */
131         while( p_item->i_type == CONFIG_HINT_CATEGORY )
132         {
133             StringItemWithView * stringItem;
134             stringItem = new StringItemWithView( p_item->psz_text );
135             p_item++;
136             BuildConfigView( stringItem, &p_item, true );
137             fOutline->AddItem( stringItem );
138         }
139     }
140
141     for( int i = 0; i < p_list->i_count; i++ )
142     {
143         p_module = (module_t*) p_list->p_values[i].p_object;
144
145         if( !strcmp( p_module->psz_object_name, "main" ) )
146             continue;
147
148         /* If the module has no config option, ignore it */
149         p_item = p_module->p_config;
150         if( !p_item )
151         {
152             continue;
153         }
154         do
155         {
156             if( p_item->i_type & CONFIG_ITEM )
157             {
158                 break;
159             }
160         } while( p_item->i_type != CONFIG_HINT_END && p_item++ );
161
162         if( p_item->i_type == CONFIG_HINT_END )
163         {
164             continue;
165         }
166
167         /* Create the capability tree if it doesn't already exist */
168         char * psz_capability;
169         psz_capability = p_module->psz_capability;
170         if( !psz_capability || !*psz_capability )
171         {
172             /* Empty capability ? Let's look at the submodules */
173             module_t * p_submodule;
174             for( int j = 0; j < p_module->i_children; j++ )
175             {
176                 p_submodule = (module_t*)p_module->pp_children[ j ];
177                 if( p_submodule->psz_capability &&
178                         *p_submodule->psz_capability )
179                 {
180                     psz_capability = p_submodule->psz_capability;
181                     break;
182                 }
183             }
184         }
185
186         StringItemWithView * capabilityItem;
187         capabilityItem = NULL;
188         for( int j = 0;
189              j < fOutline->CountItemsUnder( modulesItem, true ); j++ )
190         {
191             if( !strcmp( ((StringItemWithView*)
192                 fOutline->ItemUnderAt( modulesItem, true, j ))->Text(),
193                          psz_capability ) )
194             {
195                 capabilityItem = (StringItemWithView*)
196                     fOutline->ItemUnderAt( modulesItem, true, j );
197                 break;
198             }
199         }
200         if( !capabilityItem )
201         {
202              capabilityItem = new StringItemWithView( psz_capability );
203              fOutline->AddUnder( capabilityItem, modulesItem );
204         }
205
206         /* Now add the item ! */
207         StringItemWithView * stringItem;
208         stringItem = new StringItemWithView( p_module->psz_object_name );
209         BuildConfigView( stringItem, &p_item, false );
210         fOutline->AddUnder( stringItem, capabilityItem );
211     }
212
213     vlc_list_release( p_list );
214
215     /* Set the correct values */
216     ApplyChanges( false );
217
218     /* Sort items, collapse the tree */
219     fOutline->FullListSortItems( compare_func );
220     fOutline->Collapse( modulesItem );
221     for( int i = 0; i < fOutline->CountItemsUnder( modulesItem, true ); i++ )
222         fOutline->Collapse( fOutline->ItemUnderAt( modulesItem, true, i ) );
223
224     /* Select the first item */
225     fOutline->Select( 0 );
226
227     /* Add the buttons */
228     BButton * button;
229     rect = Bounds();
230     rect.InsetBy( 10, 10 );
231     rect.left = rect.right - 80;
232     rect.top = rect.bottom - 25;
233     button = new BButton( rect, "", _("Apply"), new BMessage( PREFS_APPLY ),
234                           B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM );
235     button->MakeDefault( true );
236     fPrefsView->AddChild( button );
237     rect.OffsetBy( -90, 0 );
238     button = new BButton( rect, "", _("Save"), new BMessage( PREFS_SAVE ),
239                           B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM );
240     fPrefsView->AddChild( button );
241     rect.OffsetBy( -90, 0 );
242     button = new BButton( rect, "", _("Defaults"),
243                           new BMessage( PREFS_DEFAULTS ),
244                           B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM );
245     fPrefsView->AddChild( button );
246
247     Hide();
248     Show();
249 }
250
251 /*****************************************************************************
252  * PreferencesWindow::~PreferencesWindow
253  *****************************************************************************/
254 PreferencesWindow::~PreferencesWindow()
255 {
256 }
257
258 /*****************************************************************************
259  * PreferencesWindow::QuitRequested
260  *****************************************************************************/
261 bool PreferencesWindow::QuitRequested()
262 {
263     if( !IsHidden() )
264     {
265         Hide();
266     }
267         return false;
268 }
269
270 /*****************************************************************************
271  * PreferencesWindow::MessageReceived
272  *****************************************************************************/
273 void PreferencesWindow::MessageReceived( BMessage * message )
274 {
275     switch( message->what )
276     {
277         case PREFS_ITEM_SELECTED:
278             Update();
279             break;
280
281         case PREFS_DEFAULTS:
282             config_ResetAll( p_intf );
283             ApplyChanges( false );
284             break;
285
286         case PREFS_APPLY:
287             ApplyChanges( true );
288             break;
289
290         case PREFS_SAVE:
291             SaveChanges();
292             break;
293
294         default:
295             BWindow::MessageReceived( message );
296     }
297 }
298
299 /*****************************************************************************
300  * PreferencesWindow::FrameResized
301  *****************************************************************************/
302 void PreferencesWindow::FrameResized( float width, float height )
303 {
304     BWindow::FrameResized( width, height );
305
306     UpdateScrollBar();
307 }
308
309 /*****************************************************************************
310  * PreferencesWindow::Update
311  *****************************************************************************/
312 void PreferencesWindow::Update()
313 {
314     /* Get the selected item, if any */
315     if( fOutline->CurrentSelection() < 0 )
316         return;
317     fCurrent = (StringItemWithView*)
318         fOutline->ItemAt( fOutline->CurrentSelection() );
319
320     if( !fCurrent->fConfigBox )
321         /* This is a category */
322         return;
323
324     /* Detach the old item */
325     if( fDummyView->CountChildren() > 0 )
326         fDummyView->RemoveChild( fDummyView->ChildAt( 0 ) );
327
328     /* Resize and show the new config box */
329     fCurrent->fConfigBox->ResizeTo( fDummyView->Bounds().Width(),
330                                     fDummyView->Bounds().Height() );
331     fDummyView->AddChild( fCurrent->fConfigBox );
332
333     /* Force redrawing of its children */
334     BRect rect = fCurrent->fConfigBox->Bounds();
335     rect.InsetBy( 10,10 );
336     rect.top += 10;
337     fCurrent->fConfigScroll->ResizeTo( rect.Width(), rect.Height() );
338     fCurrent->fConfigScroll->Draw( fCurrent->fConfigScroll->Bounds() );
339
340     UpdateScrollBar();
341 }
342
343
344 /*****************************************************************************
345  * PreferencesWindow::UpdateScrollBar
346  *****************************************************************************/
347 void PreferencesWindow::UpdateScrollBar()
348 {
349     /* We have to fix the scrollbar manually because it doesn't handle
350        correctly simple BViews */
351
352     if( !fCurrent )
353     {
354         return;
355     }
356
357     /* Get the available BRect for display */
358     BRect display = fCurrent->fConfigScroll->Bounds();
359     display.right -= B_V_SCROLL_BAR_WIDTH;
360
361     /* Fix the scrollbar */
362     BScrollBar * scrollBar;
363     long max;
364         BRect visible = display & fCurrent->fConfigView->Bounds();
365         BRect total = display | fCurrent->fConfigView->Bounds();
366     scrollBar = fCurrent->fConfigScroll->ScrollBar( B_VERTICAL );
367     max = (long)( fCurrent->fConfigView->Bounds().Height() - visible.Height() );
368     if( max < 0 ) max = 0;
369     scrollBar->SetRange( 0, max );
370     scrollBar->SetProportion( visible.Height() / total.Height() );
371     scrollBar->SetSteps( 10, 100 );
372 }
373
374 /*****************************************************************************
375  * PreferencesWindow::ApplyChanges
376  * Apply changes if doIt is true, revert them otherwise
377  *****************************************************************************/
378 void PreferencesWindow::ApplyChanges( bool doIt )
379 {
380     StringItemWithView * item;
381     BView              * view;
382     ConfigWidget       * child;
383     BString              string;
384
385     for( int i = 0; i < fOutline->CountItems(); i++ )
386     {
387         item = (StringItemWithView*) fOutline->ItemAt( i );
388         view = item->fConfigView;
389
390         if( !view )
391         {
392             /* This is a category */
393             continue;
394         }
395
396         for( int j = 0; j < view->CountChildren(); j++ )
397         {
398             child = (ConfigWidget*) view->ChildAt( j );
399             child->Apply( p_intf, doIt );
400         }
401     }
402 }
403
404 /*****************************************************************************
405  * PreferencesWindow::SaveChanges
406  *****************************************************************************/
407 void PreferencesWindow::SaveChanges()
408 {
409     ApplyChanges( true );
410     config_SaveConfigFile( p_intf, NULL );
411 }
412
413 /*****************************************************************************
414  * PreferencesWindow::ReallyQuit
415  *****************************************************************************/
416 void PreferencesWindow::ReallyQuit()
417 {
418     Lock();
419     Hide();
420     Quit();
421 }
422
423 /*****************************************************************************
424  * PreferencesWindow::BuildConfigView
425  *****************************************************************************/
426 void PreferencesWindow::BuildConfigView( StringItemWithView * stringItem,
427                                          module_config_t ** pp_item,
428                                          bool stop_after_category )
429 {
430     /* Build the BBox */
431     BRect rect = fDummyView->Bounds();
432     stringItem->fConfigBox = new BBox( rect, "config box", B_FOLLOW_ALL );
433     stringItem->fConfigBox->SetLabel( stringItem->fText );
434
435     /* Build the BView */
436     rect = stringItem->fConfigBox->Bounds();
437     rect.InsetBy( 10,10 );
438     rect.top += 10;
439     rect.right -= B_V_SCROLL_BAR_WIDTH + 5;
440     stringItem->fConfigView = new BView( rect, "config view",
441                                          B_FOLLOW_NONE, B_WILL_DRAW );
442     stringItem->fConfigView->SetViewColor(
443             ui_color( B_PANEL_BACKGROUND_COLOR ) );
444
445     /* Add all the settings options */
446     rect = stringItem->fConfigView->Bounds();
447     rect.InsetBy( 10, 10 );
448
449     ConfigTextControl * textControl;
450     ConfigCheckBox    * checkBox;
451     ConfigMenuField   * menuField;
452     ConfigSlider      * slider;
453     ConfigKey         * keyConfig;
454
455     for( ; (*pp_item)->i_type != CONFIG_HINT_END; (*pp_item)++ )
456     {
457         if( stop_after_category &&
458             (*pp_item)->i_type == CONFIG_HINT_CATEGORY )
459         {
460             break;
461         }
462
463         switch( (*pp_item)->i_type )
464         {
465             case CONFIG_ITEM_STRING:
466             case CONFIG_ITEM_FILE:
467             case CONFIG_ITEM_MODULE:
468             case CONFIG_ITEM_DIRECTORY:
469                 if( (*pp_item)->ppsz_list && (*pp_item)->ppsz_list[0] )
470                 {
471                     menuField = new ConfigMenuField( rect,
472                             (*pp_item)->i_type, (*pp_item)->psz_text,
473                             (*pp_item)->psz_name, (*pp_item)->ppsz_list );
474                     stringItem->fConfigView->AddChild( menuField );
475                     rect.top += menuField->Bounds().Height();
476                 }
477                 else
478                 {
479                     textControl = new ConfigTextControl( rect,
480                             (*pp_item)->i_type, (*pp_item)->psz_text,
481                             (*pp_item)->psz_name );
482                     stringItem->fConfigView->AddChild( textControl );
483                     rect.top += textControl->Bounds().Height();
484                 }
485                 break;
486
487             case CONFIG_ITEM_INTEGER:
488                 if( (*pp_item)->i_min == (*pp_item)->i_max )
489                 {
490                     textControl = new ConfigTextControl( rect,
491                             CONFIG_ITEM_INTEGER, (*pp_item)->psz_text,
492                             (*pp_item)->psz_name );
493                     stringItem->fConfigView->AddChild( textControl );
494                     rect.top += textControl->Bounds().Height();
495                 }
496                 else
497                 {
498                     slider = new ConfigSlider( rect, CONFIG_ITEM_INTEGER,
499                             (*pp_item)->psz_text, (*pp_item)->psz_name,
500                             (*pp_item)->i_min, (*pp_item)->i_max );
501                     stringItem->fConfigView->AddChild( slider );
502                     rect.top += slider->Bounds().Height();
503                 }
504                 break;
505
506             case CONFIG_ITEM_FLOAT:
507                 if( (*pp_item)->f_min == (*pp_item)->f_max )
508                 {
509                     textControl = new ConfigTextControl( rect,
510                             CONFIG_ITEM_FLOAT, (*pp_item)->psz_text,
511                             (*pp_item)->psz_name );
512                     stringItem->fConfigView->AddChild( textControl );
513                     rect.top += textControl->Bounds().Height();
514                 }
515                 else
516                 {
517                     slider = new ConfigSlider( rect, CONFIG_ITEM_FLOAT,
518                             (*pp_item)->psz_text, (*pp_item)->psz_name,
519                             100 * (*pp_item)->f_min, 100 * (*pp_item)->f_max );
520                     stringItem->fConfigView->AddChild( slider );
521                     rect.top += slider->Bounds().Height();
522                 }
523                 break;
524
525             case CONFIG_ITEM_BOOL:
526                 checkBox = new ConfigCheckBox( rect,
527                         CONFIG_ITEM_BOOL, (*pp_item)->psz_text,
528                         (*pp_item)->psz_name );
529                 stringItem->fConfigView->AddChild( checkBox );
530                 rect.top += checkBox->Bounds().Height();
531                 break;
532
533             case CONFIG_ITEM_KEY:
534                 keyConfig = new ConfigKey( rect, CONFIG_ITEM_KEY,
535                         (*pp_item)->psz_text, (*pp_item)->psz_name );
536                 stringItem->fConfigView->AddChild( keyConfig );
537                 rect.top += keyConfig->Bounds().Height();
538         }
539     }
540
541     /* Put the BView into a BScrollView */
542     stringItem->fConfigScroll =
543         new BScrollView( "config scroll", stringItem->fConfigView,
544                          B_FOLLOW_ALL, 0, false, true, B_FANCY_BORDER );
545     stringItem->fConfigScroll->SetViewColor(
546             ui_color( B_PANEL_BACKGROUND_COLOR ) );
547     stringItem->fConfigBox->AddChild( stringItem->fConfigScroll );
548
549     /* Adjust the configView size */
550     stringItem->fConfigView->ResizeTo(
551         stringItem->fConfigView->Bounds().Width(), rect.top );
552 }
553
554 ConfigWidget::ConfigWidget( BRect rect, int type, char * configName )
555     : BView( rect, NULL, B_FOLLOW_ALL, B_WILL_DRAW )
556 {
557     fConfigType = type;
558     fConfigName = strdup( configName );
559     SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
560 }
561
562 ConfigTextControl::ConfigTextControl( BRect rect, int type, char * label,
563                                       char * configName )
564     : ConfigWidget( BRect( rect.left, rect.top,
565                            rect.right, rect.top + 25 ),
566                     type, configName )
567 {
568     fTextControl = new BTextControl( Bounds(), NULL, label, NULL,
569                                      new BMessage() );
570     AddChild( fTextControl );
571 }
572
573 void ConfigTextControl::Apply( intf_thread_t * p_intf, bool doIt )
574 {
575     char string[1024];
576
577     switch( fConfigType )
578     {
579         case CONFIG_ITEM_STRING:
580         case CONFIG_ITEM_FILE:
581         case CONFIG_ITEM_MODULE:
582         case CONFIG_ITEM_DIRECTORY:
583             if( doIt )
584             {
585                 config_PutPsz( p_intf, fConfigName, fTextControl->Text() );
586             }
587             else
588             {
589                 fTextControl->SetText( config_GetPsz( p_intf, fConfigName ) );
590             }
591             break;
592         case CONFIG_ITEM_INTEGER:
593             if( doIt )
594             {
595                 config_PutInt( p_intf, fConfigName,
596                                atoi( fTextControl->Text() ) );
597             }
598             else
599             {
600                 memset( string, 0, 1024 );
601                 snprintf( string, 1023, "%d",
602                           config_GetInt( p_intf, fConfigName ) );
603                 fTextControl->SetText( string );
604             }
605             break;
606         case CONFIG_ITEM_FLOAT:
607             if( doIt )
608             {
609                 config_PutFloat( p_intf, fConfigName,
610                                  strtod( fTextControl->Text(), NULL ) );
611             }
612             else
613             {
614                 memset( string, 0, 1024 );
615                 snprintf( string, 1023, "%f",
616                           config_GetFloat( p_intf, fConfigName ) );
617                 fTextControl->SetText( string );
618             }
619             break;
620     }
621 }
622
623 ConfigCheckBox::ConfigCheckBox( BRect rect, int type, char * label,
624                                 char * configName )
625     : ConfigWidget( BRect( rect.left, rect.top,
626                            rect.right, rect.top + 25 ),
627                     type, configName )
628 {
629     fCheckBox = new BCheckBox( Bounds(), NULL, label, new BMessage() );
630     AddChild( fCheckBox );
631 }
632
633 void ConfigCheckBox::Apply( intf_thread_t * p_intf, bool doIt )
634 {
635     if( doIt )
636     {
637         config_PutInt( p_intf, fConfigName, fCheckBox->Value() );
638     }
639     else
640     {
641         fCheckBox->SetValue( config_GetInt( p_intf, fConfigName ) );
642     }
643 }
644
645 ConfigMenuField::ConfigMenuField( BRect rect, int type, char * label,
646                                   char * configName, char ** list )
647     : ConfigWidget( BRect( rect.left, rect.top,
648                            rect.right, rect.top + 25 ),
649                     type, configName )
650 {
651     BMenuItem * menuItem;
652
653     fPopUpMenu = new BPopUpMenu( "" );
654     fMenuField = new BMenuField( Bounds(), NULL, label, fPopUpMenu );
655
656     for( int i = 0; list[i]; i++ )
657     {
658         menuItem = new BMenuItem( list[i], new BMessage() );
659         fPopUpMenu->AddItem( menuItem );
660     }
661
662     AddChild( fMenuField );
663 }
664
665 void ConfigMenuField::Apply( intf_thread_t * p_intf, bool doIt )
666 {
667     BMenuItem * menuItem;
668
669     if( doIt )
670     {
671         menuItem = fPopUpMenu->FindMarked();
672         if( menuItem )
673         {
674             config_PutPsz( p_intf, fConfigName, menuItem->Label() );
675         }
676     }
677     else
678     {
679         char * value = config_GetPsz( p_intf, fConfigName );
680         if( !value )
681         {
682             value = "";
683         }
684
685         for( int i = 0; i < fPopUpMenu->CountItems(); i++ )
686         {
687             menuItem = fPopUpMenu->ItemAt( i );
688             if( !strcmp( value, menuItem->Label() ) )
689             {
690                 menuItem->SetMarked( true );
691                 break;
692             }
693         }
694     }
695 }
696
697 ConfigSlider::ConfigSlider( BRect rect, int type, char * label,
698                             char * configName, int min, int max )
699     : ConfigWidget( BRect( rect.left, rect.top,
700                            rect.right, rect.top + 40 ),
701                     type, configName )
702 {
703     fSlider = new BSlider( Bounds(), NULL, label, new BMessage(),
704                            min, max, B_TRIANGLE_THUMB );
705     AddChild( fSlider );
706 }
707
708 void ConfigSlider::Apply( intf_thread_t * p_intf, bool doIt )
709 {
710     switch( fConfigType )
711     {
712         case CONFIG_ITEM_INTEGER:
713             if( doIt )
714             {
715                 config_PutInt( p_intf, fConfigName, fSlider->Value() );
716             }
717             else
718             {
719                 fSlider->SetValue( config_GetInt( p_intf, fConfigName ) );
720             }
721             break;
722
723         case CONFIG_ITEM_FLOAT:
724             if( doIt )
725             {
726                 config_PutFloat( p_intf, fConfigName,
727                                  (float) fSlider->Value() / 100.0 );
728             }
729             else
730             {
731                 fSlider->SetValue( 100 *
732                         config_GetFloat( p_intf, fConfigName ) );
733             }
734             break;
735     }
736 }
737
738 ConfigKey::ConfigKey( BRect rect, int type, char * label,
739                             char * configName )
740     : ConfigWidget( BRect( rect.left, rect.top,
741                            rect.right, rect.top + 25 ),
742                     type, configName )
743 {
744     BRect r = Bounds();
745     BMenuItem * menuItem;
746
747     r.left = r.right - 60;
748     fPopUpMenu = new BPopUpMenu( "" );
749     fMenuField = new BMenuField( r, NULL, NULL, fPopUpMenu );
750     for( unsigned i = 0;
751          i < sizeof( vlc_keys ) / sizeof( key_descriptor_t ); i++ )
752     {
753         menuItem = new BMenuItem( vlc_keys[i].psz_key_string, NULL );
754         fPopUpMenu->AddItem( menuItem );
755     }
756
757     r.right = r.left - 10; r.left = r.left - 60;
758     fShiftCheck = new BCheckBox( r, NULL, "Shift", new BMessage );
759
760     r.right = r.left - 10; r.left = r.left - 60;
761     fCtrlCheck = new BCheckBox( r, NULL, "Ctrl", new BMessage );
762
763     r.right = r.left - 10; r.left = r.left - 60;
764     fAltCheck = new BCheckBox( r, NULL, "Alt", new BMessage );
765
766     /* Can someone tell me how we're supposed to get GUI items aligned ? */
767     r.right = r.left - 10; r.left = 0;
768     r.bottom -= 10;
769     fStringView = new BStringView( r, NULL, label );
770
771     AddChild( fStringView );
772     AddChild( fAltCheck );
773     AddChild( fCtrlCheck );
774     AddChild( fShiftCheck );
775     AddChild( fMenuField );
776 }
777
778 void ConfigKey::Apply( intf_thread_t * p_intf, bool doIt )
779 {
780     BMenuItem * menuItem;
781
782     if( doIt )
783     {
784         menuItem = fPopUpMenu->FindMarked();
785         if( menuItem )
786         {
787             int value = vlc_keys[fPopUpMenu->IndexOf( menuItem )].i_key_code;
788             if( fAltCheck->Value() )
789             {
790                 value |= KEY_MODIFIER_ALT;
791             }
792             if( fCtrlCheck->Value() )
793             {
794                 value |= KEY_MODIFIER_CTRL;
795             }
796             if( fShiftCheck->Value() )
797             {
798                 value |= KEY_MODIFIER_SHIFT;
799             }
800             config_PutInt( p_intf, fConfigName, value );
801         }
802     }
803     else
804     {
805         int value = config_GetInt( p_intf, fConfigName );
806         fAltCheck->SetValue( value & KEY_MODIFIER_ALT );
807         fCtrlCheck->SetValue( value & KEY_MODIFIER_CTRL );
808         fShiftCheck->SetValue( value & KEY_MODIFIER_SHIFT );
809
810         for( unsigned i = 0;
811              i < sizeof( vlc_keys ) / sizeof( key_descriptor_t ); i++ )
812         {
813             if( (unsigned) vlc_keys[i].i_key_code ==
814                     ( value & ~KEY_MODIFIER ) )
815             {
816                 menuItem = fPopUpMenu->ItemAt( i );
817                 menuItem->SetMarked( true );
818                 break;
819             }
820         }
821     }
822 }
823