1 /*****************************************************************************
2 * PreferencesWindow.cpp: beos interface
3 *****************************************************************************
4 * Copyright (C) 1999, 2000, 2001 VideoLAN
5 * $Id: PreferencesWindow.cpp,v 1.25 2003/05/27 13:22:45 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() */
31 #include "PreferencesWindow.h"
34 - add the needed LockLooper()s
35 - fix window resizing */
37 /* We use this function to order the items of the BOutlineView */
38 int compare_func( const BListItem * _first, const BListItem * _second )
40 StringItemWithView * first = (StringItemWithView*) _first;
41 StringItemWithView * second = (StringItemWithView*) _second;
43 /* The Modules tree at last */
44 if( !strcmp( first->Text(), _( "Modules" ) ) )
46 if( !strcmp( second->Text(), _( "Modules" ) ) )
49 /* alphabetic order */
50 return( strcmp( first->Text(), second->Text() ) );
53 /*****************************************************************************
54 * PreferencesWindow::PreferencesWindow
55 *****************************************************************************/
56 PreferencesWindow::PreferencesWindow( intf_thread_t * p_interface,
57 BRect frame, const char * name )
58 : BWindow( frame, name, B_FLOATING_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
59 B_NOT_ZOOMABLE | B_NOT_RESIZABLE ),
60 fConfigScroll( NULL ),
63 SetSizeLimits( PREFS_WINDOW_WIDTH, PREFS_WINDOW_WIDTH,
68 /* The "background" view */
69 fPrefsView = new BView( Bounds(), NULL, B_FOLLOW_ALL, B_WILL_DRAW );
70 fPrefsView->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
71 AddChild( fPrefsView );
73 /* Create the preferences tree */
75 rect.InsetBy( 10, 10 );
76 rect.right = rect.left + 150;
77 fOutline = new BOutlineListView( rect, "preferences tree",
78 B_SINGLE_SELECTION_LIST,
79 B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM );
80 BScrollView * scrollview = new BScrollView( "scrollview", fOutline,
81 B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM,
83 fPrefsView->AddChild( scrollview );
85 /* We need to be informed if the user selects an item */
86 fOutline->SetSelectionMessage( new BMessage( PREFS_ITEM_SELECTED ) );
88 /* Create a dummy view so we can correctly place the real config views later */
90 rect.left = rect.right + 15 + B_V_SCROLL_BAR_WIDTH;
91 rect.right = Bounds().right - 15;
92 fDummyView = new BView( rect, "", B_FOLLOW_ALL_SIDES, B_WILL_DRAW );
93 fDummyView->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
94 fPrefsView->AddChild( fDummyView );
96 /* Add a category for modules configuration */
97 StringItemWithView * modulesItem;
98 modulesItem = new StringItemWithView( _("Modules") );
99 fOutline->AddItem( modulesItem );
103 p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
106 msg_Warn( p_intf, "couldn't find any module !" );
110 /* First, handle the main module */
111 module_t * p_module = NULL;
112 module_config_t * p_item;
113 for( int i = 0; i < p_list->i_count; i++ )
115 p_module = (module_t*) p_list->p_values[i].p_object;
117 if( !strcmp( p_module->psz_object_name, "main" ) &&
118 ( p_item = p_module->p_config ) )
126 /* We found the main module */
127 while( p_item->i_type == CONFIG_HINT_CATEGORY )
129 StringItemWithView * stringItem;
130 stringItem = new StringItemWithView( p_item->psz_text );
132 BuildConfigView( stringItem, &p_item, true );
133 fOutline->AddItem( stringItem );
137 for( int i = 0; i < p_list->i_count; i++ )
139 p_module = (module_t*) p_list->p_values[i].p_object;
141 if( !strcmp( p_module->psz_object_name, "main" ) )
144 /* If the module has no config option, ignore it */
145 p_item = p_module->p_config;
149 if( p_item->i_type & CONFIG_ITEM )
151 } while( p_item->i_type != CONFIG_HINT_END && p_item++ );
152 if( p_item->i_type == CONFIG_HINT_END )
155 /* Create the capability tree if it doesn't already exist */
156 char * psz_capability;
157 psz_capability = p_module->psz_capability;
158 if( !psz_capability || !*psz_capability )
160 /* Empty capability ? Let's look at the submodules */
161 module_t * p_submodule;
162 for( int j = 0; j < p_module->i_children; j++ )
164 p_submodule = (module_t*)p_module->pp_children[ j ];
165 if( p_submodule->psz_capability && *p_submodule->psz_capability )
167 psz_capability = p_submodule->psz_capability;
173 StringItemWithView * capabilityItem;
174 capabilityItem = NULL;
175 for( int j = 0; j < fOutline->CountItemsUnder( modulesItem, true ); j++ )
177 if( !strcmp( ((StringItemWithView*)
178 fOutline->ItemUnderAt( modulesItem, true, j ))->Text(),
181 capabilityItem = (StringItemWithView*)
182 fOutline->ItemUnderAt( modulesItem, true, j );
186 if( !capabilityItem )
188 capabilityItem = new StringItemWithView( psz_capability );
189 fOutline->AddUnder( capabilityItem, modulesItem );
192 /* Now add the item ! */
193 StringItemWithView * stringItem;
194 stringItem = new StringItemWithView( p_module->psz_object_name );
195 BuildConfigView( stringItem, &p_item, false );
196 fOutline->AddUnder( stringItem, capabilityItem );
199 vlc_list_release( p_list );
201 /* Set the correct values */
202 ApplyChanges( false );
204 /* Sort items, collapse the tree */
205 fOutline->FullListSortItems( compare_func );
206 fOutline->Collapse( modulesItem );
207 for( int i = 0; i < fOutline->CountItemsUnder( modulesItem, true ); i++ )
208 fOutline->Collapse( fOutline->ItemUnderAt( modulesItem, true, i ) );
210 /* Select the first item */
211 fOutline->Select( 0 );
213 /* Add the buttons */
216 rect.InsetBy( 10, 10 );
217 rect.left = rect.right - 80;
218 rect.top = rect.bottom - 25;
219 button = new BButton( rect, "", _("Apply"), new BMessage( PREFS_APPLY ),
220 B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM );
221 button->MakeDefault( true );
222 fPrefsView->AddChild( button );
223 rect.OffsetBy( -90, 0 );
224 button = new BButton( rect, "", _("Save"), new BMessage( PREFS_SAVE ),
225 B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM );
226 fPrefsView->AddChild( button );
227 rect.OffsetBy( -90, 0 );
228 button = new BButton( rect, "", _("Defaults"), new BMessage( PREFS_DEFAULTS ),
229 B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM );
230 fPrefsView->AddChild( button );
236 /*****************************************************************************
237 * PreferencesWindow::~PreferencesWindow
238 *****************************************************************************/
239 PreferencesWindow::~PreferencesWindow()
243 /*****************************************************************************
244 * PreferencesWindow::QuitRequested
245 *****************************************************************************/
246 bool PreferencesWindow::QuitRequested()
253 /*****************************************************************************
254 * PreferencesWindow::MessageReceived
255 *****************************************************************************/
256 void PreferencesWindow::MessageReceived( BMessage * message )
258 switch( message->what )
260 case PREFS_ITEM_SELECTED:
265 config_ResetAll( p_intf );
266 ApplyChanges( false );
270 ApplyChanges( true );
278 BWindow::MessageReceived( message );
282 /*****************************************************************************
283 * PreferencesWindow::FrameResized
284 *****************************************************************************/
285 void PreferencesWindow::FrameResized( float width, float height )
287 BWindow::FrameResized( width, height );
292 /*****************************************************************************
293 * PreferencesWindow::Update
294 *****************************************************************************/
295 void PreferencesWindow::Update()
297 /* Get the selected item, if any */
298 if( fOutline->CurrentSelection() < 0 )
300 fCurrent = (StringItemWithView*)
301 fOutline->ItemAt( fOutline->CurrentSelection() );
303 if( !fCurrent->fConfigBox )
304 /* This is a category */
307 /* Detach the old item */
308 if( fDummyView->CountChildren() > 0 )
309 fDummyView->RemoveChild( fDummyView->ChildAt( 0 ) );
311 /* Resize and show the new config box */
312 fCurrent->fConfigBox->ResizeTo( fDummyView->Bounds().Width(),
313 fDummyView->Bounds().Height() );
314 fDummyView->AddChild( fCurrent->fConfigBox );
316 /* Force redrawing of its children */
317 BRect rect = fCurrent->fConfigBox->Bounds();
318 rect.InsetBy( 10,10 );
320 fCurrent->fConfigScroll->ResizeTo( rect.Width(), rect.Height() );
321 fCurrent->fConfigScroll->Draw( fCurrent->fConfigScroll->Bounds() );
327 /*****************************************************************************
328 * PreferencesWindow::UpdateScrollBar
329 *****************************************************************************/
330 void PreferencesWindow::UpdateScrollBar()
332 /* We have to fix the scrollbar manually because it doesn't handle
333 correctly simple BViews */
338 /* Get the available BRect for display */
339 BRect display = fCurrent->fConfigScroll->Bounds();
340 display.right -= B_V_SCROLL_BAR_WIDTH;
342 /* Fix the scrollbar */
343 BScrollBar * scrollBar;
345 BRect visible = display & fCurrent->fConfigView->Bounds();
346 BRect total = display | fCurrent->fConfigView->Bounds();
347 scrollBar = fCurrent->fConfigScroll->ScrollBar( B_VERTICAL );
348 max = (long)( fCurrent->fConfigView->Bounds().Height() - visible.Height() );
349 if( max < 0 ) max = 0;
350 scrollBar->SetRange( 0, max );
351 scrollBar->SetProportion( visible.Height() / total.Height() );
352 scrollBar->SetSteps( 10, 100 );
355 /*****************************************************************************
356 * PreferencesWindow::ApplyChanges
357 * Apply changes if doIt is true, revert them otherwise
358 *****************************************************************************/
359 void PreferencesWindow::ApplyChanges( bool doIt )
361 StringItemWithView * item;
366 for( int i = 0; i < fOutline->CountItems(); i++ )
368 item = (StringItemWithView*) fOutline->ItemAt( i );
369 view = item->fConfigView;
372 /* This is a category */
375 for( int j = 0; j < view->CountChildren(); j++ )
377 child = view->ChildAt( j );
378 name = child->Name();
379 if( !strcmp( name, "ConfigTextControl" ) )
381 ConfigTextControl * textControl;
382 textControl = (ConfigTextControl*) child;
383 switch( textControl->fConfigType )
385 case CONFIG_ITEM_STRING:
387 config_PutPsz( p_intf, textControl->fConfigName, textControl->Text() );
389 textControl->SetText( config_GetPsz( p_intf, textControl->fConfigName ) );
391 case CONFIG_ITEM_INTEGER:
393 config_PutInt( p_intf, textControl->fConfigName, atoi( textControl->Text() ) );
397 string << config_GetInt( p_intf, textControl->fConfigName );
398 textControl->SetText( string.String() );
401 case CONFIG_ITEM_FLOAT:
403 config_PutFloat( p_intf, textControl->fConfigName,
404 strtod( textControl->Text(), NULL ) );
408 string << config_GetFloat( p_intf, textControl->fConfigName );
409 textControl->SetText( string.String() );
414 else if( !strcmp( name, "ConfigCheckBox" ) )
416 ConfigCheckBox * checkBox;
417 checkBox = (ConfigCheckBox*) child;
419 config_PutInt( p_intf, checkBox->fConfigName, checkBox->Value() );
421 checkBox->SetValue( config_GetInt( p_intf, checkBox->fConfigName ) );
423 else if( !strcmp( name, "ConfigMenuField" ) )
425 ConfigMenuField * menuField;
426 menuField = (ConfigMenuField*) child;
428 BMenuItem * menuItem;
429 menu = menuField->Menu();
432 menuItem = menu->FindMarked();
434 config_PutPsz( p_intf, menuField->fConfigName, menuItem->Label() );
439 value = config_GetPsz( p_intf, menuField->fConfigName );
440 if( !value ) value = "";
441 for( int k = 0; k < menu->CountItems(); k++ )
443 menuItem = menu->ItemAt( k );
444 if( !strcmp( value, menuItem->Label() ) )
446 menuItem->SetMarked( true );
452 else if( !strcmp( name, "ConfigSlider" ) )
454 ConfigSlider * slider;
455 slider = (ConfigSlider*) child;
457 switch( slider->fConfigType )
459 case CONFIG_ITEM_INTEGER:
461 config_PutInt( p_intf, slider->fConfigName,
464 slider->SetValue( config_GetInt( p_intf,
465 slider->fConfigName ) );
468 case CONFIG_ITEM_FLOAT:
470 config_PutFloat( p_intf, slider->fConfigName,
471 (float)slider->Value() / 100.0 );
473 slider->SetValue( config_GetFloat( p_intf,
474 slider->fConfigName ) * 100.0 );
482 /*****************************************************************************
483 * PreferencesWindow::SaveChanges
484 *****************************************************************************/
485 void PreferencesWindow::SaveChanges()
487 ApplyChanges( true );
488 config_SaveConfigFile( p_intf, NULL );
491 /*****************************************************************************
492 * PreferencesWindow::ReallyQuit
493 *****************************************************************************/
494 void PreferencesWindow::ReallyQuit()
501 /*****************************************************************************
502 * PreferencesWindow::BuildConfigView
503 *****************************************************************************/
504 void PreferencesWindow::BuildConfigView( StringItemWithView * stringItem,
505 module_config_t ** pp_item,
506 bool stop_after_category )
509 BRect rect = fDummyView->Bounds();
510 stringItem->fConfigBox = new BBox( rect, "config box", B_FOLLOW_ALL );
511 stringItem->fConfigBox->SetLabel( stringItem->fText );
513 /* Build the BView */
514 rect = stringItem->fConfigBox->Bounds();
515 rect.InsetBy( 10,10 );
517 rect.right -= B_V_SCROLL_BAR_WIDTH + 5;
518 stringItem->fConfigView = new BView( rect, "config view",
519 B_FOLLOW_NONE, B_WILL_DRAW );
520 stringItem->fConfigView->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
522 /* Add all the settings options */
523 rect = stringItem->fConfigView->Bounds();
524 rect.InsetBy( 10, 10 );
525 ConfigTextControl * textControl;
526 ConfigCheckBox * checkBox;
527 ConfigMenuField * menuField;
528 ConfigSlider * slider;
531 for( ; (*pp_item)->i_type != CONFIG_HINT_END; (*pp_item)++ )
533 if( stop_after_category && (*pp_item)->i_type == CONFIG_HINT_CATEGORY )
536 /* Discard a few options */
537 if( (*pp_item)->psz_name &&
538 ( !strcmp( (*pp_item)->psz_name, "volume" ) ||
539 !strcmp( (*pp_item)->psz_name, "saved-volume" ) ||
540 !strcmp( (*pp_item)->psz_name, "advanced" ) ) )
543 switch( (*pp_item)->i_type )
545 case CONFIG_ITEM_STRING:
546 case CONFIG_ITEM_FILE:
547 case CONFIG_ITEM_MODULE:
548 case CONFIG_ITEM_DIRECTORY:
549 if( (*pp_item)->ppsz_list && (*pp_item)->ppsz_list[0] )
551 rect.bottom = rect.top + 20;
552 popUp = new BPopUpMenu( "" );
553 menuField = new ConfigMenuField( rect, (*pp_item)->psz_text,
554 popUp, (*pp_item)->psz_name );
555 BMenuItem * menuItem;
556 for( int i = 0; (*pp_item)->ppsz_list[i]; i++ )
558 menuItem = new BMenuItem( (*pp_item)->ppsz_list[i], new BMessage() );
559 popUp->AddItem( menuItem );
561 stringItem->fConfigView->AddChild( menuField );
562 rect.top = rect.bottom + 10;
566 rect.bottom = rect.top + 20;
567 textControl = new ConfigTextControl( rect, (*pp_item)->psz_text,
568 CONFIG_ITEM_STRING, (*pp_item)->psz_name );
569 stringItem->fConfigView->AddChild( textControl );
570 rect.top = rect.bottom + 10;
574 case CONFIG_ITEM_INTEGER:
576 if( (*pp_item)->i_min == (*pp_item)->i_max )
578 rect.bottom = rect.top + 20;
579 textControl = new ConfigTextControl( rect, (*pp_item)->psz_text,
581 (*pp_item)->psz_name );
582 stringItem->fConfigView->AddChild( textControl );
583 rect.top = rect.bottom + 10;
587 rect.bottom = rect.top + 30;
588 slider = new ConfigSlider( rect, (*pp_item)->psz_text,
589 CONFIG_ITEM_INTEGER, (*pp_item)->i_min,
590 (*pp_item)->i_max, (*pp_item)->psz_name );
591 stringItem->fConfigView->AddChild( slider );
592 rect.top = rect.bottom + 10;
596 case CONFIG_ITEM_FLOAT:
597 if( (*pp_item)->f_min == (*pp_item)->f_max )
599 rect.bottom = rect.top + 20;
600 textControl = new ConfigTextControl( rect, (*pp_item)->psz_text,
601 CONFIG_ITEM_FLOAT, (*pp_item)->psz_name );
602 stringItem->fConfigView->AddChild( textControl );
603 rect.top = rect.bottom + 10;
607 rect.bottom = rect.top + 30;
608 slider = new ConfigSlider( rect, (*pp_item)->psz_text,
609 CONFIG_ITEM_FLOAT, 100 * (*pp_item)->f_min,
610 100 * (*pp_item)->f_max, (*pp_item)->psz_name );
611 stringItem->fConfigView->AddChild( slider );
612 rect.top = rect.bottom + 10;
616 case CONFIG_ITEM_BOOL:
617 rect.bottom = rect.top + 20;
618 checkBox = new ConfigCheckBox( rect, (*pp_item)->psz_text,
619 (*pp_item)->psz_name );
620 stringItem->fConfigView->AddChild( checkBox );
621 rect.top = rect.bottom + 10;
626 /* Put the BView into a BScrollView */
628 stringItem->fConfigScroll =
629 new BScrollView( "config scroll", stringItem->fConfigView,
630 B_FOLLOW_ALL, 0, false, true, B_FANCY_BORDER );
631 stringItem->fConfigScroll->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
632 stringItem->fConfigBox->AddChild( stringItem->fConfigScroll );
634 /* Adjust the configView size */
635 stringItem->fConfigView->ResizeTo(
636 stringItem->fConfigView->Bounds().Width(), rect.top );