]> git.sesse.net Git - vlc/blob - modules/gui/beos/PreferencesWindow.cpp
modules/gui/beos/PreferencesWindow.cpp:
[vlc] / modules / gui / beos / PreferencesWindow.cpp
1 /*****************************************************************************
2  * PreferencesWindow.cpp: beos interface
3  *****************************************************************************
4  * Copyright (C) 1999, 2000, 2001 VideoLAN
5  * $Id: PreferencesWindow.cpp,v 1.17 2003/05/07 16:47:10 titer Exp $
6  *
7  * Authors: Eric Petit <titer@videolan.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 <InterfaceKit.h>
27 #include <SupportKit.h>
28
29 #include <vlc/vlc.h>
30 #include <vlc/intf.h>
31
32 #include "PreferencesWindow.h"
33
34 /* We use this function to order the items of the BOutlineView */
35 int compare_func( const BListItem * _first, const BListItem * _second )
36 {
37     StringItemWithView * first = (StringItemWithView*) _first;
38     StringItemWithView * second = (StringItemWithView*) _second;
39     
40     /* the beos module first */
41     if( !strcmp( first->Text(), "beos" ) )
42         return -1;
43     if( !strcmp( second->Text(), "beos" ) )
44         return 1;
45
46     /* the main module in second */
47     if( !strcmp( first->Text(), "main" ) )
48         return -1;
49     if( !strcmp( second->Text(), "main" ) )
50         return 1;
51
52     /* alphabetic order */
53     return( strcmp( first->Text(), second->Text() ) );
54 }
55
56 /*****************************************************************************
57  * StringItemWithView::StringItemWithView
58  *****************************************************************************/
59 StringItemWithView::StringItemWithView( const char * text )
60     : BStringItem( text )
61 {
62     /* We use the default constructor */
63 }
64
65 /*****************************************************************************
66  * ConfigView::ConfigView
67  *****************************************************************************/
68 ConfigView::ConfigView( BRect frame, const char * name,
69                         uint32 resizingMode, uint32 flags )
70     : BView( frame, name, resizingMode, flags )
71 {
72     /* We use the default constructor */
73 }
74
75 /*****************************************************************************
76  * PreferencesWindow::PreferencesWindow
77  *****************************************************************************/
78 PreferencesWindow::PreferencesWindow( intf_thread_t * p_interface,
79                                       BRect frame, const char * name )
80     : BWindow( frame, name, B_FLOATING_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
81                B_NOT_ZOOMABLE | B_NOT_H_RESIZABLE ),
82       fConfigScroll( NULL ),
83       p_intf( p_interface )
84 {
85     BRect rect;
86
87     /* The "background" view */
88     rgb_color background = ui_color( B_PANEL_BACKGROUND_COLOR );
89     fPrefsView = new BView( Bounds(), NULL, B_FOLLOW_ALL, B_WILL_DRAW );
90     fPrefsView->SetViewColor( background );
91     AddChild( fPrefsView );
92     
93     /* Create the preferences tree */
94     rect = Bounds();
95     rect.InsetBy( 10, 10 );
96     rect.right = rect.left + 150;
97     fOutline = new BOutlineListView( rect, "preferences tree",
98                                      B_SINGLE_SELECTION_LIST,
99                                      B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM );
100     BScrollView * scrollview = new BScrollView( "scrollview", fOutline,
101                                                 B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM,
102                                                 0, false, true );
103     fPrefsView->AddChild( scrollview );
104     
105     /* We need to be informed if the user selects an item */
106     fOutline->SetSelectionMessage( new BMessage( PREFS_ITEM_SELECTED ) );
107
108     /* Create a dummy view so we can correctly place the real config views later */
109     rect.bottom -= 40;
110     rect.left = rect.right + 15 + B_V_SCROLL_BAR_WIDTH;
111     rect.right = Bounds().right - 15;
112     fDummyView = new BView( rect, "", B_FOLLOW_ALL_SIDES, B_WILL_DRAW );
113     fPrefsView->AddChild( fDummyView );
114
115     /* Add a category for modules configuration */
116     StringItemWithView * modulesItem;
117     modulesItem = new StringItemWithView( _("Modules") );
118     modulesItem->fConfigView = NULL;
119     fOutline->AddItem( modulesItem );
120    
121     /* Fill the tree */
122     /* TODO:
123         - manage CONFIG_HINT_SUBCATEGORY
124         - use a pop-up for CONFIG_HINT_MODULE
125         - use BSliders for integer_with_range and float_with_range
126         - add the needed LockLooper()s
127         - fix horizontal window resizing
128         - make this intuitive ! */
129     vlc_list_t * p_list;
130     p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
131     if( !p_list )
132     {
133         msg_Warn( p_intf, "couldn't find any module !" );
134         return;
135     }
136
137     module_t * p_module;
138     for( int i = 0; i < p_list->i_count; i++ )
139     {
140         p_module = (module_t*) p_list->p_values[i].p_object;
141         
142         /* If the module has no config option, ignore it */
143         module_config_t * p_item;
144         p_item = p_module->p_config;
145         if( !p_item )
146             continue;
147         do
148         {
149             if( p_item->i_type & CONFIG_ITEM )
150                 break;
151         } while( p_item->i_type != CONFIG_HINT_END && p_item++ );
152         if( p_item->i_type == CONFIG_HINT_END )
153             continue;
154         
155         /* Build the config view for this module */
156         rect = fDummyView->Bounds();
157         rect.right -= B_V_SCROLL_BAR_WIDTH;
158         ConfigView * configView;
159         configView = new ConfigView( rect, "config view",
160                                      B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP, B_WILL_DRAW );
161         configView->SetViewColor( background );
162         
163         rect = configView->Bounds();
164         rect.InsetBy( 10, 10 );
165         rect.bottom = rect.top + TEXT_HEIGHT;
166         BTextControl * textControl;
167         BCheckBox * checkBox;
168
169         /* FIXME: we use the BControl name to store the VLC variable name.
170            To know what variable type it is, I add one character at the beginning
171            of the name (see ApplyChanges()); it's not pretty, but it works. To
172            be cleaned later. */    
173         char name[128];
174         p_item = p_module->p_config;
175         bool firstItem = true;
176         do
177         {
178             switch( p_item->i_type )
179             {
180                 case CONFIG_ITEM_STRING:
181                 case CONFIG_ITEM_FILE:
182                 case CONFIG_ITEM_MODULE:
183                 case CONFIG_ITEM_DIRECTORY:
184                     if( !firstItem )
185                         rect.OffsetBy( 0, 25 );
186                     else
187                         firstItem = false;
188                     
189                     memset( name, 0, 128 );
190                     sprintf( name, "s%s", p_item->psz_name );
191                     textControl = new BTextControl( rect, name, p_item->psz_text,
192                                                     "", new BMessage(),
193                                                     B_FOLLOW_NONE );
194                     configView->AddChild( textControl );
195                     break;
196
197                 case CONFIG_ITEM_INTEGER:
198                     if( !firstItem )
199                         rect.OffsetBy( 0, 25 );
200                     else
201                         firstItem = false;
202                         
203                     memset( name, 0, 128 );
204                     sprintf( name, "i%s", p_item->psz_name );
205                     textControl = new BTextControl( rect, name, p_item->psz_text,
206                                                     "", new BMessage(),
207                                                     B_FOLLOW_NONE );
208                     configView->AddChild( textControl );
209                     break;
210
211                 case CONFIG_ITEM_FLOAT:
212                     if( !firstItem )
213                         rect.OffsetBy( 0, 25 );
214                     else
215                         firstItem = false;
216                         
217                     memset( name, 0, 128 );
218                     sprintf( name, "f%s", p_item->psz_name );
219                     textControl = new BTextControl( rect, name, p_item->psz_text,
220                                                     "", new BMessage(),
221                                                     B_FOLLOW_NONE );
222                     configView->AddChild( textControl );
223                     break;
224             
225                 case CONFIG_ITEM_BOOL:
226                     if( !firstItem )
227                         rect.OffsetBy( 0,25 );
228                     else
229                        firstItem = false;
230                        
231                     memset( name, 0, 128 );
232                     sprintf( name, "b%s", p_item->psz_name );
233                     checkBox = new BCheckBox( rect, name, p_item->psz_text,
234                                               new BMessage(), B_FOLLOW_NONE );
235                     configView->AddChild( checkBox );
236                     break;
237             }
238
239         } while( p_item->i_type != CONFIG_HINT_END && p_item++ );
240     
241         /* Adjust the configView size */
242         rect.bottom += 10;
243         configView->fRealBounds = BRect( 0, 0, configView->Bounds().Width(), rect.bottom );
244         configView->ResizeTo( configView->Bounds().Width(), configView->Bounds().Height() );
245
246         /* Add the item to the tree */
247         StringItemWithView * stringItem;
248         stringItem = new StringItemWithView( p_module->psz_object_name );
249         stringItem->fConfigView = configView;
250         if( !strcmp( p_module->psz_object_name, "beos" )
251             || !strcmp( p_module->psz_object_name, "main" ) )
252             fOutline->AddItem( stringItem );
253         else
254             fOutline->AddUnder( stringItem, modulesItem );
255     }
256     
257     vlc_list_release( p_list );
258     
259     /* Set the correct values */
260     ApplyChanges( false );
261     
262     /* Sort items, collapse the Modules one */
263     fOutline->FullListSortItems( compare_func );
264     fOutline->Collapse( modulesItem );
265     
266     /* Select the first item */
267     fOutline->Select( 0 );
268     
269     /* Add the buttons */
270     BButton * button;
271     rect = Bounds();
272     rect.InsetBy( 10, 10 );
273     rect.left = rect.right - 80;
274     rect.top = rect.bottom - 25;
275     button = new BButton( rect, "", _("OK"), new BMessage( PREFS_OK ),
276                           B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM );
277     fPrefsView->AddChild( button );
278     rect.OffsetBy( -90, 0 );
279     button = new BButton( rect, "", _("Revert"), new BMessage( PREFS_REVERT ),
280                           B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM );
281     fPrefsView->AddChild( button );
282     rect.OffsetBy( -90, 0 );
283     button = new BButton( rect, "", _("Apply"), new BMessage( PREFS_APPLY ),
284                           B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM );
285     fPrefsView->AddChild( button );
286     
287     Hide();
288     Show();
289 }
290
291 /*****************************************************************************
292  * PreferencesWindow::~PreferencesWindow
293  *****************************************************************************/
294 PreferencesWindow::~PreferencesWindow()
295 {
296 }
297
298 /*****************************************************************************
299  * PreferencesWindow::QuitRequested
300  *****************************************************************************/
301 bool PreferencesWindow::QuitRequested()
302 {
303     if( !IsHidden() )
304         Hide();
305         return false;
306 }
307
308 /*****************************************************************************
309  * PreferencesWindow::MessageReceived
310  *****************************************************************************/
311 void PreferencesWindow::MessageReceived( BMessage * message )
312 {
313     switch( message->what )
314     {
315         case PREFS_ITEM_SELECTED:
316             Update();
317             break;
318         
319         case PREFS_OK:
320             ApplyChanges( true );
321             PostMessage( B_QUIT_REQUESTED );
322             break;
323         
324         case PREFS_REVERT:
325             ApplyChanges( false );
326             break;
327         
328         case PREFS_APPLY:
329             ApplyChanges( true );
330             break;
331
332         default:
333             BWindow::MessageReceived( message );
334     }
335 }
336
337 /*****************************************************************************
338  * PreferencesWindow::FrameResized
339  *****************************************************************************/
340 void PreferencesWindow::FrameResized( float width, float height )
341 {
342     BWindow::FrameResized( width, height );
343     
344     /* Get the current ConfigView */
345     ConfigView * view;
346     view = (ConfigView*) fConfigScroll->ChildAt( 0 );
347
348     view->ResizeTo( fDummyView->Bounds().Width() - B_V_SCROLL_BAR_WIDTH,
349                     fDummyView->Bounds().Height() );
350
351     UpdateScrollBar();
352 }
353
354 /*****************************************************************************
355  * PreferencesWindow::Update
356  *****************************************************************************/
357 void PreferencesWindow::Update()
358 {
359     /* Get the selected item, if any */
360     if( fOutline->CurrentSelection() < 0 )
361         return;
362     StringItemWithView * selectedItem =
363         (StringItemWithView*) fOutline->ItemAt( fOutline->CurrentSelection() );
364     
365     if( !selectedItem->fConfigView )
366         /* This must be the "Modules" item */
367         return;
368
369     if( fConfigScroll )
370     {
371         /* If we don't do this, the ConfigView will remember a wrong position */
372         BScrollBar * scrollBar = fConfigScroll->ScrollBar( B_VERTICAL );
373         scrollBar->SetValue( 0 );
374
375         /* Detach the current ConfigView, remove the BScrollView */
376         BView * view;
377         while( ( view = fConfigScroll->ChildAt( 0 ) ) )
378             fConfigScroll->RemoveChild( view );
379         fDummyView->RemoveChild( fConfigScroll );
380         delete fConfigScroll;
381     }
382     
383     selectedItem->fConfigView->ResizeTo( fDummyView->Bounds().Width() -
384                                              B_V_SCROLL_BAR_WIDTH,
385                                          fDummyView->Bounds().Height() );
386     
387     /* Create a BScrollView with the new ConfigView in it */
388     fConfigScroll = new BScrollView( "", selectedItem->fConfigView, B_FOLLOW_ALL_SIDES,
389                                      0, false, true, B_NO_BORDER );
390     fDummyView->AddChild( fConfigScroll );
391     UpdateScrollBar();
392 }
393
394
395 /*****************************************************************************
396  * PreferencesWindow::UpdateScrollBar
397  *****************************************************************************/
398 void PreferencesWindow::UpdateScrollBar()
399 {
400     /* We have to fix the scrollbar manually because it doesn't handle
401        correctly simple BViews */
402        
403     /* Get the current config view */
404     ConfigView * view;
405     view = (ConfigView*) fConfigScroll->ChildAt( 0 );
406     
407     /* Get the available BRect for display */
408     BRect display = fConfigScroll->Bounds();
409     display.right -= B_V_SCROLL_BAR_WIDTH;
410     
411     /* Fix the scrollbar */
412     BScrollBar * scrollBar;
413     long max;
414         BRect visible = display & view->fRealBounds;
415         BRect total = display | view->fRealBounds;
416     scrollBar = fConfigScroll->ScrollBar( B_VERTICAL );
417     max = (long)( view->fRealBounds.Height() - visible.Height() );
418     if( max < 0 ) max = 0;
419     scrollBar->SetRange( 0, max );
420     scrollBar->SetProportion( visible.Height() / total.Height() );
421 }
422
423 /*****************************************************************************
424  * PreferencesWindow::ApplyChanges
425  * Apply changes if doIt is true, revert them otherwise
426  *****************************************************************************/
427 void PreferencesWindow::ApplyChanges( bool doIt )
428 {
429     StringItemWithView * item;
430     ConfigView * view;
431     BView * child;
432     const char * name;
433     BString string;
434     for( int i = 0; i < fOutline->CountItems(); i++ )
435     {
436         item = (StringItemWithView*) fOutline->ItemAt( i );
437         view = item->fConfigView;
438         
439         if( !view )
440             /* This must be the "Modules" item */
441             continue;
442         
443         for( int j = 0; j < view->CountChildren(); j++ )
444         {
445             child = view->ChildAt( j );
446             name = child->Name();
447             switch( *name )
448             {
449                 case 's': /* BTextControl, string variable */
450                     if( doIt )
451                         config_PutPsz( p_intf, name + 1, ((BTextControl*)child)->Text() );
452                     else
453                         ((BTextControl*)child)->SetText( config_GetPsz( p_intf, name + 1 ) );
454                     break;
455                 case 'i': /* BTextControl, int variable */
456                     if( doIt )
457                         config_PutInt( p_intf, name + 1, atoi( ((BTextControl*)child)->Text() ) );
458                     else
459                     {
460                         string = "";
461                         string << config_GetInt( p_intf, name + 1 );
462                         ((BTextControl*)child)->SetText( string.String() );
463                     }
464                     break;
465                 case 'f': /* BTextControl, float variable */
466                     if( doIt )
467                         config_PutFloat( p_intf, name + 1,
468                                          strtod( ((BTextControl*)child)->Text(), NULL ) );
469                     else
470                     {
471                         string = "";
472                         string << config_GetFloat( p_intf, name + 1 );
473                         ((BTextControl*)child)->SetText( string.String() );
474                     }
475                     break;
476                 case 'b': /* BCheckBox, bool variable */
477                     if( doIt )
478                         config_PutInt( p_intf, name + 1, ((BCheckBox*)child)->Value() );
479                     else
480                         ((BCheckBox*)child)->SetValue( config_GetInt( p_intf, name + 1 ) );
481                     break;
482             }
483         }
484     }
485 }
486
487 /*****************************************************************************
488  * PreferencesWindow::ReallyQuit
489  *****************************************************************************/
490 void PreferencesWindow::ReallyQuit()
491 {
492     Lock();
493     Hide();
494     Quit();
495 }