1 /*****************************************************************************
2 * PreferencesWindow.cpp: beos interface
3 *****************************************************************************
4 * Copyright (C) 1999, 2000, 2001 VideoLAN
5 * $Id: PreferencesWindow.cpp,v 1.24 2003/05/25 17:21:36 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() */
29 #include "PreferencesWindow.h"
32 - add the needed LockLooper()s
33 - fix horizontal window resizing */
35 /* We use this function to order the items of the BOutlineView */
36 int compare_func( const BListItem * _first, const BListItem * _second )
38 StringItemWithView * first = (StringItemWithView*) _first;
39 StringItemWithView * second = (StringItemWithView*) _second;
41 /* The Modules tree at last */
42 if( !strcmp( first->Text(), _( "Modules" ) ) )
44 if( !strcmp( second->Text(), _( "Modules" ) ) )
47 /* alphabetic order */
48 return( strcmp( first->Text(), second->Text() ) );
51 /*****************************************************************************
52 * PreferencesWindow::PreferencesWindow
53 *****************************************************************************/
54 PreferencesWindow::PreferencesWindow( intf_thread_t * p_interface,
55 BRect frame, const char * name )
56 : BWindow( frame, name, B_FLOATING_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
57 B_NOT_ZOOMABLE | B_NOT_H_RESIZABLE ),
58 fConfigScroll( NULL ),
61 SetSizeLimits( PREFS_WINDOW_WIDTH, PREFS_WINDOW_WIDTH,
66 /* The "background" view */
67 fPrefsView = new BView( Bounds(), NULL, B_FOLLOW_ALL, B_WILL_DRAW );
68 fPrefsView->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
69 AddChild( fPrefsView );
71 /* Create the preferences tree */
73 rect.InsetBy( 10, 10 );
74 rect.right = rect.left + 150;
75 fOutline = new BOutlineListView( rect, "preferences tree",
76 B_SINGLE_SELECTION_LIST,
77 B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM );
78 BScrollView * scrollview = new BScrollView( "scrollview", fOutline,
79 B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM,
81 fPrefsView->AddChild( scrollview );
83 /* We need to be informed if the user selects an item */
84 fOutline->SetSelectionMessage( new BMessage( PREFS_ITEM_SELECTED ) );
86 /* Create a dummy view so we can correctly place the real config views later */
88 rect.left = rect.right + 15 + B_V_SCROLL_BAR_WIDTH;
89 rect.right = Bounds().right - 15;
90 fDummyView = new BView( rect, "", B_FOLLOW_ALL_SIDES, B_WILL_DRAW );
91 fDummyView->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
92 fPrefsView->AddChild( fDummyView );
94 /* Add a category for modules configuration */
95 StringItemWithView * modulesItem;
96 modulesItem = new StringItemWithView( _("Modules") );
97 fOutline->AddItem( modulesItem );
101 p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
104 msg_Warn( p_intf, "couldn't find any module !" );
108 /* First, handle the main module */
109 module_t * p_module = NULL;
110 module_config_t * p_item;
111 for( int i = 0; i < p_list->i_count; i++ )
113 p_module = (module_t*) p_list->p_values[i].p_object;
115 if( !strcmp( p_module->psz_object_name, "main" ) &&
116 ( p_item = p_module->p_config ) )
124 /* We found the main module */
125 while( p_item->i_type == CONFIG_HINT_CATEGORY )
127 StringItemWithView * stringItem;
128 stringItem = new StringItemWithView( p_item->psz_text );
130 BuildConfigView( stringItem, &p_item, true );
131 fOutline->AddItem( stringItem );
135 for( int i = 0; i < p_list->i_count; i++ )
137 p_module = (module_t*) p_list->p_values[i].p_object;
139 if( !strcmp( p_module->psz_object_name, "main" ) )
142 /* If the module has no config option, ignore it */
143 p_item = p_module->p_config;
147 if( p_item->i_type & CONFIG_ITEM )
149 } while( p_item->i_type != CONFIG_HINT_END && p_item++ );
150 if( p_item->i_type == CONFIG_HINT_END )
153 /* Create the capability tree if it doesn't already exist */
154 char * psz_capability;
155 psz_capability = p_module->psz_capability;
156 if( !psz_capability || !*psz_capability )
158 /* Empty capability ? Let's look at the submodules */
159 module_t * p_submodule;
160 for( int j = 0; j < p_module->i_children; j++ )
162 p_submodule = (module_t*)p_module->pp_children[ j ];
163 if( p_submodule->psz_capability && *p_submodule->psz_capability )
165 psz_capability = p_submodule->psz_capability;
171 StringItemWithView * capabilityItem;
172 capabilityItem = NULL;
173 for( int j = 0; j < fOutline->CountItemsUnder( modulesItem, true ); j++ )
175 if( !strcmp( ((StringItemWithView*)
176 fOutline->ItemUnderAt( modulesItem, true, j ))->Text(),
179 capabilityItem = (StringItemWithView*)
180 fOutline->ItemUnderAt( modulesItem, true, j );
184 if( !capabilityItem )
186 capabilityItem = new StringItemWithView( psz_capability );
187 fOutline->AddUnder( capabilityItem, modulesItem );
190 /* Now add the item ! */
191 StringItemWithView * stringItem;
192 stringItem = new StringItemWithView( p_module->psz_object_name );
193 BuildConfigView( stringItem, &p_item, false );
194 fOutline->AddUnder( stringItem, capabilityItem );
197 vlc_list_release( p_list );
199 /* Set the correct values */
200 ApplyChanges( false );
202 /* Sort items, collapse the tree */
203 fOutline->FullListSortItems( compare_func );
204 fOutline->Collapse( modulesItem );
205 for( int i = 0; i < fOutline->CountItemsUnder( modulesItem, true ); i++ )
206 fOutline->Collapse( fOutline->ItemUnderAt( modulesItem, true, i ) );
208 /* Select the first item */
209 fOutline->Select( 0 );
211 /* Add the buttons */
214 rect.InsetBy( 10, 10 );
215 rect.left = rect.right - 80;
216 rect.top = rect.bottom - 25;
217 button = new BButton( rect, "", _("Apply"), new BMessage( PREFS_APPLY ),
218 B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM );
219 button->MakeDefault( true );
220 fPrefsView->AddChild( button );
221 rect.OffsetBy( -90, 0 );
222 button = new BButton( rect, "", _("Save"), new BMessage( PREFS_SAVE ),
223 B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM );
224 fPrefsView->AddChild( button );
225 rect.OffsetBy( -90, 0 );
226 button = new BButton( rect, "", _("Defaults"), new BMessage( PREFS_DEFAULTS ),
227 B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM );
228 fPrefsView->AddChild( button );
234 /*****************************************************************************
235 * PreferencesWindow::~PreferencesWindow
236 *****************************************************************************/
237 PreferencesWindow::~PreferencesWindow()
241 /*****************************************************************************
242 * PreferencesWindow::QuitRequested
243 *****************************************************************************/
244 bool PreferencesWindow::QuitRequested()
251 /*****************************************************************************
252 * PreferencesWindow::MessageReceived
253 *****************************************************************************/
254 void PreferencesWindow::MessageReceived( BMessage * message )
256 switch( message->what )
258 case PREFS_ITEM_SELECTED:
263 config_ResetAll( p_intf );
264 ApplyChanges( false );
268 ApplyChanges( true );
276 BWindow::MessageReceived( message );
280 /*****************************************************************************
281 * PreferencesWindow::FrameResized
282 *****************************************************************************/
283 void PreferencesWindow::FrameResized( float width, float height )
285 BWindow::FrameResized( width, height );
290 /*****************************************************************************
291 * PreferencesWindow::Update
292 *****************************************************************************/
293 void PreferencesWindow::Update()
295 /* Get the selected item, if any */
296 if( fOutline->CurrentSelection() < 0 )
298 fCurrent = (StringItemWithView*)
299 fOutline->ItemAt( fOutline->CurrentSelection() );
301 if( !fCurrent->fConfigBox )
302 /* This is a category */
305 /* Detach the old item */
306 if( fDummyView->CountChildren() > 0 )
307 fDummyView->RemoveChild( fDummyView->ChildAt( 0 ) );
309 /* Resize and show the new config box */
310 fCurrent->fConfigBox->ResizeTo( fDummyView->Bounds().Width(),
311 fDummyView->Bounds().Height() );
312 fDummyView->AddChild( fCurrent->fConfigBox );
314 /* Force redrawing of its children */
315 BRect rect = fCurrent->fConfigBox->Bounds();
316 rect.InsetBy( 10,10 );
318 fCurrent->fConfigScroll->ResizeTo( rect.Width(), rect.Height() );
319 fCurrent->fConfigScroll->Draw( fCurrent->fConfigScroll->Bounds() );
325 /*****************************************************************************
326 * PreferencesWindow::UpdateScrollBar
327 *****************************************************************************/
328 void PreferencesWindow::UpdateScrollBar()
330 /* We have to fix the scrollbar manually because it doesn't handle
331 correctly simple BViews */
336 /* Get the available BRect for display */
337 BRect display = fCurrent->fConfigScroll->Bounds();
338 display.right -= B_V_SCROLL_BAR_WIDTH;
340 /* Fix the scrollbar */
341 BScrollBar * scrollBar;
343 BRect visible = display & fCurrent->fConfigView->Bounds();
344 BRect total = display | fCurrent->fConfigView->Bounds();
345 scrollBar = fCurrent->fConfigScroll->ScrollBar( B_VERTICAL );
346 max = (long)( fCurrent->fConfigView->Bounds().Height() - visible.Height() );
347 if( max < 0 ) max = 0;
348 scrollBar->SetRange( 0, max );
349 scrollBar->SetProportion( visible.Height() / total.Height() );
350 scrollBar->SetSteps( 10, 100 );
353 /*****************************************************************************
354 * PreferencesWindow::ApplyChanges
355 * Apply changes if doIt is true, revert them otherwise
356 *****************************************************************************/
357 void PreferencesWindow::ApplyChanges( bool doIt )
359 StringItemWithView * item;
364 for( int i = 0; i < fOutline->CountItems(); i++ )
366 item = (StringItemWithView*) fOutline->ItemAt( i );
367 view = item->fConfigView;
370 /* This is a category */
373 for( int j = 0; j < view->CountChildren(); j++ )
375 child = view->ChildAt( j );
376 name = child->Name();
377 if( !strcmp( name, "ConfigTextControl" ) )
379 ConfigTextControl * textControl;
380 textControl = (ConfigTextControl*) child;
381 switch( textControl->fConfigType )
383 case CONFIG_ITEM_STRING:
385 config_PutPsz( p_intf, textControl->fConfigName, textControl->Text() );
387 textControl->SetText( config_GetPsz( p_intf, textControl->fConfigName ) );
389 case CONFIG_ITEM_INTEGER:
391 config_PutInt( p_intf, textControl->fConfigName, atoi( textControl->Text() ) );
395 string << config_GetInt( p_intf, textControl->fConfigName );
396 textControl->SetText( string.String() );
399 case CONFIG_ITEM_FLOAT:
401 config_PutFloat( p_intf, textControl->fConfigName,
402 strtod( textControl->Text(), NULL ) );
406 string << config_GetFloat( p_intf, textControl->fConfigName );
407 textControl->SetText( string.String() );
412 else if( !strcmp( name, "ConfigCheckBox" ) )
414 ConfigCheckBox * checkBox;
415 checkBox = (ConfigCheckBox*) child;
417 config_PutInt( p_intf, checkBox->fConfigName, checkBox->Value() );
419 checkBox->SetValue( config_GetInt( p_intf, checkBox->fConfigName ) );
421 else if( !strcmp( name, "ConfigMenuField" ) )
423 ConfigMenuField * menuField;
424 menuField = (ConfigMenuField*) child;
426 BMenuItem * menuItem;
427 menu = menuField->Menu();
430 menuItem = menu->FindMarked();
432 config_PutPsz( p_intf, menuField->fConfigName, menuItem->Label() );
437 value = config_GetPsz( p_intf, menuField->fConfigName );
438 if( !value ) value = "";
439 for( int k = 0; k < menu->CountItems(); k++ )
441 menuItem = menu->ItemAt( k );
442 if( !strcmp( value, menuItem->Label() ) )
444 menuItem->SetMarked( true );
450 else if( !strcmp( name, "ConfigSlider" ) )
452 ConfigSlider * slider;
453 slider = (ConfigSlider*) child;
455 switch( slider->fConfigType )
457 case CONFIG_ITEM_INTEGER:
459 config_PutInt( p_intf, slider->fConfigName,
462 slider->SetValue( config_GetInt( p_intf,
463 slider->fConfigName ) );
466 case CONFIG_ITEM_FLOAT:
468 config_PutFloat( p_intf, slider->fConfigName,
469 (float)slider->Value() / 100.0 );
471 slider->SetValue( config_GetFloat( p_intf,
472 slider->fConfigName ) * 100.0 );
480 /*****************************************************************************
481 * PreferencesWindow::SaveChanges
482 *****************************************************************************/
483 void PreferencesWindow::SaveChanges()
485 ApplyChanges( true );
486 config_SaveConfigFile( p_intf, NULL );
489 /*****************************************************************************
490 * PreferencesWindow::ReallyQuit
491 *****************************************************************************/
492 void PreferencesWindow::ReallyQuit()
499 /*****************************************************************************
500 * PreferencesWindow::BuildConfigView
501 *****************************************************************************/
502 void PreferencesWindow::BuildConfigView( StringItemWithView * stringItem,
503 module_config_t ** pp_item,
504 bool stop_after_category )
507 BRect rect = fDummyView->Bounds();
508 stringItem->fConfigBox = new BBox( rect, "config box", B_FOLLOW_ALL );
509 stringItem->fConfigBox->SetLabel( stringItem->fText );
511 /* Build the BView */
512 rect = stringItem->fConfigBox->Bounds();
513 rect.InsetBy( 10,10 );
515 rect.right -= B_V_SCROLL_BAR_WIDTH + 5;
516 stringItem->fConfigView = new BView( rect, "config view",
517 B_FOLLOW_NONE, B_WILL_DRAW );
518 stringItem->fConfigView->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
520 /* Add all the settings options */
521 rect = stringItem->fConfigView->Bounds();
522 rect.InsetBy( 10, 10 );
523 ConfigTextControl * textControl;
524 ConfigCheckBox * checkBox;
525 ConfigMenuField * menuField;
526 ConfigSlider * slider;
529 for( ; (*pp_item)->i_type != CONFIG_HINT_END; (*pp_item)++ )
531 if( stop_after_category && (*pp_item)->i_type == CONFIG_HINT_CATEGORY )
534 /* Discard a few options */
535 if( (*pp_item)->psz_name &&
536 ( !strcmp( (*pp_item)->psz_name, "volume" ) ||
537 !strcmp( (*pp_item)->psz_name, "saved-volume" ) ||
538 !strcmp( (*pp_item)->psz_name, "advanced" ) ) )
541 switch( (*pp_item)->i_type )
543 case CONFIG_ITEM_STRING:
544 case CONFIG_ITEM_FILE:
545 case CONFIG_ITEM_MODULE:
546 case CONFIG_ITEM_DIRECTORY:
547 if( (*pp_item)->ppsz_list && (*pp_item)->ppsz_list[0] )
549 rect.bottom = rect.top + 20;
550 popUp = new BPopUpMenu( "" );
551 menuField = new ConfigMenuField( rect, (*pp_item)->psz_text,
552 popUp, (*pp_item)->psz_name );
553 BMenuItem * menuItem;
554 for( int i = 0; (*pp_item)->ppsz_list[i]; i++ )
556 menuItem = new BMenuItem( (*pp_item)->ppsz_list[i], new BMessage() );
557 popUp->AddItem( menuItem );
559 stringItem->fConfigView->AddChild( menuField );
560 rect.top = rect.bottom + 10;
564 rect.bottom = rect.top + 20;
565 textControl = new ConfigTextControl( rect, (*pp_item)->psz_text,
566 CONFIG_ITEM_STRING, (*pp_item)->psz_name );
567 stringItem->fConfigView->AddChild( textControl );
568 rect.top = rect.bottom + 10;
572 case CONFIG_ITEM_INTEGER:
574 if( (*pp_item)->i_min == (*pp_item)->i_max )
576 rect.bottom = rect.top + 20;
577 textControl = new ConfigTextControl( rect, (*pp_item)->psz_text,
579 (*pp_item)->psz_name );
580 stringItem->fConfigView->AddChild( textControl );
581 rect.top = rect.bottom + 10;
585 rect.bottom = rect.top + 30;
586 slider = new ConfigSlider( rect, (*pp_item)->psz_text,
587 CONFIG_ITEM_INTEGER, (*pp_item)->i_min,
588 (*pp_item)->i_max, (*pp_item)->psz_name );
589 stringItem->fConfigView->AddChild( slider );
590 rect.top = rect.bottom + 10;
594 case CONFIG_ITEM_FLOAT:
595 if( (*pp_item)->f_min == (*pp_item)->f_max )
597 rect.bottom = rect.top + 20;
598 textControl = new ConfigTextControl( rect, (*pp_item)->psz_text,
599 CONFIG_ITEM_FLOAT, (*pp_item)->psz_name );
600 stringItem->fConfigView->AddChild( textControl );
601 rect.top = rect.bottom + 10;
605 rect.bottom = rect.top + 30;
606 slider = new ConfigSlider( rect, (*pp_item)->psz_text,
607 CONFIG_ITEM_FLOAT, 100 * (*pp_item)->f_min,
608 100 * (*pp_item)->f_max, (*pp_item)->psz_name );
609 stringItem->fConfigView->AddChild( slider );
610 rect.top = rect.bottom + 10;
614 case CONFIG_ITEM_BOOL:
615 rect.bottom = rect.top + 20;
616 checkBox = new ConfigCheckBox( rect, (*pp_item)->psz_text,
617 (*pp_item)->psz_name );
618 stringItem->fConfigView->AddChild( checkBox );
619 rect.top = rect.bottom + 10;
624 /* Put the BView into a BScrollView */
626 stringItem->fConfigScroll =
627 new BScrollView( "config scroll", stringItem->fConfigView,
628 B_FOLLOW_ALL, 0, false, true, B_FANCY_BORDER );
629 stringItem->fConfigScroll->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
630 stringItem->fConfigBox->AddChild( stringItem->fConfigScroll );
632 /* Adjust the configView size */
633 stringItem->fConfigView->ResizeTo(
634 stringItem->fConfigView->Bounds().Width(), rect.top );