]> git.sesse.net Git - vlc/blobdiff - modules/gui/beos/PreferencesWindow.cpp
+ beos/PreferencesWindow.cpp: esthetic change (use triangle thumb style
[vlc] / modules / gui / beos / PreferencesWindow.cpp
index 41a2c654826c43c3c249ef250e88a02334666aed..ce521dcdf9a6b49fed18b3b803ccf8e08b51b06a 100644 (file)
@@ -2,7 +2,7 @@
  * PreferencesWindow.cpp: beos interface
  *****************************************************************************
  * Copyright (C) 1999, 2000, 2001 VideoLAN
- * $Id: PreferencesWindow.cpp,v 1.2 2002/11/23 15:00:54 titer Exp $
+ * $Id: PreferencesWindow.cpp,v 1.27 2003/12/22 00:06:05 titer Exp $
  *
  * Authors: Eric Petit <titer@videolan.org>
  *
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  *****************************************************************************/
 
-/* BeOS headers */
-#include <InterfaceKit.h>
+#include <stdlib.h> /* atoi(), strtod() */
+
+#include <String.h>
 
-/* VLC headers */
 #include <vlc/vlc.h>
 #include <vlc/intf.h>
+#include <vlc_keys.h>
 
-/* BeOS module headers */
-#include "VlcWrapper.h"
-#include "MsgVals.h"
 #include "PreferencesWindow.h"
 
+/* TODO:
+    - add the needed LockLooper()s
+    - fix window resizing */
+
+/* We use this function to order the items of the BOutlineView */
+static int compare_func( const BListItem * _first,
+                         const BListItem * _second )
+{
+    StringItemWithView * first = (StringItemWithView*) _first;
+    StringItemWithView * second = (StringItemWithView*) _second;
+
+    /* The Modules tree at last */
+    if( !strcmp( first->Text(), _( "Modules" ) ) )
+        return 1;
+    if( !strcmp( second->Text(), _( "Modules" ) ) )
+        return -1;
+
+    /* alphabetic order */
+    return( strcmp( first->Text(), second->Text() ) );
+}
 
 /*****************************************************************************
- * Preferences::PreferencesWindow
+ * PreferencesWindow::PreferencesWindow
  *****************************************************************************/
-PreferencesWindow::PreferencesWindow( BRect frame, const char* name,
-                                                               intf_thread_t *p_interface )
-       :       BWindow( frame, name, B_FLOATING_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
-                                B_NOT_ZOOMABLE | B_NOT_RESIZABLE | B_NOT_CLOSABLE )
+PreferencesWindow::PreferencesWindow( intf_thread_t * p_interface,
+                                      BRect frame, const char * name )
+    : BWindow( frame, name, B_FLOATING_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
+               B_NOT_ZOOMABLE | B_NOT_RESIZABLE ),
+      fConfigScroll( NULL ),
+      p_intf( p_interface )
 {
-       p_intf = p_interface;
+    SetSizeLimits( PREFS_WINDOW_WIDTH, PREFS_WINDOW_WIDTH,
+                   200, 2000 );
+
     BRect rect;
 
-    /* "background" view */
-    p_prefs_view = new BView( Bounds(), NULL, B_FOLLOW_ALL, B_WILL_DRAW );
-    p_prefs_view->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
-    AddChild( p_prefs_view );
+    /* The "background" view */
+    fPrefsView = new BView( Bounds(), NULL, B_FOLLOW_ALL, B_WILL_DRAW );
+    fPrefsView->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
+    AddChild( fPrefsView );
 
-    /* add the tabs */
+    /* Create the preferences tree */
     rect = Bounds();
-    rect.top += 10;
-    rect.bottom -= 65;
-    p_tabview = new BTabView( rect, "preferences view" );
-    p_tabview->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
-    
-    p_ffmpeg_view = new BView( p_tabview->Bounds(), NULL, B_FOLLOW_ALL, B_WILL_DRAW );
-    p_ffmpeg_view->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
-    p_adjust_view = new BView( p_tabview->Bounds(), NULL, B_FOLLOW_ALL, B_WILL_DRAW );
-    p_adjust_view->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
-    
-    p_ffmpeg_tab = new BTab();
-    p_tabview->AddTab( p_ffmpeg_view, p_ffmpeg_tab );
-    p_ffmpeg_tab->SetLabel( "Ffmpeg" );
-    
-    p_adjust_tab = new BTab();
-    p_tabview->AddTab( p_adjust_view, p_adjust_tab );
-    p_adjust_tab->SetLabel( "Adjust" );
-    
-    /* fills the tabs */
-    /* ffmpeg tab */
-    rect = p_ffmpeg_view->Bounds();
-    rect.InsetBy( 10, 10 );
-    rect.bottom = rect.top + 30;
-    p_pp_slider = new BSlider( rect, "post-processing", "MPEG4 post-processing level",
-                               new BMessage( SLIDER_UPDATE ),
-                               0, 6, B_TRIANGLE_THUMB,
-                               B_FOLLOW_LEFT, B_WILL_DRAW ); 
-    p_pp_slider->SetHashMarks(B_HASH_MARKS_BOTTOM);
-    p_pp_slider->SetHashMarkCount( 7 );
-    p_pp_slider->SetLimitLabels( "None", "Maximum" );
-    p_ffmpeg_view->AddChild( p_pp_slider );
-    
-    
-    /* adjust tab */
-    rect = p_adjust_view->Bounds();
     rect.InsetBy( 10, 10 );
-    rect.bottom = rect.top + 30;
-    p_brightness_slider = new BSlider( rect, "brightness", "Brightness",
-                                       new BMessage( SLIDER_UPDATE ),
-                                       0, 200, B_TRIANGLE_THUMB,
-                                       B_FOLLOW_LEFT, B_WILL_DRAW );
-    p_brightness_slider->SetValue( 100 * config_GetFloat( p_intf, "Brightness" ) );
-    rect.OffsetBy( 0, 40 );
-    p_contrast_slider = new BSlider( rect, "contrast", "Contrast",
-                                     new BMessage( SLIDER_UPDATE ),
-                                     0, 200, B_TRIANGLE_THUMB,
-                                     B_FOLLOW_LEFT, B_WILL_DRAW );
-    p_contrast_slider->SetValue( 100 * config_GetFloat( p_intf, "Contrast" ) );
-    rect.OffsetBy( 0, 40 );
-    p_hue_slider = new BSlider( rect, "hue", "Hue",
-                                new BMessage( SLIDER_UPDATE ),
-                                0, 360, B_TRIANGLE_THUMB,
-                                B_FOLLOW_LEFT, B_WILL_DRAW );
-    p_hue_slider->SetValue( config_GetInt( p_intf, "Hue" ) );
-    rect.OffsetBy( 0, 40 );
-    p_saturation_slider = new BSlider( rect, "saturation", "Saturation",
-                                       new BMessage( SLIDER_UPDATE ),
-                                       0, 200, B_TRIANGLE_THUMB,
-                                       B_FOLLOW_LEFT, B_WILL_DRAW );
-    p_saturation_slider->SetValue( 100 * config_GetFloat( p_intf, "Saturation" ) );
-    p_adjust_view->AddChild( p_brightness_slider );
-    p_adjust_view->AddChild( p_contrast_slider );
-    p_adjust_view->AddChild( p_hue_slider );
-    p_adjust_view->AddChild( p_saturation_slider );
-    
-    p_prefs_view->AddChild( p_tabview );
-
-    /* restart message */
-    rect = p_prefs_view->Bounds();
-    rect.bottom -= 43;
-    rect.top = rect.bottom - 10;
-    p_restart_string = new BStringView( rect, NULL, "" );
-    rgb_color redColor = {255, 0, 0, 255};
-    p_restart_string->SetHighColor(redColor);
-    p_restart_string->SetAlignment( B_ALIGN_CENTER );
-    p_prefs_view->AddChild( p_restart_string );
-
-    /* buttons */
-    BButton *p_button;
+    rect.right = rect.left + 150;
+    fOutline = new BOutlineListView( rect, "preferences tree",
+                                     B_SINGLE_SELECTION_LIST,
+                                     B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM );
+    BScrollView * scrollview =
+        new BScrollView( "scrollview", fOutline,
+                         B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM,
+                         0, false, true );
+    fPrefsView->AddChild( scrollview );
+
+    /* We need to be informed if the user selects an item */
+    fOutline->SetSelectionMessage( new BMessage( PREFS_ITEM_SELECTED ) );
+
+    /* Create a dummy view so we can correctly place the real config
+       views later */
+    rect.bottom -= 40;
+    rect.left = rect.right + 15 + B_V_SCROLL_BAR_WIDTH;
+    rect.right = Bounds().right - 15;
+    fDummyView = new BView( rect, "", B_FOLLOW_ALL_SIDES, B_WILL_DRAW );
+    fDummyView->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
+    fPrefsView->AddChild( fDummyView );
+
+    /* Add a category for modules configuration */
+    StringItemWithView * modulesItem;
+    modulesItem = new StringItemWithView( _("Modules") );
+    fOutline->AddItem( modulesItem );
+
+    /* Fill the tree */
+    vlc_list_t * p_list;
+    p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
+    if( !p_list )
+    {
+        msg_Warn( p_intf, "couldn't find any module !" );
+        return;
+    }
+
+    /* First, handle the main module */
+    module_t * p_module = NULL;
+    module_config_t * p_item;
+    for( int i = 0; i < p_list->i_count; i++ )
+    {
+        p_module = (module_t*) p_list->p_values[i].p_object;
+
+        if( !strcmp( p_module->psz_object_name, "main" ) &&
+            ( p_item = p_module->p_config ) )
+            break;
+        else
+            p_module = NULL;
+    }
+
+    if( p_module )
+    {
+        /* We found the main module */
+        while( p_item->i_type == CONFIG_HINT_CATEGORY )
+        {
+            StringItemWithView * stringItem;
+            stringItem = new StringItemWithView( p_item->psz_text );
+            p_item++;
+            BuildConfigView( stringItem, &p_item, true );
+            fOutline->AddItem( stringItem );
+        }
+    }
+
+    for( int i = 0; i < p_list->i_count; i++ )
+    {
+        p_module = (module_t*) p_list->p_values[i].p_object;
+
+        if( !strcmp( p_module->psz_object_name, "main" ) )
+            continue;
+
+        /* If the module has no config option, ignore it */
+        p_item = p_module->p_config;
+        if( !p_item )
+        {
+            continue;
+        }
+        do
+        {
+            if( p_item->i_type & CONFIG_ITEM )
+            {
+                break;
+            }
+        } while( p_item->i_type != CONFIG_HINT_END && p_item++ );
+
+        if( p_item->i_type == CONFIG_HINT_END )
+        {
+            continue;
+        }
+
+        /* Create the capability tree if it doesn't already exist */
+        char * psz_capability;
+        psz_capability = p_module->psz_capability;
+        if( !psz_capability || !*psz_capability )
+        {
+            /* Empty capability ? Let's look at the submodules */
+            module_t * p_submodule;
+            for( int j = 0; j < p_module->i_children; j++ )
+            {
+                p_submodule = (module_t*)p_module->pp_children[ j ];
+                if( p_submodule->psz_capability &&
+                        *p_submodule->psz_capability )
+                {
+                    psz_capability = p_submodule->psz_capability;
+                    break;
+                }
+            }
+        }
+
+        StringItemWithView * capabilityItem;
+        capabilityItem = NULL;
+        for( int j = 0;
+             j < fOutline->CountItemsUnder( modulesItem, true ); j++ )
+        {
+            if( !strcmp( ((StringItemWithView*)
+                fOutline->ItemUnderAt( modulesItem, true, j ))->Text(),
+                         psz_capability ) )
+            {
+                capabilityItem = (StringItemWithView*)
+                    fOutline->ItemUnderAt( modulesItem, true, j );
+                break;
+            }
+        }
+        if( !capabilityItem )
+        {
+             capabilityItem = new StringItemWithView( psz_capability );
+             fOutline->AddUnder( capabilityItem, modulesItem );
+        }
+
+        /* Now add the item ! */
+        StringItemWithView * stringItem;
+        stringItem = new StringItemWithView( p_module->psz_object_name );
+        BuildConfigView( stringItem, &p_item, false );
+        fOutline->AddUnder( stringItem, capabilityItem );
+    }
+
+    vlc_list_release( p_list );
+
+    /* Set the correct values */
+    ApplyChanges( false );
+
+    /* Sort items, collapse the tree */
+    fOutline->FullListSortItems( compare_func );
+    fOutline->Collapse( modulesItem );
+    for( int i = 0; i < fOutline->CountItemsUnder( modulesItem, true ); i++ )
+        fOutline->Collapse( fOutline->ItemUnderAt( modulesItem, true, i ) );
+
+    /* Select the first item */
+    fOutline->Select( 0 );
+
+    /* Add the buttons */
+    BButton * button;
     rect = Bounds();
     rect.InsetBy( 10, 10 );
-    rect.top = rect.bottom - 25;
     rect.left = rect.right - 80;
-    p_button = new BButton( rect, NULL, "OK", new BMessage( PREFS_OK ) );
-    p_prefs_view->AddChild( p_button );
-    
+    rect.top = rect.bottom - 25;
+    button = new BButton( rect, "", _("Apply"), new BMessage( PREFS_APPLY ),
+                          B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM );
+    button->MakeDefault( true );
+    fPrefsView->AddChild( button );
     rect.OffsetBy( -90, 0 );
-    p_button = new BButton( rect, NULL, "Cancel", new BMessage( PREFS_CANCEL ) );
-    p_prefs_view->AddChild( p_button );
-    
+    button = new BButton( rect, "", _("Save"), new BMessage( PREFS_SAVE ),
+                          B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM );
+    fPrefsView->AddChild( button );
     rect.OffsetBy( -90, 0 );
-    p_button = new BButton( rect, NULL, "Defaults", new BMessage( PREFS_DEFAULTS ) );
-    p_prefs_view->AddChild( p_button );
-    
-       // start window thread in hidden state
-       Hide();
-       Show();
+    button = new BButton( rect, "", _("Defaults"),
+                          new BMessage( PREFS_DEFAULTS ),
+                          B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM );
+    fPrefsView->AddChild( button );
+
+    Hide();
+    Show();
 }
 
 /*****************************************************************************
@@ -158,34 +255,159 @@ PreferencesWindow::~PreferencesWindow()
 {
 }
 
+/*****************************************************************************
+ * PreferencesWindow::QuitRequested
+ *****************************************************************************/
+bool PreferencesWindow::QuitRequested()
+{
+    if( !IsHidden() )
+    {
+        Hide();
+    }
+       return false;
+}
+
 /*****************************************************************************
  * PreferencesWindow::MessageReceived
  *****************************************************************************/
-void PreferencesWindow::MessageReceived( BMessage * p_message )
-{
-       switch ( p_message->what )
-       {
-           case SLIDER_UPDATE:
-           {
-               ApplyChanges();
-               break;
-           }
-           case PREFS_DEFAULTS:
-           {
-               SetDefaults();
-               break;
-           }
-           case PREFS_OK:
-           {
-               config_PutInt( p_intf, "ffmpeg-pp-q", p_pp_slider->Value() );
-            config_PutPsz( p_intf, "filter", "adjust" );
-            ApplyChanges();
-            Hide();
-           }
-               default:
-                       BWindow::MessageReceived( p_message );
-                       break;
-       }
+void PreferencesWindow::MessageReceived( BMessage * message )
+{
+    switch( message->what )
+    {
+        case PREFS_ITEM_SELECTED:
+            Update();
+            break;
+
+        case PREFS_DEFAULTS:
+            config_ResetAll( p_intf );
+            ApplyChanges( false );
+            break;
+
+        case PREFS_APPLY:
+            ApplyChanges( true );
+            break;
+
+        case PREFS_SAVE:
+            SaveChanges();
+            break;
+
+        default:
+            BWindow::MessageReceived( message );
+    }
+}
+
+/*****************************************************************************
+ * PreferencesWindow::FrameResized
+ *****************************************************************************/
+void PreferencesWindow::FrameResized( float width, float height )
+{
+    BWindow::FrameResized( width, height );
+
+    UpdateScrollBar();
+}
+
+/*****************************************************************************
+ * PreferencesWindow::Update
+ *****************************************************************************/
+void PreferencesWindow::Update()
+{
+    /* Get the selected item, if any */
+    if( fOutline->CurrentSelection() < 0 )
+        return;
+    fCurrent = (StringItemWithView*)
+        fOutline->ItemAt( fOutline->CurrentSelection() );
+
+    if( !fCurrent->fConfigBox )
+        /* This is a category */
+        return;
+
+    /* Detach the old item */
+    if( fDummyView->CountChildren() > 0 )
+        fDummyView->RemoveChild( fDummyView->ChildAt( 0 ) );
+
+    /* Resize and show the new config box */
+    fCurrent->fConfigBox->ResizeTo( fDummyView->Bounds().Width(),
+                                    fDummyView->Bounds().Height() );
+    fDummyView->AddChild( fCurrent->fConfigBox );
+
+    /* Force redrawing of its children */
+    BRect rect = fCurrent->fConfigBox->Bounds();
+    rect.InsetBy( 10,10 );
+    rect.top += 10;
+    fCurrent->fConfigScroll->ResizeTo( rect.Width(), rect.Height() );
+    fCurrent->fConfigScroll->Draw( fCurrent->fConfigScroll->Bounds() );
+
+    UpdateScrollBar();
+}
+
+
+/*****************************************************************************
+ * PreferencesWindow::UpdateScrollBar
+ *****************************************************************************/
+void PreferencesWindow::UpdateScrollBar()
+{
+    /* We have to fix the scrollbar manually because it doesn't handle
+       correctly simple BViews */
+
+    if( !fCurrent )
+    {
+        return;
+    }
+
+    /* Get the available BRect for display */
+    BRect display = fCurrent->fConfigScroll->Bounds();
+    display.right -= B_V_SCROLL_BAR_WIDTH;
+
+    /* Fix the scrollbar */
+    BScrollBar * scrollBar;
+    long max;
+       BRect visible = display & fCurrent->fConfigView->Bounds();
+       BRect total = display | fCurrent->fConfigView->Bounds();
+    scrollBar = fCurrent->fConfigScroll->ScrollBar( B_VERTICAL );
+    max = (long)( fCurrent->fConfigView->Bounds().Height() - visible.Height() );
+    if( max < 0 ) max = 0;
+    scrollBar->SetRange( 0, max );
+    scrollBar->SetProportion( visible.Height() / total.Height() );
+    scrollBar->SetSteps( 10, 100 );
+}
+
+/*****************************************************************************
+ * PreferencesWindow::ApplyChanges
+ * Apply changes if doIt is true, revert them otherwise
+ *****************************************************************************/
+void PreferencesWindow::ApplyChanges( bool doIt )
+{
+    StringItemWithView * item;
+    BView              * view;
+    ConfigWidget       * child;
+    BString              string;
+
+    for( int i = 0; i < fOutline->CountItems(); i++ )
+    {
+        item = (StringItemWithView*) fOutline->ItemAt( i );
+        view = item->fConfigView;
+
+        if( !view )
+        {
+            /* This is a category */
+            continue;
+        }
+
+        for( int j = 0; j < view->CountChildren(); j++ )
+        {
+            child = (ConfigWidget*) view->ChildAt( j );
+            child->Apply( p_intf, doIt );
+        }
+    }
+}
+
+/*****************************************************************************
+ * PreferencesWindow::SaveChanges
+ *****************************************************************************/
+void PreferencesWindow::SaveChanges()
+{
+    ApplyChanges( true );
+    config_SaveConfigFile( p_intf, NULL );
 }
 
 /*****************************************************************************
@@ -193,62 +415,409 @@ void PreferencesWindow::MessageReceived( BMessage * p_message )
  *****************************************************************************/
 void PreferencesWindow::ReallyQuit()
 {
+    Lock();
     Hide();
     Quit();
 }
 
 /*****************************************************************************
- * PreferencesWindow::SetDefaults
+ * PreferencesWindow::BuildConfigView
  *****************************************************************************/
-void PreferencesWindow::SetDefaults()
+void PreferencesWindow::BuildConfigView( StringItemWithView * stringItem,
+                                         module_config_t ** pp_item,
+                                         bool stop_after_category )
+{
+    /* Build the BBox */
+    BRect rect = fDummyView->Bounds();
+    stringItem->fConfigBox = new BBox( rect, "config box", B_FOLLOW_ALL );
+    stringItem->fConfigBox->SetLabel( stringItem->fText );
+
+    /* Build the BView */
+    rect = stringItem->fConfigBox->Bounds();
+    rect.InsetBy( 10,10 );
+    rect.top += 10;
+    rect.right -= B_V_SCROLL_BAR_WIDTH + 5;
+    stringItem->fConfigView = new BView( rect, "config view",
+                                         B_FOLLOW_NONE, B_WILL_DRAW );
+    stringItem->fConfigView->SetViewColor(
+            ui_color( B_PANEL_BACKGROUND_COLOR ) );
+
+    /* Add all the settings options */
+    rect = stringItem->fConfigView->Bounds();
+    rect.InsetBy( 10, 10 );
+
+    ConfigTextControl * textControl;
+    ConfigCheckBox    * checkBox;
+    ConfigMenuField   * menuField;
+    ConfigSlider      * slider;
+    ConfigKey         * keyConfig;
+
+    for( ; (*pp_item)->i_type != CONFIG_HINT_END; (*pp_item)++ )
+    {
+        if( stop_after_category &&
+            (*pp_item)->i_type == CONFIG_HINT_CATEGORY )
+        {
+            break;
+        }
+
+        switch( (*pp_item)->i_type )
+        {
+            case CONFIG_ITEM_STRING:
+            case CONFIG_ITEM_FILE:
+            case CONFIG_ITEM_MODULE:
+            case CONFIG_ITEM_DIRECTORY:
+                if( (*pp_item)->ppsz_list && (*pp_item)->ppsz_list[0] )
+                {
+                    menuField = new ConfigMenuField( rect,
+                            (*pp_item)->i_type, (*pp_item)->psz_text,
+                            (*pp_item)->psz_name, (*pp_item)->ppsz_list );
+                    stringItem->fConfigView->AddChild( menuField );
+                    rect.top += menuField->Bounds().Height();
+                }
+                else
+                {
+                    textControl = new ConfigTextControl( rect,
+                            (*pp_item)->i_type, (*pp_item)->psz_text,
+                            (*pp_item)->psz_name );
+                    stringItem->fConfigView->AddChild( textControl );
+                    rect.top += textControl->Bounds().Height();
+                }
+                break;
+
+            case CONFIG_ITEM_INTEGER:
+                if( (*pp_item)->i_min == (*pp_item)->i_max )
+                {
+                    textControl = new ConfigTextControl( rect,
+                            CONFIG_ITEM_INTEGER, (*pp_item)->psz_text,
+                            (*pp_item)->psz_name );
+                    stringItem->fConfigView->AddChild( textControl );
+                    rect.top += textControl->Bounds().Height();
+                }
+                else
+                {
+                    slider = new ConfigSlider( rect, CONFIG_ITEM_INTEGER,
+                            (*pp_item)->psz_text, (*pp_item)->psz_name,
+                            (*pp_item)->i_min, (*pp_item)->i_max );
+                    stringItem->fConfigView->AddChild( slider );
+                    rect.top += slider->Bounds().Height();
+                }
+                break;
+
+            case CONFIG_ITEM_FLOAT:
+                if( (*pp_item)->f_min == (*pp_item)->f_max )
+                {
+                    textControl = new ConfigTextControl( rect,
+                            CONFIG_ITEM_FLOAT, (*pp_item)->psz_text,
+                            (*pp_item)->psz_name );
+                    stringItem->fConfigView->AddChild( textControl );
+                    rect.top += textControl->Bounds().Height();
+                }
+                else
+                {
+                    slider = new ConfigSlider( rect, CONFIG_ITEM_FLOAT,
+                            (*pp_item)->psz_text, (*pp_item)->psz_name,
+                            100 * (*pp_item)->f_min, 100 * (*pp_item)->f_max );
+                    stringItem->fConfigView->AddChild( slider );
+                    rect.top += slider->Bounds().Height();
+                }
+                break;
+
+            case CONFIG_ITEM_BOOL:
+                checkBox = new ConfigCheckBox( rect,
+                        CONFIG_ITEM_BOOL, (*pp_item)->psz_text,
+                        (*pp_item)->psz_name );
+                stringItem->fConfigView->AddChild( checkBox );
+                rect.top += checkBox->Bounds().Height();
+                break;
+
+            case CONFIG_ITEM_KEY:
+                keyConfig = new ConfigKey( rect, CONFIG_ITEM_KEY,
+                        (*pp_item)->psz_text, (*pp_item)->psz_name );
+                stringItem->fConfigView->AddChild( keyConfig );
+                rect.top += keyConfig->Bounds().Height();
+        }
+    }
+
+    /* Put the BView into a BScrollView */
+    stringItem->fConfigScroll =
+        new BScrollView( "config scroll", stringItem->fConfigView,
+                         B_FOLLOW_ALL, 0, false, true, B_FANCY_BORDER );
+    stringItem->fConfigScroll->SetViewColor(
+            ui_color( B_PANEL_BACKGROUND_COLOR ) );
+    stringItem->fConfigBox->AddChild( stringItem->fConfigScroll );
+
+    /* Adjust the configView size */
+    stringItem->fConfigView->ResizeTo(
+        stringItem->fConfigView->Bounds().Width(), rect.top );
+}
+
+ConfigWidget::ConfigWidget( BRect rect, int type, char * configName )
+    : BView( rect, NULL, B_FOLLOW_ALL, B_WILL_DRAW )
 {
-    p_pp_slider->SetValue( 0 );
-    p_brightness_slider->SetValue( 100 );
-    p_contrast_slider->SetValue( 100 );
-    p_hue_slider->SetValue( 0 );
-    p_saturation_slider->SetValue( 100 );
+    fConfigType = type;
+    fConfigName = strdup( configName );
+    SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
+}
 
-    p_restart_string->SetText( config_GetInt( p_intf, "ffmpeg-pp-q" ) ?
-        "Changes will take effect after you restart playback" : "" );
-    
-    config_PutPsz( p_intf, "filter", NULL );
-    config_PutInt( p_intf, "ffmpeg-pp-q", 0 );
-    
-    ApplyChanges();
+ConfigTextControl::ConfigTextControl( BRect rect, int type, char * label,
+                                      char * configName )
+    : ConfigWidget( BRect( rect.left, rect.top,
+                           rect.right, rect.top + 25 ),
+                    type, configName )
+{
+    fTextControl = new BTextControl( Bounds(), NULL, label, NULL,
+                                     new BMessage() );
+    AddChild( fTextControl );
 }
 
-/*****************************************************************************
- * PreferencesWindow::ApplyChanges
- *****************************************************************************/
-void PreferencesWindow::ApplyChanges()
+void ConfigTextControl::Apply( intf_thread_t * p_intf, bool doIt )
 {
-    bool b_restart_needed = false;
+    char string[1024];
 
-    if( ( !config_GetPsz( p_intf, "filter" ) ||
-          strncmp( config_GetPsz( p_intf, "filter" ), "adjust", 6 ) ) &&
-        ( p_brightness_slider->Value() != 100 ||
-          p_contrast_slider->Value() != 100 ||
-          p_hue_slider->Value() ||
-          p_saturation_slider->Value() != 100 ) )
+    switch( fConfigType )
     {
-        b_restart_needed = true;
+        case CONFIG_ITEM_STRING:
+        case CONFIG_ITEM_FILE:
+        case CONFIG_ITEM_MODULE:
+        case CONFIG_ITEM_DIRECTORY:
+            if( doIt )
+            {
+                config_PutPsz( p_intf, fConfigName, fTextControl->Text() );
+            }
+            else
+            {
+                fTextControl->SetText( config_GetPsz( p_intf, fConfigName ) );
+            }
+            break;
+        case CONFIG_ITEM_INTEGER:
+            if( doIt )
+            {
+                config_PutInt( p_intf, fConfigName,
+                               atoi( fTextControl->Text() ) );
+            }
+            else
+            {
+                memset( string, 0, 1024 );
+                snprintf( string, 1023, "%d",
+                          config_GetInt( p_intf, fConfigName ) );
+                fTextControl->SetText( string );
+            }
+            break;
+        case CONFIG_ITEM_FLOAT:
+            if( doIt )
+            {
+                config_PutFloat( p_intf, fConfigName,
+                                 strtod( fTextControl->Text(), NULL ) );
+            }
+            else
+            {
+                memset( string, 0, 1024 );
+                snprintf( string, 1023, "%f",
+                          config_GetFloat( p_intf, fConfigName ) );
+                fTextControl->SetText( string );
+            }
+            break;
     }
+}
+
+ConfigCheckBox::ConfigCheckBox( BRect rect, int type, char * label,
+                                char * configName )
+    : ConfigWidget( BRect( rect.left, rect.top,
+                           rect.right, rect.top + 25 ),
+                    type, configName )
+{
+    fCheckBox = new BCheckBox( Bounds(), NULL, label, new BMessage() );
+    AddChild( fCheckBox );
+}
 
-    if( p_pp_slider->Value() != config_GetInt( p_intf, "ffmpeg-pp-q" ) )
+void ConfigCheckBox::Apply( intf_thread_t * p_intf, bool doIt )
+{
+    if( doIt )
     {
-        b_restart_needed = true;
+        config_PutInt( p_intf, fConfigName, fCheckBox->Value() );
+    }
+    else
+    {
+        fCheckBox->SetValue( config_GetInt( p_intf, fConfigName ) );
     }
-    
-    config_PutFloat( p_intf, "Brightness",
-                     (float)p_brightness_slider->Value() / 100 );
-    config_PutFloat( p_intf, "Contrast",
-                     (float)p_contrast_slider->Value() / 100 );
-    config_PutInt( p_intf, "Hue", p_hue_slider->Value() );
-    config_PutFloat( p_intf, "Saturation",
-                     (float)p_saturation_slider->Value() / 100 );
-    
-    p_restart_string->LockLooper();
-    p_restart_string->SetText( b_restart_needed ?
-        "Changes will take effect after you restart playback" : "" );
-    p_restart_string->UnlockLooper();
 }
+
+ConfigMenuField::ConfigMenuField( BRect rect, int type, char * label,
+                                  char * configName, char ** list )
+    : ConfigWidget( BRect( rect.left, rect.top,
+                           rect.right, rect.top + 25 ),
+                    type, configName )
+{
+    BMenuItem * menuItem;
+
+    fPopUpMenu = new BPopUpMenu( "" );
+    fMenuField = new BMenuField( Bounds(), NULL, label, fPopUpMenu );
+
+    for( int i = 0; list[i]; i++ )
+    {
+        menuItem = new BMenuItem( list[i], new BMessage() );
+        fPopUpMenu->AddItem( menuItem );
+    }
+
+    AddChild( fMenuField );
+}
+
+void ConfigMenuField::Apply( intf_thread_t * p_intf, bool doIt )
+{
+    BMenuItem * menuItem;
+
+    if( doIt )
+    {
+        menuItem = fPopUpMenu->FindMarked();
+        if( menuItem )
+        {
+            config_PutPsz( p_intf, fConfigName, menuItem->Label() );
+        }
+    }
+    else
+    {
+        char * value = config_GetPsz( p_intf, fConfigName );
+        if( !value )
+        {
+            value = "";
+        }
+
+        for( int i = 0; i < fPopUpMenu->CountItems(); i++ )
+        {
+            menuItem = fPopUpMenu->ItemAt( i );
+            if( !strcmp( value, menuItem->Label() ) )
+            {
+                menuItem->SetMarked( true );
+                break;
+            }
+        }
+    }
+}
+
+ConfigSlider::ConfigSlider( BRect rect, int type, char * label,
+                            char * configName, int min, int max )
+    : ConfigWidget( BRect( rect.left, rect.top,
+                           rect.right, rect.top + 40 ),
+                    type, configName )
+{
+    fSlider = new BSlider( Bounds(), NULL, label, new BMessage(),
+                           min, max, B_TRIANGLE_THUMB );
+    AddChild( fSlider );
+}
+
+void ConfigSlider::Apply( intf_thread_t * p_intf, bool doIt )
+{
+    switch( fConfigType )
+    {
+        case CONFIG_ITEM_INTEGER:
+            if( doIt )
+            {
+                config_PutInt( p_intf, fConfigName, fSlider->Value() );
+            }
+            else
+            {
+                fSlider->SetValue( config_GetInt( p_intf, fConfigName ) );
+            }
+            break;
+
+        case CONFIG_ITEM_FLOAT:
+            if( doIt )
+            {
+                config_PutFloat( p_intf, fConfigName,
+                                 (float) fSlider->Value() / 100.0 );
+            }
+            else
+            {
+                fSlider->SetValue( 100 *
+                        config_GetFloat( p_intf, fConfigName ) );
+            }
+            break;
+    }
+}
+
+ConfigKey::ConfigKey( BRect rect, int type, char * label,
+                            char * configName )
+    : ConfigWidget( BRect( rect.left, rect.top,
+                           rect.right, rect.top + 25 ),
+                    type, configName )
+{
+    BRect r = Bounds();
+    BMenuItem * menuItem;
+
+    r.left = r.right - 60;
+    fPopUpMenu = new BPopUpMenu( "" );
+    fMenuField = new BMenuField( r, NULL, NULL, fPopUpMenu );
+    for( unsigned i = 0;
+         i < sizeof( vlc_keys ) / sizeof( key_descriptor_t ); i++ )
+    {
+        menuItem = new BMenuItem( vlc_keys[i].psz_key_string, NULL );
+        fPopUpMenu->AddItem( menuItem );
+    }
+
+    r.right = r.left - 10; r.left = r.left - 60;
+    fShiftCheck = new BCheckBox( r, NULL, "Shift", new BMessage );
+
+    r.right = r.left - 10; r.left = r.left - 60;
+    fCtrlCheck = new BCheckBox( r, NULL, "Ctrl", new BMessage );
+
+    r.right = r.left - 10; r.left = r.left - 60;
+    fAltCheck = new BCheckBox( r, NULL, "Alt", new BMessage );
+
+    /* Can someone tell me how we're supposed to get GUI items aligned ? */
+    r.right = r.left - 10; r.left = 0;
+    r.bottom -= 10;
+    fStringView = new BStringView( r, NULL, label );
+
+    AddChild( fStringView );
+    AddChild( fAltCheck );
+    AddChild( fCtrlCheck );
+    AddChild( fShiftCheck );
+    AddChild( fMenuField );
+}
+
+void ConfigKey::Apply( intf_thread_t * p_intf, bool doIt )
+{
+    BMenuItem * menuItem;
+
+    if( doIt )
+    {
+        menuItem = fPopUpMenu->FindMarked();
+        if( menuItem )
+        {
+            int value = vlc_keys[fPopUpMenu->IndexOf( menuItem )].i_key_code;
+            if( fAltCheck->Value() )
+            {
+                value |= KEY_MODIFIER_ALT;
+            }
+            if( fCtrlCheck->Value() )
+            {
+                value |= KEY_MODIFIER_CTRL;
+            }
+            if( fShiftCheck->Value() )
+            {
+                value |= KEY_MODIFIER_SHIFT;
+            }
+            config_PutInt( p_intf, fConfigName, value );
+        }
+    }
+    else
+    {
+        int value = config_GetInt( p_intf, fConfigName );
+        fAltCheck->SetValue( value & KEY_MODIFIER_ALT );
+        fCtrlCheck->SetValue( value & KEY_MODIFIER_CTRL );
+        fShiftCheck->SetValue( value & KEY_MODIFIER_SHIFT );
+
+        for( unsigned i = 0;
+             i < sizeof( vlc_keys ) / sizeof( key_descriptor_t ); i++ )
+        {
+            if( (unsigned) vlc_keys[i].i_key_code ==
+                    ( value & ~KEY_MODIFIER ) )
+            {
+                menuItem = fPopUpMenu->ItemAt( i );
+                menuItem->SetMarked( true );
+                break;
+            }
+        }
+    }
+}
+