[vlc-devel] [PATCH 11/21] qml: new view for language selection in player

Prince Gupta guptaprince8832 at gmail.com
Fri Oct 23 15:21:05 CEST 2020


---
 modules/gui/qt/Makefile.am                   |   1 +
 modules/gui/qt/player/qml/ControlButtons.qml |  84 +--
 modules/gui/qt/player/qml/LanguageMenu.qml   | 710 +++++++++++++++++++
 modules/gui/qt/vlc.qrc                       |   1 +
 4 files changed, 719 insertions(+), 77 deletions(-)
 create mode 100644 modules/gui/qt/player/qml/LanguageMenu.qml

diff --git a/modules/gui/qt/Makefile.am b/modules/gui/qt/Makefile.am
index b3d7f4c94f..b3d8193749 100644
--- a/modules/gui/qt/Makefile.am
+++ b/modules/gui/qt/Makefile.am
@@ -650,6 +650,7 @@ libqt_plugin_la_QML = \
 	gui/qt/network/qml/ServicesHomeDisplay.qml \
 	gui/qt/player/qml/ControlBar.qml \
 	gui/qt/player/qml/ControlButtons.qml \
+	gui/qt/player/qml/LanguageMenu.qml \
 	gui/qt/player/qml/MiniPlayer.qml \
 	gui/qt/player/qml/Player.qml \
 	gui/qt/player/qml/PlayerButtonsLayout.qml \
diff --git a/modules/gui/qt/player/qml/ControlButtons.qml b/modules/gui/qt/player/qml/ControlButtons.qml
index 7182e73822..46e81dc809 100644
--- a/modules/gui/qt/player/qml/ControlButtons.qml
+++ b/modules/gui/qt/player/qml/ControlButtons.qml
@@ -411,92 +411,22 @@ Item{
 
             text: i18n.qtr("Languages and tracks")
 
-            PlayerMenu {
+            LanguageMenu {
                 id: langMenu
+
                 parent: rootPlayer
+                focus: true
+                x: 0
+                y: rootPlayer.positionSliderY - height
+                z: 1
+
                 onOpened: rootPlayer._menu = langMenu
                 onMenuClosed: {
                     root._lockAutoHide -= 1
                     langBtn.forceActiveFocus()
                     rootPlayer._menu = undefined
                 }
-                focus: true
-
-                title: i18n.qtr("Languages and Tracks")
-
-
-                Connections {
-                    target: player
-                    onInputChanged: {
-                        subtrackMenu.dismiss()
-                        audiotrackMenu.dismiss()
-                        videotrackMenu.dismiss()
-                        langMenu.dismiss()
-                    }
-                }
-
-                PlayerMenu {
-                    id: subtrackMenu
-                    onOpened: rootPlayer._menu = subtrackMenu
-                    parentMenu: langMenu
-                    title: i18n.qtr("Subtitle Track")
-                    enabled: player.isPlaying && player.subtitleTracks.count > 0
-                    Repeater {
-                        model: player.subtitleTracks
-                        PlayerMenuItem {
-                            parentMenu:  subtrackMenu
-                            text: model.display
-                            checkable: true
-                            checked: model.checked
-                            onTriggered: model.checked = !model.checked
-                        }
-                    }
-                    onMenuClosed: langMenu.menuClosed()
-                }
-
-                PlayerMenu {
-                    id: audiotrackMenu
-                    title: i18n.qtr("Audio Track")
-
-                    parentMenu: langMenu
-                    onOpened: rootPlayer._menu = audiotrackMenu
-
-                    enabled: player.isPlaying && player.audioTracks.count > 0
-                    Repeater {
-                        model: player.audioTracks
-                        PlayerMenuItem {
-                            parentMenu: audiotrackMenu
-
-                            text: model.display
-                            checkable: true
-                            checked: model.checked
-                            onTriggered: model.checked = !model.checked
-                        }
-                    }
-                    onMenuClosed: langMenu.menuClosed()
-                }
-
-                PlayerMenu {
-                    id: videotrackMenu
-                    title: i18n.qtr("Video Track")
-                    parentMenu: langMenu
-                    onOpened: rootPlayer._menu = videotrackMenu
-                    enabled: player.isPlaying && player.videoTracks.count > 0
-                    Repeater {
-                        model: player.videoTracks
-                        PlayerMenuItem {
-                            parentMenu: videotrackMenu
-                            text: model.display
-                            checkable: true
-                            checked: model.checked
-                            onTriggered: model.checked = !model.checked
-                        }
-                    }
-                    onMenuClosed: langMenu.menuClosed()
-                }
             }
-
-            property bool acceptFocus: true
         }
     }
 
diff --git a/modules/gui/qt/player/qml/LanguageMenu.qml b/modules/gui/qt/player/qml/LanguageMenu.qml
new file mode 100644
index 0000000000..8181b0c199
--- /dev/null
+++ b/modules/gui/qt/player/qml/LanguageMenu.qml
@@ -0,0 +1,710 @@
+
+/*****************************************************************************
+ * Copyright (C) 2020 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.Templates 2.4 as T
+import QtQuick.Layouts 1.3
+import QtQml.Models 2.11
+
+import org.videolan.vlc 0.1
+
+import "qrc:///style/"
+import "qrc:///widgets/" as Widgets
+import "qrc:///util/" as Util
+import "qrc:///util/KeyHelper.js" as KeyHelper
+
+T.Menu {
+    id: control
+
+    property var parentMenu: undefined
+    property bool _emitMenuClose: true
+    signal menuClosed
+
+    modal: true
+    cascade: false
+    closePolicy: Popup.CloseOnPressOutside | Popup.CloseOnEscape
+    height: VLCStyle.dp(296, VLCStyle.scale)
+    width: rootPlayer.width
+
+    onOpened: {
+        control._emitMenuClose = true
+
+        for (var i = 0; i < control.count; i++) {
+            if (control.itemAt(i).enabled) {
+                control.currentIndex = i
+                break
+            }
+        }
+    }
+
+    onClosed: {
+        if (control._emitMenuClose) {
+            menuClosed()
+        }
+    }
+
+    contentItem: StackView {
+        id: view
+
+        initialItem: frontPage
+        clip: true
+        focus: true
+
+        onCurrentItemChanged: currentItem.forceActiveFocus()
+
+        pushEnter: Transition {
+            PropertyAnimation {
+                property: "opacity"
+                from: 0
+                to: 1
+                duration: 200
+            }
+        }
+        pushExit: Transition {
+            PropertyAnimation {
+                property: "opacity"
+                from: 1
+                to: 0
+                duration: 200
+            }
+        }
+        popEnter: Transition {
+            PropertyAnimation {
+                property: "opacity"
+                from: 0
+                to: 1
+                duration: 200
+            }
+        }
+        popExit: Transition {
+            PropertyAnimation {
+                property: "opacity"
+                from: 1
+                to: 0
+                duration: 200
+            }
+        }
+    }
+
+    background: Rectangle {
+        color: "#212121"
+        opacity: .8
+    }
+
+    T.Overlay.modal: Rectangle {
+        color: "transparent"
+    }
+
+    function _updateWidth(isFirstPage) {
+        if (isFirstPage)
+            control.width = Qt.binding(function () {
+                return rootPlayer.width
+            })
+        else
+            control.width = Qt.binding(function () {
+                return Math.min(VLCStyle.dp(624, VLCStyle.scale),
+                                rootPlayer.width)
+            })
+    }
+
+    Behavior on width {
+        SmoothedAnimation {
+            duration: 64
+            easing.type: Easing.InOutSine
+        }
+    }
+
+    Component {
+        id: frontPage
+
+        RowLayout {
+            id: frontPageRoot
+
+            spacing: 0
+            focus: true
+            onActiveFocusChanged: if (activeFocus)
+                                      btnsCol.forceActiveFocus()
+
+            Widgets.NavigableCol {
+                id: btnsCol
+
+                focus: true
+                Layout.preferredWidth: VLCStyle.dp(72, VLCStyle.scale)
+                Layout.alignment: Qt.AlignTop | Qt.AlignLeft
+                Layout.topMargin: VLCStyle.margin_large
+                navigationRightItem: tracksListRow
+
+                model: [{
+                        "icon": VLCIcons.download,
+                        "tooltip": i18n.qtr("Download Subtitles"),
+                        "component": undefined
+                    }, {
+                        "icon": VLCIcons.time,
+                        "tooltip": i18n.qtr("Delay"),
+                        "component": delayPage
+                    }, {
+                        "icon": VLCIcons.sync,
+                        "tooltip": i18n.qtr("Sync"),
+                        "component": syncPage
+                    }, {
+                        "icon": VLCIcons.multiselect,
+                        "tooltip": i18n.qtr("Select Multiple Subtitles"),
+                        "component": undefined
+                    }]
+
+                delegate: Widgets.IconToolButton {
+                    id: btn
+
+                    iconText: modelData.icon
+                    color: "white"
+                    size: VLCStyle.dp(40, VLCStyle.scale)
+                    x: (btnsCol.width - width) / 2
+                    highlighted: index === 3
+                                 && player.subtitleTracks.multiSelect
+
+                    ToolTip.visible: btn.hovered || btn.activeFocus
+                    ToolTip.text: modelData.tooltip
+                    ToolTip.delay: 1000
+                    ToolTip.toolTip.z: 2
+
+                    onClicked: {
+                        if (index === 0) {
+                            player.openVLsub()
+                        } else if (index === 3) {
+                            player.subtitleTracks.multiSelect = !player.subtitleTracks.multiSelect
+                            focus = false
+                        } else {
+                            control._updateWidth(false)
+                            frontPageRoot.StackView.view.push(
+                                        modelData.component)
+                        }
+                    }
+                }
+            }
+
+            Widgets.NavigableRow {
+                id: tracksListRow
+
+                navigationLeftItem: btnsCol
+                Layout.fillHeight: true
+                Layout.fillWidth: true
+
+                model: [{
+                        "title": i18n.qtr("Subtitle"),
+                        "tracksModel": player.subtitleTracks
+                    }, {
+                        "title": i18n.qtr("Audio"),
+                        "tracksModel": player.audioTracks
+                    }, {
+                        "title": i18n.qtr("Video Tracks"),
+                        "tracksModel": player.videoTracks
+                    }]
+
+                delegate: Column {
+                    id: tracksListContainer
+
+                    property var tracksModel: modelData.tracksModel
+
+                    width: tracksListRow.width / 3
+                    height: tracksListRow.height
+                    focus: true
+
+                    onActiveFocusChanged: if (activeFocus)
+                                              tracksList.forceActiveFocus()
+
+                    Item {
+                        // keep it inside so "Column" doesn't mess with it
+                       Rectangle {
+                           id: separator
+
+                           x: 0
+                           y: 0
+                           width: VLCStyle.dp(2, VLCStyle.scale)
+
+                           height: tracksListContainer.height
+                           color: "white"
+                           opacity: .1
+                       }
+                    }
+
+                    Row {
+                        id: titleHeader
+
+                        width: tracksListContainer.width
+                        height: implicitHeight
+                        focus: true
+
+                        topPadding: VLCStyle.margin_large
+                        leftPadding: VLCStyle.margin_xxlarge + separator.width
+                        padding: VLCStyle.margin_xsmall
+                        clip: true
+
+                        Widgets.SubtitleLabel {
+                            id: titleText
+
+                            text: modelData.title
+                            color: "white"
+                            width: parent.width - addBtn.width
+                                   - parent.leftPadding - parent.rightPadding
+                        }
+
+                        Widgets.IconToolButton {
+                            id: addBtn
+
+                            iconText: VLCIcons.add
+                            size: VLCStyle.icon_normal
+                            color: "white"
+                            focus: true
+                            onClicked: {
+                                switch (index) {
+                                case 0:
+                                    dialogProvider.loadSubtitlesFile()
+                                    break
+                                case 1:
+                                    dialogProvider.loadAudioFile()
+                                    break
+                                case 2:
+                                    dialogProvider.loadVideoFile()
+                                    break
+                                }
+                            }
+
+                            KeyNavigation.down: tracksList
+                        }
+                    }
+
+                    ListView {
+                        id: tracksList
+
+                        model: tracksListContainer.tracksModel
+                        width: tracksListContainer.width
+                        height: tracksListContainer.height - titleHeader.height
+                        leftMargin: separator.width
+                        focus: true
+                        clip: true
+
+                        delegate: Widgets.CheckedDelegate {
+                            readonly property bool isModelChecked: model.checked
+                            clip: true
+
+                            focus: true
+                            text: model.display
+                            width: tracksListContainer.width
+                            height: VLCStyle.dp(40, VLCStyle.scale)
+                            opacity: hovered || activeFocus || checked ? 1 : .6
+                            font.weight: hovered
+                                         || activeFocus ? Font.DemiBold : Font.Normal
+
+                            onIsModelCheckedChanged: {
+                                if (model.checked !== checked)
+                                    checked = model.checked
+                            }
+
+                            onCheckedChanged: {
+                                if (model.checked !== checked)
+                                    model.checked = checked
+                            }
+                        }
+
+                        KeyNavigation.up: addBtn
+                    }
+                }
+            }
+        }
+    }
+
+    Component {
+        id: delayPage
+
+        RowLayout {
+            id: delayPageRoot
+
+            spacing: 0
+            focus: true
+            onActiveFocusChanged: if (activeFocus)
+                                      backBtn.forceActiveFocus()
+
+            Item {
+                Layout.alignment: Qt.AlignLeft | Qt.AlignTop
+                Layout.preferredWidth: VLCStyle.dp(72, VLCStyle.scale)
+                Layout.topMargin: VLCStyle.margin_large
+                Layout.fillHeight: true
+
+                Widgets.IconToolButton {
+                    id: backBtn
+
+                    anchors.horizontalCenter: parent.horizontalCenter
+                    size: VLCStyle.dp(36, VLCStyle.scale)
+                    iconText: VLCIcons.back
+                    color: "white"
+
+                    onClicked: {
+                        control._updateWidth(true)
+                        delayPageRoot.StackView.view.pop()
+                    }
+                    KeyNavigation.right: audioDelaySpin
+                }
+            }
+
+            Rectangle {
+                Layout.preferredWidth: VLCStyle.dp(2, VLCStyle.scale)
+                Layout.fillHeight: true
+                color: "white"
+                opacity: .1
+            }
+
+            ColumnLayout {
+                Layout.fillWidth: true
+                Layout.fillHeight: true
+                Layout.alignment: Qt.AlignLeft | Qt.AlignTop
+                Layout.leftMargin: VLCStyle.margin_xxlarge
+                Layout.rightMargin: VLCStyle.margin_xxlarge
+                Layout.topMargin: VLCStyle.margin_large
+                spacing: VLCStyle.margin_xxsmall
+
+                KeyNavigation.left: backBtn
+
+                Widgets.SubtitleLabel {
+                    Layout.fillWidth: true
+                    text: i18n.qtr("Audio track synchronization")
+                }
+                RowLayout {
+                    Layout.fillWidth: true
+                    spacing: VLCStyle.margin_xsmall
+
+                    Widgets.MenuCaption {
+                        text: i18n.qtr("Audio track delay")
+                        color: "white"
+
+                        Layout.fillWidth: true
+                        Layout.alignment: Qt.AlignHCenter
+                    }
+
+                    Widgets.TransparentSpinBox {
+                        id: audioDelaySpin
+
+                        property bool inhibitUpdate: true
+
+                        padding: VLCStyle.margin_xxxsmall
+                        textFromValue: function (value, locale) {
+                            return i18n.qtr("%1 ms").arg(
+                                        Number(value).toLocaleString(locale,
+                                                                     'f', 0))
+                        }
+                        valueFromText: function (text, locale) {
+                            return Number.fromLocaleString(
+                                        locale, text.substring(0,
+                                                               text.length - 3))
+                        }
+                        stepSize: 50
+                        from: -10000
+
+                        Layout.preferredWidth: VLCStyle.dp(128, VLCStyle.scale)
+                        Layout.preferredHeight: VLCStyle.dp(27, VLCStyle.scale)
+
+                        onValueChanged: {
+                            if (inhibitUpdate)
+                                return
+                            player.audioDelayMS = value
+                        }
+
+                        Component.onCompleted: {
+                            value = player.audioDelayMS
+                            inhibitUpdate = false
+                        }
+
+                        Connections {
+                            target: player
+                            onAudioDelayChanged: {
+                                inhibitUpdate = true
+                                value = player.audioDelayMS
+                                inhibitUpdate = false
+                            }
+                        }
+
+                        KeyNavigation.right: audioDelaySpinReset
+                    }
+
+                    Widgets.TabButtonExt {
+                        id: audioDelaySpinReset
+
+                        text: i18n.qtr("Reset")
+                        color: "white"
+
+                        onClicked: audioDelaySpin.value = 0
+                        KeyNavigation.left: audioDelaySpin
+                        KeyNavigation.right: primarySubSpin
+                        KeyNavigation.down: primarySubSpinReset
+                    }
+                }
+
+                Widgets.SubtitleLabel {
+                    Layout.fillWidth: true
+                    Layout.topMargin: VLCStyle.margin_large
+                    text: i18n.qtr("Subtitle synchronization")
+                }
+
+                RowLayout {
+                    Layout.fillWidth: true
+                    spacing: VLCStyle.margin_xsmall
+
+                    Widgets.MenuCaption {
+                        text: i18n.qtr("Primary subtitle delay")
+                        color: "white"
+                        Layout.fillWidth: true
+                        Layout.alignment: Qt.AlignHCenter
+                    }
+
+                    Widgets.TransparentSpinBox {
+                        id: primarySubSpin
+
+                        property bool inhibitUpdate: true
+
+                        padding: VLCStyle.margin_xxxsmall
+                        textFromValue: audioDelaySpin.textFromValue
+                        valueFromText: audioDelaySpin.valueFromText
+                        stepSize: 50
+                        from: -10000
+
+                        Layout.preferredWidth: VLCStyle.dp(128, VLCStyle.scale)
+                        Layout.preferredHeight: VLCStyle.dp(27, VLCStyle.scale)
+
+                        onValueChanged: {
+                            if (inhibitUpdate)
+                                return
+                            player.subtitleDelayMS = value
+                        }
+
+                        Component.onCompleted: {
+                            value = player.subtitleDelayMS
+                            inhibitUpdate = false
+                        }
+
+                        Connections {
+                            target: player
+                            onSubtitleDelayChanged: {
+                                inhibitUpdate = true
+                                value = player.subtitleDelayMS
+                                inhibitUpdate = false
+                            }
+                        }
+
+                        KeyNavigation.right: primarySubSpinReset
+                    }
+
+                    Widgets.TabButtonExt {
+                        id: primarySubSpinReset
+
+                        text: i18n.qtr("Reset")
+                        color: "white"
+                        focus: true
+                        onClicked: primarySubSpin.value = 0
+                        KeyNavigation.left: primarySubSpin
+                        KeyNavigation.right: secondarySubSpin
+                        KeyNavigation.up: audioDelaySpinReset
+                        KeyNavigation.down: secondarySubSpinReset
+                    }
+                }
+
+                RowLayout {
+                    Layout.fillWidth: true
+                    spacing: VLCStyle.margin_xsmall
+
+                    Widgets.MenuCaption {
+                        text: i18n.qtr("Secondary subtitle delay")
+                        color: "white"
+                        Layout.fillWidth: true
+                        Layout.alignment: Qt.AlignHCenter
+                    }
+
+                    Widgets.TransparentSpinBox {
+                        id: secondarySubSpin
+
+                        property bool inhibitUpdate: true
+
+                        padding: VLCStyle.margin_xxxsmall
+                        textFromValue: primarySubSpin.textFromValue
+                        valueFromText: primarySubSpin.valueFromText
+                        stepSize: 50
+                        from: -10000
+
+                        Layout.preferredWidth: VLCStyle.dp(128, VLCStyle.scale)
+                        Layout.preferredHeight: VLCStyle.dp(27, VLCStyle.scale)
+
+                        onValueChanged: {
+                            if (inhibitUpdate)
+                                return
+                            player.secondarySubtitleDelayMS = value
+                        }
+
+                        Component.onCompleted: {
+                            value = player.secondarySubtitleDelayMS
+                            inhibitUpdate = false
+                        }
+
+                        Connections {
+                            target: player
+                            onSecondarySubtitleDelayChanged: {
+                                inhibitUpdate = true
+                                value = player.secondarySubtitleDelayMS
+                                inhibitUpdate = false
+                            }
+                        }
+
+                        KeyNavigation.right: secondarySubSpinReset
+                    }
+
+                    Widgets.TabButtonExt {
+                        id: secondarySubSpinReset
+
+                        text: i18n.qtr("Reset")
+                        color: "white"
+                        onClicked: secondarySubSpin.value = 0
+                        KeyNavigation.left: secondarySubSpin
+                        KeyNavigation.up: primarySubSpinReset
+                    }
+                }
+            }
+        }
+    }
+
+    Component {
+        id: syncPage
+
+        RowLayout {
+            id: syncPageRoot
+
+            spacing: 0
+            focus: true
+            onActiveFocusChanged: if (activeFocus)
+                                      backBtn.forceActiveFocus()
+
+            Item {
+                Layout.alignment: Qt.AlignLeft | Qt.AlignTop
+                Layout.preferredWidth: VLCStyle.dp(72, VLCStyle.scale)
+                Layout.topMargin: VLCStyle.margin_large
+                Layout.fillHeight: true
+
+                Widgets.IconToolButton {
+                    id: backBtn
+
+                    anchors.horizontalCenter: parent.horizontalCenter
+                    size: VLCStyle.dp(36, VLCStyle.scale)
+                    iconText: VLCIcons.back
+                    color: "white"
+
+                    onClicked: {
+                        control._updateWidth(true)
+                        syncPageRoot.StackView.view.pop()
+                    }
+                    KeyNavigation.right: subSpeedSpin
+                }
+            }
+
+            Rectangle {
+                Layout.preferredWidth: VLCStyle.dp(2, VLCStyle.scale)
+                Layout.fillHeight: true
+                color: "white"
+                opacity: .1
+            }
+
+            ColumnLayout {
+                Layout.fillWidth: true
+                Layout.fillHeight: true
+                Layout.alignment: Qt.AlignLeft | Qt.AlignTop
+                Layout.leftMargin: VLCStyle.margin_xxlarge
+                Layout.rightMargin: VLCStyle.margin_xxlarge
+                Layout.topMargin: VLCStyle.margin_large
+                spacing: VLCStyle.margin_xsmall
+
+                KeyNavigation.left: backBtn
+
+                Widgets.SubtitleLabel {
+                    Layout.fillWidth: true
+                    text: i18n.qtr("Subtitles")
+                }
+                RowLayout {
+                    width: parent.width
+                    spacing: VLCStyle.margin_xsmall
+
+                    Widgets.MenuCaption {
+                        text: i18n.qtr("Subtitle Speed")
+                        color: "white"
+                        Layout.fillWidth: true
+                        Layout.alignment: Qt.AlignHCenter
+                    }
+
+                    Widgets.TransparentSpinBox {
+                        id: subSpeedSpin
+
+                        property bool inhibitUpdate: true
+
+                        padding: VLCStyle.margin_xxxsmall
+                        stepSize: 1
+                        textFromValue: function (value, locale) {
+                            return i18n.qtr("%1 fps").arg(
+                                        Number(value / 10).toLocaleString(
+                                            locale, 'f', 3))
+                        }
+                        valueFromText: function (text, locale) {
+                            return Number.fromLocaleString(
+                                        locale,
+                                        text.substring(0, text.length - 4)) * 10
+                        }
+
+                        Layout.preferredWidth: VLCStyle.dp(128, VLCStyle.scale)
+                        Layout.preferredHeight: VLCStyle.dp(27, VLCStyle.scale)
+
+                        onValueChanged: {
+                            if (inhibitUpdate)
+                                return
+                            player.subtitleFPS = value / 10
+                        }
+
+                        Component.onCompleted: {
+                            value = player.subtitleFPS * 10
+                            inhibitUpdate = false
+                        }
+
+                        Connections {
+                            target: player
+                            onSecondarySubtitleDelayChanged: {
+                                inhibitUpdate = true
+                                value = player.subtitleFPS / 10
+                                inhibitUpdate = false
+                            }
+                        }
+
+                        KeyNavigation.right: subSpeedSpinReset
+                    }
+
+                    Widgets.TabButtonExt {
+                        id: subSpeedSpinReset
+
+                        text: i18n.qtr("Reset")
+                        color: "white"
+                        onClicked: subSpeedSpin.value = 10
+
+                        KeyNavigation.right: subSpeedSpin
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/modules/gui/qt/vlc.qrc b/modules/gui/qt/vlc.qrc
index 37a424c4de..bc4ebe270a 100644
--- a/modules/gui/qt/vlc.qrc
+++ b/modules/gui/qt/vlc.qrc
@@ -300,6 +300,7 @@
         <file alias="PlayerButtonsLayout.qml">player/qml/PlayerButtonsLayout.qml</file>
         <file alias="PlayerMenu.qml">player/qml/PlayerMenu.qml</file>
         <file alias="PlayerMenuItem.qml">player/qml/PlayerMenuItem.qml</file>
+        <file alias="LanguageMenu.qml">player/qml/LanguageMenu.qml</file>
     </qresource>
     <qresource prefix="/about">
         <file alias="About.qml">dialogs/help/qml/About.qml</file>
-- 
2.25.1



More information about the vlc-devel mailing list