1 /*****************************************************************************
2 * PreferencesWindow.cpp: beos interface
3 *****************************************************************************
4 * Copyright (C) 1999, 2000, 2001 VideoLAN
7 * Authors: Eric Petit <titer@m0k.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 <vlc_config_cat.h>
33 #include "PreferencesWindow.h"
35 #define TYPE_CATEGORY 0
36 #define TYPE_SUBCATEGORY 2
39 /*****************************************************************************
40 * PreferencesWindow::PreferencesWindow
41 *****************************************************************************/
42 PreferencesWindow::PreferencesWindow( intf_thread_t * _p_intf,
43 BRect frame, const char * name )
44 : BWindow( frame, name, B_FLOATING_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
52 SetSizeLimits( PREFS_WINDOW_WIDTH, 2000, PREFS_WINDOW_HEIGHT, 2000 );
54 /* The "background" view */
55 fPrefsView = new BView( Bounds(), NULL, B_FOLLOW_ALL, B_WILL_DRAW );
56 fPrefsView->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
57 AddChild( fPrefsView );
59 /* Create a scrollable outline view for the preferences tree */
61 rect.InsetBy( 10, 10 );
62 rect.right = rect.left + 150;
63 fOutline = new BOutlineListView( rect, "preferences tree",
64 B_SINGLE_SELECTION_LIST,
65 B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM );
66 BScrollView * scrollview =
67 new BScrollView( "scrollview", fOutline,
68 B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM,
70 fPrefsView->AddChild( scrollview );
72 /* We need to be informed if the user selects an item */
73 fOutline->SetSelectionMessage( new BMessage( PREFS_ITEM_SELECTED ) );
75 /* Create a dummy, empty view so we can correctly place the real
78 rect.left = rect.right + 15 + B_V_SCROLL_BAR_WIDTH;
79 rect.right = Bounds().right - 15;
80 fDummyView = new BView( rect, "", B_FOLLOW_ALL_SIDES, B_WILL_DRAW );
81 fDummyView->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
82 fPrefsView->AddChild( fDummyView );
86 p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
89 msg_Warn( p_intf, "couldn't find any module !" );
93 /* Find the main module */
94 module_t * p_module = NULL;
95 module_config_t * p_item = NULL;
96 for( int i = 0; i < p_list->i_count; i++ )
98 p_module = (module_t*) p_list->p_values[i].p_object;
100 if( !strcmp( p_module->psz_object_name, "main" ) &&
101 ( p_item = p_module->p_config ) )
107 ConfigItem * catItem = NULL, * subcatItem, * otherItem;
111 /* We found the main module, build the category tree */
112 for( ; p_item->i_type != CONFIG_HINT_END; p_item++ )
114 switch( p_item->i_type )
116 case CONFIG_CATEGORY:
117 catItem = new ConfigItem( p_intf,
118 config_CategoryNameGet( p_item->i_value ),
122 config_CategoryHelpGet( p_item->i_value ) );
123 fOutline->AddItem( catItem );
126 case CONFIG_SUBCATEGORY:
129 subcatItem = new ConfigItem( p_intf,
130 config_CategoryNameGet( p_item->i_value ),
134 config_CategoryHelpGet( p_item->i_value ) );
135 fOutline->AddUnder( subcatItem, catItem );
139 msg_Warn( p_intf, "subcategory without a category" );
146 /* Now parse all others modules */
148 int category, subcategory, options;
150 for( int i = 0; i < p_list->i_count; i++ )
156 p_module = (module_t*) p_list->p_values[i].p_object;
158 if( !strcmp( p_module->psz_object_name, "main" ) )
161 if( p_module->b_submodule ||
162 !( p_item = p_module->p_config ) )
165 for( ; p_item->i_type != CONFIG_HINT_END; p_item++ )
167 switch( p_item->i_type )
169 case CONFIG_CATEGORY:
170 category = p_item->i_value;
172 case CONFIG_SUBCATEGORY:
173 subcategory = p_item->i_value;
176 if( p_item->i_type & CONFIG_ITEM )
179 if( options > 0 && category >= 0 && subcategory >= 0 )
185 if( options < 1 || category < 0 || subcategory < 0 )
189 fprintf( stderr, "cat %d, sub %d, %s\n", category, subcategory,
190 p_module->psz_shortname ? p_module->psz_shortname :
191 p_module->psz_object_name );
195 for( int j = 0; j < fOutline->CountItemsUnder( NULL, true ); j++ )
197 catItem = (ConfigItem*)
198 fOutline->ItemUnderAt( NULL, true, j );
199 if( catItem->ObjectId() == category )
209 for( int j = 0; j < fOutline->CountItemsUnder( catItem, true ); j++ )
211 subcatItem = (ConfigItem*)
212 fOutline->ItemUnderAt( catItem, true, j );
213 if( subcatItem->ObjectId() == subcategory )
220 subcatItem = catItem;
222 otherItem = new ConfigItem( p_intf,
223 p_module->psz_shortname ?
224 p_module->psz_shortname : p_module->psz_object_name,
225 p_module->b_submodule,
226 p_module->b_submodule ?
227 ((module_t *)p_module->p_parent)->i_object_id :
228 p_module->i_object_id,
231 fOutline->AddUnder( otherItem, subcatItem );
234 vlc_list_release( p_list );
236 for( int i = 0; i < fOutline->FullListCountItems(); i++ )
238 otherItem = (ConfigItem *)
239 fOutline->FullListItemAt( i );
240 if( fOutline->Superitem( otherItem ) )
242 fOutline->Collapse( otherItem );
246 /* Set the correct values */
247 ApplyChanges( false );
249 /* Select the first item */
250 fOutline->Select( 0 );
252 /* Add the buttons */
255 rect.InsetBy( 10, 10 );
256 rect.left = rect.right - 80;
257 rect.top = rect.bottom - 25;
258 button = new BButton( rect, "", _("Apply"), new BMessage( PREFS_APPLY ),
259 B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM );
260 button->MakeDefault( true );
261 fPrefsView->AddChild( button );
262 rect.OffsetBy( -90, 0 );
263 button = new BButton( rect, "", _("Save"), new BMessage( PREFS_SAVE ),
264 B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM );
265 fPrefsView->AddChild( button );
266 rect.OffsetBy( -90, 0 );
267 button = new BButton( rect, "", _("Defaults"),
268 new BMessage( PREFS_DEFAULTS ),
269 B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM );
270 fPrefsView->AddChild( button );
276 /*****************************************************************************
277 * PreferencesWindow::~PreferencesWindow
278 *****************************************************************************/
279 PreferencesWindow::~PreferencesWindow()
283 /*****************************************************************************
284 * PreferencesWindow::QuitRequested
285 *****************************************************************************/
286 bool PreferencesWindow::QuitRequested()
295 /*****************************************************************************
296 * PreferencesWindow::MessageReceived
297 *****************************************************************************/
298 void PreferencesWindow::MessageReceived( BMessage * message )
300 switch( message->what )
302 case PREFS_ITEM_SELECTED:
307 config_ResetAll( p_intf );
308 ApplyChanges( false );
312 ApplyChanges( true );
320 BWindow::MessageReceived( message );
324 /*****************************************************************************
325 * PreferencesWindow::FrameResized
326 *****************************************************************************/
327 void PreferencesWindow::FrameResized( float width, float height )
329 BWindow::FrameResized( width, height );
330 fCurrent->UpdateScrollBar();
333 /*****************************************************************************
334 * PreferencesWindow::Update
335 *****************************************************************************/
336 void PreferencesWindow::Update()
338 /* Get the selected item, if any */
339 if( fOutline->CurrentSelection() < 0 )
342 /* Detach the old box if any */
345 fCurrent->ResetScroll();
346 fDummyView->RemoveChild( fCurrent->Box() );
349 /* Add the new one... */
350 fCurrent = (ConfigItem *)
351 fOutline->ItemAt( fOutline->CurrentSelection() );
352 fDummyView->AddChild( fCurrent->Box() );
354 /* ...then resize it (we must resize it after it's attached or the
355 children don't get adjusted) */
356 fCurrent->Box()->ResizeTo( fDummyView->Bounds().Width(),
357 fDummyView->Bounds().Height() );
358 fCurrent->UpdateScrollBar();
361 /*****************************************************************************
362 * PreferencesWindow::ApplyChanges
363 * Apply changes if doIt is true, revert them otherwise
364 *****************************************************************************/
365 void PreferencesWindow::ApplyChanges( bool doIt )
369 for( int i = 0; i < fOutline->CountItems(); i++ )
371 item = (ConfigItem*) fOutline->ItemAt( i );
376 /*****************************************************************************
377 * PreferencesWindow::SaveChanges
378 *****************************************************************************/
379 void PreferencesWindow::SaveChanges()
381 ApplyChanges( true );
382 config_SaveConfigFile( p_intf, NULL );
385 /*****************************************************************************
386 * PreferencesWindow::ReallyQuit
387 *****************************************************************************/
388 void PreferencesWindow::ReallyQuit()
395 /***********************************************************************
396 * ConfigItem::ConfigItem
397 ***********************************************************************
399 **********************************************************************/
400 ConfigItem::ConfigItem( intf_thread_t * _p_intf, char * name,
401 bool subModule, int objectId,
402 int type, char * help )
403 : BStringItem( name )
406 fSubModule = subModule;
407 fObjectId = objectId;
409 fHelp = strdup( help );
412 r = BRect( 0, 0, 100, 100 );
413 fBox = new BBox( r, NULL, B_FOLLOW_ALL );
414 fBox->SetLabel( name );
420 if( fType == TYPE_CATEGORY )
422 /* Category: we just show the help text */
427 fTextView = new VTextView( r, NULL, B_FOLLOW_ALL, B_WILL_DRAW);
428 fTextView->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
429 fTextView->MakeEditable( false );
430 fTextView->MakeSelectable( false );
431 fTextView->Insert( fHelp );
432 fBox->AddChild( fTextView );
437 vlc_list_t * p_list = NULL;
438 module_t * p_module = NULL;
439 if( fType == TYPE_MODULE )
441 p_module = (module_t *) vlc_object_get( p_intf, fObjectId );
445 if( !( p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE,
450 for( int i = 0; i < p_list->i_count; i++ )
452 p_module = (module_t*) p_list->p_values[i].p_object;
454 if( !strcmp( p_module->psz_object_name, "main" ) )
461 if( !p_module || p_module->i_object_type != VLC_OBJECT_MODULE )
463 /* Shouldn't happen */
467 module_config_t * p_item;
468 p_item = fSubModule ? ((module_t *)p_module->p_parent)->p_config :
471 if( fType == TYPE_SUBCATEGORY )
473 for( ; p_item->i_type != CONFIG_HINT_END; p_item++ )
475 if( p_item->i_type == CONFIG_SUBCATEGORY &&
476 p_item->i_value == fObjectId )
484 r = BRect( 10,20,fBox->Bounds().right-B_V_SCROLL_BAR_WIDTH-10,
485 fBox->Bounds().bottom-10 );
486 fView = new BView( r, NULL, B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP,
487 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE );
488 fView->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
493 ConfigWidget * widget;
494 for( ; p_item->i_type != CONFIG_HINT_END; p_item++ )
496 if( ( p_item->i_type == CONFIG_CATEGORY ||
497 p_item->i_type == CONFIG_SUBCATEGORY ) &&
498 fType == TYPE_SUBCATEGORY &&
499 p_item->i_value != fObjectId )
504 widget = new ConfigWidget( p_intf, r, p_item );
505 if( !widget->InitCheck() )
510 fView->AddChild( widget );
511 r.top += widget->Bounds().Height();
514 if( fType == TYPE_MODULE )
516 vlc_object_release( p_module );
520 vlc_list_release( p_list );
523 /* Create a scroll view around our fView */
524 fScroll = new BScrollView( NULL, fView, B_FOLLOW_ALL, 0, false,
525 true, B_FANCY_BORDER );
526 fScroll->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
527 fBox->AddChild( fScroll );
529 /* Adjust fView's height to the size it actually needs (we do this
530 only now so the BScrollView fits the BBox) */
531 fView->ResizeTo( fView->Bounds().Width(), r.top + 10 );
534 /***********************************************************************
535 * ConfigItem::~ConfigItem
536 ***********************************************************************
538 **********************************************************************/
539 ConfigItem::~ConfigItem()
547 /*****************************************************************************
548 * ConfigItem::UpdateScrollBar
549 *****************************************************************************/
550 void ConfigItem::UpdateScrollBar()
552 /* We have to fix the scrollbar manually because it doesn't handle
553 correctly simple BViews */
560 /* Get the available BRect for display */
561 BRect display = fScroll->Bounds();
562 display.right -= B_V_SCROLL_BAR_WIDTH;
564 /* Fix the scrollbar */
565 BScrollBar * scrollBar;
566 BRect visible = display & fView->Bounds();
567 BRect total = display | fView->Bounds();
568 scrollBar = fScroll->ScrollBar( B_VERTICAL );
569 long max = (long)( fView->Bounds().Height() - visible.Height() );
570 if( max < 0 ) max = 0;
571 scrollBar->SetRange( 0, max );
572 scrollBar->SetProportion( visible.Height() / total.Height() );
573 scrollBar->SetSteps( 10, 100 );
575 /* We have to force redraw to avoid visual bugs when resizing
577 fScroll->Invalidate();
581 /*****************************************************************************
582 * ConfigItem::ResetScroll
583 *****************************************************************************/
584 void ConfigItem::ResetScroll()
591 fView->ScrollTo( 0, 0 );
594 /***********************************************************************
596 ***********************************************************************
598 **********************************************************************/
599 void ConfigItem::Apply( bool doIt )
601 ConfigWidget * widget;
607 /* This is a category */
611 /* Call ConfigWidget::Apply for every child of your fView */
612 for( int i = 0; i < fView->CountChildren(); i++ )
614 widget = (ConfigWidget*) fView->ChildAt( i );
615 widget->Apply( doIt );
619 /***********************************************************************
620 * ConfigWidget::ConfigWidget
621 ***********************************************************************
622 * Builds a view with the right controls for the given config variable.
623 * rect: the BRect where we place ourselves. All we care is its width
624 * and its top coordinate, since we adapt our height to take only
626 **********************************************************************/
627 ConfigWidget::ConfigWidget( intf_thread_t * _p_intf, BRect rect,
628 module_config_t * p_item )
629 : BView( rect, NULL, B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP,
635 SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
638 BMenuItem * menuItem;
639 /* Skip deprecated options */
640 if( p_item->psz_current )
645 switch( p_item->i_type )
647 case CONFIG_ITEM_MODULE:
648 case CONFIG_ITEM_MODULE_CAT:
649 case CONFIG_ITEM_MODULE_LIST_CAT:
650 case CONFIG_ITEM_STRING:
651 case CONFIG_ITEM_FILE:
652 case CONFIG_ITEM_DIRECTORY:
653 case CONFIG_ITEM_INTEGER:
654 case CONFIG_ITEM_FLOAT:
655 ResizeTo( Bounds().Width(), 25 );
656 fTextControl = new VTextControl( Bounds(), NULL,
657 p_item->psz_text, NULL, new BMessage(),
658 B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP );
659 AddChild( fTextControl );
661 case CONFIG_ITEM_KEY:
662 ResizeTo( Bounds().Width(), 25 );
664 r.left = r.right - 100;
665 fPopUpMenu = new BPopUpMenu( "" );
666 fMenuField = new BMenuField( r, NULL, NULL, fPopUpMenu,
667 B_FOLLOW_RIGHT | B_FOLLOW_TOP );
669 i < sizeof( vlc_keys ) / sizeof( key_descriptor_t );
672 menuItem = new BMenuItem( vlc_keys[i].psz_key_string, NULL );
673 fPopUpMenu->AddItem( menuItem );
675 r.right = r.left - 10; r.left = r.left - 60;
676 fShiftCheck = new BCheckBox( r, NULL, "Shift",
677 new BMessage(), B_FOLLOW_RIGHT | B_FOLLOW_TOP );
678 r.right = r.left - 10; r.left = r.left - 60;
679 fCtrlCheck = new BCheckBox( r, NULL, "Ctrl",
680 new BMessage(), B_FOLLOW_RIGHT | B_FOLLOW_TOP );
681 r.right = r.left - 10; r.left = r.left - 60;
682 fAltCheck = new BCheckBox( r, NULL, "Alt",
683 new BMessage(), B_FOLLOW_RIGHT | B_FOLLOW_TOP );
684 r.right = r.left - 10; r.left = 0; r.bottom -= 10;
685 fStringView = new BStringView( r, NULL, p_item->psz_text,
686 B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP );
687 AddChild( fStringView );
688 AddChild( fAltCheck );
689 AddChild( fCtrlCheck );
690 AddChild( fShiftCheck );
691 AddChild( fMenuField );
693 case CONFIG_ITEM_BOOL:
694 ResizeTo( Bounds().Width(), 25 );
695 fCheckBox = new BCheckBox( Bounds(), NULL, p_item->psz_text,
696 new BMessage(), B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP );
697 AddChild( fCheckBox );
707 /***********************************************************************
708 * ConfigWidget::Apply
709 ***********************************************************************
711 **********************************************************************/
712 void ConfigWidget::Apply( bool doIt )
717 case CONFIG_ITEM_STRING:
718 case CONFIG_ITEM_FILE:
719 case CONFIG_ITEM_MODULE:
720 case CONFIG_ITEM_DIRECTORY:
723 config_PutPsz( p_intf, fConfigName, fTextControl->Text() );
727 fTextControl->SetText( config_GetPsz( p_intf, fConfigName ) );
731 case CONFIG_ITEM_INTEGER:
734 config_PutInt( p_intf, fConfigName,
735 atoi( fTextControl->Text() ) );
739 memset( string, 0, 1024 );
740 snprintf( string, 1023, "%d",
741 config_GetInt( p_intf, fConfigName ) );
742 fTextControl->SetText( string );
746 case CONFIG_ITEM_FLOAT:
749 config_PutFloat( p_intf, fConfigName,
750 strtod( fTextControl->Text(), NULL ) );
754 memset( string, 0, 1024 );
755 snprintf( string, 1023, "%f",
756 config_GetFloat( p_intf, fConfigName ) );
757 fTextControl->SetText( string );
761 case CONFIG_ITEM_BOOL:
764 config_PutInt( p_intf, fConfigName, fCheckBox->Value() );
768 fCheckBox->SetValue( config_GetInt( p_intf, fConfigName ) );
772 case CONFIG_ITEM_KEY:
775 menuItem = fPopUpMenu->FindMarked();
778 int value = vlc_keys[fPopUpMenu->IndexOf( menuItem )].i_key_code;
779 if( fAltCheck->Value() )
781 value |= KEY_MODIFIER_ALT;
783 if( fCtrlCheck->Value() )
785 value |= KEY_MODIFIER_CTRL;
787 if( fShiftCheck->Value() )
789 value |= KEY_MODIFIER_SHIFT;
791 config_PutInt( p_intf, fConfigName, value );
796 int value = config_GetInt( p_intf, fConfigName );
797 fAltCheck->SetValue( value & KEY_MODIFIER_ALT );
798 fCtrlCheck->SetValue( value & KEY_MODIFIER_CTRL );
799 fShiftCheck->SetValue( value & KEY_MODIFIER_SHIFT );
802 i < sizeof( vlc_keys ) / sizeof( key_descriptor_t ); i++ )
804 if( (unsigned) vlc_keys[i].i_key_code ==
805 ( value & ~KEY_MODIFIER ) )
807 menuItem = fPopUpMenu->ItemAt( i );
808 menuItem->SetMarked( true );
819 VTextView::VTextView( BRect frame, const char *name,
820 uint32 resizingMode, uint32 flags )
821 : BTextView( frame, name, BRect( 10,10,10,10 ), resizingMode, flags )
823 FrameResized( Bounds().Width(), Bounds().Height() );
826 void VTextView::FrameResized( float width, float height )
828 BTextView::FrameResized( width, height );
829 SetTextRect( BRect( 10,10, width-11, height-11 ) );
832 VTextControl::VTextControl( BRect frame, const char *name,
833 const char *label, const char *text,
834 BMessage * message, uint32 resizingMode )
835 : BTextControl( frame, name, label, text, message, resizingMode )
837 FrameResized( Bounds().Width(), Bounds().Height() );
840 void VTextControl::FrameResized( float width, float height )
842 BTextControl::FrameResized( width, height );
843 SetDivider( width / 2 );