[vlc-commits] qml: add playback speed control widget

Prince Gupta git at videolan.org
Tue Apr 6 13:12:08 UTC 2021


vlc | branch: master | Prince Gupta <guptaprince8832 at gmail.com> | Tue Mar  9 19:30:04 2021 +0530| [3030082915ae67155da12f331fff1fec77b48422] | committer: Pierre Lamot

qml: add playback speed control widget

fixes #22268

Signed-off-by: Pierre Lamot <pierre at videolabs.io>

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=3030082915ae67155da12f331fff1fec77b48422
---

 modules/gui/qt/Makefile.am                   |   1 +
 modules/gui/qt/player/control_list_model.hpp |   1 +
 modules/gui/qt/player/qml/ControlButtons.qml |  74 +++++++++++-
 modules/gui/qt/player/qml/PlaybackSpeed.qml  | 173 +++++++++++++++++++++++++++
 modules/gui/qt/vlc.qrc                       |   1 +
 5 files changed, 247 insertions(+), 3 deletions(-)

diff --git a/modules/gui/qt/Makefile.am b/modules/gui/qt/Makefile.am
index 969a6c0035..ca5509a76b 100644
--- a/modules/gui/qt/Makefile.am
+++ b/modules/gui/qt/Makefile.am
@@ -709,6 +709,7 @@ libqt_plugin_la_QML = \
 	gui/qt/player/qml/ControlBar.qml \
 	gui/qt/player/qml/ControlButtons.qml \
 	gui/qt/player/qml/LanguageMenu.qml \
+	gui/qt/player/qml/PlaybackSpeed.qml \
 	gui/qt/player/qml/MiniPlayer.qml \
 	gui/qt/player/qml/PIPPlayer.qml \
 	gui/qt/player/qml/Player.qml \
diff --git a/modules/gui/qt/player/control_list_model.hpp b/modules/gui/qt/player/control_list_model.hpp
index 34d2f1aebe..c25701f9d2 100644
--- a/modules/gui/qt/player/control_list_model.hpp
+++ b/modules/gui/qt/player/control_list_model.hpp
@@ -64,6 +64,7 @@ public:
         BUTTON_MAX,
         PLAYER_SWITCH_BUTTON,
         ARTWORK_INFO,
+        PLAYBACK_SPEED_BUTTON,
 
         SPLITTER = 0x20,
         VOLUME,
diff --git a/modules/gui/qt/player/qml/ControlButtons.qml b/modules/gui/qt/player/qml/ControlButtons.qml
index 10aa86b3c5..0eeb88a00b 100644
--- a/modules/gui/qt/player/qml/ControlButtons.qml
+++ b/modules/gui/qt/player/qml/ControlButtons.qml
@@ -26,6 +26,7 @@ import org.videolan.vlc 0.1
 import "qrc:///widgets/" as Widgets
 import "qrc:///style/"
 import "qrc:///util/KeyHelper.js" as KeyHelper
+import "qrc:///util/Helpers.js" as Helpers
 
 Item{
     id: controlButtons
@@ -66,7 +67,8 @@ Item{
         { id:  ControlListModel.WIDGET_SPACER, label: VLCIcons.space, text: i18n.qtr("Spacer")},
         { id:  ControlListModel.WIDGET_SPACER_EXTEND, label: VLCIcons.space, text: i18n.qtr("Expanding Spacer")},
         { id:  ControlListModel.PLAYER_SWITCH_BUTTON, label: VLCIcons.fullscreen, text: i18n.qtr("Switch Player")},
-        { id:  ControlListModel.ARTWORK_INFO, label: VLCIcons.info, text: i18n.qtr("Artwork Info")}
+        { id:  ControlListModel.ARTWORK_INFO, label: VLCIcons.info, text: i18n.qtr("Artwork Info")},
+        { id:  ControlListModel.PLAYBACK_SPEED_BUTTON, label: "1x", text: i18n.qtr("Playback Speed")}
     ]
 
     function returnbuttondelegate(inpID){
@@ -103,6 +105,7 @@ Item{
         case ControlListModel.TELETEXT_BUTTONS: return teletextdelegate
         case ControlListModel.PLAYER_SWITCH_BUTTON: return playerSwitchBtnDelegate
         case ControlListModel.ARTWORK_INFO: return artworkInfoDelegate
+        case ControlListModel.PLAYBACK_SPEED_BUTTON: return playbackSpeedButtonDelegate
         }
         console.log("button delegate id " + inpID +  " doesn't exists")
         return spacerDelegate
@@ -882,8 +885,8 @@ Item{
                         text: i18n.qtr("%1\n%2").arg(titleLabel.text).arg(artistLabel.text)
                         visible: (titleLabel.implicitWidth > titleLabel.width || artistLabel.implicitWidth > titleLabel.width)
                                  && (artworkInfoMouseArea.containsMouse || artworkInfoItem.active)
-                        delay: 500 
-                         
+                        delay: 500
+
                         contentItem: Text {
                                   text: i18n.qtr("%1\n%2").arg(titleLabel.text).arg(artistLabel.text)
                                   color: colors.tooltipTextColor
@@ -939,4 +942,69 @@ Item{
             }
         }
     }
+
+    Component {
+        id: playbackSpeedButtonDelegate
+
+        Widgets.IconControlButton {
+            id: playbackSpeedButton
+
+            size: VLCStyle.icon_medium
+            text: i18n.qtr("Playback Speed")
+            color: playbackSpeedPopup.visible ? colors.accent : colors.playerControlBarFg
+
+            onClicked: playbackSpeedPopup.open()
+
+            PlaybackSpeed {
+                id: playbackSpeedPopup
+
+                z: 1
+                colors: playbackSpeedButton.colors
+                focus: true
+                parent: playbackSpeedButton.paintOnly
+                        ? playbackSpeedButton // button is not part of main display (ToolbarEditorDialog)
+                        : (history.current.view === "player") ? rootPlayer : g_mainDisplay
+
+                onOpened: {
+                    // update popup coordinates
+                    //
+                    // mapFromItem is affected by various properties of source and target objects
+                    // which can't be represented in a binding expression so a initial setting in
+                    // object defination (x: clamp(...)) doesn't work, so we set x and y on initial open
+                    x = Qt.binding(function () {
+                        // coords are mapped through playbackSpeedButton.parent so that binding is generated based on playbackSpeedButton.x
+                        var mappedParentCoordinates = parent.mapFromItem(playbackSpeedButton.parent, playbackSpeedButton.x, 0)
+                        return Helpers.clamp(mappedParentCoordinates.x  - ((width - playbackSpeedButton.width) / 2),
+                                             VLCStyle.margin_xxsmall + VLCStyle.applicationHorizontalMargin,
+                                             parent.width - VLCStyle.applicationHorizontalMargin - VLCStyle.margin_xxsmall - width)
+                    })
+
+                    y = Qt.binding(function () {
+                        // coords are mapped through playbackSpeedButton.parent so that binding is generated based on playbackSpeedButton.y
+                        var mappedParentCoordinates = parent.mapFromItem(playbackSpeedButton.parent, 0, playbackSpeedButton.y)
+                        return mappedParentCoordinates.y - playbackSpeedPopup.height - VLCStyle.margin_xxsmall
+                    })
+
+                    // player related --
+                    controlButtons.requestLockUnlockAutoHide(true, controlButtons)
+                    if (!!rootPlayer)
+                        rootPlayer.menu = playbackSpeedPopup
+                }
+
+                onClosed: {
+                    controlButtons.requestLockUnlockAutoHide(false, controlButtons)
+                    playbackSpeedButton.forceActiveFocus()
+                    if (!!rootPlayer)
+                        rootPlayer.menu = undefined
+                }
+            }
+
+            Label {
+                anchors.centerIn: parent
+                font.pixelSize: VLCStyle.fontSize_normal
+                text: !playbackSpeedButton.paintOnly ? i18n.qtr("%1x").arg(+player.rate.toFixed(2)) : i18n.qtr("1x")
+                color: playbackSpeedButton.background.foregroundColor // IconToolButton.background is a FocusBackground
+            }
+        }
+    }
 }
diff --git a/modules/gui/qt/player/qml/PlaybackSpeed.qml b/modules/gui/qt/player/qml/PlaybackSpeed.qml
new file mode 100644
index 0000000000..2e1cb8d42e
--- /dev/null
+++ b/modules/gui/qt/player/qml/PlaybackSpeed.qml
@@ -0,0 +1,173 @@
+/*****************************************************************************
+ * Copyright (C) 2021 VLC authors and VideoLAN
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU 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.
+ *****************************************************************************/
+
+import QtQuick 2.11
+import QtQuick.Controls 2.4
+import QtQuick.Layouts 1.3
+
+import org.videolan.vlc 0.1
+
+import "qrc:///style/"
+import "qrc:///widgets/" as Widgets
+
+Popup {
+    id: root
+
+    property VLCColors colors: VLCStyle.nightColors
+
+    height: implicitHeight
+    width: implicitWidth
+    padding: VLCStyle.margin_small
+
+    // Popup.CloseOnPressOutside doesn't work with non-model Popup on Qt < 5.15
+    closePolicy: Popup.CloseOnPressOutside | Popup.CloseOnEscape
+    modal: true
+    Overlay.modal: Rectangle {
+       color: "transparent"
+    }
+
+    background: Rectangle {
+        color: colors.bg
+        opacity: .85
+    }
+
+    contentItem: ColumnLayout {
+        spacing: VLCStyle.margin_xsmall
+
+        Widgets.ListLabel {
+            text: i18n.qtr("Playback Speed")
+            color: root.colors.text
+            font.pixelSize: VLCStyle.fontSize_large
+
+            Layout.fillWidth: true
+            Layout.bottomMargin: VLCStyle.margin_xsmall
+        }
+
+        Slider {
+            id: speedSlider
+
+            property bool _inhibitUpdate: false
+
+            from: 0.25
+            to: 4
+            clip: true
+            implicitHeight: VLCStyle.heightBar_small
+            KeyNavigation.down: slowerButton
+
+            background: Rectangle {
+                x: speedSlider.leftPadding
+                y: speedSlider.topPadding + speedSlider.availableHeight / 2 - height / 2
+                implicitWidth: 200
+                implicitHeight: 4
+                width: speedSlider.availableWidth
+                height: implicitHeight
+                radius: 2
+                color: root.colors.bgAlt
+
+                Rectangle {
+                    width: speedSlider.visualPosition * parent.width
+                    height: parent.height
+                    radius: 2
+                    color: (speedSlider.activeFocus || speedSlider.pressed)
+                           ? root.colors.accent
+                           : root.colors.text
+                }
+            }
+
+            handle: Rectangle {
+                x: speedSlider.leftPadding + speedSlider.visualPosition * (speedSlider.availableWidth - width)
+                y: speedSlider.topPadding + speedSlider.availableHeight / 2 - height / 2
+                width: speedSlider.implicitHeight
+                height: speedSlider.implicitHeight
+                radius: speedSlider.implicitHeight
+                color: (speedSlider.activeFocus || speedSlider.pressed) ? root.colors.accent : root.colors.text
+            }
+
+            onValueChanged:  {
+                if (_inhibitUpdate)
+                    return
+                player.rate = value
+            }
+
+            function _updateFromPlayer() {
+                _inhibitUpdate = true
+                value = player.rate
+                _inhibitUpdate = false
+            }
+
+            Connections {
+                target: player
+                onRateChanged: speedSlider._updateFromPlayer()
+            }
+
+            Layout.fillWidth: true
+
+            Component.onCompleted: speedSlider._updateFromPlayer()
+        }
+
+        RowLayout {
+            spacing: 0
+            KeyNavigation.up: speedSlider
+
+            Widgets.IconControlButton {
+                id: slowerButton
+
+                iconText: VLCIcons.slower
+                colors: root.colors
+                KeyNavigation.right: resetButton
+
+                onClicked: speedSlider.decrease()
+            }
+
+            Item {
+                Layout.fillWidth: true
+            }
+
+            Widgets.IconControlButton {
+                id: resetButton
+
+                colors: root.colors
+                KeyNavigation.left: slowerButton
+                KeyNavigation.right: fasterButton
+
+                onClicked: speedSlider.value = 1.0
+
+                Label {
+                    anchors.centerIn: parent
+                    font.pixelSize: VLCStyle.fontSize_normal
+                    text: i18n.qtr("1x")
+                    color: resetButton.background.foregroundColor // IconToolButton.background is a FocusBackground
+                }
+            }
+
+            Item {
+                Layout.fillWidth: true
+            }
+
+            Widgets.IconControlButton {
+                id: fasterButton
+
+                iconText: VLCIcons.faster
+                colors: root.colors
+                KeyNavigation.left: resetButton
+
+                onClicked: speedSlider.increase()
+            }
+        }
+    }
+}
diff --git a/modules/gui/qt/vlc.qrc b/modules/gui/qt/vlc.qrc
index 5cc9022d39..b2458b6e08 100644
--- a/modules/gui/qt/vlc.qrc
+++ b/modules/gui/qt/vlc.qrc
@@ -332,6 +332,7 @@
         <file alias="PlayerMenuItem.qml">player/qml/PlayerMenuItem.qml</file>
         <file alias="LanguageMenu.qml">player/qml/LanguageMenu.qml</file>
         <file alias="ButtonsLayout.qml">player/qml/ButtonsLayout.qml</file>
+        <file alias="PlaybackSpeed.qml">player/qml/PlaybackSpeed.qml</file>
     </qresource>
     <qresource prefix="/about">
         <file alias="About.qml">dialogs/help/qml/About.qml</file>



More information about the vlc-commits mailing list