[UI] Move controls bar to its own component.
This commit is contained in:
parent
d3a2cf00b7
commit
f1d1fdccbd
|
@ -427,7 +427,7 @@ void MpvPlayerBackend::handle_mpv_event(mpv_event* event)
|
||||||
} else if (strcmp(prop->name, "demuxer-cache-duration") == 0) {
|
} else if (strcmp(prop->name, "demuxer-cache-duration") == 0) {
|
||||||
if (prop->format == MPV_FORMAT_DOUBLE) {
|
if (prop->format == MPV_FORMAT_DOUBLE) {
|
||||||
double duration = *(double*)prop->data;
|
double duration = *(double*)prop->data;
|
||||||
QMetaObject::invokeMethod(this, "setCachedDuration", Q_ARG(QVariant, duration));
|
QMetaObject::invokeMethod(findChild<QObject*>("progressBar"), "setCachedDuration", Q_ARG(QVariant, duration));
|
||||||
}
|
}
|
||||||
} else if (strcmp(prop->name, "playlist-pos") == 0) {
|
} else if (strcmp(prop->name, "playlist-pos") == 0) {
|
||||||
if (prop->format == MPV_FORMAT_DOUBLE) {
|
if (prop->format == MPV_FORMAT_DOUBLE) {
|
||||||
|
|
382
src/qml/ControlsBar.qml
Normal file
382
src/qml/ControlsBar.qml
Normal file
|
@ -0,0 +1,382 @@
|
||||||
|
import QtQuick 2.11
|
||||||
|
import QtQuick.Controls 2.4
|
||||||
|
import QtQuick.Dialogs 1.3
|
||||||
|
import QtQuick.Layouts 1.11
|
||||||
|
import QtQuick.Window 2.11
|
||||||
|
import Qt.labs.settings 1.0
|
||||||
|
import Qt.labs.platform 1.0 as LabsPlatform
|
||||||
|
import player 1.0
|
||||||
|
|
||||||
|
Item {
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
|
||||||
|
property var background: controlsBackground
|
||||||
|
property var progress: progressBar
|
||||||
|
property var controls: controlsBar
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: subtitlesBar
|
||||||
|
visible: !appearance.useMpvSubs
|
||||||
|
color: "transparent"
|
||||||
|
height: player.height / 8
|
||||||
|
anchors.bottom: controlsBackground.top
|
||||||
|
anchors.bottomMargin: 5
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.left: parent.left
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: nativeSubtitles
|
||||||
|
visible: true
|
||||||
|
anchors.left: subtitlesBar.left
|
||||||
|
anchors.right: subtitlesBar.right
|
||||||
|
height: childrenRect.height
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.bottomMargin: 10
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: subsContainer
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.rightMargin: 0
|
||||||
|
Layout.leftMargin: 0
|
||||||
|
Layout.maximumWidth: nativeSubtitles.width
|
||||||
|
color: "transparent"
|
||||||
|
height: childrenRect.height
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: nativeSubs
|
||||||
|
objectName: "nativeSubs"
|
||||||
|
onWidthChanged: {
|
||||||
|
|
||||||
|
if (width > parent.width - 10)
|
||||||
|
width = parent.width - 10
|
||||||
|
}
|
||||||
|
onTextChanged: if (width <= parent.width - 10)
|
||||||
|
width = undefined
|
||||||
|
color: "white"
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||||
|
font.pixelSize: Screen.height / 24
|
||||||
|
font.family: appearance.fontName
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
opacity: 1
|
||||||
|
background: Rectangle {
|
||||||
|
id: subsBackground
|
||||||
|
color: Qt.rgba(0, 0, 0, 0.6)
|
||||||
|
width: subsContainer.childrenRect.width
|
||||||
|
height: subsContainer.childrenRect.height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: controlsBackground
|
||||||
|
height: controlsBar.visible ? controlsBar.height + progressBackground.height
|
||||||
|
+ (progressBar.topPadding * 2)
|
||||||
|
- (progressBackground.height * 2) : 0
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
color: "black"
|
||||||
|
opacity: 0.6
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: controlsBar
|
||||||
|
height: controlsBar.visible ? Screen.height / 24 : 0
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: parent.width / 128
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: parent.width / 128
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.bottomMargin: 1
|
||||||
|
visible: true
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
Slider {
|
||||||
|
id: progressBar
|
||||||
|
objectName: "progressBar"
|
||||||
|
to: 1
|
||||||
|
value: 0.0
|
||||||
|
anchors.bottom: parent.top
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.bottomMargin: 0
|
||||||
|
anchors.topMargin: progressBackground.height
|
||||||
|
bottomPadding: 0
|
||||||
|
|
||||||
|
function setCachedDuration(val) {
|
||||||
|
cachedLength.width = ((progressBar.width / progressBar.to)
|
||||||
|
* val) - progressLength.width
|
||||||
|
}
|
||||||
|
|
||||||
|
onMoved: {
|
||||||
|
player.seekAbsolute(progressBar.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getProgressBarHeight(nyan, isMouse) {
|
||||||
|
var x = Math.max(Screen.height / 256, fun.nyanCat ? 12 : 2)
|
||||||
|
return isMouse & !fun.nyanCat ? x * 2 : x
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: mouseAreaProgressBar
|
||||||
|
y: parent.height
|
||||||
|
width: parent.width
|
||||||
|
height: parent.height
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
propagateComposedEvents: true
|
||||||
|
acceptedButtons: Qt.NoButton
|
||||||
|
}
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
id: progressBackground
|
||||||
|
x: progressBar.leftPadding
|
||||||
|
y: progressBar.topPadding + progressBar.availableHeight / 2 - height / 2
|
||||||
|
implicitHeight: progressBar.getProgressBarHeight(
|
||||||
|
fun.nyanCat,
|
||||||
|
mouseAreaProgressBar.containsMouse)
|
||||||
|
width: progressBar.availableWidth
|
||||||
|
height: implicitHeight
|
||||||
|
color: Qt.rgba(255, 255, 255, 0.6)
|
||||||
|
radius: height
|
||||||
|
Rectangle {
|
||||||
|
id: progressLength
|
||||||
|
width: progressBar.visualPosition * parent.width
|
||||||
|
height: parent.height
|
||||||
|
color: "red"
|
||||||
|
opacity: 1
|
||||||
|
radius: height
|
||||||
|
anchors.leftMargin: 100
|
||||||
|
|
||||||
|
Image {
|
||||||
|
visible: fun.nyanCat
|
||||||
|
id: rainbow
|
||||||
|
anchors.fill: parent
|
||||||
|
height: parent.height
|
||||||
|
width: parent.width
|
||||||
|
source: "qrc:/player/icons/rainbow.png"
|
||||||
|
fillMode: Image.TileHorizontally
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Rectangle {
|
||||||
|
id: cachedLength
|
||||||
|
z: 10
|
||||||
|
radius: height
|
||||||
|
anchors.left: progressLength.right
|
||||||
|
anchors.leftMargin: 2
|
||||||
|
//anchors.left: progressBar.handle.horizontalCenter
|
||||||
|
anchors.bottom: progressBar.background.bottom
|
||||||
|
anchors.top: progressBar.background.top
|
||||||
|
height: progressBar.background.height
|
||||||
|
color: "white"
|
||||||
|
opacity: 0.8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handle: Rectangle {
|
||||||
|
|
||||||
|
id: handleRect
|
||||||
|
x: progressBar.leftPadding + progressBar.visualPosition
|
||||||
|
* (progressBar.availableWidth - width)
|
||||||
|
y: progressBar.topPadding + progressBar.availableHeight / 2 - height / 2
|
||||||
|
implicitHeight: radius
|
||||||
|
implicitWidth: radius
|
||||||
|
radius: 12 + (progressBackground.height / 2)
|
||||||
|
color: fun.nyanCat ? "transparent" : "red"
|
||||||
|
//border.color: "red"
|
||||||
|
AnimatedImage {
|
||||||
|
visible: fun.nyanCat
|
||||||
|
paused: progressBar.pressed
|
||||||
|
height: 30
|
||||||
|
id: nyanimation
|
||||||
|
anchors.centerIn: parent
|
||||||
|
source: "qrc:/player/icons/nyancat.gif"
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: playlistPrevButton
|
||||||
|
objectName: "playlistPrevButton"
|
||||||
|
//icon.name: "prev"
|
||||||
|
icon.source: "icons/prev.svg"
|
||||||
|
icon.color: "white"
|
||||||
|
display: AbstractButton.IconOnly
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
visible: false
|
||||||
|
width: visible ? playPauseButton.width : 0
|
||||||
|
onClicked: {
|
||||||
|
player.prevPlaylistItem()
|
||||||
|
}
|
||||||
|
background: Rectangle {
|
||||||
|
color: "transparent"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: playPauseButton
|
||||||
|
//icon.name: "pause"
|
||||||
|
objectName: "playPauseButton"
|
||||||
|
property string iconSource: "icons/pause.svg"
|
||||||
|
icon.source: iconSource
|
||||||
|
icon.color: "white"
|
||||||
|
display: AbstractButton.IconOnly
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.left: playlistPrevButton.right
|
||||||
|
onClicked: {
|
||||||
|
player.togglePlayPause()
|
||||||
|
}
|
||||||
|
background: Rectangle {
|
||||||
|
color: "transparent"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: playlistNextButton
|
||||||
|
//icon.name: "next"
|
||||||
|
icon.source: "icons/next.svg"
|
||||||
|
icon.color: "white"
|
||||||
|
display: AbstractButton.IconOnly
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.left: playPauseButton.right
|
||||||
|
onClicked: {
|
||||||
|
player.nextPlaylistItem()
|
||||||
|
}
|
||||||
|
background: Rectangle {
|
||||||
|
color: "transparent"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: volumeButton
|
||||||
|
objectName: "volumeButton"
|
||||||
|
property string iconSource: "icons/volume-up.svg"
|
||||||
|
icon.source: iconSource
|
||||||
|
icon.color: "white"
|
||||||
|
display: AbstractButton.IconOnly
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.left: playlistNextButton.right
|
||||||
|
onClicked: {
|
||||||
|
player.toggleMute()
|
||||||
|
player.updateVolume(player.getProperty("volume"))
|
||||||
|
}
|
||||||
|
background: Rectangle {
|
||||||
|
color: "transparent"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Slider {
|
||||||
|
id: volumeBar
|
||||||
|
to: 100
|
||||||
|
value: 100
|
||||||
|
palette.dark: "#f00"
|
||||||
|
|
||||||
|
implicitWidth: Math.max(
|
||||||
|
background ? background.implicitWidth : 0,
|
||||||
|
(handle ? handle.implicitWidth : 0)
|
||||||
|
+ leftPadding + rightPadding)
|
||||||
|
implicitHeight: Math.max(
|
||||||
|
background ? background.implicitHeight : 0,
|
||||||
|
(handle ? handle.implicitHeight : 0)
|
||||||
|
+ topPadding + bottomPadding)
|
||||||
|
|
||||||
|
anchors.left: volumeButton.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
onMoved: {
|
||||||
|
player.setVolume(Math.round(volumeBar.value).toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
handle: Rectangle {
|
||||||
|
x: volumeBar.leftPadding + volumeBar.visualPosition
|
||||||
|
* (volumeBar.availableWidth - width)
|
||||||
|
y: volumeBar.topPadding + volumeBar.availableHeight / 2 - height / 2
|
||||||
|
implicitWidth: 12
|
||||||
|
implicitHeight: 12
|
||||||
|
radius: 12
|
||||||
|
color: "#f6f6f6"
|
||||||
|
border.color: "#f6f6f6"
|
||||||
|
}
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
x: volumeBar.leftPadding
|
||||||
|
y: volumeBar.topPadding + volumeBar.availableHeight / 2 - height / 2
|
||||||
|
implicitWidth: 60
|
||||||
|
implicitHeight: 3
|
||||||
|
width: volumeBar.availableWidth
|
||||||
|
height: implicitHeight
|
||||||
|
color: "#33333311"
|
||||||
|
Rectangle {
|
||||||
|
width: volumeBar.visualPosition * parent.width
|
||||||
|
height: parent.height
|
||||||
|
color: "white"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: timeLabel
|
||||||
|
objectName: "timeLabel"
|
||||||
|
text: "0:00 / 0:00"
|
||||||
|
color: "white"
|
||||||
|
anchors.left: volumeBar.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
padding: 2
|
||||||
|
font.family: appearance.fontName
|
||||||
|
font.pixelSize: 14
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
renderType: Text.NativeRendering
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: settingsButton
|
||||||
|
//icon.name: "settings"
|
||||||
|
icon.source: "icons/settings.svg"
|
||||||
|
icon.color: "white"
|
||||||
|
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
|
||||||
|
anchors.right: fullscreenButton.left
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
display: AbstractButton.IconOnly
|
||||||
|
onClicked: {
|
||||||
|
console.log("Settings Menu Not Yet Implemented.")
|
||||||
|
}
|
||||||
|
background: Rectangle {
|
||||||
|
color: "transparent"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: fullscreenButton
|
||||||
|
//icon.name: "fullscreen"
|
||||||
|
icon.source: "icons/fullscreen.svg"
|
||||||
|
icon.color: "white"
|
||||||
|
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
display: AbstractButton.IconOnly
|
||||||
|
onClicked: {
|
||||||
|
toggleFullscreen()
|
||||||
|
}
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
color: "transparent"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,8 @@ import Qt.labs.settings 1.0
|
||||||
import Qt.labs.platform 1.0 as LabsPlatform
|
import Qt.labs.platform 1.0 as LabsPlatform
|
||||||
import player 1.0
|
import player 1.0
|
||||||
|
|
||||||
|
import "codes.js" as LanguageCodes
|
||||||
|
|
||||||
MenuBar {
|
MenuBar {
|
||||||
id: menuBar
|
id: menuBar
|
||||||
//width: parent.width
|
//width: parent.width
|
||||||
|
@ -85,50 +87,49 @@ MenuBar {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LabsPlatform.FileDialog {
|
LabsPlatform.FileDialog {
|
||||||
id: screenshotSaveDialog
|
id: screenshotSaveDialog
|
||||||
title: translate.getTranslation("SAVE_SCREENSHOT", i18n.language)
|
title: translate.getTranslation("SAVE_SCREENSHOT", i18n.language)
|
||||||
fileMode: LabsPlatform.FileDialog.SaveFile
|
fileMode: LabsPlatform.FileDialog.SaveFile
|
||||||
defaultSuffix: "png"
|
defaultSuffix: "png"
|
||||||
nameFilters: ["Images (*.png)", "All files (*)"]
|
nameFilters: ["Images (*.png)", "All files (*)"]
|
||||||
onAccepted: {
|
onAccepted: {
|
||||||
player.grabToImage(function (result) {
|
player.grabToImage(function (result) {
|
||||||
var filepath = String(screenshotSaveDialog.file).replace(
|
var filepath = String(screenshotSaveDialog.file).replace(
|
||||||
"file://", '')
|
"file://", '')
|
||||||
result.saveToFile(filepath)
|
result.saveToFile(filepath)
|
||||||
subtitlesBar.visible = appearance.useMpvSubs ? false : true
|
subtitlesBar.visible = appearance.useMpvSubs ? false : true
|
||||||
})
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LabsPlatform.FileDialog {
|
LabsPlatform.FileDialog {
|
||||||
id: fileDialog
|
id: fileDialog
|
||||||
title: translate.getTranslation("OPEN_FILE", i18n.language)
|
title: translate.getTranslation("OPEN_FILE", i18n.language)
|
||||||
nameFilters: ["All files (*)"]
|
nameFilters: ["All files (*)"]
|
||||||
onAccepted: {
|
onAccepted: {
|
||||||
player.loadFile(String(fileDialog.file))
|
player.loadFile(String(fileDialog.file))
|
||||||
fileDialog.close()
|
fileDialog.close()
|
||||||
}
|
|
||||||
onRejected: {
|
|
||||||
fileDialog.close()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
onRejected: {
|
||||||
Dialog {
|
fileDialog.close()
|
||||||
id: loadDialog
|
|
||||||
title: translate.getTranslation("URL_FILE_PATH", i18n.language)
|
|
||||||
standardButtons: StandardButton.Cancel | StandardButton.Open
|
|
||||||
onAccepted: {
|
|
||||||
player.loadFile(pathText.text)
|
|
||||||
pathText.text = ""
|
|
||||||
}
|
|
||||||
TextField {
|
|
||||||
id: pathText
|
|
||||||
placeholderText: translate.getTranslation("URL_FILE_PATH",
|
|
||||||
i18n.language)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: loadDialog
|
||||||
|
title: translate.getTranslation("URL_FILE_PATH", i18n.language)
|
||||||
|
standardButtons: StandardButton.Cancel | StandardButton.Open
|
||||||
|
onAccepted: {
|
||||||
|
player.loadFile(pathText.text)
|
||||||
|
pathText.text = ""
|
||||||
|
}
|
||||||
|
TextField {
|
||||||
|
id: pathText
|
||||||
|
placeholderText: translate.getTranslation("URL_FILE_PATH",
|
||||||
|
i18n.language)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
delegate: MenuBarItem {
|
delegate: MenuBarItem {
|
||||||
id: menuBarItem
|
id: menuBarItem
|
||||||
|
|
396
src/qml/main.qml
396
src/qml/main.qml
|
@ -106,7 +106,7 @@ ApplicationWindow {
|
||||||
function skipToNinth(val) {
|
function skipToNinth(val) {
|
||||||
var skipto = 0
|
var skipto = 0
|
||||||
if (val != 0) {
|
if (val != 0) {
|
||||||
skipto = Math.floor(progressBar.to / 9 * val)
|
skipto = Math.floor(controlsBar.controls.progress.to / 9 * val)
|
||||||
}
|
}
|
||||||
player.seekAbsolute(skipto)
|
player.seekAbsolute(skipto)
|
||||||
}
|
}
|
||||||
|
@ -117,8 +117,8 @@ ApplicationWindow {
|
||||||
|
|
||||||
function hideControls(force) {
|
function hideControls(force) {
|
||||||
if (!isAnyMenuOpen() || force) {
|
if (!isAnyMenuOpen() || force) {
|
||||||
controlsBar.visible = false
|
controlsBar.controls.visible = false
|
||||||
controlsBackground.visible = false
|
controlsBar.background.visible = false
|
||||||
titleBar.visible = false
|
titleBar.visible = false
|
||||||
titleBackground.visible = false
|
titleBackground.visible = false
|
||||||
menuBar.visible = false
|
menuBar.visible = false
|
||||||
|
@ -126,9 +126,9 @@ ApplicationWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
function showControls() {
|
function showControls() {
|
||||||
if (!controlsBar.visible) {
|
if (!controlsBar.controls.visible) {
|
||||||
controlsBar.visible = true
|
controlsBar.controls.visible = true
|
||||||
controlsBackground.visible = true
|
controlsBar.background.visible = true
|
||||||
if (appearance.titleOnlyOnFullscreen) {
|
if (appearance.titleOnlyOnFullscreen) {
|
||||||
if (mainWindow.visibility == Window.FullScreen) {
|
if (mainWindow.visibility == Window.FullScreen) {
|
||||||
titleBar.visible = true
|
titleBar.visible = true
|
||||||
|
@ -146,7 +146,7 @@ ApplicationWindow {
|
||||||
x: 0
|
x: 0
|
||||||
y: parent.height
|
y: parent.height
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: (controlsBar.height * 2) + progressBar.height
|
height: (controlsBar.controls.height * 2) + controlsBar.progress.height
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.bottomMargin: 0
|
anchors.bottomMargin: 0
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
|
@ -290,388 +290,8 @@ ApplicationWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
ControlsBar {
|
||||||
id: controlsBackground
|
|
||||||
height: controlsBar.visible ? controlsBar.height + progressBackground.height
|
|
||||||
+ (progressBar.topPadding * 2)
|
|
||||||
- (progressBackground.height * 2) : 0
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.fillHeight: true
|
|
||||||
color: "black"
|
|
||||||
opacity: 0.6
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: subtitlesBar
|
|
||||||
visible: !appearance.useMpvSubs
|
|
||||||
color: "transparent"
|
|
||||||
height: player.height / 8
|
|
||||||
anchors.bottom: controlsBackground.top
|
|
||||||
anchors.bottomMargin: 5
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.left: parent.left
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
id: nativeSubtitles
|
|
||||||
visible: true
|
|
||||||
anchors.left: subtitlesBar.left
|
|
||||||
anchors.right: subtitlesBar.right
|
|
||||||
height: childrenRect.height
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
anchors.bottomMargin: 10
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: subsContainer
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.fillHeight: true
|
|
||||||
Layout.rightMargin: 0
|
|
||||||
Layout.leftMargin: 0
|
|
||||||
Layout.maximumWidth: nativeSubtitles.width
|
|
||||||
color: "transparent"
|
|
||||||
height: childrenRect.height
|
|
||||||
|
|
||||||
Label {
|
|
||||||
id: nativeSubs
|
|
||||||
objectName: "nativeSubs"
|
|
||||||
onWidthChanged: {
|
|
||||||
|
|
||||||
if (width > parent.width - 10)
|
|
||||||
width = parent.width - 10
|
|
||||||
}
|
|
||||||
onTextChanged: if (width <= parent.width - 10)
|
|
||||||
width = undefined
|
|
||||||
color: "white"
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
|
||||||
font.pixelSize: Screen.height / 24
|
|
||||||
font.family: appearance.fontName
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
opacity: 1
|
|
||||||
background: Rectangle {
|
|
||||||
id: subsBackground
|
|
||||||
color: Qt.rgba(0, 0, 0, 0.6)
|
|
||||||
width: subsContainer.childrenRect.width
|
|
||||||
height: subsContainer.childrenRect.height
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function setCachedDuration(val) {
|
|
||||||
cachedLength.width = ((progressBar.width / progressBar.to) * val) - progressLength.width
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: controlsBar
|
id: controlsBar
|
||||||
height: controlsBar.visible ? Screen.height / 24 : 0
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.rightMargin: parent.width / 128
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.leftMargin: parent.width / 128
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
anchors.bottomMargin: 1
|
|
||||||
visible: true
|
|
||||||
color: "transparent"
|
|
||||||
Rectangle {
|
|
||||||
id: settingsMenuBackground
|
|
||||||
anchors.fill: settingsMenu
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.fillHeight: true
|
|
||||||
visible: false
|
|
||||||
color: "black"
|
|
||||||
opacity: 0.6
|
|
||||||
radius: 5
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: settingsMenu
|
|
||||||
color: "transparent"
|
|
||||||
width: childrenRect.width
|
|
||||||
height: childrenRect.height
|
|
||||||
visible: false
|
|
||||||
anchors.right: settingsButton.right
|
|
||||||
anchors.bottom: progressBar.top
|
|
||||||
radius: 5
|
|
||||||
}
|
|
||||||
|
|
||||||
Slider {
|
|
||||||
id: progressBar
|
|
||||||
objectName: "progressBar"
|
|
||||||
to: 1
|
|
||||||
value: 0.0
|
|
||||||
anchors.bottom: parent.top
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.bottomMargin: 0
|
|
||||||
anchors.topMargin: progressBackground.height
|
|
||||||
bottomPadding: 0
|
|
||||||
|
|
||||||
onMoved: {
|
|
||||||
player.seekAbsolute(progressBar.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
function getProgressBarHeight(nyan, isMouse) {
|
|
||||||
var x = Math.max(Screen.height / 256, fun.nyanCat ? 12 : 2)
|
|
||||||
return isMouse & !fun.nyanCat ? x * 2 : x
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: mouseAreaProgressBar
|
|
||||||
y: parent.height
|
|
||||||
width: parent.width
|
|
||||||
height: parent.height
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
propagateComposedEvents: true
|
|
||||||
acceptedButtons: Qt.NoButton
|
|
||||||
}
|
|
||||||
|
|
||||||
background: Rectangle {
|
|
||||||
id: progressBackground
|
|
||||||
x: progressBar.leftPadding
|
|
||||||
y: progressBar.topPadding + progressBar.availableHeight / 2 - height / 2
|
|
||||||
implicitHeight: progressBar.getProgressBarHeight(
|
|
||||||
fun.nyanCat,
|
|
||||||
mouseAreaProgressBar.containsMouse)
|
|
||||||
width: progressBar.availableWidth
|
|
||||||
height: implicitHeight
|
|
||||||
color: Qt.rgba(255, 255, 255, 0.6)
|
|
||||||
radius: height
|
|
||||||
Rectangle {
|
|
||||||
id: progressLength
|
|
||||||
width: progressBar.visualPosition * parent.width
|
|
||||||
height: parent.height
|
|
||||||
color: "red"
|
|
||||||
opacity: 1
|
|
||||||
radius: height
|
|
||||||
anchors.leftMargin: 100
|
|
||||||
|
|
||||||
Image {
|
|
||||||
visible: fun.nyanCat
|
|
||||||
id: rainbow
|
|
||||||
anchors.fill: parent
|
|
||||||
height: parent.height
|
|
||||||
width: parent.width
|
|
||||||
source: "qrc:/player/icons/rainbow.png"
|
|
||||||
fillMode: Image.TileHorizontally
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Rectangle {
|
|
||||||
id: cachedLength
|
|
||||||
z: 10
|
|
||||||
radius: height
|
|
||||||
anchors.left: progressLength.right
|
|
||||||
anchors.leftMargin: 2
|
|
||||||
//anchors.left: progressBar.handle.horizontalCenter
|
|
||||||
anchors.bottom: progressBar.background.bottom
|
|
||||||
anchors.top: progressBar.background.top
|
|
||||||
height: progressBar.background.height
|
|
||||||
color: "white"
|
|
||||||
opacity: 0.8
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handle: Rectangle {
|
|
||||||
|
|
||||||
id: handleRect
|
|
||||||
x: progressBar.leftPadding + progressBar.visualPosition
|
|
||||||
* (progressBar.availableWidth - width)
|
|
||||||
y: progressBar.topPadding + progressBar.availableHeight / 2 - height / 2
|
|
||||||
implicitHeight: radius
|
|
||||||
implicitWidth: radius
|
|
||||||
radius: 12 + (progressBackground.height / 2)
|
|
||||||
color: fun.nyanCat ? "transparent" : "red"
|
|
||||||
//border.color: "red"
|
|
||||||
AnimatedImage {
|
|
||||||
visible: fun.nyanCat
|
|
||||||
paused: progressBar.pressed
|
|
||||||
height: 30
|
|
||||||
id: nyanimation
|
|
||||||
anchors.centerIn: parent
|
|
||||||
source: "qrc:/player/icons/nyancat.gif"
|
|
||||||
fillMode: Image.PreserveAspectFit
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
id: playlistPrevButton
|
|
||||||
objectName: "playlistPrevButton"
|
|
||||||
//icon.name: "prev"
|
|
||||||
icon.source: "icons/prev.svg"
|
|
||||||
icon.color: "white"
|
|
||||||
display: AbstractButton.IconOnly
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
visible: false
|
|
||||||
width: visible ? playPauseButton.width : 0
|
|
||||||
onClicked: {
|
|
||||||
player.prevPlaylistItem()
|
|
||||||
}
|
|
||||||
background: Rectangle {
|
|
||||||
color: "transparent"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
id: playPauseButton
|
|
||||||
//icon.name: "pause"
|
|
||||||
objectName: "playPauseButton"
|
|
||||||
property string iconSource: "icons/pause.svg"
|
|
||||||
icon.source: iconSource
|
|
||||||
icon.color: "white"
|
|
||||||
display: AbstractButton.IconOnly
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
anchors.left: playlistPrevButton.right
|
|
||||||
onClicked: {
|
|
||||||
player.togglePlayPause()
|
|
||||||
}
|
|
||||||
background: Rectangle {
|
|
||||||
color: "transparent"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
id: playlistNextButton
|
|
||||||
//icon.name: "next"
|
|
||||||
icon.source: "icons/next.svg"
|
|
||||||
icon.color: "white"
|
|
||||||
display: AbstractButton.IconOnly
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
anchors.left: playPauseButton.right
|
|
||||||
onClicked: {
|
|
||||||
player.nextPlaylistItem()
|
|
||||||
}
|
|
||||||
background: Rectangle {
|
|
||||||
color: "transparent"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
id: volumeButton
|
|
||||||
objectName: "volumeButton"
|
|
||||||
property string iconSource: "icons/volume-up.svg"
|
|
||||||
icon.source: iconSource
|
|
||||||
icon.color: "white"
|
|
||||||
display: AbstractButton.IconOnly
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
anchors.left: playlistNextButton.right
|
|
||||||
onClicked: {
|
|
||||||
player.toggleMute()
|
|
||||||
player.updateVolume(player.getProperty("volume"))
|
|
||||||
}
|
|
||||||
background: Rectangle {
|
|
||||||
color: "transparent"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Slider {
|
|
||||||
id: volumeBar
|
|
||||||
to: 100
|
|
||||||
value: 100
|
|
||||||
palette.dark: "#f00"
|
|
||||||
|
|
||||||
implicitWidth: Math.max(
|
|
||||||
background ? background.implicitWidth : 0,
|
|
||||||
(handle ? handle.implicitWidth : 0)
|
|
||||||
+ leftPadding + rightPadding)
|
|
||||||
implicitHeight: Math.max(
|
|
||||||
background ? background.implicitHeight : 0,
|
|
||||||
(handle ? handle.implicitHeight : 0)
|
|
||||||
+ topPadding + bottomPadding)
|
|
||||||
|
|
||||||
anchors.left: volumeButton.right
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
onMoved: {
|
|
||||||
player.setVolume(Math.round(volumeBar.value).toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
handle: Rectangle {
|
|
||||||
x: volumeBar.leftPadding + volumeBar.visualPosition
|
|
||||||
* (volumeBar.availableWidth - width)
|
|
||||||
y: volumeBar.topPadding + volumeBar.availableHeight / 2 - height / 2
|
|
||||||
implicitWidth: 12
|
|
||||||
implicitHeight: 12
|
|
||||||
radius: 12
|
|
||||||
color: "#f6f6f6"
|
|
||||||
border.color: "#f6f6f6"
|
|
||||||
}
|
|
||||||
|
|
||||||
background: Rectangle {
|
|
||||||
x: volumeBar.leftPadding
|
|
||||||
y: volumeBar.topPadding + volumeBar.availableHeight / 2 - height / 2
|
|
||||||
implicitWidth: 60
|
|
||||||
implicitHeight: 3
|
|
||||||
width: volumeBar.availableWidth
|
|
||||||
height: implicitHeight
|
|
||||||
color: "#33333311"
|
|
||||||
Rectangle {
|
|
||||||
width: volumeBar.visualPosition * parent.width
|
|
||||||
height: parent.height
|
|
||||||
color: "white"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id: timeLabel
|
|
||||||
objectName: "timeLabel"
|
|
||||||
text: "0:00 / 0:00"
|
|
||||||
color: "white"
|
|
||||||
anchors.left: volumeBar.right
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
padding: 2
|
|
||||||
font.family: appearance.fontName
|
|
||||||
font.pixelSize: 14
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
renderType: Text.NativeRendering
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
id: settingsButton
|
|
||||||
//icon.name: "settings"
|
|
||||||
icon.source: "icons/settings.svg"
|
|
||||||
icon.color: "white"
|
|
||||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
|
|
||||||
anchors.right: fullscreenButton.left
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
display: AbstractButton.IconOnly
|
|
||||||
onClicked: {
|
|
||||||
settingsMenu.visible = !settingsMenu.visible
|
|
||||||
settingsMenuBackground.visible = !settingsMenuBackground.visible
|
|
||||||
}
|
|
||||||
background: Rectangle {
|
|
||||||
color: "transparent"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
id: fullscreenButton
|
|
||||||
//icon.name: "fullscreen"
|
|
||||||
icon.source: "icons/fullscreen.svg"
|
|
||||||
icon.color: "white"
|
|
||||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
display: AbstractButton.IconOnly
|
|
||||||
onClicked: {
|
|
||||||
toggleFullscreen()
|
|
||||||
}
|
|
||||||
|
|
||||||
background: Rectangle {
|
|
||||||
color: "transparent"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
<file>CustomComboBox.qml</file>
|
<file>CustomComboBox.qml</file>
|
||||||
<file>CustomMenuItem.qml</file>
|
<file>CustomMenuItem.qml</file>
|
||||||
<file>CustomMenu.qml</file>
|
<file>CustomMenu.qml</file>
|
||||||
|
<file>ControlsBar.qml</file>
|
||||||
<file>MainMenu.qml</file>
|
<file>MainMenu.qml</file>
|
||||||
<file>TrackItem.qml</file>
|
<file>TrackItem.qml</file>
|
||||||
<file>AudioDeviceItem.qml</file>
|
<file>AudioDeviceItem.qml</file>
|
||||||
|
|
Loading…
Reference in a new issue