]> git.sesse.net Git - vlc/blob - modules/gui/beos/PreferencesWindow.cpp
beos/*: first pass at fixing the BeOS prefs
[vlc] / modules / gui / beos / PreferencesWindow.cpp
1 /*****************************************************************************
2  * PreferencesWindow.cpp: beos interface
3  *****************************************************************************
4  * Copyright (C) 1999, 2000, 2001 VideoLAN
5  * $Id$
6  *
7  * Authors: Eric Petit <titer@m0k.org>
8  *
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.
13  *
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.
18  *
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  *****************************************************************************/
23
24 #include <stdlib.h> /* atoi(), strtod() */
25
26 #include <String.h>
27
28 #include <vlc/vlc.h>
29 #include <vlc/intf.h>
30 #include <vlc_keys.h>
31 #include <vlc_config_cat.h>
32
33 #include "PreferencesWindow.h"
34
35 #define TYPE_CATEGORY 0
36 #define TYPE_SUBCATEGORY 2
37 #define TYPE_MODULE 3
38
39 /*****************************************************************************
40  * PreferencesWindow::PreferencesWindow
41  *****************************************************************************/
42 PreferencesWindow::PreferencesWindow( intf_thread_t * p_interface,
43                                       BRect frame, const char * name )
44     : BWindow( frame, name, B_FLOATING_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
45                B_NOT_ZOOMABLE ),
46       fConfigScroll( NULL ),
47       p_intf( p_interface )
48 {
49     BRect rect;
50
51     /* The "background" view */
52     fPrefsView = new BView( Bounds(), NULL, B_FOLLOW_ALL, B_WILL_DRAW );
53     fPrefsView->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
54     AddChild( fPrefsView );
55
56     /* Create a scrollable outline view for the preferences tree */
57     rect = Bounds();
58     rect.InsetBy( 10, 10 );
59     rect.right = rect.left + 150;
60     fOutline = new BOutlineListView( rect, "preferences tree",
61                                      B_SINGLE_SELECTION_LIST,
62                                      B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM );
63     BScrollView * scrollview =
64         new BScrollView( "scrollview", fOutline,
65                          B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM,
66                          0, false, true );
67     fPrefsView->AddChild( scrollview );
68
69     /* We need to be informed if the user selects an item */
70     fOutline->SetSelectionMessage( new BMessage( PREFS_ITEM_SELECTED ) );
71
72     /* Create a dummy, empty view so we can correctly place the real
73        config views later */
74     rect.bottom -= 40;
75     rect.left = rect.right + 15 + B_V_SCROLL_BAR_WIDTH;
76     rect.right = Bounds().right - 15;
77     fDummyView = new BView( rect, "", B_FOLLOW_ALL_SIDES, B_WILL_DRAW );
78     fDummyView->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
79     fPrefsView->AddChild( fDummyView );
80
81     /* Fill the tree */
82     vlc_list_t * p_list;
83     p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
84     if( !p_list )
85     {
86         msg_Warn( p_intf, "couldn't find any module !" );
87         return;
88     }
89
90     /* Find the main module */
91     module_t * p_module = NULL;
92     module_config_t * p_item = NULL;
93     for( int i = 0; i < p_list->i_count; i++ )
94     {
95         p_module = (module_t*) p_list->p_values[i].p_object;
96
97         if( !strcmp( p_module->psz_object_name, "main" ) &&
98             ( p_item = p_module->p_config ) )
99             break;
100         else
101             p_module = NULL;
102     }
103
104     ConfigItem * catItem = NULL, * subcatItem, * otherItem;
105
106     if( p_module )
107     {
108         /* We found the main module, build the category tree */
109         for( ; p_item->i_type != CONFIG_HINT_END; p_item++ )
110         {
111             switch( p_item->i_type )
112             {
113                 case CONFIG_CATEGORY:
114                     catItem = new ConfigItem( p_intf,
115                         config_CategoryNameGet( p_item->i_value ),
116                         false,
117                         p_item->i_value,
118                         TYPE_CATEGORY,
119                         config_CategoryHelpGet( p_item->i_value ) );
120                     fOutline->AddItem( catItem );
121                     break;
122
123                 case CONFIG_SUBCATEGORY:
124                     if( catItem )
125                     {
126                         subcatItem = new ConfigItem( p_intf,
127                             config_CategoryNameGet( p_item->i_value ),
128                             false,
129                             p_item->i_value,
130                             TYPE_SUBCATEGORY,
131                             config_CategoryHelpGet( p_item->i_value ) );
132                         fOutline->AddUnder( subcatItem, catItem );
133                     }
134                     else
135                     {
136                         msg_Warn( p_intf, "subcategory without a category" );
137                     }
138                     break;
139             }
140         }
141     }
142
143     /* Now parse all others modules */
144
145     int category, subcategory, options;
146
147     for( int i = 0; i < p_list->i_count; i++ )
148     {
149         category    = -1;
150         subcategory = -1;
151         options     = 0;
152
153         p_module = (module_t*) p_list->p_values[i].p_object;
154
155         if( !strcmp( p_module->psz_object_name, "main" ) )
156             continue;
157
158         if( p_module->b_submodule ||
159             !( p_item = p_module->p_config ) )
160             continue;
161
162         for( ; p_item->i_type != CONFIG_HINT_END; p_item++ )
163         {
164             switch( p_item->i_type )
165             {
166                 case CONFIG_CATEGORY:
167                     category = p_item->i_value;
168                     break;
169                 case CONFIG_SUBCATEGORY:
170                     subcategory = p_item->i_value;
171                     break;
172                 default:
173                     if( p_item->i_type & CONFIG_ITEM )
174                         options++;
175             }
176             if( options > 0 && category >= 0 && subcategory >= 0 )
177             {
178                 break;
179             }
180         }
181
182         if( options < 1 || category < 0 || subcategory < 0 )
183             continue;
184
185         fprintf( stderr, "cat %d, sub %d, %s\n", category, subcategory,
186                  p_module->psz_shortname ? p_module->psz_shortname :
187                  p_module->psz_object_name );
188
189         catItem = NULL;
190         for( int j = 0; j < fOutline->CountItemsUnder( NULL, true ); j++ )
191         {
192             catItem = (ConfigItem*)
193                 fOutline->ItemUnderAt( NULL, true, j );
194             if( catItem->ObjectId() == category )
195                 break;
196             else
197                 catItem = NULL;
198         }
199
200         if( !catItem )
201             continue;
202
203         subcatItem = NULL;
204         for( int j = 0; j < fOutline->CountItemsUnder( catItem, true ); j++ )
205         {
206             subcatItem = (ConfigItem*)
207                 fOutline->ItemUnderAt( catItem, true, j );
208             if( subcatItem->ObjectId() == subcategory )
209                 break;
210             else
211                 subcatItem = NULL;
212         }
213
214         if( !subcatItem )
215             subcatItem = catItem;
216
217         otherItem = new ConfigItem( p_intf,
218             p_module->psz_shortname ?
219               p_module->psz_shortname : p_module->psz_object_name,
220             p_module->b_submodule,
221             p_module->b_submodule ?
222               ((module_t *)p_module->p_parent)->i_object_id :
223               p_module->i_object_id,
224             TYPE_MODULE,
225             NULL );
226         fOutline->AddUnder( otherItem, subcatItem );
227     }
228
229     vlc_list_release( p_list );
230
231     for( int i = 0; i < fOutline->FullListCountItems(); i++ )
232     {
233         otherItem = (ConfigItem *)
234             fOutline->FullListItemAt( i );
235         if( fOutline->Superitem( otherItem ) )
236         {
237             fOutline->Collapse( otherItem );
238         }
239     }
240
241     /* Set the correct values */
242     ApplyChanges( false );
243
244     /* Select the first item */
245     fOutline->Select( 0 );
246
247     /* Add the buttons */
248     BButton * button;
249     rect = Bounds();
250     rect.InsetBy( 10, 10 );
251     rect.left = rect.right - 80;
252     rect.top = rect.bottom - 25;
253     button = new BButton( rect, "", _("Apply"), new BMessage( PREFS_APPLY ),
254                           B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM );
255     button->MakeDefault( true );
256     fPrefsView->AddChild( button );
257     rect.OffsetBy( -90, 0 );
258     button = new BButton( rect, "", _("Save"), new BMessage( PREFS_SAVE ),
259                           B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM );
260     fPrefsView->AddChild( button );
261     rect.OffsetBy( -90, 0 );
262     button = new BButton( rect, "", _("Defaults"),
263                           new BMessage( PREFS_DEFAULTS ),
264                           B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM );
265     fPrefsView->AddChild( button );
266
267     Hide();
268     Show();
269 }
270
271 /*****************************************************************************
272  * PreferencesWindow::~PreferencesWindow
273  *****************************************************************************/
274 PreferencesWindow::~PreferencesWindow()
275 {
276 }
277
278 /*****************************************************************************
279  * PreferencesWindow::QuitRequested
280  *****************************************************************************/
281 bool PreferencesWindow::QuitRequested()
282 {
283     if( !IsHidden() )
284     {
285         Hide();
286     }
287     return false;
288 }
289
290 /*****************************************************************************
291  * PreferencesWindow::MessageReceived
292  *****************************************************************************/
293 void PreferencesWindow::MessageReceived( BMessage * message )
294 {
295     switch( message->what )
296     {
297         case PREFS_ITEM_SELECTED:
298             Update();
299             break;
300
301         case PREFS_DEFAULTS:
302             config_ResetAll( p_intf );
303             ApplyChanges( false );
304             break;
305
306         case PREFS_APPLY:
307             ApplyChanges( true );
308             break;
309
310         case PREFS_SAVE:
311             SaveChanges();
312             break;
313
314         default:
315             BWindow::MessageReceived( message );
316     }
317 }
318
319 /*****************************************************************************
320  * PreferencesWindow::FrameResized
321  *****************************************************************************/
322 void PreferencesWindow::FrameResized( float width, float height )
323 {
324     BWindow::FrameResized( width, height );
325
326     UpdateScrollBar();
327 }
328
329 /*****************************************************************************
330  * PreferencesWindow::Update
331  *****************************************************************************/
332 void PreferencesWindow::Update()
333 {
334     /* Get the selected item, if any */
335     if( fOutline->CurrentSelection() < 0 )
336         return;
337     fCurrent = (ConfigItem*)
338         fOutline->ItemAt( fOutline->CurrentSelection() );
339
340     /* Detach the old box if any */
341     if( fDummyView->CountChildren() > 0 )
342         fDummyView->RemoveChild( fDummyView->ChildAt( 0 ) );
343
344     /* Add the new one... */
345     fDummyView->AddChild( fCurrent->Box() );
346
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
352 #if 0
353     /* Force redrawing of its children */
354     BRect rect = fCurrent->fConfigBox->Bounds();
355     rect.InsetBy( 10,10 );
356     rect.top += 10;
357     fCurrent->fConfigScroll->ResizeTo( rect.Width(), rect.Height() );
358     fCurrent->fConfigScroll->Draw( fCurrent->fConfigScroll->Bounds() );
359
360     UpdateScrollBar();
361 #endif
362 }
363
364
365 /*****************************************************************************
366  * PreferencesWindow::UpdateScrollBar
367  *****************************************************************************/
368 void PreferencesWindow::UpdateScrollBar()
369 {
370     /* We have to fix the scrollbar manually because it doesn't handle
371        correctly simple BViews */
372
373 #if 0
374     if( !fCurrent )
375     {
376         return;
377     }
378
379     /* Get the available BRect for display */
380     BRect display = fCurrent->fConfigScroll->Bounds();
381     display.right -= B_V_SCROLL_BAR_WIDTH;
382
383     /* Fix the scrollbar */
384     BScrollBar * scrollBar;
385     long max;
386         BRect visible = display & fCurrent->fConfigView->Bounds();
387         BRect total = display | fCurrent->fConfigView->Bounds();
388     scrollBar = fCurrent->fConfigScroll->ScrollBar( B_VERTICAL );
389     max = (long)( fCurrent->fConfigView->Bounds().Height() - visible.Height() );
390     if( max < 0 ) max = 0;
391     scrollBar->SetRange( 0, max );
392     scrollBar->SetProportion( visible.Height() / total.Height() );
393     scrollBar->SetSteps( 10, 100 );
394 #endif
395 }
396
397 /*****************************************************************************
398  * PreferencesWindow::ApplyChanges
399  * Apply changes if doIt is true, revert them otherwise
400  *****************************************************************************/
401 void PreferencesWindow::ApplyChanges( bool doIt )
402 {
403     ConfigItem * item;
404
405     for( int i = 0; i < fOutline->CountItems(); i++ )
406     {
407         item = (ConfigItem*) fOutline->ItemAt( i );
408         item->Apply( doIt );
409     }
410 }
411
412 /*****************************************************************************
413  * PreferencesWindow::SaveChanges
414  *****************************************************************************/
415 void PreferencesWindow::SaveChanges()
416 {
417     ApplyChanges( true );
418     config_SaveConfigFile( p_intf, NULL );
419 }
420
421 /*****************************************************************************
422  * PreferencesWindow::ReallyQuit
423  *****************************************************************************/
424 void PreferencesWindow::ReallyQuit()
425 {
426     Lock();
427     Hide();
428     Quit();
429 }
430
431 /***********************************************************************
432  * ConfigItem::ConfigItem
433  ***********************************************************************
434  *
435  **********************************************************************/
436 ConfigItem::ConfigItem( intf_thread_t * _p_intf, char * name,
437                         bool subModule, int objectId,
438                         int type, char * help )
439     : BStringItem( name )
440 {
441     p_intf     = _p_intf;
442     fSubModule = subModule;
443     fObjectId  = objectId;
444     fType      = type;
445     fHelp      = strdup( help );
446
447     fTextView = NULL;
448
449     BRect r;
450     r = BRect( 0, 0, 100, 100 );
451     fBox = new BBox( r, NULL, B_FOLLOW_ALL );
452     fBox->SetLabel( name );
453
454     if( fType == TYPE_CATEGORY )
455     {
456         r = fBox->Bounds();
457         r.InsetBy( 10, 10 );
458         r.top += 5;
459
460         fTextView = new VTextView( r, NULL, B_FOLLOW_ALL, B_WILL_DRAW);
461         fTextView->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
462         fTextView->MakeEditable( false );
463         fTextView->MakeSelectable( false );
464         fTextView->Insert( fHelp );
465         fBox->AddChild( fTextView );
466     }
467 }
468
469 /***********************************************************************
470  * ConfigItem::~ConfigItem
471  ***********************************************************************
472  *
473  **********************************************************************/
474 ConfigItem::~ConfigItem()
475 {
476     if( fHelp )
477     {
478         free( fHelp );
479     }
480 }
481
482 /***********************************************************************
483  * ConfigItem::Apply
484  ***********************************************************************
485  *
486  **********************************************************************/
487 void ConfigItem::Apply( bool doIt )
488 {
489     ConfigWidget * widget;
490
491     return;
492
493     if( !fView )
494     {
495         /* This is a category */
496         return;
497     }
498
499     /* Call ConfigWidget::Apply for every child of your fView */
500     for( int i = 0; i < fView->CountChildren(); i++ )
501     {
502         widget = (ConfigWidget*) fView->ChildAt( i );
503         widget->Apply( doIt );
504     }
505 }
506
507 /***********************************************************************
508  * ConfigWidget::ConfigWidget
509  ***********************************************************************
510  * Builds a view with the right controls for the given config variable.
511  *  rect: the BRect where we place ourselves. All we care is its width
512  *    and its top coordinate, since we adapt our height to take only
513  *    the place we need
514  **********************************************************************/
515 ConfigWidget::ConfigWidget( intf_thread_t * _p_intf, BRect rect,
516                             module_config_t * p_item )
517     : BView( rect, NULL, B_FOLLOW_ALL, B_WILL_DRAW )
518 {
519 #if 0
520     fType = type;
521
522     switch( fType )
523     {
524         case CONFIG_ITEM_STRING:
525         case CONFIG_ITEM_FILE:
526         case CONFIG_ITEM_MODULE:
527         case CONFIG_ITEM_DIRECTORY:
528         case CONFIG_ITEM_INTEGER:
529         case CONFIG_ITEM_FLOAT:
530             ResizeTo( Bounds().Width(), 25 );
531             fTextControl = new BTextControl( Bounds(), NULL, label, NULL,
532                                      new BMessage() );
533             AddChild( fTextControl );
534             break;
535
536         case CONFIG_ITEM_BOOL:
537             ResizeTo( Bounds().Width(), 25 );
538             fCheckBox = new BCheckBox( Bounds(), NULL, label, new BMessage() );
539             AddChild( fCheckBox );
540             break;
541
542         case CONFIG_ITEM_KEY:
543             ResizeTo( Bounds().Width(), 25 );
544             r.left = r.right - 60;
545             fPopUpMenu = new BPopUpMenu( "" );
546             fMenuField = new BMenuField( r, NULL, NULL, fPopUpMenu );
547             for( unsigned i = 0;
548                  i < sizeof( vlc_keys ) / sizeof( key_descriptor_t ); i++ )
549             {
550                 menuItem = new BMenuItem( vlc_keys[i].psz_key_string, NULL );
551                 fPopUpMenu->AddItem( menuItem );
552             }
553         
554             r.right = r.left - 10; r.left = r.left - 60;
555             fShiftCheck = new BCheckBox( r, NULL, "Shift", new BMessage );
556         
557             r.right = r.left - 10; r.left = r.left - 60;
558             fCtrlCheck = new BCheckBox( r, NULL, "Ctrl", new BMessage );
559         
560             r.right = r.left - 10; r.left = r.left - 60;
561             fAltCheck = new BCheckBox( r, NULL, "Alt", new BMessage );
562         
563             /* Can someone tell me how we're supposed to get GUI items aligned ? */
564             r.right = r.left - 10; r.left = 0;
565             r.bottom -= 10;
566             fStringView = new BStringView( r, NULL, label );
567         
568             AddChild( fStringView );
569             AddChild( fAltCheck );
570             AddChild( fCtrlCheck );
571             AddChild( fShiftCheck );
572             AddChild( fMenuField );
573             break;
574 #endif
575 }
576
577 /***********************************************************************
578  * ConfigWidget::Apply
579  ***********************************************************************
580  *
581  **********************************************************************/
582 void ConfigWidget::Apply( bool doIt )
583 {
584 #if 0
585     switch( fType )
586     {
587         case CONFIG_ITEM_STRING:
588         case CONFIG_ITEM_FILE:
589         case CONFIG_ITEM_MODULE:
590         case CONFIG_ITEM_DIRECTORY:
591             if( doIt )
592             {
593                 config_PutPsz( p_intf, fConfigName, fTextControl->Text() );
594             }
595             else
596             {
597                 fTextControl->SetText( config_GetPsz( p_intf, fConfigName ) );
598             }
599             break;
600
601         case CONFIG_ITEM_INTEGER:
602             if( doIt )
603             {
604                 config_PutInt( p_intf, fConfigName,
605                                atoi( fTextControl->Text() ) );
606             }
607             else
608             {
609                 memset( string, 0, 1024 );
610                 snprintf( string, 1023, "%d",
611                           config_GetInt( p_intf, fConfigName ) );
612                 fTextControl->SetText( string );
613             }
614             break;
615
616         case CONFIG_ITEM_FLOAT:
617             if( doIt )
618             {
619                 config_PutFloat( p_intf, fConfigName,
620                                  strtod( fTextControl->Text(), NULL ) );
621             }
622             else
623             {
624                 memset( string, 0, 1024 );
625                 snprintf( string, 1023, "%f",
626                           config_GetFloat( p_intf, fConfigName ) );
627                 fTextControl->SetText( string );
628             }
629             break;
630
631         case CONFIG_ITEM_BOOL:
632             if( doIt )
633             {
634                 config_PutInt( p_intf, fConfigName, fCheckBox->Value() );
635             }
636             else
637             {
638                 fCheckBox->SetValue( config_GetInt( p_intf, fConfigName ) );
639             }
640             break;
641
642         case CONFIG_ITEM_KEY:
643             if( doIt )
644             {
645                 menuItem = fPopUpMenu->FindMarked();
646                 if( menuItem )
647                 {
648                     int value = vlc_keys[fPopUpMenu->IndexOf( menuItem )].i_key_code;
649                     if( fAltCheck->Value() )
650                     {
651                         value |= KEY_MODIFIER_ALT;
652                     }
653                     if( fCtrlCheck->Value() )
654                     {
655                         value |= KEY_MODIFIER_CTRL;
656                     }
657                     if( fShiftCheck->Value() )
658                     {
659                         value |= KEY_MODIFIER_SHIFT;
660                     }
661                     config_PutInt( p_intf, fConfigName, value );
662                 }
663             }
664             else
665             {
666                 int value = config_GetInt( p_intf, fConfigName );
667                 fAltCheck->SetValue( value & KEY_MODIFIER_ALT );
668                 fCtrlCheck->SetValue( value & KEY_MODIFIER_CTRL );
669                 fShiftCheck->SetValue( value & KEY_MODIFIER_SHIFT );
670         
671                 for( unsigned i = 0;
672                      i < sizeof( vlc_keys ) / sizeof( key_descriptor_t ); i++ )
673                 {
674                     if( (unsigned) vlc_keys[i].i_key_code ==
675                             ( value & ~KEY_MODIFIER ) )
676                     {
677                         menuItem = fPopUpMenu->ItemAt( i );
678                         menuItem->SetMarked( true );
679                         break;
680                     }
681                 }
682             }
683
684             break;
685     }
686 #endif
687 }
688
689 VTextView::VTextView( BRect frame, const char *name,
690                       uint32 resizingMode, uint32 flags )
691     : BTextView( frame, name, BRect( 10,10,10,10 ), resizingMode, flags )
692 {
693     FrameResized( Bounds().Width(), Bounds().Height() );
694 }
695
696 void VTextView::FrameResized( float width, float height )
697 {
698     BTextView::FrameResized( width, height );
699     SetTextRect( BRect( 10,10, width-11, height-11 ) );
700 }