[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