1 /*****************************************************************************
2 * PreferencesWindow.cpp: beos interface
3 *****************************************************************************
4 * Copyright (C) 1999, 2000, 2001 VideoLAN
5 * $Id: PreferencesWindow.cpp,v 1.27 2003/12/22 00:06:05 titer Exp $
7 * Authors: Eric Petit <titer@videolan.org>
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 #include <stdlib.h> /* atoi(), strtod() */
32 #include "PreferencesWindow.h"
35 - add the needed LockLooper()s
36 - fix window resizing */
38 /* We use this function to order the items of the BOutlineView */
39 static int compare_func( const BListItem * _first,
40 const BListItem * _second )
42 StringItemWithView * first = (StringItemWithView*) _first;
43 StringItemWithView * second = (StringItemWithView*) _second;
45 /* The Modules tree at last */
46 if( !strcmp( first->Text(), _( "Modules" ) ) )
48 if( !strcmp( second->Text(), _( "Modules" ) ) )
51 /* alphabetic order */
52 return( strcmp( first->Text(), second->Text() ) );
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 ),
65 SetSizeLimits( PREFS_WINDOW_WIDTH, PREFS_WINDOW_WIDTH,
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 );
75 /* Create the preferences tree */
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,
86 fPrefsView->AddChild( scrollview );
88 /* We need to be informed if the user selects an item */
89 fOutline->SetSelectionMessage( new BMessage( PREFS_ITEM_SELECTED ) );
91 /* Create a dummy view so we can correctly place the real config
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 );
100 /* Add a category for modules configuration */
101 StringItemWithView * modulesItem;
102 modulesItem = new StringItemWithView( _("Modules") );
103 fOutline->AddItem( modulesItem );
107 p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
110 msg_Warn( p_intf, "couldn't find any module !" );
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++ )
119 p_module = (module_t*) p_list->p_values[i].p_object;
121 if( !strcmp( p_module->psz_object_name, "main" ) &&
122 ( p_item = p_module->p_config ) )
130 /* We found the main module */
131 while( p_item->i_type == CONFIG_HINT_CATEGORY )
133 StringItemWithView * stringItem;
134 stringItem = new StringItemWithView( p_item->psz_text );
136 BuildConfigView( stringItem, &p_item, true );
137 fOutline->AddItem( stringItem );
141 for( int i = 0; i < p_list->i_count; i++ )
143 p_module = (module_t*) p_list->p_values[i].p_object;
145 if( !strcmp( p_module->psz_object_name, "main" ) )
148 /* If the module has no config option, ignore it */
149 p_item = p_module->p_config;
156 if( p_item->i_type & CONFIG_ITEM )
160 } while( p_item->i_type != CONFIG_HINT_END && p_item++ );
162 if( p_item->i_type == CONFIG_HINT_END )
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 )
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++ )
176 p_submodule = (module_t*)p_module->pp_children[ j ];
177 if( p_submodule->psz_capability &&
178 *p_submodule->psz_capability )
180 psz_capability = p_submodule->psz_capability;
186 StringItemWithView * capabilityItem;
187 capabilityItem = NULL;
189 j < fOutline->CountItemsUnder( modulesItem, true ); j++ )
191 if( !strcmp( ((StringItemWithView*)
192 fOutline->ItemUnderAt( modulesItem, true, j ))->Text(),
195 capabilityItem = (StringItemWithView*)
196 fOutline->ItemUnderAt( modulesItem, true, j );
200 if( !capabilityItem )
202 capabilityItem = new StringItemWithView( psz_capability );
203 fOutline->AddUnder( capabilityItem, modulesItem );
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 );
213 vlc_list_release( p_list );
215 /* Set the correct values */
216 ApplyChanges( false );
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 ) );
224 /* Select the first item */
225 fOutline->Select( 0 );
227 /* Add the buttons */
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 );
251 /*****************************************************************************
252 * PreferencesWindow::~PreferencesWindow
253 *****************************************************************************/
254 PreferencesWindow::~PreferencesWindow()
258 /*****************************************************************************
259 * PreferencesWindow::QuitRequested
260 *****************************************************************************/
261 bool PreferencesWindow::QuitRequested()
270 /*****************************************************************************
271 * PreferencesWindow::MessageReceived
272 *****************************************************************************/
273 void PreferencesWindow::MessageReceived( BMessage * message )
275 switch( message->what )
277 case PREFS_ITEM_SELECTED:
282 config_ResetAll( p_intf );
283 ApplyChanges( false );
287 ApplyChanges( true );
295 BWindow::MessageReceived( message );
299 /*****************************************************************************
300 * PreferencesWindow::FrameResized
301 *****************************************************************************/
302 void PreferencesWindow::FrameResized( float width, float height )
304 BWindow::FrameResized( width, height );
309 /*****************************************************************************
310 * PreferencesWindow::Update
311 *****************************************************************************/
312 void PreferencesWindow::Update()
314 /* Get the selected item, if any */
315 if( fOutline->CurrentSelection() < 0 )
317 fCurrent = (StringItemWithView*)
318 fOutline->ItemAt( fOutline->CurrentSelection() );
320 if( !fCurrent->fConfigBox )
321 /* This is a category */
324 /* Detach the old item */
325 if( fDummyView->CountChildren() > 0 )
326 fDummyView->RemoveChild( fDummyView->ChildAt( 0 ) );
328 /* Resize and show the new config box */
329 fCurrent->fConfigBox->ResizeTo( fDummyView->Bounds().Width(),
330 fDummyView->Bounds().Height() );
331 fDummyView->AddChild( fCurrent->fConfigBox );
333 /* Force redrawing of its children */
334 BRect rect = fCurrent->fConfigBox->Bounds();
335 rect.InsetBy( 10,10 );
337 fCurrent->fConfigScroll->ResizeTo( rect.Width(), rect.Height() );
338 fCurrent->fConfigScroll->Draw( fCurrent->fConfigScroll->Bounds() );
344 /*****************************************************************************
345 * PreferencesWindow::UpdateScrollBar
346 *****************************************************************************/
347 void PreferencesWindow::UpdateScrollBar()
349 /* We have to fix the scrollbar manually because it doesn't handle
350 correctly simple BViews */
357 /* Get the available BRect for display */
358 BRect display = fCurrent->fConfigScroll->Bounds();
359 display.right -= B_V_SCROLL_BAR_WIDTH;
361 /* Fix the scrollbar */
362 BScrollBar * scrollBar;
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 );
374 /*****************************************************************************
375 * PreferencesWindow::ApplyChanges
376 * Apply changes if doIt is true, revert them otherwise
377 *****************************************************************************/
378 void PreferencesWindow::ApplyChanges( bool doIt )
380 StringItemWithView * item;
382 ConfigWidget * child;
385 for( int i = 0; i < fOutline->CountItems(); i++ )
387 item = (StringItemWithView*) fOutline->ItemAt( i );
388 view = item->fConfigView;
392 /* This is a category */
396 for( int j = 0; j < view->CountChildren(); j++ )
398 child = (ConfigWidget*) view->ChildAt( j );
399 child->Apply( p_intf, doIt );
404 /*****************************************************************************
405 * PreferencesWindow::SaveChanges
406 *****************************************************************************/
407 void PreferencesWindow::SaveChanges()
409 ApplyChanges( true );
410 config_SaveConfigFile( p_intf, NULL );
413 /*****************************************************************************
414 * PreferencesWindow::ReallyQuit
415 *****************************************************************************/
416 void PreferencesWindow::ReallyQuit()
423 /*****************************************************************************
424 * PreferencesWindow::BuildConfigView
425 *****************************************************************************/
426 void PreferencesWindow::BuildConfigView( StringItemWithView * stringItem,
427 module_config_t ** pp_item,
428 bool stop_after_category )
431 BRect rect = fDummyView->Bounds();
432 stringItem->fConfigBox = new BBox( rect, "config box", B_FOLLOW_ALL );
433 stringItem->fConfigBox->SetLabel( stringItem->fText );
435 /* Build the BView */
436 rect = stringItem->fConfigBox->Bounds();
437 rect.InsetBy( 10,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 ) );
445 /* Add all the settings options */
446 rect = stringItem->fConfigView->Bounds();
447 rect.InsetBy( 10, 10 );
449 ConfigTextControl * textControl;
450 ConfigCheckBox * checkBox;
451 ConfigMenuField * menuField;
452 ConfigSlider * slider;
453 ConfigKey * keyConfig;
455 for( ; (*pp_item)->i_type != CONFIG_HINT_END; (*pp_item)++ )
457 if( stop_after_category &&
458 (*pp_item)->i_type == CONFIG_HINT_CATEGORY )
463 switch( (*pp_item)->i_type )
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] )
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();
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();
487 case CONFIG_ITEM_INTEGER:
488 if( (*pp_item)->i_min == (*pp_item)->i_max )
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();
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();
506 case CONFIG_ITEM_FLOAT:
507 if( (*pp_item)->f_min == (*pp_item)->f_max )
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();
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();
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();
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();
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 );
549 /* Adjust the configView size */
550 stringItem->fConfigView->ResizeTo(
551 stringItem->fConfigView->Bounds().Width(), rect.top );
554 ConfigWidget::ConfigWidget( BRect rect, int type, char * configName )
555 : BView( rect, NULL, B_FOLLOW_ALL, B_WILL_DRAW )
558 fConfigName = strdup( configName );
559 SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
562 ConfigTextControl::ConfigTextControl( BRect rect, int type, char * label,
564 : ConfigWidget( BRect( rect.left, rect.top,
565 rect.right, rect.top + 25 ),
568 fTextControl = new BTextControl( Bounds(), NULL, label, NULL,
570 AddChild( fTextControl );
573 void ConfigTextControl::Apply( intf_thread_t * p_intf, bool doIt )
577 switch( fConfigType )
579 case CONFIG_ITEM_STRING:
580 case CONFIG_ITEM_FILE:
581 case CONFIG_ITEM_MODULE:
582 case CONFIG_ITEM_DIRECTORY:
585 config_PutPsz( p_intf, fConfigName, fTextControl->Text() );
589 fTextControl->SetText( config_GetPsz( p_intf, fConfigName ) );
592 case CONFIG_ITEM_INTEGER:
595 config_PutInt( p_intf, fConfigName,
596 atoi( fTextControl->Text() ) );
600 memset( string, 0, 1024 );
601 snprintf( string, 1023, "%d",
602 config_GetInt( p_intf, fConfigName ) );
603 fTextControl->SetText( string );
606 case CONFIG_ITEM_FLOAT:
609 config_PutFloat( p_intf, fConfigName,
610 strtod( fTextControl->Text(), NULL ) );
614 memset( string, 0, 1024 );
615 snprintf( string, 1023, "%f",
616 config_GetFloat( p_intf, fConfigName ) );
617 fTextControl->SetText( string );
623 ConfigCheckBox::ConfigCheckBox( BRect rect, int type, char * label,
625 : ConfigWidget( BRect( rect.left, rect.top,
626 rect.right, rect.top + 25 ),
629 fCheckBox = new BCheckBox( Bounds(), NULL, label, new BMessage() );
630 AddChild( fCheckBox );
633 void ConfigCheckBox::Apply( intf_thread_t * p_intf, bool doIt )
637 config_PutInt( p_intf, fConfigName, fCheckBox->Value() );
641 fCheckBox->SetValue( config_GetInt( p_intf, fConfigName ) );
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 ),
651 BMenuItem * menuItem;
653 fPopUpMenu = new BPopUpMenu( "" );
654 fMenuField = new BMenuField( Bounds(), NULL, label, fPopUpMenu );
656 for( int i = 0; list[i]; i++ )
658 menuItem = new BMenuItem( list[i], new BMessage() );
659 fPopUpMenu->AddItem( menuItem );
662 AddChild( fMenuField );
665 void ConfigMenuField::Apply( intf_thread_t * p_intf, bool doIt )
667 BMenuItem * menuItem;
671 menuItem = fPopUpMenu->FindMarked();
674 config_PutPsz( p_intf, fConfigName, menuItem->Label() );
679 char * value = config_GetPsz( p_intf, fConfigName );
685 for( int i = 0; i < fPopUpMenu->CountItems(); i++ )
687 menuItem = fPopUpMenu->ItemAt( i );
688 if( !strcmp( value, menuItem->Label() ) )
690 menuItem->SetMarked( true );
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 ),
703 fSlider = new BSlider( Bounds(), NULL, label, new BMessage(),
704 min, max, B_TRIANGLE_THUMB );
708 void ConfigSlider::Apply( intf_thread_t * p_intf, bool doIt )
710 switch( fConfigType )
712 case CONFIG_ITEM_INTEGER:
715 config_PutInt( p_intf, fConfigName, fSlider->Value() );
719 fSlider->SetValue( config_GetInt( p_intf, fConfigName ) );
723 case CONFIG_ITEM_FLOAT:
726 config_PutFloat( p_intf, fConfigName,
727 (float) fSlider->Value() / 100.0 );
731 fSlider->SetValue( 100 *
732 config_GetFloat( p_intf, fConfigName ) );
738 ConfigKey::ConfigKey( BRect rect, int type, char * label,
740 : ConfigWidget( BRect( rect.left, rect.top,
741 rect.right, rect.top + 25 ),
745 BMenuItem * menuItem;
747 r.left = r.right - 60;
748 fPopUpMenu = new BPopUpMenu( "" );
749 fMenuField = new BMenuField( r, NULL, NULL, fPopUpMenu );
751 i < sizeof( vlc_keys ) / sizeof( key_descriptor_t ); i++ )
753 menuItem = new BMenuItem( vlc_keys[i].psz_key_string, NULL );
754 fPopUpMenu->AddItem( menuItem );
757 r.right = r.left - 10; r.left = r.left - 60;
758 fShiftCheck = new BCheckBox( r, NULL, "Shift", new BMessage );
760 r.right = r.left - 10; r.left = r.left - 60;
761 fCtrlCheck = new BCheckBox( r, NULL, "Ctrl", new BMessage );
763 r.right = r.left - 10; r.left = r.left - 60;
764 fAltCheck = new BCheckBox( r, NULL, "Alt", new BMessage );
766 /* Can someone tell me how we're supposed to get GUI items aligned ? */
767 r.right = r.left - 10; r.left = 0;
769 fStringView = new BStringView( r, NULL, label );
771 AddChild( fStringView );
772 AddChild( fAltCheck );
773 AddChild( fCtrlCheck );
774 AddChild( fShiftCheck );
775 AddChild( fMenuField );
778 void ConfigKey::Apply( intf_thread_t * p_intf, bool doIt )
780 BMenuItem * menuItem;
784 menuItem = fPopUpMenu->FindMarked();
787 int value = vlc_keys[fPopUpMenu->IndexOf( menuItem )].i_key_code;
788 if( fAltCheck->Value() )
790 value |= KEY_MODIFIER_ALT;
792 if( fCtrlCheck->Value() )
794 value |= KEY_MODIFIER_CTRL;
796 if( fShiftCheck->Value() )
798 value |= KEY_MODIFIER_SHIFT;
800 config_PutInt( p_intf, fConfigName, value );
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 );
811 i < sizeof( vlc_keys ) / sizeof( key_descriptor_t ); i++ )
813 if( (unsigned) vlc_keys[i].i_key_code ==
814 ( value & ~KEY_MODIFIER ) )
816 menuItem = fPopUpMenu->ItemAt( i );
817 menuItem->SetMarked( true );