[vlc-devel] [PATCH 01/21] qt: qml: enable aligned player controlbar customization

Fatih Uzunoglu fuzun54 at outlook.com
Sat Nov 7 17:53:20 CET 2020


this patch allows to customize player toolbar/controlbar in a way that controls can be aligned to left, center or right. it also fixes the broken cursor management in the customization window (toolbareditor).
---
 .../dialogs/toolbar/qml/EditorDNDDelegate.qml |  97 ++++-
 .../qt/dialogs/toolbar/qml/EditorDNDView.qml  |  86 ++--
 .../dialogs/toolbar/qml/EditorTabButton.qml   |  22 +-
 .../qt/dialogs/toolbar/qml/ToolbarEditor.qml  | 409 ++++++++++++++++--
 .../toolbar/qml/ToolbarEditorButtonList.qml   |  80 +++-
 .../gui/qt/dialogs/toolbar/toolbareditor.cpp  |  48 +-
 .../gui/qt/dialogs/toolbar/toolbareditor.hpp  |   2 -
 .../gui/qt/player/playercontrolbarmodel.cpp   | 114 +++--
 .../gui/qt/player/playercontrolbarmodel.hpp   |   4 +-
 modules/gui/qt/player/qml/ControlBar.qml      |  96 +++-
 modules/gui/qt/player/qml/MiniPlayer.qml      | 225 ++++++----
 11 files changed, 945 insertions(+), 238 deletions(-)

diff --git a/modules/gui/qt/dialogs/toolbar/qml/EditorDNDDelegate.qml b/modules/gui/qt/dialogs/toolbar/qml/EditorDNDDelegate.qml
index 2503c127ba..a11f21291a 100644
--- a/modules/gui/qt/dialogs/toolbar/qml/EditorDNDDelegate.qml
+++ b/modules/gui/qt/dialogs/toolbar/qml/EditorDNDDelegate.qml
@@ -27,16 +27,36 @@ import "qrc:///style/"
 MouseArea {
     id: dragArea
 
+    property int controlId: model.id
     property bool held: false
     property bool dropVisible: false
     property var dndView: null
     anchors.verticalCenter: parent.verticalCenter
-    cursorShape: dropVisible ? Qt.DragMoveCursor : Qt.OpenHandCursor
+    cursorShape: Qt.OpenHandCursor
     drag.target: held ? content : undefined
     width: buttonloader.width
     height: VLCStyle.icon_medium
     hoverEnabled: true
 
+    property alias containsDrag: dropArea.containsDrag
+
+    onHeldChanged: {
+        if (held) {
+            removeInfoRectVisible = true
+        }
+        else {
+            removeInfoRectVisible = false
+        }
+    }
+
+    Rectangle {
+        z: -1
+        anchors.fill: parent
+
+        visible: dragArea.containsMouse && !held
+        color: VLCStyle.colors.bgHover
+    }
+
     Rectangle {
         z: 1
         width: VLCStyle.dp(2, VLCStyle.scale)
@@ -44,27 +64,39 @@ MouseArea {
         anchors {
             left: parent.left
             verticalCenter: parent.verticalCenter
+            leftMargin: index === 0 ? 0 : -width
         }
         antialiasing: true
         visible: dropVisible
         color: VLCStyle.colors.accent
     }
-    onPressed: held = true
+
+    onPressed: {
+        held = true
+        root._held = true
+    }
+
     onEntered: playerBtnDND.currentIndex = index
 
-    onExited: {
-        if(containsPress)
-            dndView.deleteBtn = true
+    onWheel: {
+        playerBtnDND.wheelScroll(wheel.angleDelta.y)
     }
 
     onReleased: {
         drag.target.Drag.drop()
         held = false
-        if(dndView.deleteBtn){
-            dndView.deleteBtn = false
-            dndView.model.remove(
-                        dragArea.DelegateModel.itemsIndex)
-        }
+        root._held = false
+    }
+
+    onPositionChanged: {
+        var pos = this.mapToGlobal(mouseX, mouseY)
+        updatePos(pos.x, pos.y)
+    }
+
+    function updatePos(x, y) {
+        var pos = root.mapFromGlobal(x, y)
+        content.x = pos.x
+        content.y = pos.y
     }
 
     Rectangle {
@@ -75,6 +107,9 @@ MouseArea {
             horizontalCenter: parent.horizontalCenter
             verticalCenter: parent.verticalCenter
         }
+
+        opacity: held ? 0.75 : 1.0
+
         Loader{
             id: buttonloader
             anchors {
@@ -95,26 +130,44 @@ MouseArea {
                 anchors { horizontalCenter: undefined; verticalCenter: undefined }
             }
         }
+
+        onXChanged: {
+            root.handleScroll(this)
+        }
     }
+
     DropArea {
+        id: dropArea
         anchors.fill: parent
 
         onEntered: {
+            if ((drag.source === null ||
+                 (drag.source.dndView === playerBtnDND &&
+                  (parent.DelegateModel.itemsIndex === drag.source.DelegateModel.itemsIndex + 1))))
+                return
+
+            if (held)
+                return
+
             dropVisible = true
-            dndView.deleteBtn = false
         }
 
         onExited: {
+            if (held)
+                return
+
             dropVisible = false
-            if(!dndView.addBtn)
-                dndView.deleteBtn = true
         }
 
         onDropped: {
-            if (drag.source.objectName == "buttonsList")
-                dndView.model.insert(parent.DelegateModel.itemsIndex,
-                                            {"id" : drag.source.mIndex})
-            else{
+            if (!dropVisible)
+                return
+
+            if (held)
+                return
+
+            if (drag.source.dndView === playerBtnDND) {
+                // moving from same section
                 var srcIndex = drag.source.DelegateModel.itemsIndex
                 var destIndex = parent.DelegateModel.itemsIndex
 
@@ -122,6 +175,16 @@ MouseArea {
                     destIndex -= 1
                 playerBtnDND.model.move(srcIndex,destIndex)
             }
+            else if (drag.source.objectName == "buttonsList"){
+                // moving from buttonsList
+                dndView.model.insert(parent.DelegateModel.itemsIndex, {"id" : drag.source.mIndex})
+            }
+            else {
+                // moving between sections
+                dndView.model.insert(parent.DelegateModel.itemsIndex, {"id" : drag.source.controlId})
+                drag.source.dndView.model.remove(drag.source.DelegateModel.itemsIndex)
+            }
+
             dropVisible = false
         }
     }
diff --git a/modules/gui/qt/dialogs/toolbar/qml/EditorDNDView.qml b/modules/gui/qt/dialogs/toolbar/qml/EditorDNDView.qml
index 0b4b4cf54f..b44077ea30 100644
--- a/modules/gui/qt/dialogs/toolbar/qml/EditorDNDView.qml
+++ b/modules/gui/qt/dialogs/toolbar/qml/EditorDNDView.qml
@@ -25,25 +25,45 @@ import "qrc:///style/"
 
 ListView {
     id: playerBtnDND
-    spacing: VLCStyle.margin_xxsmall
+    spacing: VLCStyle.margin_xsmall
     orientation: Qt.Horizontal
     clip: true
-    property bool deleteBtn: false
-    property bool addBtn: false
-    onDeleteBtnChanged: {
-        if(deleteBtn)
-            toolbareditor.deleteCursor()
+
+    property bool containsDrag: footerItem.dropVisible
+
+    property alias scrollBar: scrollBar
+
+    ScrollBar.horizontal: ScrollBar {
+        id: scrollBar
+        policy: playerBtnDND.contentWidth > playerBtnDND.width ? ScrollBar.AlwaysOn : ScrollBar.AsNeeded
+    }
+
+    function wheelScroll(delta) {
+        if (delta > 0)
+            scrollBar.decrease()
         else
-            toolbareditor.restoreCursor()
+            scrollBar.increase()
     }
 
-    ScrollBar.horizontal: ScrollBar {}
+    MouseArea {
+        anchors.fill: parent
+        z: 1
+
+        visible: root._held
 
-    footer: Item {
+        cursorShape: visible ? Qt.DragMoveCursor : Qt.ArrowCursor
+    }
+
+    footer: MouseArea {
         height: VLCStyle.icon_medium
-        width: height
+        width: Math.max(height, playerBtnDND.width - x)
         anchors.verticalCenter: parent.verticalCenter
         property bool dropVisible: false
+
+        onWheel: {
+            wheelScroll(wheel.angleDelta.y)
+        }
+
         Rectangle {
             z: 2
             width: VLCStyle.dp(2, VLCStyle.scale)
@@ -59,38 +79,50 @@ ListView {
             anchors.fill: parent
 
             onEntered: {
+                if (drag.source.dndView === playerBtnDND && drag.source.DelegateModel.itemsIndex === playerBtnDND.count - 1)
+                    return
+
                 dropVisible = true
-                playerBtnDND.deleteBtn = false
             }
 
             onExited: {
                 dropVisible = false
-                playerBtnDND.deleteBtn = true
             }
 
             onDropped: {
-                if (drag.source.objectName == "buttonsList"){
-                    playerBtnDND.model.insert(playerBtnDND.count,
-                                             {"id" : drag.source.mIndex})
+                if (!dropVisible)
+                    return
+
+                if (drag.source.dndView === playerBtnDND) {
+                    // moving from same section
+                    playerBtnDND.model.move(drag.source.DelegateModel.itemsIndex, playerBtnDND.count - 1)
+                }
+                else if (drag.source.objectName == "buttonsList"){
+                    // moving from buttonsList
+                    playerBtnDND.model.insert(playerBtnDND.count, {"id" : drag.source.mIndex})
+                }
+                else {
+                    // moving between sections
+                    playerBtnDND.model.insert(playerBtnDND.count, {"id" : drag.source.controlId})
+                    drag.source.dndView.model.remove(drag.source.DelegateModel.itemsIndex)
                 }
-                else
-                    playerBtnDND.model.move(
-                                drag.source.DelegateModel.itemsIndex,
-                                playerBtnDND.count-1)
+
                 dropVisible = false
             }
         }
-
     }
 
     delegate: EditorDNDDelegate {
         dndView: playerBtnDND
-    }
-    highlight: Rectangle{
-        anchors.verticalCenter: currentIndex > 0 ? parent.verticalCenter : undefined
-        color: VLCStyle.colors.bgHover
-    }
 
-    highlightMoveDuration: 0 //ms
-    highlightResizeDuration: 0 //ms
+        onContainsDragChanged: {
+            for(var child in playerBtnDND.contentItem.children) {
+                if (playerBtnDND.contentItem.children[child].containsDrag === true) {
+                    playerBtnDND.containsDrag = true
+                    return
+                }
+            }
+            playerBtnDND.containsDrag = Qt.binding(function() { return footerItem.dropVisible; } )
+        }
+    }
 }
diff --git a/modules/gui/qt/dialogs/toolbar/qml/EditorTabButton.qml b/modules/gui/qt/dialogs/toolbar/qml/EditorTabButton.qml
index 7623729942..b9a105e580 100644
--- a/modules/gui/qt/dialogs/toolbar/qml/EditorTabButton.qml
+++ b/modules/gui/qt/dialogs/toolbar/qml/EditorTabButton.qml
@@ -26,6 +26,8 @@ TabButton {
     property int index: 0
     property bool active: index == bar.currentIndex
 
+    implicitWidth: VLCStyle.button_width_large
+
     contentItem: Text {
         text: mainPlayerControl.text
         color: VLCStyle.colors.buttonText
@@ -34,9 +36,23 @@ TabButton {
     }
 
     background: Rectangle {
-        width: VLCStyle.button_width_large
-        height: VLCStyle.heightBar_normal
         color: active ? VLCStyle.colors.bgAlt : hovered ? VLCStyle.colors.bgHover : VLCStyle.colors.bg
-        radius: 2
+
+        border.color: VLCStyle.colors.accent
+        border.width: active ? VLCStyle.dp(1, VLCStyle.scale) : 0
+
+        Rectangle {
+            width: parent.width - parent.border.width * 2
+            anchors.horizontalCenter: parent.horizontalCenter
+            anchors.top: parent.bottom
+
+            anchors.topMargin: -(height / 2)
+
+            color: parent.color
+
+            visible: active
+
+            height: parent.border.width * 2
+        }
     }
 }
diff --git a/modules/gui/qt/dialogs/toolbar/qml/ToolbarEditor.qml b/modules/gui/qt/dialogs/toolbar/qml/ToolbarEditor.qml
index 709816d66a..607b36b0c2 100644
--- a/modules/gui/qt/dialogs/toolbar/qml/ToolbarEditor.qml
+++ b/modules/gui/qt/dialogs/toolbar/qml/ToolbarEditor.qml
@@ -29,50 +29,274 @@ Rectangle{
     id: root
     color: VLCStyle.colors.bg
 
+    property bool _held: false
+
+    property alias removeInfoRectVisible: buttonList.removeInfoRectVisible
+
+    MouseArea {
+        anchors.fill: parent
+        z: -1
+
+        visible: _held
+
+        cursorShape: visible ? Qt.ForbiddenCursor : Qt.ArrowCursor
+    }
+
     ColumnLayout{
         anchors.fill: parent
         spacing: 0
+
         TabBar {
             id: bar
             Layout.preferredHeight: VLCStyle.heightBar_normal
-            Layout.preferredWidth: VLCStyle.button_width_large * bar.count
+
+            z: 1
+
+            spacing: VLCStyle.dp(1) // this causes binding loop warning in Qt 5.11.3 probably due to a bug
 
             EditorTabButton {
                 id: mainPlayerTab
+
+                anchors.top: parent.top
+                anchors.bottom: parent.bottom
+
                 index: 0
                 text: i18n.qtr("Mainplayer")
             }
 
             EditorTabButton {
                 id: miniPlayerTab
+
+                anchors.top: parent.top
+                anchors.bottom: parent.bottom
+
                 index: 1
                 text: i18n.qtr("Miniplayer")
             }
         }
+
         Rectangle{
-            Layout.preferredHeight: VLCStyle.heightBar_large
+            Layout.preferredHeight: VLCStyle.heightBar_large * 1.25
             Layout.fillWidth: true
-            radius: 2
+
             color: VLCStyle.colors.bgAlt
 
+            border.color: VLCStyle.colors.accent
+            border.width: VLCStyle.dp(1, VLCStyle.scale)
+
             StackLayout{
                 anchors.fill: parent
                 currentIndex: bar.currentIndex
 
-                EditorDNDView {
-                    id : playerBtnDND
-                    Layout.preferredHeight: VLCStyle.heightBar_large
+                RowLayout {
+                    Layout.preferredHeight: VLCStyle.heightBar_large * 1.25
                     Layout.fillWidth: true
-                    model: playerControlBarModel
+
+                    TextMetrics {
+                        id: leftMetric
+                        text: i18n.qtr("L   E   F   T")
+                        font.pixelSize: VLCStyle.fontSize_xxlarge
+                    }
+
+                    TextMetrics {
+                        id: centerMetric
+                        text: i18n.qtr("C   E   N   T   E   R")
+                        font.pixelSize: VLCStyle.fontSize_xxlarge
+                    }
+
+                    TextMetrics {
+                        id: rightMetric
+                        text: i18n.qtr("R   I   G   H   T")
+                        font.pixelSize: VLCStyle.fontSize_xxlarge
+                    }
+
+                    EditorDNDView {
+                        id : playerBtnDND_left
+                        Layout.fillHeight: true
+
+                        Layout.fillWidth: count > 0 || (playerBtnDND_left.count === 0 && playerBtnDND_center.count === 0 && playerBtnDND_right.count === 0)
+                        Layout.minimumWidth: centerMetric.width
+                        Layout.leftMargin: VLCStyle.margin_xsmall
+                        Layout.rightMargin: VLCStyle.margin_xsmall
+
+                        model: playerControlBarModel_left
+
+                        Text {
+                            anchors.fill: parent
+
+                            text: leftMetric.text
+                            verticalAlignment: Text.AlignVCenter
+                            font.pixelSize: VLCStyle.fontSize_xxlarge
+                            color: VLCStyle.colors.menuCaption
+                            horizontalAlignment: Text.AlignHCenter
+                            visible: (parent.count === 0)
+                        }
+                    }
+
+                    Rectangle {
+                        Layout.preferredWidth: VLCStyle.margin_small
+
+                        Layout.fillHeight: true
+                        Layout.topMargin: VLCStyle.dp(1, VLCStyle.scale)
+                        Layout.bottomMargin: VLCStyle.dp(1, VLCStyle.scale)
+                        Layout.alignment: Qt.AlignVCenter
+
+                        color: VLCStyle.colors.bg
+                    }
+
+                    EditorDNDView {
+                        id : playerBtnDND_center
+                        Layout.fillHeight: true
+
+                        Layout.fillWidth: count > 0 || (playerBtnDND_left.count === 0 && playerBtnDND_center.count === 0 && playerBtnDND_right.count === 0)
+                        Layout.minimumWidth: centerMetric.width
+                        Layout.leftMargin: VLCStyle.margin_xsmall
+                        Layout.rightMargin: VLCStyle.margin_xsmall
+
+                        model: playerControlBarModel_center
+
+                        Text {
+                            anchors.fill: parent
+
+                            text: centerMetric.text
+                            verticalAlignment: Text.AlignVCenter
+                            font.pixelSize: VLCStyle.fontSize_xxlarge
+                            color: VLCStyle.colors.menuCaption
+                            horizontalAlignment: Text.AlignHCenter
+                            visible: (parent.count === 0)
+                        }
+                    }
+
+                    Rectangle {
+                        Layout.preferredWidth: VLCStyle.margin_small
+
+                        Layout.fillHeight: true
+                        Layout.topMargin: VLCStyle.dp(1, VLCStyle.scale)
+                        Layout.bottomMargin: VLCStyle.dp(1, VLCStyle.scale)
+                        Layout.alignment: Qt.AlignVCenter
+
+                        color: VLCStyle.colors.bg
+                    }
+
+                    EditorDNDView {
+                        id : playerBtnDND_right
+                        Layout.fillHeight: true
+
+                        Layout.fillWidth: count > 0 || (playerBtnDND_left.count === 0 && playerBtnDND_center.count === 0 && playerBtnDND_right.count === 0)
+                        Layout.minimumWidth: centerMetric.width
+                        Layout.leftMargin: VLCStyle.margin_xsmall
+                        Layout.rightMargin: VLCStyle.margin_xsmall
+
+                        model: playerControlBarModel_right
+
+                        Text {
+                            anchors.fill: parent
+
+                            text: rightMetric.text
+                            verticalAlignment: Text.AlignVCenter
+                            font.pixelSize: VLCStyle.fontSize_xxlarge
+                            color: VLCStyle.colors.menuCaption
+                            horizontalAlignment: Text.AlignHCenter
+                            visible: (parent.count === 0)
+                        }
+                    }
                 }
 
-                EditorDNDView {
-                    id : miniPlayerBtnDND
-                    Layout.preferredHeight: VLCStyle.heightBar_large
+                RowLayout {
+                    Layout.preferredHeight: VLCStyle.heightBar_large * 1.25
                     Layout.fillWidth: true
-                    model: miniPlayerModel
-                }
 
+                    EditorDNDView {
+                        id : miniPlayerBtnDND_left
+                        Layout.fillHeight: true
+
+                        Layout.fillWidth: count > 0 || (miniPlayerBtnDND_left.count === 0 && miniPlayerBtnDND_center.count === 0 && miniPlayerBtnDND_right.count === 0)
+                        Layout.minimumWidth: centerMetric.width
+                        Layout.leftMargin: VLCStyle.margin_xsmall
+                        Layout.rightMargin: VLCStyle.margin_xsmall
+
+                        model: miniPlayerModel_left
+
+                        Text {
+                            anchors.fill: parent
+
+                            text: leftMetric.text
+                            verticalAlignment: Text.AlignVCenter
+                            font.pixelSize: VLCStyle.fontSize_xxlarge
+                            color: VLCStyle.colors.menuCaption
+                            horizontalAlignment: Text.AlignHCenter
+                            visible: (parent.count === 0)
+                        }
+                    }
+
+                    Rectangle {
+                        Layout.preferredWidth: VLCStyle.margin_small
+
+                        Layout.fillHeight: true
+                        Layout.topMargin: VLCStyle.dp(1, VLCStyle.scale)
+                        Layout.bottomMargin: VLCStyle.dp(1, VLCStyle.scale)
+                        Layout.alignment: Qt.AlignVCenter
+
+                        color: VLCStyle.colors.bg
+                    }
+
+                    EditorDNDView {
+                        id : miniPlayerBtnDND_center
+                        Layout.fillHeight: true
+
+                        Layout.fillWidth: count > 0 || (miniPlayerBtnDND_left.count === 0 && miniPlayerBtnDND_center.count === 0 && miniPlayerBtnDND_right.count === 0)
+                        Layout.minimumWidth: centerMetric.width
+                        Layout.leftMargin: VLCStyle.margin_xsmall
+                        Layout.rightMargin: VLCStyle.margin_xsmall
+
+                        model: miniPlayerModel_center
+
+                        Text {
+                            anchors.fill: parent
+
+                            text: centerMetric.text
+                            verticalAlignment: Text.AlignVCenter
+                            font.pixelSize: VLCStyle.fontSize_xxlarge
+                            color: VLCStyle.colors.menuCaption
+                            horizontalAlignment: Text.AlignHCenter
+                            visible: (parent.count === 0)
+                        }
+                    }
+
+                    Rectangle {
+                        Layout.preferredWidth: VLCStyle.margin_small
+
+                        Layout.fillHeight: true
+                        Layout.topMargin: VLCStyle.dp(1, VLCStyle.scale)
+                        Layout.bottomMargin: VLCStyle.dp(1, VLCStyle.scale)
+                        Layout.alignment: Qt.AlignVCenter
+
+                        color: VLCStyle.colors.bg
+                    }
+
+                    EditorDNDView {
+                        id : miniPlayerBtnDND_right
+                        Layout.fillHeight: true
+
+                        Layout.fillWidth: count > 0 || (miniPlayerBtnDND_left.count === 0 && miniPlayerBtnDND_center.count === 0 && miniPlayerBtnDND_right.count === 0)
+                        Layout.minimumWidth: centerMetric.width
+                        Layout.leftMargin: VLCStyle.margin_xsmall
+                        Layout.rightMargin: VLCStyle.margin_xsmall
+
+                        model: miniPlayerModel_right
+
+                        Text {
+                            anchors.fill: parent
+
+                            text: rightMetric.text
+                            verticalAlignment: Text.AlignVCenter
+                            font.pixelSize: VLCStyle.fontSize_xxlarge
+                            color: VLCStyle.colors.menuCaption
+                            horizontalAlignment: Text.AlignHCenter
+                            visible: (parent.count === 0)
+                        }
+                    }
+                }
             }
         }
 
@@ -94,46 +318,95 @@ Rectangle{
                 }
 
                 ToolbarEditorButtonList {
+                    id: buttonList
+
                     Layout.fillWidth: true
                     Layout.fillHeight: true
                     Layout.margins: VLCStyle.margin_xxsmall
                 }
             }
         }
-
-
     }
 
     function getProfileConfig(){
-        return playerControlBarModel.getConfig() + "|" + miniPlayerModel.getConfig()
+        return "%1#%2#%3 | %4#%5#%6".arg(playerControlBarModel_left.getConfig())
+                                    .arg(playerControlBarModel_center.getConfig())
+                                    .arg(playerControlBarModel_right.getConfig())
+                                    .arg(miniPlayerModel_left.getConfig())
+                                    .arg(miniPlayerModel_center.getConfig())
+                                    .arg(miniPlayerModel_right.getConfig())
     }
 
     Connections{
         target: toolbareditor
         onUpdatePlayerModel: {
-            playerBtnDND.currentIndex = -1
-            miniPlayerBtnDND.currentIndex = -1
-            if (toolbarName == "MainPlayerToolbar")
-                playerControlBarModel.reloadConfig(config)
-            else
-                miniPlayerModel.reloadConfig(config)
+            playerBtnDND_left.currentIndex = -1
+            playerBtnDND_center.currentIndex = -1
+            playerBtnDND_right.currentIndex = -1
+
+            miniPlayerBtnDND_left.currentIndex = -1
+            miniPlayerBtnDND_center.currentIndex = -1
+            miniPlayerBtnDND_right.currentIndex = -1
+
+            if (toolbarName == "MainPlayerToolbar-left")
+                playerControlBarModel_left.reloadConfig(config)
+            else if (toolbarName == "MainPlayerToolbar-center")
+                playerControlBarModel_center.reloadConfig(config)
+            else if (toolbarName == "MainPlayerToolbar-right")
+                playerControlBarModel_right.reloadConfig(config)
+            else if (toolbarName == "MiniPlayerToolbar-left")
+                miniPlayerModel_left.reloadConfig(config)
+            else if (toolbarName == "MiniPlayerToolbar-center")
+                miniPlayerModel_center.reloadConfig(config)
+            else if (toolbarName == "MiniPlayerToolbar-right")
+                miniPlayerModel_right.reloadConfig(config)
         }
+
         onSaveConfig: {
-            miniPlayerModel.saveConfig()
-            playerControlBarModel.saveConfig()
+            miniPlayerModel_left.saveConfig()
+            miniPlayerModel_center.saveConfig()
+            miniPlayerModel_right.saveConfig()
+
+            playerControlBarModel_left.saveConfig()
+            playerControlBarModel_center.saveConfig()
+            playerControlBarModel_right.saveConfig()
         }
     }
 
     PlayerControlBarModel {
-        id: playerControlBarModel
+        id: playerControlBarModel_left
+        mainCtx: mainctx
+        configName: "MainPlayerToolbar-left"
+    }
+
+    PlayerControlBarModel {
+        id: playerControlBarModel_center
+        mainCtx: mainctx
+        configName: "MainPlayerToolbar-center"
+    }
+
+    PlayerControlBarModel {
+        id: playerControlBarModel_right
+        mainCtx: mainctx
+        configName: "MainPlayerToolbar-right"
+    }
+
+    PlayerControlBarModel {
+        id: miniPlayerModel_left
+        mainCtx: mainctx
+        configName: "MiniPlayerToolbar-left"
+    }
+
+    PlayerControlBarModel {
+        id: miniPlayerModel_center
         mainCtx: mainctx
-        configName: "MainPlayerToolbar"
+        configName: "MiniPlayerToolbar-center"
     }
 
     PlayerControlBarModel {
-        id: miniPlayerModel
+        id: miniPlayerModel_right
         mainCtx: mainctx
-        configName: "MiniPlayerToolbar"
+        configName: "MiniPlayerToolbar-right"
     }
 
     Player.ControlButtons{
@@ -149,17 +422,90 @@ Rectangle{
         id: buttonDragItem
         visible: false
         Drag.active: visible
-        Drag.hotSpot.x: width / 2
-        Drag.hotSpot.y: height / 2
         color: VLCStyle.colors.buttonText
 
+        opacity: 0.75
+
         function updatePos(x, y) {
             var pos = root.mapFromGlobal(x, y)
-            this.x = pos.x - 20
-            this.y = pos.y - 20
+            this.x = pos.x
+            this.y = pos.y
+        }
+
+        onXChanged: {
+            handleScroll(this)
+        }
+    }
+
+    property int _scrollingDirection: 0
+
+    function getHoveredListView() {
+        if (playerBtnDND_left.containsDrag)
+            return playerBtnDND_left
+        else if (playerBtnDND_center.containsDrag)
+            return playerBtnDND_center
+        else if (playerBtnDND_right.containsDrag)
+            return playerBtnDND_right
+        else if (miniPlayerBtnDND_left.containsDrag)
+            return miniPlayerBtnDND_left
+        else if (miniPlayerBtnDND_center.containsDrag)
+            return miniPlayerBtnDND_center
+        else if (miniPlayerBtnDND_right.containsDrag)
+            return miniPlayerBtnDND_right
+        else
+            return undefined
+    }
+
+    function handleScroll(dragItem) {
+        var view = root.getHoveredListView()
+
+        if (view === undefined) {
+            upAnimation.target = null
+            downAnimation.target = null
+
+            _scrollingDirection = 0
+            return
+        }
+
+        upAnimation.target = view
+        downAnimation.target = view
+
+        downAnimation.to = Qt.binding(function() { return view.contentWidth - view.width; })
+
+        var dragItemX = root.mapToGlobal(dragItem.x, dragItem.y).x
+        var viewX     = root.mapToGlobal(view.x, view.y).x
+
+        var leftDiff  = (viewX + VLCStyle.dp(20, VLCStyle.scale)) - dragItemX
+        var rightDiff = dragItemX - (viewX + view.width - VLCStyle.dp(20, VLCStyle.scale))
+
+        if( !view.atXBeginning && leftDiff > 0 ) {
+            _scrollingDirection = -1
+        }
+        else if( !view.atXEnd && rightDiff > 0 ) {
+            _scrollingDirection = 1
+        }
+        else {
+            _scrollingDirection = 0
         }
     }
 
+    SmoothedAnimation {
+        id: upAnimation
+        property: "contentX"
+        to: 0
+        running: root._scrollingDirection === -1 && target !== null
+
+        velocity: VLCStyle.dp(150, VLCStyle.scale)
+    }
+
+    SmoothedAnimation {
+        id: downAnimation
+        property: "contentX"
+        running: root._scrollingDirection === 1 && target !== null
+
+        velocity: VLCStyle.dp(150, VLCStyle.scale)
+    }
+
     /*
       Match the QML theme to
       native part. Using Qt Style Sheet to
@@ -171,4 +517,3 @@ Rectangle{
                                ";selection-background-color:"+
                                VLCStyle.colors.bgHover);
 }
-
diff --git a/modules/gui/qt/dialogs/toolbar/qml/ToolbarEditorButtonList.qml b/modules/gui/qt/dialogs/toolbar/qml/ToolbarEditorButtonList.qml
index f0091e3f7b..93eb2c0c50 100644
--- a/modules/gui/qt/dialogs/toolbar/qml/ToolbarEditorButtonList.qml
+++ b/modules/gui/qt/dialogs/toolbar/qml/ToolbarEditorButtonList.qml
@@ -36,7 +36,72 @@ GridView{
 
     highlightMoveDuration: 0 //ms
 
-    delegate:MouseArea{
+    property alias removeInfoRectVisible: removeInfoRect.visible
+
+    DropArea {
+        id: dropArea
+        anchors.fill: parent
+
+        z: 3
+
+        function isFromList() {
+            if (drag.source.objectName === "buttonsList")
+                return true
+            else
+                return false
+        }
+
+        onDropped: {
+            if (isFromList())
+                return
+
+            drag.source.dndView.model.remove(drag.source.DelegateModel.itemsIndex)
+        }
+    }
+
+    Rectangle {
+        id: removeInfoRect
+        anchors.fill: parent
+        z: 2
+
+        visible: false
+
+        opacity: 0.8
+        color: VLCStyle.colors.bg
+
+        border.color: VLCStyle.colors.menuCaption
+        border.width: VLCStyle.dp(2, VLCStyle.scale)
+
+        Text {
+            anchors.centerIn: parent
+
+            text: VLCIcons.del
+            verticalAlignment: Text.AlignVCenter
+            horizontalAlignment: Text.AlignHCenter
+
+            font.pointSize: VLCStyle.fontHeight_xxxlarge
+
+            font.family: VLCIcons.fontFamily
+            color: VLCStyle.colors.menuCaption
+        }
+
+        MouseArea {
+            anchors.fill: parent
+
+            cursorShape: visible ? Qt.DragMoveCursor : Qt.ArrowCursor
+        }
+    }
+
+    MouseArea {
+        anchors.fill: parent
+        z: 1
+
+        visible: root._held
+
+        cursorShape: visible ? Qt.DragMoveCursor : Qt.ArrowCursor
+    }
+
+    delegate: MouseArea {
         id:dragArea
         objectName: "buttonsList"
         hoverEnabled: true
@@ -53,18 +118,21 @@ GridView{
             buttonDragItem.text = controlButtons.buttonL[model.index].label
             buttonDragItem.Drag.source = dragArea
             held = true
-            var pos = this.mapToGlobal( mouseX, mouseY)
-            buttonDragItem.updatePos(pos.x, pos.y)
-            playerBtnDND.addBtn = true
-            miniPlayerBtnDND.addBtn = true
+            root._held = true
         }
 
         onReleased: {
             drag.target.Drag.drop()
             buttonDragItem.visible = false
             held = false
-            playerBtnDND.addBtn = false
+            root._held = false
         }
+
+        onPositionChanged: {
+            var pos = this.mapToGlobal(mouseX, mouseY)
+            buttonDragItem.updatePos(pos.x, pos.y)
+        }
+
         onEntered: allButtonsView.currentIndex = index
 
         ColumnLayout{
diff --git a/modules/gui/qt/dialogs/toolbar/toolbareditor.cpp b/modules/gui/qt/dialogs/toolbar/toolbareditor.cpp
index 39195f989d..d6efb5584a 100644
--- a/modules/gui/qt/dialogs/toolbar/toolbareditor.cpp
+++ b/modules/gui/qt/dialogs/toolbar/toolbareditor.cpp
@@ -35,9 +35,9 @@
 #define PROFILE_NAME_1 "Minimalist Style"
 #define VALUE_1 "0;64;3;1;4;64;11;64;34;64;9;64;33 | 3;0;1;4"
 #define PROFILE_NAME_2 "One-Liner Style"
-#define VALUE_2 "0;64;3;1;4;64;7;9;8;64;64;11;10;12;13;65;33 | 17;3;0;1;4;18"
+#define VALUE_2 "0;64;3;1;4;64;7;9;8;64;64;11;10;12;13;#33 | 17;3;0;1;4;18"
 #define PROFILE_NAME_3 "Simplest Style"
-#define VALUE_3 "33;65;0;4;1;65;7 | 3;0;4"
+#define VALUE_3 "33;#0;4;1;#7 | 3;0;4"
 
 ToolbarEditorDialog::ToolbarEditorDialog( QWidget *_w, intf_thread_t *_p_intf)
     : QVLCDialog( _w,  _p_intf )
@@ -80,11 +80,16 @@ ToolbarEditorDialog::ToolbarEditorDialog( QWidget *_w, intf_thread_t *_p_intf)
     /* Load defaults ones if we have no combos */
     if( i_size == 0 )
     {
+        profileCombo->addItem( qtr("Default Style"), PlayerControlBarModel::getSerializedDefaultStyle() );
         profileCombo->addItem( PROFILE_NAME_1, QString( VALUE_1 ) );
         profileCombo->addItem( PROFILE_NAME_2, QString( VALUE_2 ) );
         profileCombo->addItem( PROFILE_NAME_3, QString( VALUE_3 ) );
+        profileCombo->setCurrentIndex(0);
+    }
+    else
+    {
+        profileCombo->setCurrentIndex( -1 );
     }
-    profileCombo->setCurrentIndex( -1 );
 
     /* Drag and Drop */
     editorView = new QQuickWidget(this);
@@ -175,17 +180,28 @@ void ToolbarEditorDialog::changeProfile( int i )
 {
     QStringList qs_list = profileCombo->itemData( i ).toString().split( "|" );
     if( qs_list.count() < 2 )
-            return;
-    emit updatePlayerModel("MainPlayerToolbar",qs_list[0]);
-    emit updatePlayerModel("MiniPlayerToolbar",qs_list[1]);
-}
-
-void ToolbarEditorDialog::deleteCursor()
-{
-    QApplication::setOverrideCursor(Qt::ForbiddenCursor);
-}
-
-void ToolbarEditorDialog::restoreCursor()
-{
-    QApplication::restoreOverrideCursor();
+        return;
+
+    QStringList align_list_main = qs_list[0].split("#");
+    QStringList align_list_mini = qs_list[1].split("#");
+
+    emit updatePlayerModel("MainPlayerToolbar-left", align_list_main[0]);
+    if(align_list_main.size() >= 2)
+        emit updatePlayerModel("MainPlayerToolbar-center", align_list_main[1]);
+    else
+        emit updatePlayerModel("MainPlayerToolbar-center", "");
+    if(align_list_main.size() >= 3)
+        emit updatePlayerModel("MainPlayerToolbar-right", align_list_main[2]);
+    else
+        emit updatePlayerModel("MainPlayerToolbar-right", "");
+
+    emit updatePlayerModel("MiniPlayerToolbar-left", align_list_mini[0]);
+    if(align_list_mini.size() >= 2)
+        emit updatePlayerModel("MiniPlayerToolbar-center", align_list_mini[1]);
+    else
+        emit updatePlayerModel("MiniPlayerToolbar-center", "");
+    if(align_list_mini.size() >= 3)
+        emit updatePlayerModel("MiniPlayerToolbar-right", align_list_mini[2]);
+    else
+        emit updatePlayerModel("MiniPlayerToolbar-right", "");
 }
diff --git a/modules/gui/qt/dialogs/toolbar/toolbareditor.hpp b/modules/gui/qt/dialogs/toolbar/toolbareditor.hpp
index 2002b335a2..01d27b0efc 100644
--- a/modules/gui/qt/dialogs/toolbar/toolbareditor.hpp
+++ b/modules/gui/qt/dialogs/toolbar/toolbareditor.hpp
@@ -37,8 +37,6 @@ public:
 public slots:
     Q_INVOKABLE void close();
     Q_INVOKABLE void cancel();
-    Q_INVOKABLE void deleteCursor();
-    Q_INVOKABLE void restoreCursor();
 
 private slots:
     void newProfile();
diff --git a/modules/gui/qt/player/playercontrolbarmodel.cpp b/modules/gui/qt/player/playercontrolbarmodel.cpp
index d38060da49..70cb6425b9 100644
--- a/modules/gui/qt/player/playercontrolbarmodel.cpp
+++ b/modules/gui/qt/player/playercontrolbarmodel.cpp
@@ -20,31 +20,40 @@
 #include "qt.hpp"
 #include "playercontrolbarmodel.hpp"
 
-
-static const PlayerControlBarModel::IconToolButton MAIN_TB_DEFAULT[] = {
-                                                                           {PlayerControlBarModel::LANG_BUTTON},
-                                                                           {PlayerControlBarModel::MENU_BUTTON},
-                                                                           {PlayerControlBarModel::WIDGET_SPACER_EXTEND},
-                                                                           {PlayerControlBarModel::RANDOM_BUTTON},
-                                                                           {PlayerControlBarModel::PREVIOUS_BUTTON},
-                                                                           {PlayerControlBarModel::PLAY_BUTTON},
-                                                                           {PlayerControlBarModel::NEXT_BUTTON},
-                                                                           {PlayerControlBarModel::LOOP_BUTTON},
-                                                                           {PlayerControlBarModel::WIDGET_SPACER_EXTEND},
-                                                                           {PlayerControlBarModel::VOLUME},
-                                                                           {PlayerControlBarModel::FULLSCREEN_BUTTON}
+enum default_align {
+    LEFT = 0,
+    CENTER,
+    RIGHT,
+    SIZE
+};
+
+static const QVector<PlayerControlBarModel::IconToolButton> MAIN_TB_DEFAULT[default_align::SIZE] = {
+                                                                            // left
+                                                                            {{PlayerControlBarModel::LANG_BUTTON},
+                                                                            {PlayerControlBarModel::MENU_BUTTON}},
+                                                                            // center
+                                                                            {{PlayerControlBarModel::RANDOM_BUTTON},
+                                                                            {PlayerControlBarModel::PREVIOUS_BUTTON},
+                                                                            {PlayerControlBarModel::PLAY_BUTTON},
+                                                                            {PlayerControlBarModel::NEXT_BUTTON},
+                                                                            {PlayerControlBarModel::LOOP_BUTTON}},
+                                                                            // right
+                                                                            {{PlayerControlBarModel::VOLUME},
+                                                                            {PlayerControlBarModel::FULLSCREEN_BUTTON}}
                                                                        };
 
-static const PlayerControlBarModel::IconToolButton MINI_TB_DEFAULT[] = {
-                                                                           {PlayerControlBarModel::WIDGET_SPACER_EXTEND},
-                                                                           {PlayerControlBarModel::RANDOM_BUTTON},
+static const QVector<PlayerControlBarModel::IconToolButton> MINI_TB_DEFAULT[default_align::SIZE] = {
+                                                                           // left
+                                                                           {},
+                                                                           // center
+                                                                           {{PlayerControlBarModel::RANDOM_BUTTON},
                                                                            {PlayerControlBarModel::PREVIOUS_BUTTON},
                                                                            {PlayerControlBarModel::PLAY_BUTTON},
                                                                            {PlayerControlBarModel::NEXT_BUTTON},
-                                                                           {PlayerControlBarModel::LOOP_BUTTON},
-                                                                           {PlayerControlBarModel::WIDGET_SPACER_EXTEND},
-                                                                           {PlayerControlBarModel::VOLUME},
-                                                                           {PlayerControlBarModel::PLAYER_SWITCH_BUTTON}
+                                                                           {PlayerControlBarModel::LOOP_BUTTON}},
+                                                                           // right
+                                                                           {{PlayerControlBarModel::VOLUME},
+                                                                           {PlayerControlBarModel::PLAYER_SWITCH_BUTTON}}
                                                                        };
 
 
@@ -72,7 +81,8 @@ void PlayerControlBarModel::reloadConfig(QString config)
 {
     beginResetModel();
     mButtons.clear();
-    parseAndAdd(config);
+    if (!config.isEmpty())
+        parseAndAdd(config);
     endResetModel();
 }
 
@@ -85,19 +95,36 @@ void PlayerControlBarModel::reloadModel()
 
     if (!config.isNull() && config.canConvert<QString>())
         parseAndAdd(config.toString());
-    else if (configName == "MainPlayerToolbar")
-        parseDefault(MAIN_TB_DEFAULT, ARRAY_SIZE(MAIN_TB_DEFAULT));
     else
-        parseDefault(MINI_TB_DEFAULT, ARRAY_SIZE(MINI_TB_DEFAULT));
-    
+    {
+        QString alignment = configName.split("-").at(1);
+        if (configName.startsWith("MainPlayerToolbar"))
+        {
+            if (alignment == "left")
+                parseDefault(MAIN_TB_DEFAULT[default_align::LEFT]);
+            else if (alignment == "center")
+                parseDefault(MAIN_TB_DEFAULT[default_align::CENTER]);
+            else if (alignment == "right")
+                parseDefault(MAIN_TB_DEFAULT[default_align::RIGHT]);
+        }
+        else
+        {
+            if (alignment == "left")
+                parseDefault(MINI_TB_DEFAULT[default_align::LEFT]);
+            else if (alignment == "center")
+                parseDefault(MINI_TB_DEFAULT[default_align::CENTER]);
+            else if (alignment == "right")
+                parseDefault(MINI_TB_DEFAULT[default_align::RIGHT]);
+        }
+    }
     endResetModel();
 }
 
-void PlayerControlBarModel::parseDefault(const PlayerControlBarModel::IconToolButton* config, const size_t config_size)
+void PlayerControlBarModel::parseDefault(const QVector<PlayerControlBarModel::IconToolButton>& config)
 {
-    beginInsertRows(QModelIndex(),rowCount(),rowCount() + config_size);
-    for (size_t i = 0; i < config_size; i++)
-        mButtons.append(config[i]);
+    beginInsertRows(QModelIndex(),rowCount(),rowCount() + config.size());
+    for (const auto& i : config)
+        mButtons.append(i);
     endInsertRows();
 }
 
@@ -107,7 +134,7 @@ void PlayerControlBarModel::parseAndAdd(const QString &config)
 
     for (const QString& iconPropertyTxt : config.split( ";", QString::SkipEmptyParts ) )
     {
-        QStringList list2 = iconPropertyTxt.split( "-" );
+        QStringList list2 = iconPropertyTxt.trimmed().split( "-" );
 
         if( list2.count() < 1 )
         {
@@ -217,6 +244,33 @@ void PlayerControlBarModel::setConfigName(QString name)
     emit configNameChanged(name);
 }
 
+QString PlayerControlBarModel::getSerializedDefaultStyle()
+{
+    QString out;
+
+    auto serialize = [](auto style)
+    {
+          QString _out;
+          for (size_t i = 0; i < default_align::SIZE; i++)
+          {
+              for (const auto& it : style[i])
+              {
+                  _out += QString::number(it.id) + ";";
+              }
+              _out.chop(1);
+              _out += "#";
+          }
+          _out.chop(1);
+          return _out;
+    };
+
+    out += serialize(MAIN_TB_DEFAULT);
+    out += " | ";
+    out += serialize(MINI_TB_DEFAULT);
+
+    return out;
+}
+
 void PlayerControlBarModel::insert(int index, QVariantMap bdata)
 {
     beginInsertRows(QModelIndex(),index,index);
diff --git a/modules/gui/qt/player/playercontrolbarmodel.hpp b/modules/gui/qt/player/playercontrolbarmodel.hpp
index e497ca51e3..0e84a31bcd 100644
--- a/modules/gui/qt/player/playercontrolbarmodel.hpp
+++ b/modules/gui/qt/player/playercontrolbarmodel.hpp
@@ -100,6 +100,8 @@ public:
     inline QString getConfigName() { return configName; }
     void setConfigName(QString name);
 
+    static QString getSerializedDefaultStyle();
+
 signals:
     void ctxChanged(QmlMainContext*);
     void configNameChanged(QString);
@@ -112,7 +114,7 @@ private:
     QString configName;
 
     void parseAndAdd(const QString& config);
-    void parseDefault(const IconToolButton* config, const size_t config_size);
+    void parseDefault(const QVector<IconToolButton>& config);
 
     bool setButtonAt(int index, const IconToolButton &button);
     void addProfiles();
diff --git a/modules/gui/qt/player/qml/ControlBar.qml b/modules/gui/qt/player/qml/ControlBar.qml
index f085b7075d..ec12f97ce2 100644
--- a/modules/gui/qt/player/qml/ControlBar.qml
+++ b/modules/gui/qt/player/qml/ControlBar.qml
@@ -89,31 +89,79 @@ Widgets.NavigableFocusScope {
             parentWindow: mainInterfaceRect
         }
 
+        RowLayout {
+            Layout.fillWidth: true
+            Layout.bottomMargin: VLCStyle.margin_xsmall
 
-        PlayerButtonsLayout {
-            id: buttons
+            PlayerButtonsLayout {
+                id: buttons_left
 
-            model: playerControlBarModel
-            forceColors: true
+                model: playerControlBarModel_left
+                forceColors: true
 
-            Layout.fillHeight: true
-            Layout.fillWidth: true
+                focus: true
 
-            focus: true
+                navigationParent: root
+                navigationUp: function(index) {
+                    if (trackPositionSlider.enabled)
+                        trackPositionSlider.focus = true
+                    else
+                        root.navigationUp(index)
+                }
 
-            navigationParent: root
-            navigationUp: function(index) {
-                if (trackPositionSlider.enabled)
-                    trackPositionSlider.focus = true
-                else
-                    root.navigationUp(index)
+                Keys.priority: Keys.AfterItem
+                Keys.onPressed: defaultKeyAction(event, 0)
             }
 
+            Item {
+                Layout.fillWidth: true
+            }
 
-            Keys.priority: Keys.AfterItem
-            Keys.onPressed: defaultKeyAction(event, 0)
-        }
+            PlayerButtonsLayout {
+                id: buttons_center
+
+                model: playerControlBarModel_center
+                forceColors: true
+
+                focus: true
+
+                navigationParent: root
+                navigationUp: function(index) {
+                    if (trackPositionSlider.enabled)
+                        trackPositionSlider.focus = true
+                    else
+                        root.navigationUp(index)
+                }
+
+
+                Keys.priority: Keys.AfterItem
+                Keys.onPressed: defaultKeyAction(event, 0)
+            }
+
+            Item {
+                Layout.fillWidth: true
+            }
+
+            PlayerButtonsLayout {
+                id: buttons_right
+
+                model: playerControlBarModel_right
+                forceColors: true
+
+                focus: true
 
+                navigationParent: root
+                navigationUp: function(index) {
+                    if (trackPositionSlider.enabled)
+                        trackPositionSlider.focus = true
+                    else
+                        root.navigationUp(index)
+                }
+
+                Keys.priority: Keys.AfterItem
+                Keys.onPressed: defaultKeyAction(event, 0)
+            }
+        }
     }
     Connections{
         target: mainInterface
@@ -121,9 +169,21 @@ Widgets.NavigableFocusScope {
     }
 
     PlayerControlBarModel{
-        id:playerControlBarModel
+        id:playerControlBarModel_left
+        mainCtx: mainctx
+        configName: "MainPlayerToolbar-left"
+    }
+
+    PlayerControlBarModel{
+        id:playerControlBarModel_center
+        mainCtx: mainctx
+        configName: "MainPlayerToolbar-center"
+    }
+
+    PlayerControlBarModel{
+        id:playerControlBarModel_right
         mainCtx: mainctx
-        configName: "MainPlayerToolbar"
+        configName: "MainPlayerToolbar-right"
     }
 
     ControlButtons{
diff --git a/modules/gui/qt/player/qml/MiniPlayer.qml b/modules/gui/qt/player/qml/MiniPlayer.qml
index 368c98c0ef..4610938296 100644
--- a/modules/gui/qt/player/qml/MiniPlayer.qml
+++ b/modules/gui/qt/player/qml/MiniPlayer.qml
@@ -103,135 +103,188 @@ Widgets.NavigableFocusScope {
                 tint: VLCStyle.colors.blendColors(VLCStyle.colors.bg, VLCStyle.colors.banner, 0.85)
             }
 
-            RowLayout {
+            Widgets.FocusBackground {
+                id: playingItemInfo
+
                 anchors {
-                    fill: parent
+                    top: parent.top
+                    bottom: parent.bottom
+                    left: parent.left
 
-                    leftMargin: VLCStyle.applicationHorizontalMargin
-                    rightMargin: VLCStyle.applicationHorizontalMargin
+                    leftMargin: VLCStyle.applicationHorizontalMargin + VLCStyle.margin_normal
                     bottomMargin: VLCStyle.applicationVerticalMargin
                 }
+                width: playingItemInfoRow.width
+                focus: true
 
-                spacing: VLCStyle.margin_normal
-
-                Widgets.FocusBackground {
-                    id: playingItemInfo
-                    Layout.fillHeight: true
-                    Layout.preferredWidth: playingItemInfoRow.implicitWidth
-                    width: childrenRect.width
-                    focus: true
-                    Layout.leftMargin: VLCStyle.margin_normal
+                MouseArea {
+                    anchors.fill: parent
+                    onClicked: history.push(["player"])
+                }
 
-                    MouseArea {
-                        anchors.fill: parent
-                        onClicked: history.push(["player"])
+                Keys.onPressed: {
+                    if (KeyHelper.matchOk(event) ) {
+                        event.accepted = true
                     }
+                }
+                Keys.onReleased: {
+                    if (!event.accepted && KeyHelper.matchOk(event))
+                        history.push(["player"])
+                }
 
-                    Keys.onPressed: {
-                        if (KeyHelper.matchOk(event) ) {
-                            event.accepted = true
-                        }
-                    }
-                    Keys.onReleased: {
-                        if (!event.accepted && KeyHelper.matchOk(event))
-                            history.push(["player"])
-                    }
 
+                Row {
+                    id: playingItemInfoRow
+                    anchors.top: parent.top
+                    anchors.bottom: parent.bottom
+                    anchors.left: parent.left
 
-                    Row {
-                        id: playingItemInfoRow
-                        anchors.top: parent.top
-                        anchors.bottom: parent.bottom
-
-                        Item {
-                            anchors.verticalCenter: parent.verticalCenter
-                            implicitHeight: childrenRect.height
-                            implicitWidth:  childrenRect.width
-
-                            Rectangle {
-                                id: coverRect
-                                anchors.fill: cover
-                                color: VLCStyle.colors.bg
-                            }
-
-                            DropShadow {
-                                anchors.fill: coverRect
-                                source: coverRect
-                                radius: 8
-                                samples: 17
-                                color: VLCStyle.colors.glowColorBanner
-                                spread: 0.2
-                            }
-
-                            Image {
-                                id: cover
-
-                                source: (mainPlaylistController.currentItem.artwork && mainPlaylistController.currentItem.artwork.toString())
-                                        ? mainPlaylistController.currentItem.artwork
-                                        : VLCStyle.noArtAlbum
-                                fillMode: Image.PreserveAspectFit
-
-                                width: VLCStyle.dp(60, VLCStyle.scale)
-                                height: VLCStyle.dp(60, VLCStyle.scale)
-                            }
+                    Item {
+                        anchors.verticalCenter: parent.verticalCenter
+                        implicitHeight: childrenRect.height
+                        implicitWidth:  childrenRect.width
+
+                        Rectangle {
+                            id: coverRect
+                            anchors.fill: cover
+                            color: VLCStyle.colors.bg
                         }
 
-                        Column {
-                            anchors.verticalCenter: parent.verticalCenter
-                            leftPadding: VLCStyle.margin_xsmall
+                        DropShadow {
+                            anchors.fill: coverRect
+                            source: coverRect
+                            radius: 8
+                            samples: 17
+                            color: VLCStyle.colors.glowColorBanner
+                            spread: 0.2
+                        }
 
-                            Widgets.MenuLabel {
-                                id: titleLabel
-                                text: mainPlaylistController.currentItem.title
-                            }
+                        Image {
+                            id: cover
 
-                            Widgets.MenuCaption {
-                                id: artistLabel
-                                text: mainPlaylistController.currentItem.artist
-                            }
+                            source: (mainPlaylistController.currentItem.artwork && mainPlaylistController.currentItem.artwork.toString())
+                                    ? mainPlaylistController.currentItem.artwork
+                                    : VLCStyle.noArtAlbum
+                            fillMode: Image.PreserveAspectFit
 
-                            Widgets.MenuCaption {
-                                id: progressIndicator
-                                text: player.time.toString() + " / " + player.length.toString()
-                            }
+                            width: VLCStyle.dp(60, VLCStyle.scale)
+                            height: VLCStyle.dp(60, VLCStyle.scale)
                         }
                     }
 
-                    KeyNavigation.right: buttonrow
+                    Column {
+                        anchors.verticalCenter: parent.verticalCenter
+                        leftPadding: VLCStyle.margin_xsmall
+
+                        Widgets.MenuLabel {
+                            id: titleLabel
+                            text: mainPlaylistController.currentItem.title
+                        }
+
+                        Widgets.MenuCaption {
+                            id: artistLabel
+                            text: mainPlaylistController.currentItem.artist
+                        }
+
+                        Widgets.MenuCaption {
+                            id: progressIndicator
+                            text: player.time.toString() + " / " + player.length.toString()
+                        }
+                    }
                 }
 
-                Item {
-                    Layout.fillWidth: true
+                KeyNavigation.right: buttonrow_left
+            }
+
+
+            RowLayout {
+                anchors {
+                    top: parent.top
+                    bottom: parent.bottom
+                    left: playingItemInfo.right
+                    right: parent.right
+
+                    leftMargin: VLCStyle.applicationHorizontalMargin
+                    rightMargin: VLCStyle.applicationHorizontalMargin
+                    bottomMargin: VLCStyle.applicationVerticalMargin
                 }
 
+                spacing: VLCStyle.margin_large
+
                 PlayerButtonsLayout {
-                    id: buttonrow
+                    id: buttonrow_left
 
-                    model: miniPlayerModel
+                    model: miniPlayerModel_left
                     defaultSize: VLCStyle.icon_normal
 
-                    Layout.alignment: Qt.AlignVCenter
-                    Layout.fillWidth: true
+                    Layout.alignment: Qt.AlignLeft
                     Layout.preferredHeight: buttonrow.implicitHeight
                     Layout.leftMargin: VLCStyle.margin_normal
                     Layout.rightMargin: VLCStyle.margin_normal
 
                     navigationParent: root
                     navigationLeftItem: playingItemInfo
+                    navigationRightItem: buttonrow_center
+                }
+
+                PlayerButtonsLayout {
+                    id: buttonrow_center
+
+                    model: miniPlayerModel_center
+                    defaultSize: VLCStyle.icon_normal
+
+                    Layout.alignment: Qt.AlignHCenter
+                    Layout.preferredHeight: buttonrow.implicitHeight
+                    Layout.leftMargin: VLCStyle.margin_normal
+                    Layout.rightMargin: VLCStyle.margin_normal
+
+                    navigationParent: root
+                    navigationLeftItem: buttonrow_left
+                    navigationRightItem: buttonrow_center
+                }
+
+                PlayerButtonsLayout {
+                    id: buttonrow_right
+
+                    model: miniPlayerModel_right
+                    defaultSize: VLCStyle.icon_normal
+
+                    Layout.alignment: Qt.AlignRight
+                    Layout.preferredHeight: buttonrow.implicitHeight
+                    Layout.leftMargin: VLCStyle.margin_normal
+                    Layout.rightMargin: VLCStyle.margin_normal
+
+                    navigationParent: root
+                    navigationLeftItem: buttonrow_center
                 }
             }
 
+
             Connections{
                 target: mainInterface
                 onToolBarConfUpdated: {
-                    miniPlayerModel.reloadModel()
+                    miniPlayerModel_left.reloadModel()
+                    miniPlayerModel_center.reloadModel()
+                    miniPlayerModel_right.reloadModel()
                 }
             }
 
             PlayerControlBarModel {
-                id: miniPlayerModel
+                id: miniPlayerModel_left
+                mainCtx: mainctx
+                configName: "MiniPlayerToolbar-left"
+            }
+
+            PlayerControlBarModel {
+                id: miniPlayerModel_center
+                mainCtx: mainctx
+                configName: "MiniPlayerToolbar-center"
+            }
+
+            PlayerControlBarModel {
+                id: miniPlayerModel_right
                 mainCtx: mainctx
-                configName: "MiniPlayerToolbar"
+                configName: "MiniPlayerToolbar-right"
             }
 
             ControlButtons {
-- 
2.25.1



More information about the vlc-devel mailing list