You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
342 lines
12 KiB
342 lines
12 KiB
/*****************************************************************************
|
|
* Copyright (C) 2019 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.
|
|
*****************************************************************************/
|
|
|
|
// NOTE: All imports used throughout the interface
|
|
// must be imported here as well:
|
|
import QtQml
|
|
import QtQml.Models
|
|
import QtQuick
|
|
import QtQuick.Layouts
|
|
import QtQuick.Templates
|
|
import QtQuick.Controls
|
|
import QtQuick.Window
|
|
|
|
import VLC.MainInterface
|
|
import VLC.Widgets as Widgets
|
|
import VLC.Style
|
|
import VLC.Util
|
|
import VLC.Playlist
|
|
import VLC.Player
|
|
|
|
Item {
|
|
id: root
|
|
|
|
property bool _interfaceReady: false
|
|
property bool _playlistReady: false
|
|
property bool _extendedFrameVisible: MainCtx.windowSuportExtendedFrame
|
|
&& MainCtx.clientSideDecoration
|
|
&& (MainCtx.intfMainWindow.visibility === Window.Windowed)
|
|
|
|
//when exiting minimal mode, what is the page to restore
|
|
property bool _minimalRestorePlayer: false
|
|
|
|
readonly property var _pageModel: [
|
|
{ name: "mc", url: "qrc:///qt/qml/VLC/MainInterface/MainDisplay.qml" },
|
|
{ name: "player", url:"qrc:///qt/qml/VLC/Player/Player.qml" },
|
|
{ name: "minimal", url:"qrc:///qt/qml/VLC/Player/MinimalView.qml" },
|
|
]
|
|
|
|
property var _oldHistoryPath: ([])
|
|
|
|
function setInitialView() {
|
|
//set the initial view
|
|
if (!MainPlaylistController.empty)
|
|
MainCtx.requestShowPlayerView()
|
|
else
|
|
MainCtx.requestShowMainView()
|
|
}
|
|
|
|
function loadCurrentHistoryView(focusReason) {
|
|
contextSaver.save(_oldHistoryPath)
|
|
|
|
stackView.loadView(History.viewPath, History.viewProp, focusReason)
|
|
|
|
contextSaver.restore(History.viewPath)
|
|
_oldHistoryPath = History.viewPath
|
|
}
|
|
|
|
ModelSortSettingHandler {
|
|
id: contextSaver
|
|
}
|
|
|
|
Item {
|
|
id: g_mainInterface
|
|
|
|
anchors.fill: parent
|
|
anchors.topMargin: MainCtx.windowExtendedMargin
|
|
anchors.leftMargin: MainCtx.windowExtendedMargin
|
|
anchors.rightMargin: MainCtx.windowExtendedMargin
|
|
anchors.bottomMargin: MainCtx.windowExtendedMargin
|
|
|
|
Binding {
|
|
target: VLCStyle
|
|
property: "appWidth"
|
|
value: g_mainInterface.width
|
|
}
|
|
|
|
Binding {
|
|
target: VLCStyle
|
|
property: "appHeight"
|
|
value: g_mainInterface.height
|
|
}
|
|
|
|
Binding {
|
|
target: MainCtx
|
|
property: "windowExtendedMargin"
|
|
value: _extendedFrameVisible ? 20 : 0
|
|
}
|
|
|
|
Window.onWindowChanged: {
|
|
if (Window.window && !Qt.colorEqual(Window.window.color, "transparent")) {
|
|
Window.window.color = Qt.binding(function() { return theme.bg.primary })
|
|
}
|
|
}
|
|
|
|
ColorContext {
|
|
id: theme
|
|
palette: VLCStyle.palette
|
|
colorSet: ColorContext.View
|
|
}
|
|
|
|
Widgets.ToolTipExt {
|
|
id: attachedToolTip
|
|
|
|
parent: null
|
|
z: 99
|
|
colorContext.palette: parent && parent.colorContext ? parent.colorContext.palette
|
|
: VLCStyle.palette
|
|
|
|
Component.onCompleted: {
|
|
MainCtx.setAttachedToolTip(this)
|
|
}
|
|
}
|
|
|
|
Loader {
|
|
id: playlistWindowLoader
|
|
asynchronous: true
|
|
active: !MainCtx.playlistDocked
|
|
source: "qrc:///qt/qml/VLC/Playlist/PlaylistDetachedWindow.qml"
|
|
}
|
|
|
|
Connections {
|
|
target: MainPlaylistController
|
|
|
|
function onInitializedChanged() {
|
|
console.assert(MainPlaylistController.initialized)
|
|
if (root._interfaceReady && !root._playlistReady) {
|
|
root._playlistReady = true
|
|
setInitialView()
|
|
}
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: History
|
|
function onNavigate(focusReason) {
|
|
loadCurrentHistoryView(focusReason)
|
|
MainCtx.mediaLibraryVisible = !History.match(History.viewPath, ["player"])
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: MainCtx
|
|
|
|
function onRequestShowMainView() {
|
|
root._minimalRestorePlayer = false
|
|
if (MainCtx.minimalView)
|
|
return
|
|
|
|
if (History.match(History.viewPath, ["mc"]))
|
|
return
|
|
|
|
if (MainCtx.hasEmbededVideo && MainCtx.canShowVideoPIP === false)
|
|
MainPlaylistController.stop()
|
|
|
|
if (History.previousEmpty) {
|
|
History.update(["mc", "home"])
|
|
loadCurrentHistoryView(Qt.OtherFocusReason)
|
|
} else
|
|
History.previous()
|
|
}
|
|
|
|
function onRequestShowPlayerView() {
|
|
root._minimalRestorePlayer = true
|
|
if (MainCtx.minimalView)
|
|
return
|
|
|
|
if (!History.match(History.viewPath, ["player"]))
|
|
History.push(["player"])
|
|
}
|
|
|
|
function onMinimalViewChanged() {
|
|
const isCurrentlyMinimal = History.match(History.viewPath, ["minimal"])
|
|
|
|
if (MainCtx.minimalView && !isCurrentlyMinimal) {
|
|
const isCurrentlyPlayer = History.match(History.viewPath, ["player"])
|
|
if (isCurrentlyPlayer) {
|
|
History.update(["minimal"])
|
|
loadCurrentHistoryView(Qt.OtherFocusReason)
|
|
} else {
|
|
History.push(["minimal"])
|
|
}
|
|
} else if (!MainCtx.minimalView && isCurrentlyMinimal) {
|
|
if (root._minimalRestorePlayer) {
|
|
History.update(["player"])
|
|
loadCurrentHistoryView(Qt.OtherFocusReason)
|
|
} else {
|
|
History.previous()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Component.onCompleted: {
|
|
root._interfaceReady = true
|
|
if (!root._playlistReady && MainPlaylistController.initialized) {
|
|
root._playlistReady = true
|
|
setInitialView()
|
|
}
|
|
}
|
|
|
|
DropArea {
|
|
anchors.fill: parent
|
|
z: -1
|
|
|
|
onEntered: (drag) => {
|
|
// Do not handle internal drag here:
|
|
if (!drag.source) {
|
|
// Foreign drag, check if valid:
|
|
if (drag.hasUrls || drag.hasText) {
|
|
drag.accepted = true
|
|
return
|
|
}
|
|
}
|
|
|
|
drag.accepted = false
|
|
}
|
|
|
|
onDropped: (drop) => {
|
|
let urls = []
|
|
if (drop.hasUrls) {
|
|
|
|
for (let i = 0; i < drop.urls.length; i++)
|
|
urls.push(drop.urls[i])
|
|
|
|
} else if (drop.hasText) {
|
|
/* Browsers give content as text if you dnd the addressbar,
|
|
so check if mimedata has valid url in text and use it
|
|
if we didn't get any normal Urls()*/
|
|
|
|
if (drop.text.includes("\n")) {
|
|
const normalizedLineEndingsDropText = drop.text.replace("\r\n", "\n")
|
|
urls.push(...normalizedLineEndingsDropText.split("\n"))
|
|
} else {
|
|
urls.push(drop.text)
|
|
}
|
|
}
|
|
|
|
if (urls.length > 0) {
|
|
/* D&D of a subtitles file, add it on the fly */
|
|
if (Player.isStarted && urls.length == 1) {
|
|
if (Player.associateSubtitleFile(urls[0])) {
|
|
drop.accept()
|
|
return
|
|
}
|
|
}
|
|
|
|
MainPlaylistController.append(urls, true)
|
|
drop.accept()
|
|
}
|
|
}
|
|
}
|
|
|
|
Widgets.PageLoader {
|
|
id: stackView
|
|
anchors.fill: parent
|
|
focus: true
|
|
clip: _extendedFrameVisible
|
|
|
|
pageModel: _pageModel
|
|
|
|
Connections {
|
|
target: Player
|
|
function onPlayingStateChanged() {
|
|
if (Player.playingState === Player.PLAYING_STATE_STOPPED) {
|
|
MainCtx.requestShowMainView()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Loader {
|
|
asynchronous: true
|
|
source: "qrc:///qt/qml/VLC/Menus/GlobalShortcuts.qml"
|
|
}
|
|
|
|
MouseArea {
|
|
/// handles mouse navigation buttons
|
|
anchors.fill: parent
|
|
acceptedButtons: Qt.BackButton
|
|
cursorShape: undefined
|
|
onClicked: History.previous()
|
|
}
|
|
|
|
Loader {
|
|
active: {
|
|
const windowVisibility = MainCtx.intfMainWindow.visibility
|
|
return MainCtx.clientSideDecoration && !MainCtx.platformHandlesResizeWithCSD()
|
|
&& (windowVisibility !== Window.Maximized)
|
|
&& (windowVisibility !== Window.FullScreen)
|
|
|
|
}
|
|
Component.onCompleted: {
|
|
setSource(
|
|
"qrc:///qt/qml/VLC/Widgets/CSDMouseStealer.qml", {
|
|
target: g_mainInterface,
|
|
anchorInside: Qt.binding(() => !_extendedFrameVisible)
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
//draw the window drop shadow ourselve when the windowing system doesn't
|
|
//provide them but support extended frame
|
|
Widgets.RoundedRectangleShadow {
|
|
id: effect
|
|
parent: g_mainInterface
|
|
hollow: Window.window && (Window.window.color.a < 1.0) // the interface may be translucent if the window has backdrop blur
|
|
blending: false // stacked below everything, no need for blending even though it is not opaque
|
|
visible: _extendedFrameVisible && !MainCtx.platformHandlesShadowsWithCSD()
|
|
opacity: 0.5
|
|
|
|
// Blur radius can not be greater than (margin / compensationFactor), as in that case it would need bigger
|
|
// size than the window to compensate. If you want bigger blur radius, either decrease the compensation
|
|
// factor which can lead to visible clipping, or increase the window extended margin:
|
|
property real activeBlurRadius: (MainCtx.windowExtendedMargin / effect.compensationFactor)
|
|
|
|
blurRadius: MainCtx.intfMainWindow.active ? activeBlurRadius
|
|
: (activeBlurRadius / 2.0)
|
|
|
|
Behavior on blurRadius {
|
|
// FIXME: Use UniformAnimator instead
|
|
NumberAnimation {
|
|
duration: VLCStyle.duration_veryShort
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|