[vlc-commits] [Git][videolan/vlc][master] 7 commits: qt: fix `StringListConfigControl` height

Jean-Baptiste Kempf (@jbk) gitlab at videolan.org
Sun Mar 6 00:23:07 UTC 2022



Jean-Baptiste Kempf pushed to branch master at VideoLAN / VLC


Commits:
b8acf760 by Lyndon Brown at 2022-03-05T23:55:49+00:00
qt: fix `StringListConfigControl` height

Experiments proved that `fixed` should be the default for this type of
control; it otherwise expands to capture additional height in some layouts.

- - - - -
44d814b9 by Lyndon Brown at 2022-03-05T23:55:49+00:00
qt: remove stray widget deletion

Our control classes are not widgets, deriving from `QObject` not `QWidget`.
Their component widgets are inserted into an external parent widget which
effectively passes ownership to that widget - when that widget is destroyed
any widgets it encapsulates will automatically also be destroyed.
Destructors of our control classes should thus not attempt to delete their
component widgets, since unless the control object is destroyed first, the
destructor will get called twice.

The unnecessary explicit deletion of this component widget within this
control class destructor was thus risking such double-destruction. This did
not seem to be occurring within the current codebase, however I happened to
encounter it in some later work.

- - - - -
f54fcbc6 by Lyndon Brown at 2022-03-05T23:55:49+00:00
qt: remove unused method

- - - - -
7f35d0fc by Lyndon Brown at 2022-03-05T23:55:49+00:00
qt: clean up prefs control layout insertion

Rename `fillGrid()` to `insertInto()` and expose publically instead of
pointlessly hiding behind `insertIntoExistingGrid()`.

- - - - -
3eb4edb3 by Lyndon Brown at 2022-03-05T23:55:49+00:00
qt: enable creating controls in box layouts

Needed shortly for the editing dialog of 'expert' prefs mode.

Note that I have not implemented it for `KeySelectorControl` since
I intend to exclude hotkeys entirely from expert mode.

- - - - -
8b75d973 by Lyndon Brown at 2022-03-05T23:55:49+00:00
qt: add expert preferences mode

This gives a table listing all options, similar to and inspired by the
`about:config` interface in Firefox.

Unique benefits:
 - It highlights which options have been modified from default state.
 - It allows selective resetting of individual options to default values.

Support is included to toggle booleans with a simple double-click.
Double-clicking on other types opens the edit dialog.

For colour selection items, the modify action directly opens the Qt
colour selection dialog rather than present the colour control used in
the advanced preferences view, since this is much cleaner.

Note that the existing simple and advanced views are not linked; if you
change an option in one view, that change is not reflected in the other,
and saving changes only uses the state from the selected view. The same
is currently true of the new expert mode, though I plan to later change
this behaviour (for all three).

Note also that hotkey items are deliberately excluded from this view.
The dedicated hotkey editor is best suited to managing hotkeys. It does
not work well to include the set of 224 unique hotkey options within this
table, especially since we'd have to duplicate the code checking for
duplicate assignments if we allow editing of them as with all other
option types within this interface. It may seem odd for the 'expert'
mode to be the only one without hotkey editing, however the hotkey editor
does not really fit well into 'advanced' mode either, and I have plans to
propose separating the hotkey editor entirely from within the set of
three views in a small redesign.

Fixes #18607.

- - - - -
626d25ae by Lyndon Brown at 2022-03-05T23:55:49+00:00
qt: replace `--qt-advanced-pref` to allow for new expert mode selection

- - - - -


13 changed files:

- modules/gui/qt/Makefile.am
- modules/gui/qt/dialogs/open/open_panels.cpp
- + modules/gui/qt/dialogs/preferences/expert_model.cpp
- + modules/gui/qt/dialogs/preferences/expert_model.hpp
- + modules/gui/qt/dialogs/preferences/expert_view.cpp
- + modules/gui/qt/dialogs/preferences/expert_view.hpp
- modules/gui/qt/dialogs/preferences/preferences.cpp
- modules/gui/qt/dialogs/preferences/preferences.hpp
- modules/gui/qt/dialogs/preferences/preferences_widgets.cpp
- modules/gui/qt/dialogs/preferences/preferences_widgets.hpp
- modules/gui/qt/dialogs/preferences/simple_preferences.cpp
- modules/gui/qt/qt.cpp
- po/POTFILES.in


Changes:

=====================================
modules/gui/qt/Makefile.am
=====================================
@@ -110,6 +110,10 @@ libqt_plugin_la_SOURCES = \
 	gui/qt/dialogs/podcast/podcast_configuration.hpp \
 	gui/qt/dialogs/preferences/complete_preferences.cpp \
 	gui/qt/dialogs/preferences/complete_preferences.hpp \
+	gui/qt/dialogs/preferences/expert_model.cpp \
+	gui/qt/dialogs/preferences/expert_model.hpp \
+	gui/qt/dialogs/preferences/expert_view.cpp \
+	gui/qt/dialogs/preferences/expert_view.hpp \
 	gui/qt/dialogs/preferences/preferences.cpp \
 	gui/qt/dialogs/preferences/preferences.hpp \
 	gui/qt/dialogs/preferences/preferences_widgets.cpp \
@@ -368,6 +372,8 @@ nodist_libqt_plugin_la_SOURCES = \
 	gui/qt/dialogs/plugins/plugins.moc.cpp \
 	gui/qt/dialogs/podcast/podcast_configuration.moc.cpp \
 	gui/qt/dialogs/preferences/complete_preferences.moc.cpp \
+	gui/qt/dialogs/preferences/expert_model.moc.cpp \
+	gui/qt/dialogs/preferences/expert_view.moc.cpp \
 	gui/qt/dialogs/preferences/preferences.moc.cpp \
 	gui/qt/dialogs/preferences/preferences_widgets.moc.cpp \
 	gui/qt/dialogs/preferences/simple_preferences.moc.cpp \


=====================================
modules/gui/qt/dialogs/open/open_panels.cpp
=====================================
@@ -823,12 +823,12 @@ void CaptureOpenPanel::initialize()
     int line = 0;
     module_config_t *p_config = config_FindConfig( "dshow-vdev" );
     vdevDshowW = new StringListConfigControl( p_config, this );
-    vdevDshowW->insertIntoExistingGrid( dshowDevLayout, line );
+    vdevDshowW->insertInto( dshowDevLayout, line );
     line++;
 
     p_config = config_FindConfig( "dshow-adev" );
     adevDshowW = new StringListConfigControl( p_config, this );
-    adevDshowW->insertIntoExistingGrid( dshowDevLayout, line );
+    adevDshowW->insertInto( dshowDevLayout, line );
     line++;
 
     /* dshow Properties */


=====================================
modules/gui/qt/dialogs/preferences/expert_model.cpp
=====================================
@@ -0,0 +1,434 @@
+/*****************************************************************************
+ * expert_model.cpp : Detailed preferences overview - model
+ *****************************************************************************
+ * Copyright (C) 2019-2022 VLC authors and VideoLAN
+ *
+ * Authors: Lyndon Brown <jnqnfe at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <QVariant>
+#include <QString>
+#include <QFont>
+#include <QGuiApplication>
+#include <QClipboard>
+#include <QMenu>
+#include <QDialogButtonBox>
+#include <QPushButton>
+#include <QColorDialog>
+#include <QVBoxLayout>
+#include <QAction>
+#include <QContextMenuEvent>
+
+#include "expert_model.hpp"
+#include "preferences_widgets.hpp"
+
+#include <vlc_config_cat.h>
+#include <vlc_modules.h>
+
+#define COLUMN_COUNT 4
+
+/*********************************************************************
+ * Model Item
+ *********************************************************************/
+ExpertPrefsTableItem::ExpertPrefsTableItem( module_config_t *config,
+                                            const QString &mod_name,
+                                            const QString &mod_name_pretty,
+                                            bool is_core )
+{
+    cfg_item = config;
+
+    if( CONFIG_CLASS( getType() ) == CONFIG_ITEM_STRING &&
+        config->value.psz != nullptr )
+    {
+        config->value.psz = strdup( config->value.psz );
+    }
+
+    /* Create table entry name from dot-prefixing module name to option name.
+       Many plugins dash-prefix their name to their option names, which we must
+       skip over here to replace the dash with a dot. */
+    QString option_name = config->psz_name;
+    int mod_name_len = mod_name.length();
+    if( !is_core && option_name.length() > mod_name_len &&
+        option_name.startsWith( mod_name ) && option_name[mod_name_len] == '-' )
+        option_name.remove( 0, mod_name_len + 1 );
+    name = QString( "%1.%2" ).arg( mod_name ).arg( option_name );
+    /* Some options use underscores when they shouldn't. Let's not pointlessly
+       leak that imperfection into our interface. */
+    name.replace( "_", "-" );
+
+    /* Create "title" text label for info panel. */
+    title = QString( "%1 :: %2" ).arg( mod_name_pretty ).arg( config->psz_text );
+    description = QString(); /* We'll use lazy creation */
+
+    updateMatchesDefault();
+    updateValueDisplayString();
+}
+
+ExpertPrefsTableItem::~ExpertPrefsTableItem()
+{
+    if( CONFIG_CLASS( getType() ) == CONFIG_ITEM_STRING )
+    {
+        free( cfg_item->value.psz );
+        cfg_item->value.psz = nullptr;
+    }
+}
+
+const QString &ExpertPrefsTableItem::getDescription()
+{
+    if( description.isNull() ) /* Lazy creation */
+    {
+        if( cfg_item->psz_longtext )
+            description = qfut( cfg_item->psz_longtext );
+        else if( cfg_item->psz_text )
+            description = qfut( cfg_item->psz_text );
+        else
+            description = QStringLiteral( u"" );
+    }
+    return description;
+}
+
+void ExpertPrefsTableItem::updateMatchesDefault()
+{
+    switch ( CONFIG_CLASS( getType() ) )
+    {
+        case CONFIG_ITEM_FLOAT:
+            matches_default = (cfg_item->value.f == cfg_item->orig.f);
+            break;
+        case CONFIG_ITEM_BOOL:
+        case CONFIG_ITEM_INTEGER:
+            matches_default = (cfg_item->value.i == cfg_item->orig.i);
+            break;
+        case CONFIG_ITEM_STRING:
+        {
+            bool orig_is_empty = (cfg_item->orig.psz == nullptr || cfg_item->orig.psz[0] == '\0');
+            bool curr_is_empty = (cfg_item->value.psz == nullptr || cfg_item->value.psz[0] == '\0');
+            if (orig_is_empty)
+                matches_default = curr_is_empty;
+            else if( curr_is_empty )
+                matches_default = false;
+            else
+                matches_default = (strcmp( cfg_item->value.psz, cfg_item->orig.psz ) == 0);
+            break;
+        }
+        default:
+            vlc_assert_unreachable();
+            break;
+    }
+}
+
+void ExpertPrefsTableItem::updateValueDisplayString()
+{
+    switch ( CONFIG_CLASS( getType() ) )
+    {
+        case CONFIG_ITEM_BOOL:
+            /* Do nothing - set at the model level to allow reusing cached translation lookup */
+            break;
+        case CONFIG_ITEM_FLOAT:
+            displayed_value = QString( "%L1" ).arg( cfg_item->value.f, 0, 'g' );
+            break;
+        case CONFIG_ITEM_INTEGER:
+            if( cfg_item->i_type == CONFIG_ITEM_RGB )
+            {
+                QString hex_upper = QString( "%1" ).arg( cfg_item->value.i, 0, 16 ).toUpper();
+                displayed_value = QString( "0x" ).append( hex_upper );
+            }
+            else
+                displayed_value = QString( "%L1" ).arg( cfg_item->value.i );
+            break;
+        case CONFIG_ITEM_STRING:
+            if( cfg_item->i_type != CONFIG_ITEM_PASSWORD )
+                displayed_value = cfg_item->value.psz;
+            else if( cfg_item->value.psz && *cfg_item->value.psz != '\0' )
+                displayed_value = QStringLiteral( u"•••••" );
+            else
+                displayed_value = QStringLiteral( u"" );
+            break;
+        default:
+            break;
+    }
+}
+
+void ExpertPrefsTableItem::setToDefault()
+{
+    /* Note, this modifies our local copy of the item only */
+    if( CONFIG_CLASS( getType() ) == CONFIG_ITEM_STRING )
+    {
+        free( cfg_item->value.psz );
+        cfg_item->value.psz = (cfg_item->orig.psz) ? strdup( cfg_item->orig.psz ) : nullptr;
+    }
+    else
+        cfg_item->value = cfg_item->orig;
+
+    matches_default = true;
+    updateValueDisplayString();
+}
+
+void ExpertPrefsTableItem::toggleBoolean()
+{
+    assert( CONFIG_CLASS( getType() ) == CONFIG_ITEM_BOOL );
+    /* Note, this modifies our local copy of the item only */
+    cfg_item->value.i = !cfg_item->value.i;
+    updateMatchesDefault();
+    /* Note, display text is updated by the model for efficiency */
+}
+
+/* search name and value columns */
+bool ExpertPrefsTableItem::contains( const QString &text, Qt::CaseSensitivity cs )
+{
+    return ( name.contains( text, cs ) || displayed_value.contains( text, cs ) );
+}
+
+/*********************************************************************
+ * Model
+ *********************************************************************/
+ExpertPrefsTableModel::ExpertPrefsTableModel( module_t **mod_list, size_t mod_count,
+                                              QWidget *parent_ ) :
+    QAbstractListModel( parent_ )
+{
+    /* Cache translations of common text */
+    state_same_text       = qtr( "default" );
+    state_different_text  = qtr( "modified" );
+    true_text             = qtr( "true" );
+    false_text            = qtr( "false" );
+    type_boolean_text     = qtr( "boolean" );
+    type_float_text       = qtr( "float" );
+    type_integer_text     = qtr( "integer" );
+    type_color_text       = qtr( "color" );
+    type_string_text      = qtr( "string" );
+    type_password_text    = qtr( "password" );
+    type_module_text      = qtr( "module" );
+    type_module_list_text = qtr( "module-list" );
+    type_file_text        = qtr( "file" );
+    type_directory_text   = qtr( "directory" );
+    type_font_text        = qtr( "font" );
+    type_unknown_text     = qtr( "unknown" );
+
+    items.reserve( 1400 );
+    for( size_t i = 0; i < mod_count; i++ )
+    {
+        module_t *mod = mod_list[i];
+
+        unsigned confsize;
+        module_config_t *const config = module_config_get( mod, &confsize );
+        if( confsize == 0 )
+            continue;
+        config_sets.append( config );
+
+        bool is_core = module_is_main( mod );
+        QString mod_name = module_get_object( mod );
+        QString mod_name_pretty = is_core ? qtr( "Core" ) : module_GetShortName( mod );
+
+        enum vlc_config_subcat subcat = SUBCAT_UNKNOWN;
+
+        for( size_t j = 0; j < confsize; j++ )
+        {
+            module_config_t *cfg_item = config + j;
+
+            if( cfg_item->i_type == CONFIG_SUBCATEGORY )
+            {
+                subcat = (enum vlc_config_subcat) cfg_item->value.i;
+                continue;
+            }
+            if( subcat == SUBCAT_UNKNOWN || subcat == SUBCAT_HIDDEN )
+                continue;
+            /* Exclude hotkey items in favour of them being edited exclusively
+               via the dedicated hotkey editor. */
+            if( cfg_item->i_type == CONFIG_ITEM_KEY )
+                continue;
+
+            if( CONFIG_ITEM( cfg_item->i_type ) )
+            {
+                ExpertPrefsTableItem *item =
+                    new ExpertPrefsTableItem( cfg_item, mod_name, mod_name_pretty, is_core );
+
+                if( CONFIG_CLASS( cfg_item->i_type ) == CONFIG_ITEM_BOOL )
+                {
+                    /* Set the translated display text from cached lookup */
+                    item->displayed_value = ( cfg_item->value.i == 0 ) ? false_text : true_text;
+                }
+
+                /* Sorted list insertion */
+                int insert_index = 0;
+                while( insert_index < items.count() )
+                {
+                    if( item->name.compare( items[insert_index]->name ) < 0 )
+                        break;
+                    insert_index++;
+                }
+                items.insert( insert_index, item );
+            }
+        }
+    }
+};
+
+ExpertPrefsTableModel::~ExpertPrefsTableModel()
+{
+    items.clear(); /* We must destroy the items before releasing the config set */
+    foreach ( module_config_t *config_set, config_sets )
+        module_config_free( config_set );
+}
+
+QVariant ExpertPrefsTableModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+    if( orientation == Qt::Horizontal && role == Qt::DisplayRole )
+    {
+        switch ( section )
+        {
+            case NameField:  return qtr( "Option" );
+            case StateField: return qtr( "Status" );
+            case TypeField:  return qtr( "Type" );
+            case ValueField: return qtr( "Value" );
+        }
+    }
+    return QVariant();
+}
+
+int ExpertPrefsTableModel::rowCount( const QModelIndex &parent ) const
+{
+    return parent.isValid() ? 0 : items.count();
+}
+
+int ExpertPrefsTableModel::columnCount( const QModelIndex &parent ) const
+{
+    return parent.isValid() ? 0 : COLUMN_COUNT;
+}
+
+QVariant ExpertPrefsTableModel::data( const QModelIndex &index, int role ) const
+{
+    ExpertPrefsTableItem *item = itemAt( index );
+    switch ( role )
+    {
+        case Qt::DisplayRole:
+        {
+            switch ( index.column() )
+            {
+                case NameField:  return item->name;
+                case ValueField: return item->displayed_value;
+                case StateField: return (item->matches_default) ? state_same_text
+                                                                : state_different_text;
+                case TypeField:
+                {
+                    switch ( item->cfg_item->i_type )
+                    {
+                        case CONFIG_ITEM_BOOL:             return type_boolean_text;     break;
+                        case CONFIG_ITEM_FLOAT:            return type_float_text;       break;
+                        case CONFIG_ITEM_INTEGER:          return type_integer_text;     break;
+                        case CONFIG_ITEM_RGB:              return type_color_text;       break;
+                        case CONFIG_ITEM_STRING:           return type_string_text;      break;
+                        case CONFIG_ITEM_PASSWORD:         return type_password_text;    break;
+                        case CONFIG_ITEM_MODULE_CAT:
+                        case CONFIG_ITEM_MODULE:           return type_module_text;      break;
+                        case CONFIG_ITEM_MODULE_LIST_CAT:
+                        case CONFIG_ITEM_MODULE_LIST:      return type_module_list_text; break;
+                        case CONFIG_ITEM_LOADFILE:
+                        case CONFIG_ITEM_SAVEFILE:         return type_file_text;        break;
+                        case CONFIG_ITEM_DIRECTORY:        return type_directory_text;   break;
+                        case CONFIG_ITEM_FONT:             return type_font_text;        break;
+                        default:                           return type_unknown_text;     break;
+                    }
+                }
+            }
+            break;
+        }
+        case Qt::FontRole:
+        {
+            QFont font = QFont();
+            font.setBold( (item->matches_default) ? false : true );
+            return font;
+        }
+        case TypeClassRole:
+            return CONFIG_CLASS( item->getType() );
+        case CopyValueRole:
+        {
+            switch ( CONFIG_CLASS( item->getType() ) )
+            {
+                case CONFIG_ITEM_BOOL:
+                    // Note, no translation wanted here!
+                    return (item->cfg_item->value.i == 0) ? QStringLiteral( u"false")
+                                                          : QStringLiteral( u"true" );
+                case CONFIG_ITEM_FLOAT:
+                    return QString( "%1" ).arg( item->cfg_item->value.f );
+                case CONFIG_ITEM_INTEGER:
+                    // For RGB it is presumably more useful to give a hex form that can be
+                    // copy-pasted into a colour selection dialog rather than the raw int.
+                    if( item->getType() == CONFIG_ITEM_RGB )
+                        return QString( "#%1" ).arg( item->cfg_item->value.i, 0, 16 );
+                    return QString( "%1" ).arg( item->cfg_item->value.i );
+                case CONFIG_ITEM_STRING:
+                    return item->cfg_item->value.psz;
+                default:
+                    break;
+            }
+        }
+        default: break;
+    }
+    return QVariant();
+}
+
+void ExpertPrefsTableModel::toggleBoolean( const QModelIndex &index )
+{
+    ExpertPrefsTableItem *item = itemAt( index );
+    item->toggleBoolean();
+    /* Set the translated display text from cached lookup */
+    item->displayed_value = ( item->cfg_item->value.i == 0 ) ? false_text : true_text;
+    notifyUpdatedRow( index.row() );
+}
+
+void ExpertPrefsTableModel::setItemToDefault( const QModelIndex &index )
+{
+    ExpertPrefsTableItem *item = itemAt( index );
+    item->setToDefault();
+    if( CONFIG_CLASS( item->cfg_item->i_type ) == CONFIG_ITEM_BOOL )
+    {
+        /* Set the translated display text from cached lookup */
+        item->displayed_value = ( item->cfg_item->value.i == 0 ) ? false_text : true_text;
+    }
+    notifyUpdatedRow( index.row() );
+}
+
+void ExpertPrefsTableModel::notifyUpdatedRow( int row )
+{
+    emit dataChanged( index( row, 0 ), index( row, COLUMN_COUNT - 1 ) );
+}
+
+bool ExpertPrefsTableModel::submit()
+{
+    for( int i= 0 ; i < items.count(); i++ )
+    {
+        ExpertPrefsTableItem *item = items[i];
+
+        /* save from copy to actual */
+        switch ( CONFIG_CLASS( item->getType() ) )
+        {
+            case CONFIG_ITEM_BOOL:
+            case CONFIG_ITEM_INTEGER:
+                config_PutInt( item->cfg_item->psz_name, item->cfg_item->value.i );
+                break;
+            case CONFIG_ITEM_FLOAT:
+                config_PutFloat( item->cfg_item->psz_name, item->cfg_item->value.f );
+                break;
+            case CONFIG_ITEM_STRING:
+                config_PutPsz( item->cfg_item->psz_name, item->cfg_item->value.psz );
+                break;
+        }
+    }
+    return true;
+}


=====================================
modules/gui/qt/dialogs/preferences/expert_model.hpp
=====================================
@@ -0,0 +1,133 @@
+/*****************************************************************************
+ * expert_model.hpp : Detailed preferences overview - model
+ *****************************************************************************
+ * Copyright (C) 2019-2022 VLC authors and VideoLAN
+ *
+ * Authors: Lyndon Brown <jnqnfe at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifndef VLC_QT_EXPERT_PREFERENCES_MODEL_HPP_
+#define VLC_QT_EXPERT_PREFERENCES_MODEL_HPP_
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+
+#include <QAbstractListModel>
+
+#include "qt.hpp"
+
+class ConfigControl;
+class ExpertPrefsTableModel;
+
+class ExpertPrefsTableItem
+{
+    friend ExpertPrefsTableModel;
+
+public:
+    ExpertPrefsTableItem( module_config_t *, const QString &, const QString &, bool );
+    ~ExpertPrefsTableItem();
+    int getType() const { return cfg_item->i_type; }
+    const QString &getTitle() const { return title; }
+    const QString &getDescription();
+    module_config_t *getConfig() const { return cfg_item; }
+    bool matchesDefault() const { return matches_default; }
+    void updateMatchesDefault();
+    void updateValueDisplayString();
+    /** Search filter helper */
+    bool contains( const QString &text, Qt::CaseSensitivity cs );
+
+private:
+    void setToDefault();
+    void toggleBoolean();
+    /** Name shown in table entry, combining module name and option name */
+    QString name;
+    /** The displayed value text */
+    QString displayed_value;
+    /** "Pretty" name for info panel */
+    QString title;
+    /** Description for info panel */
+    QString description;
+    /** The local copy of the corresponding option */
+    module_config_t *cfg_item;
+    /** Is item state different to the default value? */
+    bool matches_default;
+};
+
+class ExpertPrefsTableModel : public QAbstractListModel
+{
+    Q_OBJECT
+
+public:
+    ExpertPrefsTableModel( module_t **, size_t, QWidget * = nullptr );
+    ~ExpertPrefsTableModel();
+    enum ItemField
+    {
+        NameField,
+        StateField,
+        TypeField,
+        ValueField,
+    };
+    enum DataRoles
+    {
+        TypeClassRole = Qt::UserRole,
+        CopyValueRole
+    };
+    ExpertPrefsTableItem *itemAt( int row ) const
+    {
+        assert( row < items.count() );
+        return items[ row ];
+    }
+    ExpertPrefsTableItem *itemAt( const QModelIndex &index ) const
+    {
+        return itemAt( index.row() );
+    }
+    void toggleBoolean( const QModelIndex & );
+    void setItemToDefault( const QModelIndex & );
+    void notifyUpdatedRow( int );
+    bool submit();
+    /* Standard model interface */
+    QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const override;
+    int rowCount( const QModelIndex &parent = QModelIndex() ) const override;
+    int columnCount( const QModelIndex &parent = QModelIndex() ) const override;
+    QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const override;
+
+private:
+    QList<module_config_t *> config_sets;
+    QList<ExpertPrefsTableItem*> items;
+    /* Cached translations of common text */
+    QString state_same_text;
+    QString state_different_text;
+    QString true_text;
+    QString false_text;
+    QString type_boolean_text;
+    QString type_float_text;
+    QString type_integer_text;
+    QString type_color_text;
+    QString type_string_text;
+    QString type_password_text;
+    QString type_module_text;
+    QString type_module_list_text;
+    QString type_file_text;
+    QString type_directory_text;
+    QString type_font_text;
+    QString type_unknown_text;
+};
+
+#endif


=====================================
modules/gui/qt/dialogs/preferences/expert_view.cpp
=====================================
@@ -0,0 +1,281 @@
+/*****************************************************************************
+ * expert_view.cpp : Detailed preferences overview - view
+ *****************************************************************************
+ * Copyright (C) 2019-2022 VLC authors and VideoLAN
+ *
+ * Authors: Lyndon Brown <jnqnfe at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <QString>
+#include <QFont>
+#include <QGuiApplication>
+#include <QClipboard>
+#include <QMenu>
+#include <QDialogButtonBox>
+#include <QPushButton>
+#include <QColorDialog>
+#include <QVBoxLayout>
+#include <QAction>
+#include <QContextMenuEvent>
+
+#include "expert_view.hpp"
+#include "preferences_widgets.hpp"
+
+#include <vlc_config_cat.h>
+#include <vlc_modules.h>
+
+#define COLUMN_COUNT 4
+/*********************************************************************
+ * The Table
+ *********************************************************************/
+ExpertPrefsTable::ExpertPrefsTable( QWidget *parent ) :
+    QTreeView( parent )
+{
+    setSelectionBehavior( QAbstractItemView::SelectRows );
+    setSelectionMode( QAbstractItemView::SingleSelection );
+    setAlternatingRowColors( true );
+
+    setStyleSheet( "QTreeView::item { padding: 9px 0; }" );
+
+    /* edit sub-dialog (reusable) */
+    expert_edit = new ExpertPrefsEditDialog( this );
+
+    connect( this, &QAbstractItemView::doubleClicked, this, &ExpertPrefsTable::doubleClicked );
+
+    /* context menu actions */
+    reset_action = new QAction( qtr( "&Reset" ), this );
+    toggle_action = new QAction( qtr( "&Toggle" ), this );
+    modify_action = new QAction( qtr( "&Modify" ), this );
+    copy_name_action = new QAction( qtr( "Copy &name" ), this );
+    copy_value_action = new QAction( qtr( "Copy &value" ), this );
+
+    connect( reset_action, &QAction::triggered, this, &ExpertPrefsTable::resetItem );
+    connect( toggle_action, &QAction::triggered, this, QOverload<>::of(&ExpertPrefsTable::toggleItem) );
+    connect( modify_action, &QAction::triggered, this, QOverload<>::of(&ExpertPrefsTable::modifyItem) );
+    connect( copy_name_action, &QAction::triggered, this, &ExpertPrefsTable::copyItemName );
+    connect( copy_value_action, &QAction::triggered, this, &ExpertPrefsTable::copyItemValue );
+}
+
+void ExpertPrefsTable::applyAll()
+{
+    model()->submit();
+}
+
+/* apply filter on tree */
+void ExpertPrefsTable::filter( const QString &text, bool modified_only )
+{
+    bool text_nonempty = !text.isEmpty();
+
+    ExpertPrefsTableModel *model = myModel();
+    for( int i = 0 ; i < model->rowCount(); i++ )
+    {
+        ExpertPrefsTableItem *item = model->itemAt( i );
+        bool hide = ( ( modified_only && item->matchesDefault() ) ||
+                      ( text_nonempty && !item->contains( text, Qt::CaseInsensitive ) ) );
+        setRowHidden( i, QModelIndex(), hide );
+    }
+}
+
+#ifndef QT_NO_CONTEXTMENU
+void ExpertPrefsTable::contextMenuEvent( QContextMenuEvent *event )
+{
+    QModelIndex index = currentIndex();
+    if( !index.isValid() || isRowHidden( index.row(), QModelIndex() ) )
+        return;
+    /* Avoid menu from right-click on empty space after last item */
+    if( event->reason() == QContextMenuEvent::Mouse &&
+        !indexAt( viewport()->mapFromGlobal( event->globalPos() ) ).isValid() )
+        return;
+
+    ExpertPrefsTableItem *item = myModel()->itemAt( index );
+
+    QMenu *menu = new QMenu();
+    menu->setAttribute(Qt::WA_DeleteOnClose);
+
+    if( CONFIG_CLASS( item->getType() ) == CONFIG_ITEM_BOOL )
+        menu->addAction( toggle_action );
+    else
+        menu->addAction( modify_action );
+    menu->addSeparator();
+    menu->addAction( copy_name_action );
+    menu->addAction( copy_value_action );
+    copy_value_action->setEnabled( item->getType() != CONFIG_ITEM_PASSWORD );
+    menu->addSeparator();
+    menu->addAction( reset_action );
+    reset_action->setEnabled( !item->matchesDefault() );
+
+    menu->popup( event->globalPos() );
+}
+#endif // QT_NO_CONTEXTMENU
+
+void ExpertPrefsTable::resetItem()
+{
+    QModelIndex index = currentIndex();
+    if( !index.isValid() )
+        return;
+    myModel()->setItemToDefault( index );
+}
+
+void ExpertPrefsTable::toggleItem()
+{
+    toggleItem( currentIndex() );
+}
+
+/* this obviously only applies to boolean options! */
+void ExpertPrefsTable::toggleItem( const QModelIndex &index )
+{
+    if( !index.isValid() )
+        return;
+    myModel()->toggleBoolean( index );
+}
+
+void ExpertPrefsTable::modifyItem()
+{
+    QModelIndex index = currentIndex();
+    if( !index.isValid() )
+        return;
+    modifyItem( index );
+}
+
+void ExpertPrefsTable::modifyItem( const QModelIndex &index )
+{
+    ExpertPrefsTableItem *item = myModel()->itemAt( index );
+    module_config_t *cfg_item = item->getConfig();
+    /* For colour items it's much cleaner here to directly show a `QColorDialog`
+       than provide indirect access to one via an `ExpertPrefsEditDialog` with a
+       `ColorConfigControl`. */
+    if( item->getType() == CONFIG_ITEM_RGB )
+    {
+        QColor color = QColorDialog::getColor( QColor( cfg_item->value.i ) );
+        if( color.isValid() )
+        {
+            cfg_item->value.i = (color.red() << 16) + (color.green() << 8) + color.blue();
+            item->updateMatchesDefault();
+            item->updateValueDisplayString();
+            myModel()->notifyUpdatedRow( index.row() );
+        }
+    }
+    else
+    {
+        ConfigControl *control = ConfigControl::createControl( cfg_item, nullptr );
+        expert_edit->setControl( control, item );
+        expert_edit->exec();
+    }
+}
+
+void ExpertPrefsTable::copyItemName()
+{
+    QModelIndex index = currentIndex();
+    if( !index.isValid() )
+        return;
+
+    QClipboard *clipboard = QGuiApplication::clipboard();
+
+    QModelIndex name_index = myModel()->index( index.row(), ExpertPrefsTableModel::NameField );
+    clipboard->setText( name_index.data( Qt::DisplayRole ).toString() );
+}
+
+void ExpertPrefsTable::copyItemValue()
+{
+    QModelIndex index = currentIndex();
+    if( !index.isValid() )
+        return;
+
+    QClipboard *clipboard = QGuiApplication::clipboard();
+    clipboard->setText( index.data( ExpertPrefsTableModel::CopyValueRole ).toString() );
+}
+
+void ExpertPrefsTable::doubleClicked( const QModelIndex &index )
+{
+    if( index.data( ExpertPrefsTableModel::TypeClassRole ).toInt() == CONFIG_ITEM_BOOL )
+    {
+        toggleItem( index );
+        myModel()->notifyUpdatedRow( index.row() );
+    }
+    else
+        modifyItem( index );
+}
+
+/*********************************************************************
+ * The Edit Dialog
+ *********************************************************************/
+ExpertPrefsEditDialog::ExpertPrefsEditDialog( ExpertPrefsTable *_table ) :
+    QDialog( _table ), table( _table )
+{
+    table_item = nullptr;
+    control = nullptr;
+    control_widget = nullptr;
+
+    setWindowTitle( qtr( "Set option value" ) );
+    setWindowRole( "vlc-preferences" );
+    setWindowModality( Qt::WindowModal );
+
+    setMinimumSize( 380, 110 );
+
+    layout = new QVBoxLayout( this );
+
+    QDialogButtonBox *buttonBox = new QDialogButtonBox();
+    QPushButton *ok = new QPushButton( qtr( "&Ok" ) );
+    QPushButton *cancel = new QPushButton( qtr( "&Cancel" ) );
+    buttonBox->addButton( ok, QDialogButtonBox::AcceptRole );
+    buttonBox->addButton( cancel, QDialogButtonBox::RejectRole );
+    layout->addWidget( buttonBox );
+
+    connect( buttonBox, &QDialogButtonBox::accepted, this, &ExpertPrefsEditDialog::accept );
+    connect( buttonBox, &QDialogButtonBox::rejected, this, &ExpertPrefsEditDialog::reject );
+
+    setLayout( layout );
+}
+
+void ExpertPrefsEditDialog::setControl( ConfigControl *control_, ExpertPrefsTableItem *table_item_ )
+{
+    table_item = table_item_;
+    control = control_;
+    control_widget = new QWidget( this );
+    control_widget->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
+    QVBoxLayout *control_layout = new QVBoxLayout( control_widget );
+    control->insertInto( control_layout );
+    layout->insertWidget( 0, control_widget );
+}
+
+void ExpertPrefsEditDialog::clearControl()
+{
+    delete control;
+    delete control_widget;
+    control = nullptr;
+    control_widget = nullptr;
+    table_item = nullptr;
+}
+
+void ExpertPrefsEditDialog::accept()
+{
+    control->storeValue();
+    table_item->updateMatchesDefault();
+    table_item->updateValueDisplayString();
+    clearControl();
+    QDialog::accept();
+}
+
+void ExpertPrefsEditDialog::reject()
+{
+    clearControl();
+    QDialog::reject();
+}


=====================================
modules/gui/qt/dialogs/preferences/expert_view.hpp
=====================================
@@ -0,0 +1,101 @@
+/*****************************************************************************
+ * expert_view.hpp : Detailed preferences overview - view
+ *****************************************************************************
+ * Copyright (C) 2019-2022 VLC authors and VideoLAN
+ *
+ * Authors: Lyndon Brown <jnqnfe at gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifndef VLC_QT_EXPERT_PREFERENCES_VIEW_HPP_
+#define VLC_QT_EXPERT_PREFERENCES_VIEW_HPP_
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "expert_model.hpp"
+
+#include <QTreeView>
+#include <QDialog>
+
+#include "qt.hpp"
+
+class QVBoxLayout;
+class QAction;
+class QContextMenuEvent;
+
+class ConfigControl;
+class ExpertPrefsEditDialog;
+
+class ExpertPrefsTable : public QTreeView
+{
+    Q_OBJECT
+
+public:
+    ExpertPrefsTable( QWidget *parent = nullptr );
+    ExpertPrefsTableModel *myModel()
+    {
+        return static_cast<ExpertPrefsTableModel *>( model() );
+    }
+    void applyAll();
+    void filter( const QString &text, bool );
+
+protected:
+#ifndef QT_NO_CONTEXTMENU
+    void contextMenuEvent(QContextMenuEvent *event) Q_DECL_OVERRIDE;
+#endif // QT_NO_CONTEXTMENU
+
+private:
+    void modifyItem( const QModelIndex & );
+    void toggleItem( const QModelIndex & );
+    QAction *reset_action;
+    QAction *toggle_action;
+    QAction *modify_action;
+    QAction *copy_name_action;
+    QAction *copy_value_action;
+    ExpertPrefsEditDialog *expert_edit;
+
+private slots:
+    void resetItem();
+    void toggleItem();
+    void modifyItem();
+    void copyItemName();
+    void copyItemValue();
+    void doubleClicked( const QModelIndex & );
+};
+
+class ExpertPrefsEditDialog : public QDialog
+{
+    Q_OBJECT
+public:
+    ExpertPrefsEditDialog( ExpertPrefsTable * );
+    void setControl( ConfigControl *, ExpertPrefsTableItem * );
+
+private:
+    void clearControl();
+    ExpertPrefsTable *table;
+    ExpertPrefsTableItem *table_item;
+    QVBoxLayout *layout;
+    QWidget *control_widget;
+    ConfigControl *control;
+
+private slots:
+    void accept();
+    void reject();
+};
+
+#endif


=====================================
modules/gui/qt/dialogs/preferences/preferences.cpp
=====================================
@@ -29,6 +29,7 @@
 #include "widgets/native/qvlcframe.hpp"
 #include "dialogs/errors/errors.hpp"
 
+#include "expert_view.hpp"
 #include "dialogs/preferences/complete_preferences.hpp"
 #include "dialogs/preferences/simple_preferences.hpp"
 #include "widgets/native/searchlineedit.hpp"
@@ -73,8 +74,11 @@ PrefsDialog::PrefsDialog( QWindow *parent, qt_intf_t *_p_intf )
     simple->setToolTip( qtr( "Switch to simple preferences view" ) );
     all = new QRadioButton( qtr("All"), types );
     all->setToolTip( qtr( "Switch to full preferences view" ) );
+    expert = new QRadioButton( qtr("Expert"), types );
+    expert->setToolTip( qtr( "Switch to expert preferences view" ) );
     types_l->addWidget( simple );
     types_l->addWidget( all );
+    types_l->addWidget( expert );
     types->setLayout( types_l );
     simple->setChecked( true );
 
@@ -131,6 +135,30 @@ PrefsDialog::PrefsDialog( QWindow *parent, qt_intf_t *_p_intf )
 
     stack->insertWidget( ADVANCED, advanced_split_widget );
 
+    /* Expert view (panel) */
+    expert_widget = new QWidget;
+    expert_widget_layout = new QGridLayout;
+    expert_widget->setLayout( expert_widget_layout );
+
+    expert_table_filter = nullptr;
+    expert_table = nullptr;
+
+    expert_text = new QLabel;
+    expert_longtext = new QLabel;
+
+    expert_text->setWordWrap(true);
+    expert_longtext->setWordWrap(true);
+
+    QFont textFont = QApplication::font();
+    textFont.setPointSize( textFont.pointSize() + 2 );
+    textFont.setUnderline( true );
+    expert_text->setFont( textFont );
+
+    expert_widget_layout->addWidget( expert_text, 2, 0, 1, 2 );
+    expert_widget_layout->addWidget( expert_longtext, 3, 0, 1, 2 );
+
+    stack->insertWidget( EXPERT, expert_widget );
+
     /* Layout  */
     main_layout->addWidget( stack, 0, 0, 3, 3 );
     main_layout->addWidget( types, 3, 0, 2, 1 );
@@ -138,10 +166,12 @@ PrefsDialog::PrefsDialog( QWindow *parent, qt_intf_t *_p_intf )
     main_layout->setRowStretch( 2, 4 );
     main_layout->setMargin( 9 );
 
-    if( var_InheritBool( p_intf, "qt-advanced-pref" ) )
-        setAdvanced();
-    else
-        setSimple();
+    switch( var_InheritInteger( p_intf, "qt-initial-prefs-view" ) )
+    {
+        case 2:  setExpert();   break;
+        case 1:  setAdvanced(); break;
+        default: setSimple();   break;
+    }
 
     BUTTONACT( save, &PrefsDialog::save );
     BUTTONACT( cancel, &PrefsDialog::cancel );
@@ -149,6 +179,7 @@ PrefsDialog::PrefsDialog( QWindow *parent, qt_intf_t *_p_intf )
 
     BUTTONACT( simple, &PrefsDialog::setSimple );
     BUTTONACT( all, &PrefsDialog::setAdvanced );
+    BUTTONACT( expert, &PrefsDialog::setExpert );
 
     QVLCTools::restoreWidgetPosition( p_intf, "Preferences", this, QSize( 850, 700 ) );
 }
@@ -158,12 +189,55 @@ PrefsDialog::~PrefsDialog()
     module_list_free( p_list );
 }
 
+void PrefsDialog::setExpert()
+{
+    /* Lazy creation */
+    if( !expert_table )
+    {
+        if ( !p_list )
+            p_list = module_list_get( &count );
+
+        expert_table_filter = new SearchLineEdit( expert_widget );
+        expert_table_filter->setMinimumHeight( 26 );
+        expert_table_filter_modified = new QCheckBox( qtr( "Modified only" ), expert_widget );
+
+        QShortcut *search = new QShortcut( QKeySequence( QKeySequence::Find ), expert_table_filter );
+
+        ExpertPrefsTableModel *table_model = new ExpertPrefsTableModel( p_list, count, this );
+        expert_table = new ExpertPrefsTable( expert_widget );
+        expert_table->setModel( table_model );
+        expert_table->resizeColumnToContents( ExpertPrefsTableModel::NameField );
+
+        expert_widget_layout->addWidget( expert_table_filter, 0, 0 );
+        expert_widget_layout->addWidget( expert_table_filter_modified, 0, 1 );
+        expert_widget_layout->addWidget( expert_table, 1, 0, 1, 2 );
+
+        connect( expert_table->selectionModel(), &QItemSelectionModel::currentChanged,
+                 this, &PrefsDialog::changeExpertDesc );
+        connect( expert_table_filter, &SearchLineEdit::textChanged,
+                 this, &PrefsDialog::expertTableFilterChanged );
+        connect( expert_table_filter_modified, &QCheckBox::toggled,
+                 this, &PrefsDialog::expertTableFilterModifiedToggled );
+        connect( search, &QShortcut::activated,
+                 expert_table_filter, QOverload<>::of(&SearchLineEdit::setFocus) );
+
+        /* Set initial selection */
+        expert_table->setCurrentIndex(
+                expert_table->model()->index( 0, 0, QModelIndex() ) );
+    }
+
+    expert->setChecked( true );
+    stack->setCurrentIndex( EXPERT );
+    setWindowTitle( qtr( "Expert Preferences" ) );
+}
+
 void PrefsDialog::setAdvanced()
 {
     /* Lazy creation */
     if( !advanced_tree )
     {
-        p_list = module_list_get( &count );
+        if ( !p_list )
+            p_list = module_list_get( &count );
 
         advanced_tree = new PrefsTree( p_intf, advanced_tree_panel, p_list, count );
 
@@ -237,12 +311,23 @@ void PrefsDialog::changeAdvPanel( QTreeWidgetItem *item )
     if( !node->panel )
     {
         node->panel = new AdvPrefsPanel( p_intf, advanced_panels_stack, node );
-        advanced_panels_stack->insertWidget( advanced_panels_stack->count(),
-                                             node->panel );
+        advanced_panels_stack->addWidget( node->panel );
     }
     advanced_panels_stack->setCurrentWidget( node->panel );
 }
 
+/* Changing from one Expert item description to another */
+void PrefsDialog::changeExpertDesc( const QModelIndex &current, const QModelIndex &previous )
+{
+    Q_UNUSED( previous );
+    if( !current.isValid() )
+       return;
+    ExpertPrefsTableItem *item = expert_table->myModel()->itemAt( current );
+
+    expert_text->setText( item->getTitle() );
+    expert_longtext->setText( item->getDescription() );
+}
+
 /* Actual apply and save for the preferences */
 void PrefsDialog::save()
 {
@@ -259,6 +344,11 @@ void PrefsDialog::save()
         msg_Dbg( p_intf, "Saving the advanced preferences" );
         advanced_tree->applyAll();
     }
+    else if( expert->isChecked() && expert_table->isVisible() )
+    {
+        msg_Dbg( p_intf, "Saving the expert preferences" );
+        expert_table->applyAll();
+    }
 
     /* Save to file */
     if( config_SaveConfigFile( p_intf ) != 0 )
@@ -309,6 +399,16 @@ void PrefsDialog::reset()
     }
 }
 
+void PrefsDialog::expertTableFilterModifiedToggled( bool checked )
+{
+    expert_table->filter( expert_table_filter->text(), checked );
+}
+
+void PrefsDialog::expertTableFilterChanged( const QString & text )
+{
+    expert_table->filter( text, expert_table_filter_modified->isChecked() );
+}
+
 void PrefsDialog::advancedTreeFilterChanged( const QString & text )
 {
     advanced_tree->filter( text );


=====================================
modules/gui/qt/dialogs/preferences/preferences.hpp
=====================================
@@ -26,6 +26,7 @@
 #include "widgets/native/qvlcframe.hpp"
 #include "dialogs/preferences/simple_preferences.hpp"
 
+class ExpertPrefsTable;
 class PrefsTree;
 class SPrefsCatList;
 class SPrefsPanel;
@@ -53,9 +54,9 @@ private:
     QStackedWidget *stack;
 
     /* View selection */
-    enum { SIMPLE, ADVANCED };
+    enum { SIMPLE, ADVANCED, EXPERT };
     QGroupBox *types;
-    QRadioButton *simple, *all;
+    QRadioButton *simple, *all, *expert;
 
     /* Simple view components */
     QWidget *simple_split_widget;
@@ -72,13 +73,26 @@ private:
     PrefsTree *advanced_tree;
     QStackedWidget *advanced_panels_stack;
 
+    /* Expert view components */
+    QWidget *expert_widget;
+    QGridLayout *expert_widget_layout;
+    SearchLineEdit *expert_table_filter;
+    QCheckBox *expert_table_filter_modified;
+    ExpertPrefsTable *expert_table;
+    QLabel *expert_text;
+    QLabel *expert_longtext;
+
 private slots:
+    void setExpert();
     void setAdvanced();
     void setSimple();
 
+    void changeExpertDesc( const QModelIndex &, const QModelIndex & );
     void changeAdvPanel( QTreeWidgetItem * );
     void changeSimplePanel( int );
     void advancedTreeFilterChanged( const QString & );
+    void expertTableFilterChanged( const QString & );
+    void expertTableFilterModifiedToggled( bool );
     void onlyLoadedToggled();
 
     void save();


=====================================
modules/gui/qt/dialogs/preferences/preferences_widgets.cpp
=====================================
@@ -85,8 +85,7 @@ QString formatTooltip(const QString & tooltip)
 }
 
 ConfigControl *ConfigControl::createControl( module_config_t *p_item,
-                                             QWidget *parent,
-                                             QGridLayout *l, int line )
+                                             QWidget *parent )
 {
     ConfigControl *p_control = NULL;
 
@@ -144,24 +143,27 @@ ConfigControl *ConfigControl::createControl( module_config_t *p_item,
     default:
         break;
     }
-    if ( p_control ) p_control->insertIntoExistingGrid( l, line );
     return p_control;
 }
 
-/* Inserts controls into layouts
-   This is sub-optimal in the OO way, as controls's code still
-   depends on Layout classes. We should use layout inserters [friend]
-   classes, but it's unlikely we had to deal with a different layout.*/
-void ConfigControl::insertInto( QBoxLayout *layout )
+ConfigControl *ConfigControl::createControl( module_config_t *item,
+                                             QWidget *parent,
+                                             QGridLayout *l, int line )
 {
-    QGridLayout *sublayout = new QGridLayout();
-    fillGrid( sublayout, 0 );
-    layout->addLayout( sublayout );
+    ConfigControl *control = createControl( item, parent );
+    if ( control )
+        control->insertInto( l, line );
+    return control;
 }
 
-void ConfigControl::insertIntoExistingGrid( QGridLayout *l, int line )
+ConfigControl *ConfigControl::createControl( module_config_t *item,
+                                             QWidget *parent,
+                                             QBoxLayout *l, int index )
 {
-    fillGrid( l, line );
+    ConfigControl *control = createControl( item, parent );
+    if ( control )
+        control->insertInto( l, index );
+    return control;
 }
 
 /*******************************************************
@@ -212,6 +214,13 @@ VStringConfigControl::doApply()
     config_PutPsz( getName(), qtu( getValue() ) );
 }
 
+void VStringConfigControl::storeValue()
+{
+    /* Note, this modifies our local copy of the item only */
+    free( p_item->value.psz );
+    p_item->value.psz = strdup( qtu( getValue() ) );
+}
+
 /*********** String **************/
 StringConfigControl::StringConfigControl( module_config_t *_p_item,
                                           QWidget *_parent ) :
@@ -231,13 +240,19 @@ StringConfigControl::StringConfigControl( module_config_t *_p_item,
     finish( );
 }
 
-void StringConfigControl::fillGrid( QGridLayout *l, int line )
+void StringConfigControl::insertInto( QGridLayout *l, int line )
 {
     l->addWidget( label, line, 0 );
     l->setColumnMinimumWidth( 1, 10 );
     l->addWidget( text, line, LAST_COLUMN, Qt::AlignRight );
 }
 
+void StringConfigControl::insertInto( QBoxLayout *l, int index )
+{
+    l->insertWidget( index, label );
+    l->insertWidget( index + 1, text );
+}
+
 void StringConfigControl::finish()
 {
     text->setText( qfu(p_item->value.psz) );
@@ -310,7 +325,7 @@ FileConfigControl::FileConfigControl( module_config_t *_p_item,
     finish( );
 }
 
-void FileConfigControl::fillGrid( QGridLayout *l, int line )
+void FileConfigControl::insertInto( QGridLayout *l, int line )
 {
     l->addWidget( label, line, 0 );
     l->setColumnMinimumWidth( 1, 10 );
@@ -321,6 +336,16 @@ void FileConfigControl::fillGrid( QGridLayout *l, int line )
     l->addLayout( textAndButton, line, LAST_COLUMN );
 }
 
+void FileConfigControl::insertInto( QBoxLayout *l, int index )
+{
+    l->insertWidget( index, label );
+    QHBoxLayout *textAndButton = new QHBoxLayout();
+    textAndButton->setMargin( 0 );
+    textAndButton->addWidget( text, 2 );
+    textAndButton->addWidget( browse, 0 );
+    l->insertLayout( index + 1, textAndButton );
+}
+
 void FileConfigControl::updateField()
 {
     QString file;
@@ -416,12 +441,18 @@ FontConfigControl::FontConfigControl( module_config_t *_p_item,
     }
 }
 
-void FontConfigControl::fillGrid( QGridLayout *l, int line )
+void FontConfigControl::insertInto( QGridLayout *l, int line )
 {
     l->addWidget( label, line, 0 );
     l->addWidget( font, line, 1, 1, -1 );
 }
 
+void FontConfigControl::insertInto( QBoxLayout *l, int index )
+{
+    l->insertWidget( index, label );
+    l->insertWidget( index + 1, font );
+}
+
 void FontConfigControl::changeVisibility( bool visible )
 {
     font->setVisible( visible );
@@ -441,7 +472,7 @@ StringListConfigControl::StringListConfigControl( module_config_t *_p_item,
     label = new QLabel( qfut(p_item->psz_text), p );
     combo = new QComboBox( p );
     combo->setMinimumWidth( MINWIDTH_BOX );
-    combo->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Preferred );
+    combo->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed );
 
     /* needed to see update from getting choice list where callback used */
     module_config_t *p_module_config = config_FindConfig( p_item->psz_name );
@@ -463,12 +494,18 @@ StringListConfigControl::StringListConfigControl( module_config_t *_p_item,
     finish( p_module_config );
 }
 
-void StringListConfigControl::fillGrid( QGridLayout *l, int line )
+void StringListConfigControl::insertInto( QGridLayout *l, int line )
 {
     l->addWidget( label, line, 0 );
     l->addWidget( combo, line, LAST_COLUMN, Qt::AlignRight );
 }
 
+void StringListConfigControl::insertInto( QBoxLayout *l, int index )
+{
+    l->insertWidget( index, label );
+    l->insertWidget( index + 1, combo );
+}
+
 void StringListConfigControl::comboIndexChanged( int i_index )
 {
     Q_UNUSED( i_index );
@@ -582,12 +619,18 @@ ModuleConfigControl::ModuleConfigControl( module_config_t *_p_item,
     finish( );
 }
 
-void ModuleConfigControl::fillGrid( QGridLayout *l, int line )
+void ModuleConfigControl::insertInto( QGridLayout *l, int line )
 {
     l->addWidget( label, line, 0 );
     l->addWidget( combo, line, LAST_COLUMN );
 }
 
+void ModuleConfigControl::insertInto( QBoxLayout *l, int index )
+{
+    l->insertWidget( index, label );
+    l->insertWidget( index + 1, combo );
+}
+
 void ModuleConfigControl::finish( )
 {
     combo->setEditable( false );
@@ -676,18 +719,22 @@ ModuleListConfigControl::ModuleListConfigControl( module_config_t *_p_item,
         text->setToolTip( formatTooltip( qfut( p_item->psz_longtext) ) );
 }
 
-void ModuleListConfigControl::fillGrid( QGridLayout *l, int line )
+void ModuleListConfigControl::insertInto( QGridLayout *l, int line )
 {
     l->addWidget( groupBox, line, 0, 1, -1 );
 }
 
+void ModuleListConfigControl::insertInto( QBoxLayout *l, int index )
+{
+    l->insertWidget( index, groupBox );
+}
+
 ModuleListConfigControl::~ModuleListConfigControl()
 {
     foreach ( checkBoxListItem *it, modules )
         free( it->psz_module );
     qDeleteAll( modules );
     modules.clear();
-    delete groupBox;
 }
 
 void ModuleListConfigControl::checkbox_lists( module_t *p_parser )
@@ -811,6 +858,12 @@ VIntConfigControl::doApply()
     config_PutInt( getName(), getValue() );
 }
 
+void VIntConfigControl::storeValue()
+{
+    /* Note, this modifies our local copy of the item only */
+    p_item->value.i = getValue();
+}
+
 /*********** Integer **************/
 IntegerConfigControl::IntegerConfigControl( module_config_t *_p_item,
                                             QWidget *p ) :
@@ -833,12 +886,18 @@ IntegerConfigControl::IntegerConfigControl( module_config_t *_p_item,
     finish();
 }
 
-void IntegerConfigControl::fillGrid( QGridLayout *l, int line )
+void IntegerConfigControl::insertInto( QGridLayout *l, int line )
 {
     l->addWidget( label, line, 0 );
     l->addWidget( spin, line, LAST_COLUMN, Qt::AlignRight );
 }
 
+void IntegerConfigControl::insertInto( QBoxLayout *l, int index )
+{
+    l->insertWidget( index, label );
+    l->insertWidget( index + 1, spin );
+}
+
 void IntegerConfigControl::finish()
 {
     spin->setMaximum( 2000000000 );
@@ -921,7 +980,6 @@ int IntegerRangeSliderConfigControl::getValue() const
     return slider->value();
 }
 
-
 /********* Integer / choice list **********/
 IntegerListConfigControl::IntegerListConfigControl( module_config_t *_p_item,
                                                     QWidget *p ) :
@@ -951,13 +1009,19 @@ IntegerListConfigControl::IntegerListConfigControl( module_config_t *_p_item,
     finish( p_module_config );
 }
 
-void IntegerListConfigControl::fillGrid( QGridLayout *l, int line )
+void IntegerListConfigControl::insertInto( QGridLayout *l, int line )
 {
     l->addWidget( label, line, 0 );
     l->addWidget( combo, line, LAST_COLUMN, Qt::AlignRight );
 }
 
-void IntegerListConfigControl::finish(module_config_t *p_module_config )
+void IntegerListConfigControl::insertInto( QBoxLayout *l, int index )
+{
+    l->insertWidget( index, label );
+    l->insertWidget( index + 1, combo );
+}
+
+void IntegerListConfigControl::finish( module_config_t *p_module_config )
 {
     combo->setEditable( false );
 
@@ -1016,11 +1080,16 @@ BoolConfigControl::BoolConfigControl( module_config_t *_p_item,
     finish();
 }
 
-void BoolConfigControl::fillGrid( QGridLayout *l, int line )
+void BoolConfigControl::insertInto( QGridLayout *l, int line )
 {
     l->addWidget( checkbox, line, 0, 1, -1 );
 }
 
+void BoolConfigControl::insertInto( QBoxLayout *l, int index )
+{
+    l->insertWidget( index, checkbox );
+}
+
 void BoolConfigControl::finish()
 {
     checkbox->setChecked( p_item->value.i );
@@ -1058,12 +1127,18 @@ ColorConfigControl::ColorConfigControl( module_config_t *_p_item,
     finish();
 }
 
-void ColorConfigControl::fillGrid( QGridLayout *l, int line )
+void ColorConfigControl::insertInto( QGridLayout *l, int line )
 {
     l->addWidget( label, line, 0 );
     l->addWidget( color_but, line, LAST_COLUMN, Qt::AlignRight );
 }
 
+void ColorConfigControl::insertInto( QBoxLayout *l, int index )
+{
+    l->insertWidget( index, label );
+    l->insertWidget( index + 1, color_but );
+}
+
 void ColorConfigControl::finish()
 {
     i_color = p_item->value.i;
@@ -1117,6 +1192,12 @@ VFloatConfigControl::doApply()
     config_PutFloat( getName(), getValue() );
 }
 
+void VFloatConfigControl::storeValue()
+{
+    /* Note, this modifies our local copy of the item only */
+    p_item->value.f = getValue();
+}
+
 /*********** Float **************/
 FloatConfigControl::FloatConfigControl( module_config_t *_p_item,
                                         QWidget *p ) :
@@ -1140,12 +1221,18 @@ FloatConfigControl::FloatConfigControl( module_config_t *_p_item,
     finish();
 }
 
-void FloatConfigControl::fillGrid( QGridLayout *l, int line )
+void FloatConfigControl::insertInto( QGridLayout *l, int line )
 {
     l->addWidget( label, line, 0 );
     l->addWidget( spin, line, LAST_COLUMN, Qt::AlignRight );
 }
 
+void FloatConfigControl::insertInto( QBoxLayout *l, int index )
+{
+    l->insertWidget( index, label );
+    l->insertWidget( index + 1, spin );
+}
+
 void FloatConfigControl::finish()
 {
     spin->setMaximum( 2000000000. );
@@ -1241,7 +1328,7 @@ KeySelectorControl::KeySelectorControl( QWidget *p ) : ConfigControl( nullptr )
              this, &KeySelectorControl::filter );
 }
 
-void KeySelectorControl::fillGrid( QGridLayout *l, int line )
+void KeySelectorControl::insertInto( QGridLayout *l, int line )
 {
     QGridLayout *gLayout = new QGridLayout();
     gLayout->addWidget( label, 0, 0, 1, 4 );


=====================================
modules/gui/qt/dialogs/preferences/preferences_widgets.hpp
=====================================
@@ -85,18 +85,21 @@ public:
     void hide() { changeVisibility( false ); }
     void show() { changeVisibility( true ); }
     /* ConfigControl factory */
+    static ConfigControl * createControl( module_config_t*, QWidget* );
     static ConfigControl * createControl( module_config_t*, QWidget*,
                                           QGridLayout *, int line = 0 );
-    /* Inserts control into another layout block, using a sublayout */
-    void insertInto( QBoxLayout * );
-    /* Inserts control into an existing grid layout */
-    void insertIntoExistingGrid( QGridLayout*, int );
+    static ConfigControl * createControl( module_config_t*, QWidget*,
+                                          QBoxLayout *, int line = 0 );
+    /** Inserts control into an existing grid layout */
+    virtual void insertInto( QGridLayout*, int row = 0 ) { Q_UNUSED( row ); }
+    /** Inserts control into an existing box layout */
+    virtual void insertInto( QBoxLayout*, int index = 0 ) { Q_UNUSED( index ); }
     virtual void doApply() = 0;
+    virtual void storeValue() = 0;
 protected:
     ConfigControl( module_config_t *_p_conf ) : p_item( _p_conf ) {}
     virtual void changeVisibility( bool ) { }
     module_config_t *p_item;
-    virtual void fillGrid( QGridLayout*, int ) {}
 signals:
     void changed();
 };
@@ -110,6 +113,7 @@ class VIntConfigControl : public ConfigControl
 public:
     virtual int getValue() const = 0;
     virtual void doApply() Q_DECL_OVERRIDE;
+    virtual void storeValue() Q_DECL_OVERRIDE;
 protected:
     VIntConfigControl( module_config_t *i ) : ConfigControl(i) {}
 };
@@ -120,11 +124,12 @@ class IntegerConfigControl : public VIntConfigControl
 public:
     IntegerConfigControl( module_config_t *, QWidget * );
     IntegerConfigControl( module_config_t *, QLabel*, QSpinBox* );
+    void insertInto( QGridLayout*, int row = 0 ) Q_DECL_OVERRIDE;
+    void insertInto( QBoxLayout*, int index = 0 ) Q_DECL_OVERRIDE;
     int getValue() const Q_DECL_OVERRIDE;
 protected:
     QSpinBox *spin;
     void changeVisibility( bool ) Q_DECL_OVERRIDE;
-    void fillGrid( QGridLayout*, int ) Q_DECL_OVERRIDE;
 private:
     QLabel *label;
     void finish();
@@ -161,10 +166,11 @@ Q_OBJECT
 public:
     IntegerListConfigControl( module_config_t *, QWidget * );
     IntegerListConfigControl( module_config_t *, QLabel *, QComboBox* );
+    void insertInto( QGridLayout*, int row = 0 ) Q_DECL_OVERRIDE;
+    void insertInto( QBoxLayout*, int index = 0 ) Q_DECL_OVERRIDE;
     int getValue() const Q_DECL_OVERRIDE;
 protected:
     void changeVisibility( bool ) Q_DECL_OVERRIDE;
-    void fillGrid( QGridLayout*, int ) Q_DECL_OVERRIDE;
 private:
     void finish(module_config_t * );
     QLabel *label;
@@ -177,10 +183,11 @@ class BoolConfigControl : public VIntConfigControl
 public:
     BoolConfigControl( module_config_t *, QWidget * );
     BoolConfigControl( module_config_t *, QLabel *, QAbstractButton* );
+    void insertInto( QGridLayout*, int row = 0 ) Q_DECL_OVERRIDE;
+    void insertInto( QBoxLayout*, int index = 0 ) Q_DECL_OVERRIDE;
     int getValue() const Q_DECL_OVERRIDE;
 protected:
     void changeVisibility( bool ) Q_DECL_OVERRIDE;
-    void fillGrid( QGridLayout*, int ) Q_DECL_OVERRIDE;
 private:
     QAbstractButton *checkbox;
     void finish();
@@ -193,10 +200,11 @@ public:
     ColorConfigControl( module_config_t *, QWidget * );
     ColorConfigControl( module_config_t *, QLabel *, QAbstractButton* );
     virtual ~ColorConfigControl() { delete color_px; }
+    void insertInto( QGridLayout*, int row = 0 ) Q_DECL_OVERRIDE;
+    void insertInto( QBoxLayout*, int index = 0 ) Q_DECL_OVERRIDE;
     int getValue() const Q_DECL_OVERRIDE;
 protected:
     void changeVisibility( bool ) Q_DECL_OVERRIDE;
-    void fillGrid( QGridLayout*, int ) Q_DECL_OVERRIDE;
 private:
     QLabel *label;
     QAbstractButton *color_but;
@@ -216,6 +224,7 @@ class VFloatConfigControl : public ConfigControl
 public:
     virtual float getValue() const = 0;
     void doApply() Q_DECL_OVERRIDE;
+    void storeValue() Q_DECL_OVERRIDE;
 protected:
     VFloatConfigControl( module_config_t *i ) : ConfigControl(i) {}
 };
@@ -226,11 +235,12 @@ class FloatConfigControl : public VFloatConfigControl
 public:
     FloatConfigControl( module_config_t *, QWidget * );
     FloatConfigControl( module_config_t *, QLabel*, QDoubleSpinBox* );
+    void insertInto( QGridLayout*, int row = 0 ) Q_DECL_OVERRIDE;
+    void insertInto( QBoxLayout*, int index = 0 ) Q_DECL_OVERRIDE;
     float getValue() const Q_DECL_OVERRIDE;
 
 protected:
     void changeVisibility( bool ) Q_DECL_OVERRIDE;
-    void fillGrid( QGridLayout*, int ) Q_DECL_OVERRIDE;
     QDoubleSpinBox *spin;
 
 private:
@@ -257,6 +267,7 @@ class VStringConfigControl : public ConfigControl
 public:
     virtual QString getValue() const = 0;
     void doApply() Q_DECL_OVERRIDE;
+    void storeValue() Q_DECL_OVERRIDE;
 protected:
     VStringConfigControl( module_config_t *i ) : ConfigControl(i) {}
 };
@@ -267,10 +278,11 @@ class StringConfigControl : public VStringConfigControl
 public:
     StringConfigControl( module_config_t *, QWidget * );
     StringConfigControl( module_config_t *, QLabel *, QLineEdit* );
+    void insertInto( QGridLayout*, int row = 0 ) Q_DECL_OVERRIDE;
+    void insertInto( QBoxLayout*, int index = 0 ) Q_DECL_OVERRIDE;
     QString getValue() const Q_DECL_OVERRIDE;
 protected:
     void changeVisibility( bool ) Q_DECL_OVERRIDE;
-    void fillGrid( QGridLayout*, int ) Q_DECL_OVERRIDE;
     QLineEdit *text;
 private:
     void finish();
@@ -293,12 +305,13 @@ class FileConfigControl : public VStringConfigControl
 public:
     FileConfigControl( module_config_t *, QWidget * );
     FileConfigControl( module_config_t *, QLabel *, QLineEdit *, QPushButton * );
+    void insertInto( QGridLayout*, int row = 0 ) Q_DECL_OVERRIDE;
+    void insertInto( QBoxLayout*, int index = 0 ) Q_DECL_OVERRIDE;
     QString getValue() const Q_DECL_OVERRIDE;
 public slots:
     virtual void updateField();
 protected:
     void changeVisibility( bool ) Q_DECL_OVERRIDE;
-    void fillGrid( QGridLayout*, int ) Q_DECL_OVERRIDE;
     void finish();
     QLineEdit *text;
     QLabel *label;
@@ -321,10 +334,11 @@ class FontConfigControl : public VStringConfigControl
 public:
     FontConfigControl( module_config_t *, QWidget * );
     FontConfigControl( module_config_t *, QLabel *, QFontComboBox *);
+    void insertInto( QGridLayout*, int row = 0 ) Q_DECL_OVERRIDE;
+    void insertInto( QBoxLayout*, int index = 0 ) Q_DECL_OVERRIDE;
     QString getValue() const Q_DECL_OVERRIDE;
 protected:
     void changeVisibility( bool ) Q_DECL_OVERRIDE;
-    void fillGrid( QGridLayout*, int ) Q_DECL_OVERRIDE;
     QLabel *label;
     QFontComboBox *font;
 };
@@ -335,10 +349,11 @@ class ModuleConfigControl : public VStringConfigControl
 public:
     ModuleConfigControl( module_config_t *, QWidget * );
     ModuleConfigControl( module_config_t *, QLabel *, QComboBox* );
+    void insertInto( QGridLayout*, int row = 0 ) Q_DECL_OVERRIDE;
+    void insertInto( QBoxLayout*, int index = 0 ) Q_DECL_OVERRIDE;
     QString getValue() const Q_DECL_OVERRIDE;
 protected:
     void changeVisibility( bool ) Q_DECL_OVERRIDE;
-    void fillGrid( QGridLayout*, int ) Q_DECL_OVERRIDE;
 private:
     void finish( );
     QLabel *label;
@@ -356,14 +371,14 @@ class ModuleListConfigControl : public VStringConfigControl
     friend class ConfigControl;
 public:
     ModuleListConfigControl( module_config_t *, QWidget *, bool );
-//    ModuleListConfigControl( module_config_t *, QLabel *, QComboBox*, bool );
     virtual ~ModuleListConfigControl();
+    void insertInto( QGridLayout*, int row = 0 ) Q_DECL_OVERRIDE;
+    void insertInto( QBoxLayout*, int index = 0 ) Q_DECL_OVERRIDE;
     QString getValue() const Q_DECL_OVERRIDE;
 public slots:
     void onUpdate();
 protected:
     void changeVisibility( bool ) Q_DECL_OVERRIDE;
-    void fillGrid( QGridLayout*, int ) Q_DECL_OVERRIDE;
 private:
     void finish( bool );
     void checkbox_lists(module_t*);
@@ -379,10 +394,11 @@ class StringListConfigControl : public VStringConfigControl
 public:
     StringListConfigControl( module_config_t *, QWidget * );
     StringListConfigControl( module_config_t *, QLabel *, QComboBox* );
+    void insertInto( QGridLayout*, int row = 0 ) Q_DECL_OVERRIDE;
+    void insertInto( QBoxLayout*, int index = 0 ) Q_DECL_OVERRIDE;
     QString getValue() const Q_DECL_OVERRIDE;
 protected:
     void changeVisibility( bool ) Q_DECL_OVERRIDE;
-    void fillGrid( QGridLayout*, int ) Q_DECL_OVERRIDE;
     QComboBox *combo;
 private:
     void finish(module_config_t * );
@@ -404,7 +420,9 @@ class KeySelectorControl : public ConfigControl
 
 public:
     KeySelectorControl( QWidget * );
+    void insertInto( QGridLayout*, int row = 0 ) Q_DECL_OVERRIDE;
     void doApply() Q_DECL_OVERRIDE;
+    void storeValue() {};
     enum ColumnIndex
     {
         ACTION_COL = 0,
@@ -420,7 +438,6 @@ protected:
     void tableContextMenuEvent( QContextMenuEvent * );
 #endif
     void changeVisibility( bool ) Q_DECL_OVERRIDE;
-    void fillGrid( QGridLayout*, int ) Q_DECL_OVERRIDE;
     void unset( KeyTableItem *, enum ColumnIndex );
     void unset( QTreeWidgetItem *, int );
     void reset( KeyTableItem *, enum ColumnIndex );


=====================================
modules/gui/qt/dialogs/preferences/simple_preferences.cpp
=====================================
@@ -997,21 +997,21 @@ SPrefsPanel::SPrefsPanel( qt_intf_t *_p_intf, QWidget *_parent,
 
             panel_label->setText( qtr( "Configure Hotkeys" ) );
             control = new KeySelectorControl( this );
-            control->insertIntoExistingGrid( gLayout, line );
+            control->insertInto( gLayout, line );
             controls.append( control );
 
             line++;
 
             p_config = config_FindConfig( "hotkeys-y-wheel-mode" );
             control = new IntegerListConfigControl( p_config, this );
-            control->insertIntoExistingGrid( gLayout, line );
+            control->insertInto( gLayout, line );
             controls.append( control );
 
             line++;
 
             p_config = config_FindConfig( "hotkeys-x-wheel-mode" );
             control = new IntegerListConfigControl( p_config, this );
-            control->insertIntoExistingGrid( gLayout, line );
+            control->insertInto( gLayout, line );
             controls.append( control );
 
 #ifdef _WIN32
@@ -1019,7 +1019,7 @@ SPrefsPanel::SPrefsPanel( qt_intf_t *_p_intf, QWidget *_parent,
 
             p_config = config_FindConfig( "qt-disable-volume-keys" );
             control = new BoolConfigControl( p_config, this );
-            control->insertIntoExistingGrid( gLayout, line );
+            control->insertInto( gLayout, line );
             controls.append( control );
 #endif
             break;


=====================================
modules/gui/qt/qt.cpp
=====================================
@@ -116,10 +116,9 @@ static void ShowDialog   ( intf_thread_t *, int, int, intf_dialog_args_t * );
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
-#define ADVANCED_PREFS_TEXT N_( "Show advanced preferences over simple ones" )
-#define ADVANCED_PREFS_LONGTEXT N_( "Show advanced preferences and not simple "\
-                                    "preferences when opening the preferences "\
-                                    "dialog." )
+#define INITIAL_PREFS_VIEW_TEXT N_( "Select the initial preferences view" )
+#define INITIAL_PREFS_VIEW_LONGTEXT N_( "Select which preferences view to show upon "\
+                                        "opening the preferences dialog." )
 
 #define SYSTRAY_TEXT N_( "Systray icon" )
 #define SYSTRAY_LONGTEXT N_( "Show an icon in the systray " \
@@ -249,6 +248,10 @@ static void ShowDialog   ( intf_thread_t *, int, int, intf_dialog_args_t * );
 #define SMOOTH_SCROLLING_TEXT N_( "Use smooth scrolling in Flickable based views" )
 #define SMOOTH_SCROLLING_LONGTEXT N_( "Deactivating this option will disable smooth scrolling in Flickable based views (such as the Playqueue)" )
 
+static const int initial_prefs_view_list[] = { 0, 1, 2 };
+static const char *const initial_prefs_view_list_texts[] =
+    { N_("Simple"), N_("Advanced"), N_("Expert") };
+
 static const int i_notification_list[] =
     { NOTIFICATION_NEVER, NOTIFICATION_MINIMIZED, NOTIFICATION_ALWAYS };
 
@@ -374,8 +377,10 @@ vlc_module_begin ()
                nullptr )
 
 
-    add_bool( "qt-advanced-pref", false, ADVANCED_PREFS_TEXT,
-              ADVANCED_PREFS_LONGTEXT )
+    add_obsolete_bool( "qt-advanced-pref" ) /* since 4.0.0 */
+    add_integer( "qt-initial-prefs-view", 0, INITIAL_PREFS_VIEW_TEXT, INITIAL_PREFS_VIEW_LONGTEXT )
+        change_integer_range( 0, 2 )
+        change_integer_list( initial_prefs_view_list, initial_prefs_view_list_texts )
     add_bool( "qt-error-dialogs", true, ERROR_TEXT,
               nullptr )
 


=====================================
po/POTFILES.in
=====================================
@@ -681,6 +681,10 @@ modules/gui/qt/dialogs/fingerprint/chromaprint.cpp
 modules/gui/qt/dialogs/fingerprint/chromaprint.hpp
 modules/gui/qt/dialogs/preferences/complete_preferences.cpp
 modules/gui/qt/dialogs/preferences/complete_preferences.hpp
+modules/gui/qt/dialogs/preferences/expert_model.cpp
+modules/gui/qt/dialogs/preferences/expert_model.hpp
+modules/gui/qt/dialogs/preferences/expert_view.cpp
+modules/gui/qt/dialogs/preferences/expert_view.hpp
 modules/gui/qt/menus/custom_menus.cpp
 modules/gui/qt/menus/custom_menus.hpp
 modules/gui/qt/menus/qml_menu_wrapper.cpp



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/9ec6146c39f8fce14a7a2d07f08a42aecb27cba7...626d25ae39f32e6a755f95d472359e335ff43c1a

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/9ec6146c39f8fce14a7a2d07f08a42aecb27cba7...626d25ae39f32e6a755f95d472359e335ff43c1a
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list