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 for( int j = 0; j < fOutline->CountItemsUnder( NULL, true ); j++ )
191 catItem = (ConfigItem*)
192 fOutline->ItemUnderAt( NULL, true, j );
193 if( catItem->ObjectId() == category )
203 for( int j = 0; j < fOutline->CountItemsUnder( catItem, true ); j++ )
205 subcatItem = (ConfigItem*)
206 fOutline->ItemUnderAt( catItem, true, j );
207 if( subcatItem->ObjectId() == subcategory )
214 subcatItem = catItem;
216 otherItem = new ConfigItem( p_intf,
217 p_module->psz_shortname ?
218 p_module->psz_shortname : p_module->psz_object_name,
219 p_module->b_submodule,
220 p_module->b_submodule ?
221 ((module_t *)p_module->p_parent)->i_object_id :
222 p_module->i_object_id,
225 fOutline->AddUnder( otherItem, subcatItem );
228 vlc_list_release( p_list );
230 /* Collapse the whole tree */
231 for( int i = 0; i < fOutline->FullListCountItems(); i++ )
233 otherItem = (ConfigItem *) fOutline->FullListItemAt( i );
234 fOutline->Collapse( otherItem );
237 /* Set the correct values */
240 /* Select the first item */
241 fOutline->Select( 0 );
243 /* Add the buttons */
246 rect.InsetBy( 10, 10 );
247 rect.left = rect.right - 80;
248 rect.top = rect.bottom - 25;
249 button = new BButton( rect, "", _("Apply"), new BMessage( PREFS_APPLY ),
250 B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM );
251 button->MakeDefault( true );
252 fPrefsView->AddChild( button );
253 rect.OffsetBy( -90, 0 );
254 button = new BButton( rect, "", _("Save"), new BMessage( PREFS_SAVE ),
255 B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM );
256 fPrefsView->AddChild( button );
257 rect.OffsetBy( -90, 0 );
258 button = new BButton( rect, "", _("Defaults"),
259 new BMessage( PREFS_DEFAULTS ),
260 B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM );
261 fPrefsView->AddChild( button );
267 /*****************************************************************************
268 * PreferencesWindow::~PreferencesWindow
269 *****************************************************************************/
270 PreferencesWindow::~PreferencesWindow()
274 /*****************************************************************************
275 * PreferencesWindow::QuitRequested
276 *****************************************************************************/
277 bool PreferencesWindow::QuitRequested()
286 /*****************************************************************************
287 * PreferencesWindow::MessageReceived
288 *****************************************************************************/
289 void PreferencesWindow::MessageReceived( BMessage * message )
291 switch( message->what )
293 case PREFS_ITEM_SELECTED:
298 config_ResetAll( p_intf );
299 config_SaveConfigFile( p_intf, NULL );
309 config_SaveConfigFile( p_intf, NULL );
313 BWindow::MessageReceived( message );
317 /*****************************************************************************
318 * PreferencesWindow::FrameResized
319 *****************************************************************************/
320 void PreferencesWindow::FrameResized( float width, float height )
322 BWindow::FrameResized( width, height );
323 fCurrent->UpdateScrollBar();
326 /*****************************************************************************
327 * PreferencesWindow::Update
328 *****************************************************************************/
329 void PreferencesWindow::Update()
331 /* Get the selected item, if any */
332 if( fOutline->CurrentSelection() < 0 )
335 /* Detach the old box if any */
338 fCurrent->ResetScroll();
339 fDummyView->RemoveChild( fCurrent->Box() );
342 /* Add the new one... */
343 fCurrent = (ConfigItem *)
344 fOutline->ItemAt( fOutline->CurrentSelection() );
345 fDummyView->AddChild( fCurrent->Box() );
347 /* ...then resize it (we must resize it after it's attached or the
348 children don't get adjusted) */
349 fCurrent->Box()->ResizeTo( fDummyView->Bounds().Width(),
350 fDummyView->Bounds().Height() );
351 fCurrent->UpdateScrollBar();
354 /*****************************************************************************
355 * PreferencesWindow::Apply
356 * Apply changes if doIt is true, revert them otherwise
357 *****************************************************************************/
358 void PreferencesWindow::Apply( bool doIt )
362 for( int i = 0; i < fOutline->FullListCountItems(); i++ )
364 item = (ConfigItem*) fOutline->FullListItemAt( i );
369 /*****************************************************************************
370 * PreferencesWindow::ReallyQuit
371 *****************************************************************************/
372 void PreferencesWindow::ReallyQuit()
379 /***********************************************************************
380 * ConfigItem::ConfigItem
381 ***********************************************************************
383 **********************************************************************/
384 ConfigItem::ConfigItem( intf_thread_t * _p_intf, char * name,
385 bool subModule, int objectId,
386 int type, char * help )
387 : BStringItem( name )
390 fSubModule = subModule;
391 fObjectId = objectId;
393 fHelp = strdup( help );
396 r = BRect( 0, 0, 100, 100 );
397 fBox = new BBox( r, NULL, B_FOLLOW_ALL );
398 fBox->SetLabel( name );
404 if( fType == TYPE_CATEGORY )
406 /* Category: we just show the help text */
411 fTextView = new VTextView( r, NULL, B_FOLLOW_ALL, B_WILL_DRAW);
412 fTextView->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
413 fTextView->MakeEditable( false );
414 fTextView->MakeSelectable( false );
415 fTextView->Insert( fHelp );
416 fBox->AddChild( fTextView );
421 vlc_list_t * p_list = NULL;
422 module_t * p_module = NULL;
423 if( fType == TYPE_MODULE )
425 p_module = (module_t *) vlc_object_get( p_intf, fObjectId );
429 if( !( p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE,
434 for( int i = 0; i < p_list->i_count; i++ )
436 p_module = (module_t*) p_list->p_values[i].p_object;
438 if( !strcmp( p_module->psz_object_name, "main" ) )
445 if( !p_module || p_module->i_object_type != VLC_OBJECT_MODULE )
447 /* Shouldn't happen */
451 module_config_t * p_item;
452 p_item = fSubModule ? ((module_t *)p_module->p_parent)->p_config :
455 if( fType == TYPE_SUBCATEGORY )
457 for( ; p_item->i_type != CONFIG_HINT_END; p_item++ )
459 if( p_item->i_type == CONFIG_SUBCATEGORY &&
460 p_item->i_value == fObjectId )
468 r = BRect( 10,20,fBox->Bounds().right-B_V_SCROLL_BAR_WIDTH-10,
469 fBox->Bounds().bottom-10 );
470 fView = new BView( r, NULL, B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP,
471 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE );
472 fView->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
477 ConfigWidget * widget;
478 for( ; p_item->i_type != CONFIG_HINT_END; p_item++ )
480 if( ( p_item->i_type == CONFIG_CATEGORY ||
481 p_item->i_type == CONFIG_SUBCATEGORY ) &&
482 fType == TYPE_SUBCATEGORY &&
483 p_item->i_value != fObjectId )
488 widget = new ConfigWidget( p_intf, r, p_item );
489 if( !widget->InitCheck() )
494 fView->AddChild( widget );
495 r.top += widget->Bounds().Height();
498 if( fType == TYPE_MODULE )
500 vlc_object_release( p_module );
504 vlc_list_release( p_list );
507 /* Create a scroll view around our fView */
508 fScroll = new BScrollView( NULL, fView, B_FOLLOW_ALL, 0, false,
509 true, B_FANCY_BORDER );
510 fScroll->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
511 fBox->AddChild( fScroll );
513 /* Adjust fView's height to the size it actually needs (we do this
514 only now so the BScrollView fits the BBox) */
515 fView->ResizeTo( fView->Bounds().Width(), r.top + 10 );
518 /***********************************************************************
519 * ConfigItem::~ConfigItem
520 ***********************************************************************
522 **********************************************************************/
523 ConfigItem::~ConfigItem()
531 /*****************************************************************************
532 * ConfigItem::UpdateScrollBar
533 *****************************************************************************/
534 void ConfigItem::UpdateScrollBar()
536 /* We have to fix the scrollbar manually because it doesn't handle
537 correctly simple BViews */
544 /* Get the available BRect for display */
545 BRect display = fScroll->Bounds();
546 display.right -= B_V_SCROLL_BAR_WIDTH;
548 /* Fix the scrollbar */
549 BScrollBar * scrollBar;
550 BRect visible = display & fView->Bounds();
551 BRect total = display | fView->Bounds();
552 scrollBar = fScroll->ScrollBar( B_VERTICAL );
553 long max = (long)( fView->Bounds().Height() - visible.Height() );
554 if( max < 0 ) max = 0;
555 scrollBar->SetRange( 0, max );
556 scrollBar->SetProportion( visible.Height() / total.Height() );
557 scrollBar->SetSteps( 10, 100 );
559 /* We have to force redraw to avoid visual bugs when resizing
561 fScroll->Invalidate();
565 /*****************************************************************************
566 * ConfigItem::ResetScroll
567 *****************************************************************************/
568 void ConfigItem::ResetScroll()
575 fView->ScrollTo( 0, 0 );
578 /***********************************************************************
580 ***********************************************************************
582 **********************************************************************/
583 void ConfigItem::Apply( bool doIt )
590 /* Call ConfigWidget::Apply for every child of your fView */
591 ConfigWidget * widget;
592 for( int i = 0; i < fView->CountChildren(); i++ )
594 widget = (ConfigWidget*) fView->ChildAt( i );
595 widget->Apply( doIt );
599 /***********************************************************************
600 * ConfigWidget::ConfigWidget
601 ***********************************************************************
602 * Builds a view with the right controls for the given config variable.
603 * rect: the BRect where we place ourselves. All we care is its width
604 * and its top coordinate, since we adapt our height to take only
606 **********************************************************************/
607 ConfigWidget::ConfigWidget( intf_thread_t * _p_intf, BRect rect,
608 module_config_t * p_item )
609 : BView( rect, NULL, B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP,
614 SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
617 BMenuItem * menuItem;
618 /* Skip deprecated options */
619 if( p_item->psz_current )
627 fType = p_item->i_type;
628 fName = strdup( p_item->psz_name );
632 case CONFIG_ITEM_MODULE:
633 case CONFIG_ITEM_MODULE_CAT:
634 case CONFIG_ITEM_MODULE_LIST_CAT:
635 case CONFIG_ITEM_STRING:
636 case CONFIG_ITEM_FILE:
637 case CONFIG_ITEM_DIRECTORY:
638 case CONFIG_ITEM_INTEGER:
639 case CONFIG_ITEM_FLOAT:
640 ResizeTo( Bounds().Width(), 25 );
641 fTextControl = new VTextControl( Bounds(), NULL,
642 p_item->psz_text, NULL, new BMessage(),
643 B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP );
644 AddChild( fTextControl );
646 case CONFIG_ITEM_KEY:
647 ResizeTo( Bounds().Width(), 25 );
649 r.left = r.right - 100;
650 fPopUpMenu = new BPopUpMenu( "" );
651 fMenuField = new BMenuField( r, NULL, NULL, fPopUpMenu,
652 B_FOLLOW_RIGHT | B_FOLLOW_TOP );
654 i < sizeof( vlc_keys ) / sizeof( key_descriptor_t );
657 menuItem = new BMenuItem( vlc_keys[i].psz_key_string, NULL );
658 fPopUpMenu->AddItem( menuItem );
660 r.right = r.left - 10; r.left = r.left - 60;
661 fShiftCheck = new BCheckBox( r, NULL, "Shift",
662 new BMessage(), B_FOLLOW_RIGHT | B_FOLLOW_TOP );
663 r.right = r.left - 10; r.left = r.left - 60;
664 fCtrlCheck = new BCheckBox( r, NULL, "Ctrl",
665 new BMessage(), B_FOLLOW_RIGHT | B_FOLLOW_TOP );
666 r.right = r.left - 10; r.left = r.left - 60;
667 fAltCheck = new BCheckBox( r, NULL, "Alt",
668 new BMessage(), B_FOLLOW_RIGHT | B_FOLLOW_TOP );
669 r.right = r.left - 10; r.left = 0; r.bottom -= 10;
670 fStringView = new BStringView( r, NULL, p_item->psz_text,
671 B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP );
672 AddChild( fStringView );
673 AddChild( fAltCheck );
674 AddChild( fCtrlCheck );
675 AddChild( fShiftCheck );
676 AddChild( fMenuField );
678 case CONFIG_ITEM_BOOL:
679 ResizeTo( Bounds().Width(), 25 );
680 fCheckBox = new BCheckBox( Bounds(), NULL, p_item->psz_text,
681 new BMessage(), B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP );
682 AddChild( fCheckBox );
692 ConfigWidget::~ConfigWidget()
697 /***********************************************************************
698 * ConfigWidget::Apply
699 ***********************************************************************
701 **********************************************************************/
702 void ConfigWidget::Apply( bool doIt )
704 BMenuItem * menuItem;
710 case CONFIG_ITEM_STRING:
711 case CONFIG_ITEM_FILE:
712 case CONFIG_ITEM_MODULE:
713 case CONFIG_ITEM_MODULE_CAT:
714 case CONFIG_ITEM_MODULE_LIST_CAT:
715 case CONFIG_ITEM_DIRECTORY:
718 config_PutPsz( p_intf, fName, fTextControl->Text() );
722 fTextControl->SetText( config_GetPsz( p_intf, fName ) );
726 case CONFIG_ITEM_INTEGER:
729 config_PutInt( p_intf, fName, atoi( fTextControl->Text() ) );
733 snprintf( string, 256, "%d", config_GetInt( p_intf, fName ) );
734 fTextControl->SetText( string );
738 case CONFIG_ITEM_FLOAT:
741 config_PutFloat( p_intf, fName, atof( fTextControl->Text() ) );
745 snprintf( string, 256, "%f", config_GetFloat( p_intf, fName ) );
746 fTextControl->SetText( string );
750 case CONFIG_ITEM_KEY:
753 menuItem = fPopUpMenu->FindMarked();
756 val.i_int = vlc_keys[fPopUpMenu->IndexOf( menuItem )].i_key_code;
757 if( fAltCheck->Value() )
759 val.i_int |= KEY_MODIFIER_ALT;
761 if( fCtrlCheck->Value() )
763 val.i_int |= KEY_MODIFIER_CTRL;
765 if( fShiftCheck->Value() )
767 val.i_int |= KEY_MODIFIER_SHIFT;
769 var_Set( p_intf->p_vlc, fName, val );
774 val.i_int = config_GetInt( p_intf, fName );
775 fAltCheck->SetValue( val.i_int & KEY_MODIFIER_ALT );
776 fCtrlCheck->SetValue( val.i_int & KEY_MODIFIER_CTRL );
777 fShiftCheck->SetValue( val.i_int & KEY_MODIFIER_SHIFT );
780 i < sizeof( vlc_keys ) / sizeof( key_descriptor_t ); i++ )
782 if( (unsigned) vlc_keys[i].i_key_code ==
783 ( val.i_int & ~KEY_MODIFIER ) )
785 menuItem = fPopUpMenu->ItemAt( i );
786 menuItem->SetMarked( true );
793 case CONFIG_ITEM_BOOL:
796 config_PutInt( p_intf, fName, fCheckBox->Value() );
800 fCheckBox->SetValue( config_GetInt( p_intf, fName ) );
809 VTextView::VTextView( BRect frame, const char *name,
810 uint32 resizingMode, uint32 flags )
811 : BTextView( frame, name, BRect( 10,10,10,10 ), resizingMode, flags )
813 FrameResized( Bounds().Width(), Bounds().Height() );
816 void VTextView::FrameResized( float width, float height )
818 BTextView::FrameResized( width, height );
819 SetTextRect( BRect( 10,10, width-11, height-11 ) );
822 VTextControl::VTextControl( BRect frame, const char *name,
823 const char *label, const char *text,
824 BMessage * message, uint32 resizingMode )
825 : BTextControl( frame, name, label, text, message, resizingMode )
827 FrameResized( Bounds().Width(), Bounds().Height() );
830 void VTextControl::FrameResized( float width, float height )
832 BTextControl::FrameResized( width, height );
833 SetDivider( width / 2 );