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