1 /*****************************************************************************
2 * PreferencesWindow.cpp: beos interface
3 *****************************************************************************
4 * Copyright (C) 1999, 2000, 2001 VideoLAN
5 * $Id: PreferencesWindow.cpp,v 1.22 2003/05/17 18:30:41 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 - handle CONFIG_HINT_SUBCATEGORY
33 - use BSliders for integer_with_range and float_with_range
34 - add the needed LockLooper()s
35 - fix horizontal 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_H_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 !" );
111 /* First, handle the main module */
112 module_t * p_module = NULL;
113 module_config_t * p_item;
114 for( int i = 0; i < p_list->i_count; i++ )
116 p_module = (module_t*) p_list->p_values[i].p_object;
118 if( !strcmp( p_module->psz_object_name, "main" ) &&
119 ( p_item = p_module->p_config ) )
127 /* We found the main module */
128 while( p_item->i_type == CONFIG_HINT_CATEGORY )
130 StringItemWithView * stringItem;
131 stringItem = new StringItemWithView( p_item->psz_text );
133 stringItem->fConfigView = BuildConfigView( &p_item, true );
134 fOutline->AddItem( stringItem );
138 for( int i = 0; i < p_list->i_count; i++ )
140 p_module = (module_t*) p_list->p_values[i].p_object;
142 if( !strcmp( p_module->psz_object_name, "main" ) )
145 /* If the module has no config option, ignore it */
146 p_item = p_module->p_config;
150 if( p_item->i_type & CONFIG_ITEM )
152 } while( p_item->i_type != CONFIG_HINT_END && p_item++ );
153 if( p_item->i_type == CONFIG_HINT_END )
156 /* Create the capability tree if it doesn't already exist */
157 char * psz_capability;
158 psz_capability = p_module->psz_capability;
159 if( !psz_capability || !*psz_capability )
161 /* Empty capability ? Let's look at the submodules */
162 module_t * p_submodule;
163 for( int j = 0; j < p_module->i_children; j++ )
165 p_submodule = (module_t*)p_module->pp_children[ j ];
166 if( p_submodule->psz_capability && *p_submodule->psz_capability )
168 psz_capability = p_submodule->psz_capability;
174 StringItemWithView * capabilityItem;
175 capabilityItem = NULL;
176 for( int j = 0; j < fOutline->CountItemsUnder( modulesItem, true ); j++ )
178 if( !strcmp( ((StringItemWithView*)
179 fOutline->ItemUnderAt( modulesItem, true, j ))->Text(),
182 capabilityItem = (StringItemWithView*)
183 fOutline->ItemUnderAt( modulesItem, true, j );
187 if( !capabilityItem )
189 capabilityItem = new StringItemWithView( psz_capability );
190 fOutline->AddUnder( capabilityItem, modulesItem );
193 /* Now add the item ! */
194 StringItemWithView * stringItem;
195 stringItem = new StringItemWithView( p_module->psz_object_name );
196 stringItem->fConfigView = BuildConfigView( &p_item, false );
197 fOutline->AddUnder( stringItem, capabilityItem );
200 vlc_list_release( p_list );
202 /* Set the correct values */
203 ApplyChanges( false );
205 /* Sort items, collapse the tree */
206 fOutline->FullListSortItems( compare_func );
207 fOutline->Collapse( modulesItem );
208 for( int i = 0; i < fOutline->CountItemsUnder( modulesItem, true ); i++ )
209 fOutline->Collapse( fOutline->ItemUnderAt( modulesItem, true, i ) );
211 /* Select the first item */
212 fOutline->Select( 0 );
214 /* Add the buttons */
217 rect.InsetBy( 10, 10 );
218 rect.left = rect.right - 80;
219 rect.top = rect.bottom - 25;
220 button = new BButton( rect, "", _("Apply"), new BMessage( PREFS_APPLY ),
221 B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM );
222 button->MakeDefault( true );
223 fPrefsView->AddChild( button );
224 rect.OffsetBy( -90, 0 );
225 button = new BButton( rect, "", _("Save"), new BMessage( PREFS_SAVE ),
226 B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM );
227 fPrefsView->AddChild( button );
228 rect.OffsetBy( -90, 0 );
229 button = new BButton( rect, "", _("Defaults"), new BMessage( PREFS_DEFAULTS ),
230 B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM );
231 fPrefsView->AddChild( button );
237 /*****************************************************************************
238 * PreferencesWindow::~PreferencesWindow
239 *****************************************************************************/
240 PreferencesWindow::~PreferencesWindow()
244 /*****************************************************************************
245 * PreferencesWindow::QuitRequested
246 *****************************************************************************/
247 bool PreferencesWindow::QuitRequested()
254 /*****************************************************************************
255 * PreferencesWindow::MessageReceived
256 *****************************************************************************/
257 void PreferencesWindow::MessageReceived( BMessage * message )
259 switch( message->what )
261 case PREFS_ITEM_SELECTED:
266 config_ResetAll( p_intf );
267 ApplyChanges( false );
271 ApplyChanges( true );
279 BWindow::MessageReceived( message );
283 /*****************************************************************************
284 * PreferencesWindow::FrameResized
285 *****************************************************************************/
286 void PreferencesWindow::FrameResized( float width, float height )
288 BWindow::FrameResized( width, height );
290 /* Get the current config BView */
292 view = fConfigScroll->ChildAt( 0 );
297 /*****************************************************************************
298 * PreferencesWindow::Update
299 *****************************************************************************/
300 void PreferencesWindow::Update()
302 /* Get the selected item, if any */
303 if( fOutline->CurrentSelection() < 0 )
305 StringItemWithView * selectedItem =
306 (StringItemWithView*) fOutline->ItemAt( fOutline->CurrentSelection() );
308 if( !selectedItem->fConfigView )
309 /* This is a category */
314 /* If we don't do this, the config BView will remember a wrong position */
315 BScrollBar * scrollBar = fConfigScroll->ScrollBar( B_VERTICAL );
316 scrollBar->SetValue( 0 );
318 /* Detach the current config BView, remove the BScrollView */
320 while( ( view = fConfigScroll->ChildAt( 0 ) ) )
321 fConfigScroll->RemoveChild( view );
322 fDummyView->RemoveChild( fConfigScroll );
323 delete fConfigScroll;
326 /* Create a BScrollView with the new config BView in it */
327 BRect oldBounds = selectedItem->fConfigView->Bounds();
328 selectedItem->fConfigView->ResizeTo( fDummyView->Bounds().Width() -
329 B_V_SCROLL_BAR_WIDTH,
330 fDummyView->Bounds().Height() );
331 fConfigScroll = new BScrollView( "", selectedItem->fConfigView, B_FOLLOW_ALL_SIDES,
332 0, false, true, B_NO_BORDER );
333 fConfigScroll->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
334 fDummyView->AddChild( fConfigScroll );
335 selectedItem->fConfigView->ResizeTo( oldBounds.Width(),
336 oldBounds.Height() );
341 /*****************************************************************************
342 * PreferencesWindow::UpdateScrollBar
343 *****************************************************************************/
344 void PreferencesWindow::UpdateScrollBar()
346 /* We have to fix the scrollbar manually because it doesn't handle
347 correctly simple BViews */
349 /* Get the current config view */
351 view = fConfigScroll->ChildAt( 0 );
353 /* Get the available BRect for display */
354 BRect display = fConfigScroll->Bounds();
355 display.right -= B_V_SCROLL_BAR_WIDTH;
357 /* Fix the scrollbar */
358 BScrollBar * scrollBar;
360 BRect visible = display & view->Bounds();
361 BRect total = display | view->Bounds();
362 scrollBar = fConfigScroll->ScrollBar( B_VERTICAL );
363 max = (long)( view->Bounds().Height() - visible.Height() );
364 if( max < 0 ) max = 0;
365 scrollBar->SetRange( 0, max );
366 scrollBar->SetProportion( visible.Height() / total.Height() );
367 scrollBar->SetSteps( 10, 100 );
370 /*****************************************************************************
371 * PreferencesWindow::ApplyChanges
372 * Apply changes if doIt is true, revert them otherwise
373 *****************************************************************************/
374 void PreferencesWindow::ApplyChanges( bool doIt )
376 StringItemWithView * item;
381 for( int i = 0; i < fOutline->CountItems(); i++ )
383 item = (StringItemWithView*) fOutline->ItemAt( i );
384 view = item->fConfigView;
387 /* This is a category */
390 for( int j = 0; j < view->CountChildren(); j++ )
392 child = view->ChildAt( j );
393 name = child->Name();
394 if( !strcmp( name, "ConfigTextControl" ) )
396 ConfigTextControl * textControl;
397 textControl = (ConfigTextControl*) child;
398 switch( textControl->fConfigType )
400 case CONFIG_ITEM_STRING:
402 config_PutPsz( p_intf, textControl->fConfigName, textControl->Text() );
404 textControl->SetText( config_GetPsz( p_intf, textControl->fConfigName ) );
406 case CONFIG_ITEM_INTEGER:
408 config_PutInt( p_intf, textControl->fConfigName, atoi( textControl->Text() ) );
412 string << config_GetInt( p_intf, textControl->fConfigName );
413 textControl->SetText( string.String() );
416 case CONFIG_ITEM_FLOAT:
418 config_PutFloat( p_intf, textControl->fConfigName,
419 strtod( textControl->Text(), NULL ) );
423 string << config_GetFloat( p_intf, textControl->fConfigName );
424 textControl->SetText( string.String() );
429 else if( !strcmp( name, "ConfigCheckBox" ) )
431 ConfigCheckBox * checkBox;
432 checkBox = (ConfigCheckBox*) child;
434 config_PutInt( p_intf, checkBox->fConfigName, checkBox->Value() );
436 checkBox->SetValue( config_GetInt( p_intf, checkBox->fConfigName ) );
438 else if( !strcmp( name, "ConfigMenuField" ) )
440 ConfigMenuField * menuField;
441 menuField = (ConfigMenuField*) child;
443 BMenuItem * menuItem;
444 menu = menuField->Menu();
447 menuItem = menu->FindMarked();
449 config_PutPsz( p_intf, menuField->fConfigName, menuItem->Label() );
454 value = config_GetPsz( p_intf, menuField->fConfigName );
455 if( !value ) value = "";
456 for( int k = 0; k < menu->CountItems(); k++ )
458 menuItem = menu->ItemAt( k );
459 if( !strcmp( value, menuItem->Label() ) )
461 menuItem->SetMarked( true );
471 /*****************************************************************************
472 * PreferencesWindow::SaveChanges
473 *****************************************************************************/
474 void PreferencesWindow::SaveChanges()
476 ApplyChanges( true );
477 config_SaveConfigFile( p_intf, NULL );
480 /*****************************************************************************
481 * PreferencesWindow::ReallyQuit
482 *****************************************************************************/
483 void PreferencesWindow::ReallyQuit()
490 /*****************************************************************************
491 * PreferencesWindow::BuildConfigView
492 *****************************************************************************/
493 BView * PreferencesWindow::BuildConfigView( module_config_t ** pp_item,
494 bool stop_after_category )
496 /* Build the config view for this module */
497 BRect rect = fDummyView->Bounds();
498 rect.right -= B_V_SCROLL_BAR_WIDTH;
500 configView = new BView( rect, "config view",
501 B_FOLLOW_NONE, B_WILL_DRAW );
502 configView->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
504 rect = configView->Bounds();
505 rect.InsetBy( 10, 10 );
506 rect.bottom = rect.top + TEXT_HEIGHT;
507 ConfigTextControl * textControl;
508 ConfigCheckBox * checkBox;
509 ConfigMenuField * menuField;
512 bool firstItem = true;
513 bool categoryHit = false;
516 switch( (*pp_item)->i_type )
518 case CONFIG_ITEM_STRING:
519 case CONFIG_ITEM_FILE:
520 case CONFIG_ITEM_MODULE:
521 case CONFIG_ITEM_DIRECTORY:
523 rect.OffsetBy( 0, 25 );
527 if( (*pp_item)->ppsz_list && (*pp_item)->ppsz_list[0] )
529 popUp = new BPopUpMenu( "" );
530 menuField = new ConfigMenuField( rect, (*pp_item)->psz_text,
531 popUp, (*pp_item)->psz_name );
532 BMenuItem * menuItem;
533 for( int i = 0; (*pp_item)->ppsz_list[i]; i++ )
535 menuItem = new BMenuItem( (*pp_item)->ppsz_list[i], new BMessage() );
536 popUp->AddItem( menuItem );
538 configView->AddChild( menuField );
542 textControl = new ConfigTextControl( rect, (*pp_item)->psz_text,
543 CONFIG_ITEM_STRING, (*pp_item)->psz_name );
544 configView->AddChild( textControl );
548 case CONFIG_ITEM_INTEGER:
550 rect.OffsetBy( 0, 25 );
554 textControl = new ConfigTextControl( rect, (*pp_item)->psz_text,
555 CONFIG_ITEM_INTEGER, (*pp_item)->psz_name );
556 configView->AddChild( textControl );
559 case CONFIG_ITEM_FLOAT:
561 rect.OffsetBy( 0, 25 );
565 textControl = new ConfigTextControl( rect, (*pp_item)->psz_text,
566 CONFIG_ITEM_FLOAT, (*pp_item)->psz_name );
567 configView->AddChild( textControl );
570 case CONFIG_ITEM_BOOL:
571 if( !strcmp( (*pp_item)->psz_name, "advanced" ) )
572 /* Don't show this one, the interface doesn't handle it anyway */
576 rect.OffsetBy( 0,25 );
580 checkBox = new ConfigCheckBox( rect, (*pp_item)->psz_text,
581 (*pp_item)->psz_name );
582 configView->AddChild( checkBox );
585 case CONFIG_HINT_CATEGORY:
586 if( stop_after_category )
590 } while( !categoryHit &&
591 (*pp_item)->i_type != CONFIG_HINT_END &&
594 /* Adjust the configView size */
596 configView->ResizeTo( configView->Bounds().Width(), rect.bottom );