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