forked from qt-creator/qt-creator
This adds the QML source for the Qt Design Studio Welcome page. The source code was private before. Change-Id: I5dcb900ed9a17b1bc3bbcaf50f649ebeb61cc8bf Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
631 lines
22 KiB
QML
631 lines
22 KiB
QML
// Copyright (C) 2024 The Qt Company Ltd.
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
|
|
import QtQuick
|
|
import QtQuick.Controls
|
|
import QtQuick.Layouts
|
|
import WelcomeScreen 1.0
|
|
import ExampleCheckout 1.0
|
|
|
|
Item {
|
|
id: root
|
|
width: Constants.thumbnailSize
|
|
height: Constants.thumbnailSize
|
|
clip: true
|
|
state: "normal"
|
|
|
|
property bool textWrapped: false
|
|
property bool hasDescription: false
|
|
property bool hasPath: false
|
|
property bool hasUpdate: false
|
|
property bool downloadable: false
|
|
property int numberOfPanels: 3
|
|
|
|
enum Type {
|
|
RecentProject,
|
|
Example,
|
|
Tutorial
|
|
}
|
|
|
|
property int type: ThumbnailDelegate.Type.RecentProject
|
|
|
|
property alias projectNameLabelText: projectNameLabel.text
|
|
property alias projectPathLabelText: projectPathLabel.text
|
|
property alias thumbnailPlaceholderSource: thumbnailPlaceholder.source
|
|
|
|
property alias downloadUrl: downloader.url
|
|
property alias tempFile: downloader.outputFile
|
|
property alias completeBaseName: downloader.completeBaseName
|
|
property alias targetPath: extractor.targetPath
|
|
|
|
property alias bannerLabelText: updateText.text
|
|
|
|
enum Panel {
|
|
InBetween,
|
|
Download,
|
|
Main,
|
|
Details
|
|
}
|
|
|
|
property int currentPanel: ThumbnailDelegate.Panel.Main
|
|
|
|
signal clicked()
|
|
signal rightClicked()
|
|
|
|
function startDownload() {
|
|
twirlToDownloadAnimation.start()
|
|
downloadPanel.text = downloadPanel.downloadText
|
|
downloadPanel.allowCancel = true
|
|
downloadPanel.value = Qt.binding(function() { return downloader.progress })
|
|
downloader.start()
|
|
mouseArea.enabled = false
|
|
}
|
|
|
|
function thumbnailClicked() {
|
|
if (root.type === ThumbnailDelegate.Type.RecentProject
|
|
|| root.type === ThumbnailDelegate.Type.Tutorial)
|
|
root.clicked() // open recent project/tutorial
|
|
|
|
if (Constants.loadingProgress < 95)
|
|
return
|
|
if (root.type === ThumbnailDelegate.Type.Example) {
|
|
if (root.downloadable
|
|
&& !downloadButton.alreadyDownloaded
|
|
&& !downloadButton.downloadUnavailable) {
|
|
root.startDownload()
|
|
} else if (downloadButton.alreadyDownloaded) {
|
|
root.clicked() // open example
|
|
}
|
|
}
|
|
}
|
|
|
|
MouseArea {
|
|
id: mouseArea
|
|
anchors.fill: parent
|
|
propagateComposedEvents: true
|
|
hoverEnabled: true
|
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
|
|
|
Connections {
|
|
target: mouseArea
|
|
function onClicked(mouse) {
|
|
if (mouse.button === Qt.RightButton)
|
|
root.rightClicked()
|
|
else
|
|
root.thumbnailClicked(mouse)
|
|
}
|
|
}
|
|
}
|
|
|
|
CustomDialog {
|
|
id: overwriteDialog
|
|
title: qsTr("Overwrite Example?")
|
|
standardButtons: Dialog.Yes | Dialog.No
|
|
modal: true
|
|
anchors.centerIn: parent
|
|
|
|
onAccepted: root.startDownload()
|
|
|
|
Text {
|
|
width: parent.width
|
|
horizontalAlignment: Text.AlignHCenter
|
|
font.pixelSize: 12
|
|
color: Constants.currentGlobalText
|
|
text: qsTr("Example already exists.<br>Do you want to replace it?")
|
|
}
|
|
}
|
|
|
|
Item {
|
|
id: canvas
|
|
width: Constants.thumbnailSize
|
|
height: Constants.thumbnailSize * root.numberOfPanels
|
|
|
|
DownloadPanel {
|
|
id: downloadPanel
|
|
|
|
height: Constants.thumbnailSize
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.bottom: mainPanel.top
|
|
radius: 10
|
|
value: downloader.progress
|
|
|
|
readonly property string downloadText: qsTr("Downloading...")
|
|
readonly property string extractText: qsTr("Extracting...")
|
|
|
|
onCancelRequested: downloader.cancel()
|
|
}
|
|
|
|
Rectangle {
|
|
id: mainPanel
|
|
height: Constants.thumbnailSize
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
color: "#ea8c8c"
|
|
radius: 10
|
|
|
|
property bool multiline: (projectNameLabelMetric.width >= projectNameLabel.width)
|
|
|
|
TextMetrics {
|
|
id: projectNameLabelMetric
|
|
text: projectNameLabel.text
|
|
font: projectNameLabel.font
|
|
}
|
|
|
|
Image {
|
|
id: thumbnailPlaceholder
|
|
anchors.fill: parent
|
|
anchors.bottomMargin: Constants.imageBottomMargin
|
|
anchors.rightMargin: Constants.thumbnailMargin
|
|
anchors.leftMargin: Constants.thumbnailMargin
|
|
anchors.topMargin: Constants.thumbnailMargin
|
|
fillMode: Image.PreserveAspectFit
|
|
verticalAlignment: Image.AlignTop
|
|
mipmap: true
|
|
}
|
|
|
|
Rectangle {
|
|
id: projectNameBackground
|
|
height: mainPanel.multiline && !root.hasPath ? Constants.titleHeightMultiline
|
|
: Constants.titleHeight
|
|
color: "#e5b0e4"
|
|
radius: 3
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.top: thumbnailPlaceholder.bottom
|
|
anchors.topMargin: Constants.titleBackgroundTopMargin
|
|
anchors.leftMargin: Constants.thumbnailMargin
|
|
anchors.rightMargin: Constants.thumbnailMargin
|
|
|
|
Text {
|
|
id: projectNameLabel
|
|
color: Constants.currentGlobalText
|
|
text: typeof(displayName) === "undefined" ? projectName : displayName
|
|
elide: root.hasPath ? Text.ElideMiddle : Text.ElideRight
|
|
font.pixelSize: 16
|
|
wrapMode: Text.WordWrap
|
|
maximumLineCount: 2
|
|
clip: false
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.leftMargin: Constants.titleMargin
|
|
anchors.rightMargin: Constants.titleMargin
|
|
|
|
MouseArea {
|
|
id: projectNameMouseArea
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
// Only enable the MouseArea if label actually contains text
|
|
enabled: projectNameLabel.text !== "" ? true : false
|
|
|
|
Connections {
|
|
target: projectNameMouseArea
|
|
onClicked: root.thumbnailClicked()
|
|
}
|
|
}
|
|
|
|
ToolTip {
|
|
id: projectNameToolTip
|
|
y: -projectNameToolTip.height
|
|
visible: projectNameMouseArea.containsMouse && projectNameLabel.truncated
|
|
text: projectNameLabel.text
|
|
delay: 1000
|
|
height: 20
|
|
background: Rectangle {
|
|
color: Constants.currentToolTipBackground
|
|
border.color: Constants.currentToolTipOutline
|
|
border.width: 1
|
|
}
|
|
contentItem: Text {
|
|
color: Constants.currentToolTipText
|
|
text: projectNameToolTip.text
|
|
verticalAlignment: Text.AlignVCenter
|
|
}
|
|
}
|
|
}
|
|
|
|
DownloadButton {
|
|
id: downloadButton
|
|
|
|
anchors.right: parent.right
|
|
anchors.top: parent.top
|
|
visible: root.downloadable
|
|
enabled: !downloadButton.downloadUnavailable
|
|
|
|
globalHover: (mouseArea.containsMouse || projectNameMouseArea.containsMouse)
|
|
&& !downloadButton.alreadyDownloaded
|
|
&& !downloadButton.downloadUnavailable
|
|
&& !downloadButton.updateAvailable
|
|
|
|
alreadyDownloaded: extractor.targetFolderExists
|
|
downloadUnavailable: !downloader.available
|
|
updateAvailable: downloader.lastModified > extractor.birthTime
|
|
|
|
FileDownloader {
|
|
id: downloader
|
|
downloadEnabled: $dataModel.downloadEnabled()
|
|
probeUrl: true
|
|
|
|
onFinishedChanged: {
|
|
downloadPanel.text = downloadPanel.extractText
|
|
downloadPanel.allowCancel = false
|
|
downloadPanel.value = Qt.binding(function() { return extractor.progress })
|
|
extractor.extract()
|
|
}
|
|
|
|
onDownloadStarting: {
|
|
$dataModel.usageStatisticsDownloadExample(downloader.name)
|
|
}
|
|
|
|
onDownloadCanceled: {
|
|
downloadPanel.text = ""
|
|
downloadPanel.value = 0
|
|
twirlToMainAnimation.start()
|
|
mouseArea.enabled = true
|
|
}
|
|
}
|
|
|
|
FileExtractor {
|
|
id: extractor
|
|
archiveName: downloader.completeBaseName
|
|
sourceFile: downloader.outputFile
|
|
targetPath: $dataModel.targetPath()
|
|
alwaysCreateDir: true
|
|
clearTargetPathContents: true
|
|
onFinishedChanged: {
|
|
twirlToMainAnimation.start()
|
|
root.bannerLabelText = qsTr("Recently Downloaded")
|
|
mouseArea.enabled = true
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: downloadButton
|
|
onDownloadClicked: {
|
|
if (downloadButton.alreadyDownloaded) {
|
|
overwriteDialog.open()
|
|
} else {
|
|
if (downloadButton.enabled)
|
|
root.startDownload()
|
|
}
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: $dataModel
|
|
onTargetPathMustChange: (path) => {
|
|
extractor.changeTargetPath(path)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Text {
|
|
id: projectPathLabel
|
|
visible: root.hasPath
|
|
color: Constants.currentBrand
|
|
text: typeof(prettyFilePath) === "undefined" ? "" : prettyFilePath
|
|
elide: Text.ElideLeft
|
|
renderType: Text.NativeRendering
|
|
font.pixelSize: 16
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.top: projectNameBackground.bottom
|
|
anchors.topMargin: 5
|
|
anchors.rightMargin: Constants.thumbnailMargin
|
|
anchors.leftMargin: Constants.thumbnailMargin
|
|
leftPadding: 5
|
|
|
|
MouseArea {
|
|
id: projectPathMouseArea
|
|
anchors.fill: parent
|
|
hoverEnabled: true
|
|
// Only enable the MouseArea if label actually contains text
|
|
enabled: projectPathLabel.text !== ""
|
|
}
|
|
|
|
ToolTip {
|
|
id: projectPathToolTip
|
|
y: -projectPathToolTip.height
|
|
visible: projectPathMouseArea.containsMouse && projectPathLabel.truncated
|
|
text: projectPathLabel.text
|
|
delay: 1000
|
|
height: 20
|
|
background: Rectangle {
|
|
color: Constants.currentToolTipBackground
|
|
border.color: Constants.currentToolTipOutline
|
|
border.width: 1
|
|
}
|
|
contentItem: Text {
|
|
color: Constants.currentToolTipText
|
|
text: projectPathToolTip.text
|
|
verticalAlignment: Text.AlignVCenter
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
id: updateBackground
|
|
width: 200
|
|
height: 25
|
|
visible: root.bannerLabelText !== ""
|
|
color: Constants.currentBrand
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.top: parent.top
|
|
anchors.topMargin: 0
|
|
anchors.rightMargin: Constants.thumbnailMargin
|
|
anchors.leftMargin: Constants.thumbnailMargin
|
|
|
|
Text {
|
|
id: updateText
|
|
color: Constants.darkActiveGlobalText
|
|
text: typeof(displayName) === "bannerText" ? "" : bannerText
|
|
anchors.fill: parent
|
|
font.pixelSize: 12
|
|
horizontalAlignment: Text.AlignHCenter
|
|
verticalAlignment: Text.AlignVCenter
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
id: detailsPanel
|
|
height: Constants.thumbnailSize
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.top: mainPanel.bottom
|
|
color: Constants.currentNormalThumbnailBackground
|
|
radius: 10
|
|
|
|
Text {
|
|
id: recentProjectInfo
|
|
color: Constants.currentGlobalText
|
|
text: typeof(description) === "undefined" ? "" : description
|
|
anchors.fill: parent
|
|
font.pixelSize: 12
|
|
horizontalAlignment: Text.AlignHCenter
|
|
verticalAlignment: Text.AlignTop
|
|
wrapMode: Text.WordWrap
|
|
anchors.margins: Constants.thumbnailMargin
|
|
anchors.topMargin: 25
|
|
}
|
|
|
|
TagArea {
|
|
id: tagArea
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.bottom: parent.bottom
|
|
anchors.bottomMargin: Constants.thumbnailMargin
|
|
anchors.rightMargin: Constants.thumbnailMargin
|
|
anchors.leftMargin: Constants.thumbnailMargin
|
|
tags: typeof(tagData) === "undefined" ? "" : tagData.split(",")
|
|
}
|
|
}
|
|
}
|
|
|
|
states: [
|
|
State {
|
|
name: "normal"
|
|
when: !mouseArea.containsMouse && !(mouseArea.pressedButtons & Qt.LeftButton)
|
|
&& !projectPathMouseArea.containsMouse && !projectNameMouseArea.containsMouse
|
|
&& !downloadButton.isHovered && !twirlButtonDown.isHovered
|
|
&& !twirlButtonUp.isHovered
|
|
|
|
PropertyChanges {
|
|
target: mainPanel
|
|
color: Constants.currentNormalThumbnailBackground
|
|
border.width: 0
|
|
}
|
|
PropertyChanges {
|
|
target: detailsPanel
|
|
color: Constants.currentNormalThumbnailBackground
|
|
border.width: 0
|
|
}
|
|
PropertyChanges {
|
|
target: projectNameBackground
|
|
color: Constants.currentNormalThumbnailLabelBackground
|
|
}
|
|
PropertyChanges {
|
|
target: twirlButtonDown
|
|
parentHovered: false
|
|
}
|
|
PropertyChanges {
|
|
target: twirlButtonUp
|
|
parentHovered: false
|
|
}
|
|
},
|
|
State {
|
|
name: "hover"
|
|
when: (mouseArea.containsMouse || projectPathMouseArea.containsMouse
|
|
|| projectNameMouseArea.containsMouse || downloadButton.isHovered
|
|
|| twirlButtonDown.isHovered || twirlButtonUp.isHovered)
|
|
&& !(mouseArea.pressedButtons & Qt.LeftButton) && !root.hasDescription
|
|
|
|
PropertyChanges {
|
|
target: mainPanel
|
|
color: Constants.currentHoverThumbnailBackground
|
|
border.width: 0
|
|
}
|
|
PropertyChanges {
|
|
target: detailsPanel
|
|
color: Constants.currentHoverThumbnailBackground
|
|
border.width: 0
|
|
}
|
|
PropertyChanges {
|
|
target: projectNameBackground
|
|
color: Constants.currentHoverThumbnailLabelBackground
|
|
}
|
|
PropertyChanges {
|
|
target: thumbnailPlaceholder
|
|
visible: true
|
|
}
|
|
PropertyChanges {
|
|
target: twirlButtonDown
|
|
parentHovered: true
|
|
}
|
|
PropertyChanges {
|
|
target: twirlButtonUp
|
|
parentHovered: true
|
|
}
|
|
},
|
|
State {
|
|
name: "press"
|
|
when: (mouseArea.pressedButtons & Qt.LeftButton) && !root.hasDescription
|
|
|
|
PropertyChanges {
|
|
target: mainPanel
|
|
color: Constants.currentHoverThumbnailBackground
|
|
border.color: Constants.currentBrand
|
|
border.width: 2
|
|
}
|
|
PropertyChanges {
|
|
target: detailsPanel
|
|
color: Constants.currentHoverThumbnailBackground
|
|
border.color: Constants.currentBrand
|
|
border.width: 2
|
|
}
|
|
PropertyChanges {
|
|
target: projectNameBackground
|
|
color: Constants.currentBrand
|
|
}
|
|
PropertyChanges {
|
|
target: thumbnailPlaceholder
|
|
visible: true
|
|
}
|
|
PropertyChanges {
|
|
target: projectNameLabel
|
|
color: Constants.darkActiveGlobalText
|
|
}
|
|
},
|
|
State {
|
|
name: "hoverDescription"
|
|
when: mouseArea.containsMouse && !(mouseArea.pressedButtons & Qt.LeftButton)
|
|
&& root.hasDescription
|
|
|
|
PropertyChanges {
|
|
target: mainPanel
|
|
color: Constants.currentHoverThumbnailBackground
|
|
border.width: 0
|
|
}
|
|
PropertyChanges {
|
|
target: projectNameBackground
|
|
color: Constants.currentHoverThumbnailLabelBackground
|
|
}
|
|
PropertyChanges {
|
|
target: thumbnailPlaceholder
|
|
visible: true
|
|
}
|
|
},
|
|
State {
|
|
name: "pressDescription"
|
|
when: (mouseArea.pressedButtons & Qt.LeftButton) && root.hasDescription
|
|
|
|
PropertyChanges {
|
|
target: mainPanel
|
|
color: Constants.currentHoverThumbnailBackground
|
|
border.color: Constants.currentBrand
|
|
border.width: 2
|
|
}
|
|
PropertyChanges {
|
|
target: projectNameBackground
|
|
color: Constants.currentBrand
|
|
}
|
|
PropertyChanges {
|
|
target: thumbnailPlaceholder
|
|
visible: true
|
|
}
|
|
}
|
|
]
|
|
|
|
TwirlButton {
|
|
id: twirlButtonDown
|
|
height: 20
|
|
visible: root.currentPanel === ThumbnailDelegate.Panel.Main
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.bottom: parent.bottom
|
|
|
|
Connections {
|
|
target: twirlButtonDown
|
|
onTriggerRelease: twirlToDetailsAnimation.start()
|
|
}
|
|
}
|
|
|
|
TwirlButton {
|
|
id: twirlButtonUp
|
|
height: 20
|
|
visible: root.currentPanel === ThumbnailDelegate.Panel.Details
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.top: parent.top
|
|
rotation: 180
|
|
|
|
Connections {
|
|
target: twirlButtonUp
|
|
onTriggerRelease: twirlToMainAnimation.start()
|
|
}
|
|
}
|
|
|
|
NumberAnimation {
|
|
id: twirlToDetailsAnimation
|
|
target: canvas
|
|
property: "y"
|
|
easing.bezierCurve: [0.972,-0.176,0.0271,1.16,1,1]
|
|
duration: 250
|
|
alwaysRunToEnd: true
|
|
to: -Constants.thumbnailSize // dynamic size because of rescale - needs to be inverted because animation goes into negative range
|
|
from: canvas.y
|
|
}
|
|
|
|
NumberAnimation {
|
|
id: twirlToMainAnimation
|
|
target: canvas
|
|
property: "y"
|
|
easing.bezierCurve: [0.972,-0.176,0.0271,1.16,1,1]
|
|
alwaysRunToEnd: true
|
|
duration: 250
|
|
to: 0
|
|
from: canvas.y
|
|
}
|
|
|
|
NumberAnimation {
|
|
id: twirlToDownloadAnimation
|
|
target: canvas
|
|
property: "y"
|
|
easing.bezierCurve: [0.972,-0.176,0.0271,1.16,1,1]
|
|
alwaysRunToEnd: true
|
|
duration: 250
|
|
to: Constants.thumbnailSize
|
|
from: canvas.y
|
|
}
|
|
|
|
Connections {
|
|
target: twirlToDetailsAnimation
|
|
onStarted: root.currentPanel = ThumbnailDelegate.Panel.InBetween
|
|
onFinished: {
|
|
root.currentPanel = ThumbnailDelegate.Panel.Details
|
|
canvas.y = Qt.binding(function() {return -Constants.thumbnailSize })
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: twirlToMainAnimation
|
|
onStarted: root.currentPanel = ThumbnailDelegate.Panel.InBetween
|
|
onFinished: {
|
|
root.currentPanel = ThumbnailDelegate.Panel.Main
|
|
canvas.y = Qt.binding(function() {return 0 })
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: twirlToDownloadAnimation
|
|
onStarted: root.currentPanel = ThumbnailDelegate.Panel.InBetween
|
|
onFinished: {
|
|
root.currentPanel = ThumbnailDelegate.Panel.Download
|
|
canvas.y = Qt.binding(function() {return Constants.thumbnailSize })
|
|
}
|
|
}
|
|
}
|