diff --git a/share/qtcreator/qmldesigner/welcomepage/BrandBar.qml b/share/qtcreator/qmldesigner/welcomepage/BrandBar.qml
new file mode 100644
index 00000000000..721e2b06dd9
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/BrandBar.qml
@@ -0,0 +1,64 @@
+// 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 WelcomeScreen 1.0
+
+Item {
+ id: brandBar
+ width: 850
+ height: 150
+
+ Image {
+ id: brandIcon
+ width: 100
+ height: 100
+ anchors.verticalCenter: parent.verticalCenter
+ source: "images/ds.png"
+ fillMode: Image.PreserveAspectFit
+ }
+
+ Text {
+ id: welcomeTo
+ color: Constants.currentGlobalText
+ text: qsTr("Welcome to")
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.left: brandIcon.right
+ anchors.leftMargin: 5
+ verticalAlignment: Text.AlignVCenter
+ font.pixelSize: 36
+ font.family: "titillium web"
+ }
+
+ Text {
+ id: brandLabel
+ color: Constants.currentBrand
+ text: qsTr("Qt Design Studio")
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.left: welcomeTo.right
+ anchors.leftMargin: 8
+ verticalAlignment: Text.AlignVCenter
+ font.pixelSize: 36
+ font.family: "titillium web"
+ }
+
+ Text {
+ width: 291
+ height: 55
+ color: Constants.currentGlobalText
+ text: {
+ if (Constants.communityEdition)
+ return qsTr("Community Edition")
+ if (Constants.enterpriseEdition)
+ return qsTr("Enterprise Edition")
+ return qsTr("Professional Edition")
+ }
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.left: brandLabel.right
+ anchors.leftMargin: 8
+ verticalAlignment: Text.AlignVCenter
+ font.pixelSize: 36
+ font.family: "titillium web"
+ }
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/CheckButton.ui.qml b/share/qtcreator/qmldesigner/welcomepage/CheckButton.ui.qml
new file mode 100644
index 00000000000..1e1f4557a1c
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/CheckButton.ui.qml
@@ -0,0 +1,108 @@
+// 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.Templates
+import WelcomeScreen 1.0
+
+Button {
+ id: control
+
+ implicitWidth: Math.max(
+ buttonBackground ? buttonBackground.implicitWidth : 0,
+ textItem.implicitWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(
+ buttonBackground ? buttonBackground.implicitHeight : 0,
+ textItem.implicitHeight + topPadding + bottomPadding)
+ leftPadding: 4
+ rightPadding: 4
+
+ text: "My Button"
+ checkable: true
+ state: "normal"
+
+ property bool decorated: false
+
+ background: Rectangle {
+ id: buttonBackground
+ color: "#00000000"
+ implicitWidth: 100
+ implicitHeight: 40
+ opacity: buttonBackground.enabled ? 1 : 0.3
+ radius: 2
+ border.color: "#047eff"
+ anchors.fill: parent
+ }
+
+ contentItem: Text {
+ id: textItem
+ text: control.text
+ font.pixelSize: 18
+ opacity: textItem.enabled ? 1.0 : 0.3
+ color: "#047eff"
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Rectangle {
+ id: decoration
+ width: 10
+ visible: control.decorated
+ color: Constants.currentBrand
+ border.color: Constants.currentBrand
+ anchors.right: parent.right
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ anchors.rightMargin: 1
+ anchors.bottomMargin: 1
+ anchors.topMargin: 1
+ }
+
+ states: [
+ State {
+ name: "normal"
+ when: !control.down && !control.hovered && !control.checked
+
+ PropertyChanges {
+ target: buttonBackground
+ color: Constants.currentPushButtonNormalBackground
+ border.color: Constants.currentPushButtonNormalOutline
+ }
+
+ PropertyChanges {
+ target: textItem
+ color: Constants.currentGlobalText
+ }
+ },
+ State {
+ name: "hover"
+ when: control.hovered && !control.checked && !control.down
+
+ PropertyChanges {
+ target: textItem
+ color: Constants.currentGlobalText
+ }
+
+ PropertyChanges {
+ target: buttonBackground
+ color: Constants.currentPushButtonHoverBackground
+ border.color: Constants.currentPushButtonHoverOutline
+ }
+ },
+ State {
+ name: "active"
+ when: control.checked || control.down
+
+ PropertyChanges {
+ target: textItem
+ color: Constants.darkActiveGlobalText
+ }
+
+ PropertyChanges {
+ target: buttonBackground
+ color: Constants.currentBrand
+ border.color: "#00000000"
+ }
+ }
+ ]
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/CustomDialog.qml b/share/qtcreator/qmldesigner/welcomepage/CustomDialog.qml
new file mode 100644
index 00000000000..76b3c4c8e70
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/CustomDialog.qml
@@ -0,0 +1,42 @@
+// 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 WelcomeScreen 1.0
+
+Dialog {
+ id: root
+ padding: 12
+
+ background: Rectangle {
+ color: Constants.currentDialogBackground
+ border.color: Constants.currentDialogBorder
+ border.width: 1
+ }
+
+ header: Label {
+ text: root.title
+ visible: root.title
+ elide: Label.ElideRight
+ font.bold: true
+ padding: 12
+ color: Constants.currentGlobalText
+
+ background: Rectangle {
+ x: 1
+ y: 1
+ width: parent.width - 2
+ height: parent.height - 1
+ color: Constants.currentDialogBackground
+ }
+ }
+
+ footer: CustomDialogButtonBox {
+ visible: count > 0
+ }
+
+ Overlay.modal: Rectangle {
+ color: Color.transparent(Constants.currentDialogBackground, 0.5)
+ }
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/CustomDialogButtonBox.qml b/share/qtcreator/qmldesigner/welcomepage/CustomDialogButtonBox.qml
new file mode 100644
index 00000000000..8437e5dbe35
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/CustomDialogButtonBox.qml
@@ -0,0 +1,25 @@
+// 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 WelcomeScreen 1.0
+
+DialogButtonBox {
+ id: root
+ padding: 12
+ alignment: Qt.AlignRight | Qt.AlignBottom
+
+ background: Rectangle {
+ implicitHeight: 40
+ x: 1
+ y: 1
+ width: parent.width - 2
+ height: parent.height - 2
+ color: Constants.currentDialogBackground
+ }
+
+ delegate: DialogButton {
+ width: root.count === 1 ? root.availableWidth / 2 : undefined
+ }
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/CustomGrid.qml b/share/qtcreator/qmldesigner/welcomepage/CustomGrid.qml
new file mode 100644
index 00000000000..bc7c4faf4ab
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/CustomGrid.qml
@@ -0,0 +1,41 @@
+// 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.Layouts
+import WelcomeScreen 1.0
+import DataModels 1.0
+
+Item {
+ id: gridContainer
+ width: 1460
+ height: 760
+
+ property alias hover: scrollView.outsideHover
+ property alias model: gridView.model
+ property alias delegate: gridView.delegate
+
+ Connections {
+ target: gridContainer
+ onWidthChanged: Constants.responsiveResize(gridContainer.width)
+ }
+
+ CustomScrollView {
+ id: scrollView
+ anchors.fill: parent
+
+ GridView {
+ id: gridView
+ clip: true
+ anchors.fill: parent
+ rightMargin: -Constants.gridSpacing
+ bottomMargin: -Constants.gridSpacing
+ boundsBehavior: Flickable.StopAtBounds
+ cellWidth: Constants.gridCellSize
+ cellHeight: Constants.gridCellSize
+
+ model: ExamplesModel {}
+ delegate: ThumbnailDelegate {}
+ }
+ }
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/CustomScrollBar.qml b/share/qtcreator/qmldesigner/welcomepage/CustomScrollBar.qml
new file mode 100644
index 00000000000..1cc020774fd
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/CustomScrollBar.qml
@@ -0,0 +1,98 @@
+// 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.Templates as T
+import WelcomeScreen 1.0
+import StudioTheme 1.0 as StudioTheme
+
+T.ScrollBar {
+ id: control
+
+ property bool show: false
+ property bool otherInUse: false
+ property bool isNeeded: control.size < 1.0
+ property bool inUse: control.hovered || control.pressed
+ property int thickness: control.inUse || control.otherInUse ? 10 : 8
+
+ property bool scrollBarVisible: parent.childrenRect.height > parent.height
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ hoverEnabled: true
+ padding: 0
+ minimumSize: orientation === Qt.Horizontal ? height / width : width / height
+
+ opacity: 0.0
+
+ contentItem: Rectangle {
+ implicitWidth: control.thickness
+ implicitHeight: control.thickness
+ radius: width / 2
+ color: control.inUse ? Constants.currentScrollBarHandle
+ : Constants.currentScrollBarHandle_idle
+ }
+
+ background: Rectangle {
+ id: controlTrack
+ color: Constants.currentScrollBarTrack
+ opacity: control.inUse || control.otherInUse ? 0.3 : 0.0
+ radius: width / 2
+
+ Behavior on opacity {
+ PropertyAnimation {
+ duration: 100
+ easing.type: Easing.InOutQuad
+ }
+ }
+ }
+
+ states: [
+ State {
+ name: "show"
+ when: control.show
+ PropertyChanges {
+ target: control
+ opacity: 1.0
+ }
+ },
+ State {
+ name: "hide"
+ when: !control.show
+ PropertyChanges {
+ target: control
+ opacity: 0.0
+ }
+ }
+ ]
+
+ transitions: Transition {
+ from: "show"
+ SequentialAnimation {
+ PauseAnimation { duration: 450 }
+ NumberAnimation {
+ target: control
+ duration: 200
+ property: "opacity"
+ to: 0.0
+ }
+ }
+ }
+
+ Behavior on thickness {
+ PropertyAnimation {
+ duration: 100
+ easing.type: Easing.InOutQuad
+ }
+ }
+
+ Behavior on x {
+ PropertyAnimation {
+ duration: 100
+ easing.type: Easing.InOutQuad
+ }
+ }
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/CustomScrollView.qml b/share/qtcreator/qmldesigner/welcomepage/CustomScrollView.qml
new file mode 100644
index 00000000000..5526cb3e1d6
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/CustomScrollView.qml
@@ -0,0 +1,25 @@
+// 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.Templates as T
+
+T.ScrollView {
+ id: control
+
+ property bool outsideHover: false
+
+ hoverEnabled: true
+
+ T.ScrollBar.vertical: CustomScrollBar {
+ id: verticalScrollBar
+ parent: control
+ x: control.width + (verticalScrollBar.inUse ? 4 : 5)
+ y: control.topPadding
+ height: control.availableHeight
+ orientation: Qt.Vertical
+
+ show: (control.hovered || control.focus || control.outsideHover)
+ && verticalScrollBar.isNeeded
+ }
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/DialogButton.qml b/share/qtcreator/qmldesigner/welcomepage/DialogButton.qml
new file mode 100644
index 00000000000..e7fb13e0422
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/DialogButton.qml
@@ -0,0 +1,89 @@
+// 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.Templates
+import WelcomeScreen 1.0
+
+Button {
+ id: root
+
+ implicitWidth: Math.max(
+ background ? background.implicitWidth : 0,
+ textItem.implicitWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(
+ background ? background.implicitHeight : 0,
+ textItem.implicitHeight + topPadding + bottomPadding)
+ leftPadding: 4
+ rightPadding: 4
+
+
+ background: Rectangle {
+ id: background
+ implicitWidth: 80
+ implicitHeight: 20
+ opacity: enabled ? 1 : 0.3
+ radius: 2
+ color: Constants.currentPushButtonNormalBackground
+ border.color: Constants.currentPushButtonNormalOutline
+ anchors.fill: parent
+ }
+
+ contentItem: Text {
+ id: textItem
+ text: root.text
+ font.pixelSize: 12
+ opacity: enabled ? 1.0 : 0.3
+ color: Constants.currentGlobalText
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ states: [
+ State {
+ name: "default"
+ when: !root.down && !root.hovered && !root.checked
+
+ PropertyChanges {
+ target: background
+ color: Constants.currentPushButtonNormalBackground
+ border.color: Constants.currentPushButtonNormalOutline
+ }
+
+ PropertyChanges {
+ target: textItem
+ color: Constants.currentGlobalText
+ }
+ },
+ State {
+ name: "hover"
+ when: root.hovered && !root.checked && !root.down
+
+ PropertyChanges {
+ target: textItem
+ color: Constants.currentGlobalText
+ }
+
+ PropertyChanges {
+ target: background
+ color: Constants.currentPushButtonHoverBackground
+ border.color: Constants.currentPushButtonHoverOutline
+ }
+ },
+ State {
+ name: "active"
+ when: root.checked || root.down
+
+ PropertyChanges {
+ target: textItem
+ color: Constants.currentActiveGlobalText
+ }
+
+ PropertyChanges {
+ target: background
+ color: Constants.currentBrand
+ border.color: "#00000000"
+ }
+ }
+ ]
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/DownloadButton.qml b/share/qtcreator/qmldesigner/welcomepage/DownloadButton.qml
new file mode 100644
index 00000000000..07f107eb330
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/DownloadButton.qml
@@ -0,0 +1,134 @@
+// 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 WelcomeScreen 1.0
+import StudioTheme 1.0 as StudioTheme
+
+Item {
+ id: root
+ width: 30
+ height: 30
+ state: "default"
+
+ property bool dowloadPressed: false
+ property bool isHovered: mouseArea.containsMouse
+
+ property bool globalHover: false
+
+ property bool alreadyDownloaded: false
+ property bool updateAvailable: false
+ property bool downloadUnavailable: false
+
+ signal downloadClicked()
+
+ property color currentColor: {
+ if (root.updateAvailable)
+ return Constants.amberLight
+ if (root.alreadyDownloaded)
+ return Constants.greenLight
+ if (root.downloadUnavailable)
+ return Constants.redLight
+
+ return Constants.currentGlobalText
+ }
+
+ property string currentIcon: {
+ if (root.updateAvailable)
+ return StudioTheme.Constants.downloadUpdate
+ if (root.alreadyDownloaded)
+ return StudioTheme.Constants.downloaded
+ if (root.downloadUnavailable)
+ return StudioTheme.Constants.downloadUnavailable
+
+ return StudioTheme.Constants.download
+ }
+
+ property string currentToolTipText: {
+ if (root.updateAvailable)
+ return qsTr("Update available.")
+ if (root.alreadyDownloaded)
+ return qsTr("Example was already downloaded.")
+ if (root.downloadUnavailable)
+ return qsTr("Network or example is not available or the link is broken.")
+
+ return qsTr("Download the example.")
+ }
+
+ Text {
+ id: downloadIcon
+ color: root.currentColor
+ font.family: StudioTheme.Constants.iconFont.family
+ text: root.currentIcon
+ anchors.fill: parent
+ font.pixelSize: 22
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ anchors.bottomMargin: 0
+ }
+
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+ hoverEnabled: true
+ propagateComposedEvents: true
+
+ Connections {
+ target: mouseArea
+ onClicked: root.downloadClicked()
+ }
+ }
+
+ ToolTip {
+ id: toolTip
+ y: -toolTip.height
+ visible: mouseArea.containsMouse
+ text: root.currentToolTipText
+ delay: 1000
+ height: 20
+ background: Rectangle {
+ color: Constants.currentToolTipBackground
+ border.color: Constants.currentToolTipOutline
+ border.width: 1
+ }
+ contentItem: Text {
+ color: Constants.currentToolTipText
+ text: toolTip.text
+ verticalAlignment: Text.AlignVCenter
+ }
+ }
+
+ states: [
+ State {
+ name: "default"
+ when: !mouseArea.pressed && !mouseArea.containsMouse && !root.globalHover
+ PropertyChanges {
+ target: downloadIcon
+ color: root.currentColor
+ }
+ },
+ State {
+ name: "pressed"
+ when: mouseArea.pressed && mouseArea.containsMouse
+ PropertyChanges {
+ target: downloadIcon
+ color: Constants.currentBrand
+ scale: 1.2
+ }
+ },
+ State {
+ name: "hover"
+ when: mouseArea.containsMouse && !mouseArea.pressed && !root.globalHover
+ PropertyChanges {
+ target: downloadIcon
+ scale: 1.2
+ }
+ },
+ State {
+ name: "globalHover"
+ extend: "hover"
+ when: root.globalHover && !mouseArea.pressed && !mouseArea.containsMouse
+ }
+ ]
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/DownloadPanel.qml b/share/qtcreator/qmldesigner/welcomepage/DownloadPanel.qml
new file mode 100644
index 00000000000..8cd70997871
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/DownloadPanel.qml
@@ -0,0 +1,79 @@
+// 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 WelcomeScreen 1.0
+
+Rectangle {
+ id: root
+ color: Constants.currentNormalThumbnailBackground
+
+ property alias value: progressBar.value
+ property alias text: progressLabel.text
+ property alias allowCancel: progressBar.closeButtonVisible
+
+ readonly property int pixelSize: 12
+ readonly property int textMargin: 5
+
+ signal cancelRequested
+
+ DownloadProgressBar {
+ id: progressBar
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: pushButton.top
+ anchors.bottomMargin: 40
+ anchors.rightMargin: 10
+ anchors.leftMargin: 10
+
+ onCancelRequested: root.cancelRequested()
+
+ Text {
+ id: progressLabel
+ color: Constants.currentGlobalText
+ text: qsTr("Progress:")
+ anchors.top: parent.bottom
+ anchors.topMargin: root.textMargin
+ anchors.left: parent.left
+ font.pixelSize: root.pixelSize
+ }
+
+ Text {
+ id: progressAmount
+ color: Constants.currentGlobalText
+ text: stringMapper.text
+ anchors.top: parent.bottom
+ anchors.topMargin: root.textMargin
+ anchors.right: percentSign.left
+ anchors.rightMargin: root.textMargin
+ font.pixelSize: root.pixelSize
+ }
+
+ Text {
+ id: percentSign
+ color: Constants.currentGlobalText
+ text: qsTr("%")
+ anchors.right: parent.right
+ anchors.top: parent.bottom
+ anchors.topMargin: root.textMargin
+ font.pixelSize: root.pixelSize
+ }
+ }
+
+ PushButton {
+ id: pushButton
+ y: 177
+ visible: progressBar.downloadFinished
+ text: qsTr("Open")
+ anchors.bottom: parent.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottomMargin: 40
+ }
+
+ StringMapper {
+ id: stringMapper
+ decimals: 1
+ input: root.value
+ }
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/DownloadProgressBar.qml b/share/qtcreator/qmldesigner/welcomepage/DownloadProgressBar.qml
new file mode 100644
index 00000000000..5fb0f637cad
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/DownloadProgressBar.qml
@@ -0,0 +1,80 @@
+// 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 WelcomeScreen 1.0
+import StudioTheme as StudioTheme
+
+Item {
+ id: progressBar
+ width: 272
+ height: 25
+ property bool downloadFinished: false
+ property int value: 0
+ property bool closeButtonVisible
+ //property alias numberAnimationRunning: numberAnimation.running
+
+ readonly property int margin: 4
+
+ signal cancelRequested
+
+ Rectangle {
+ id: progressBarGroove
+ color: Constants.currentNormalThumbnailLabelBackground
+ anchors.fill: parent
+ }
+
+ Rectangle {
+ id: progressBarTrack
+ width: progressBar.value * ((progressBar.width - closeButton.width) - 2 * progressBar.margin) / 100
+ color: Constants.currentBrand
+ border.color: "#002e769e"
+ anchors.left: parent.left
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ anchors.margins: progressBar.margin
+ }
+
+ Text {
+ id: closeButton
+ visible: progressBar.closeButtonVisible
+ width: 20
+ text: StudioTheme.Constants.closeCross
+ color: Constants.currentBrand
+ horizontalAlignment: Qt.AlignHCenter
+ verticalAlignment: Qt.AlignVCenter
+ font.family: StudioTheme.Constants.iconFont.family
+ font.pixelSize: StudioTheme.Values.myIconFontSize
+
+ anchors.right: parent.right
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ anchors.margins: progressBar.margin
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: {
+ progressBar.cancelRequested()
+ }
+ }
+ }
+
+/*
+ NumberAnimation {
+ id: numberAnimation
+ target: progressBarTrack
+ property: "width"
+ duration: 2500
+ easing.bezierCurve: [0.197,0.543,0.348,0.279,0.417,0.562,0.437,0.757,0.548,0.731,0.616,0.748,0.728,0.789,0.735,0.982,1,1]
+ alwaysRunToEnd: true
+ to: progressBar.width
+ from: 0
+ }
+
+ Connections {
+ target: numberAnimation
+ onFinished: progressBar.downloadFinished = true
+ }
+*/
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/MainGridStack.qml b/share/qtcreator/qmldesigner/welcomepage/MainGridStack.qml
new file mode 100644
index 00000000000..73b023bddc0
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/MainGridStack.qml
@@ -0,0 +1,166 @@
+// 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 projectmodel 1.0
+import DataModels 1.0
+import UiTour
+import StudioControls as StudioControls
+
+Item {
+ id: thumbnails
+ width: 1500
+ height: 800
+ clip: true
+
+ property alias stackLayoutCurrentIndex: gridStackLayout.currentIndex
+ property var projectModel: Constants.projectModel
+
+ Rectangle {
+ id: thumbnailGridBack
+ color: Constants.currentThumbnailGridBackground
+ anchors.fill: parent
+
+ HoverHandler { id: hoverHandler }
+
+ StackLayout {
+ id: gridStackLayout
+ visible: !Constants.isListView
+ anchors.fill: parent
+ anchors.margins: Constants.gridMargins
+ currentIndex: 0
+
+ CustomGrid {
+ id: recentGrid
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ hover: hoverHandler.hovered
+ model: thumbnails.projectModel
+ delegate: ThumbnailDelegate {
+ id: delegate
+ type: ThumbnailDelegate.Type.RecentProject
+ hasPath: true
+ thumbnailPlaceholderSource: previewUrl
+ onClicked: projectModel.openProjectAt(index)
+ onRightClicked: {
+ removeMenuItem.index = index
+ contextMenu.popup(delegate)
+ }
+ }
+
+ Text {
+ text: qsTr("Create a new project using the \"Create Project\" or open an existing project using the \"Open Project\" option. ")
+ font.pixelSize: 18
+ color: Constants.currentGlobalText
+ anchors.centerIn: parent
+ width: recentGrid.width
+ horizontalAlignment: Text.AlignHCenter
+ leftPadding: 20
+ rightPadding: 20
+ wrapMode: Text.WordWrap
+ visible: projectModel.count === 0
+ }
+
+ StudioControls.Menu {
+ id: contextMenu
+
+ StudioControls.MenuItem {
+ id: removeMenuItem
+
+ property int index: -1
+
+ text: qsTr("Remove Project from Recent Projects")
+ onTriggered: projectModel.removeFromRecentProjects(removeMenuItem.index)
+ }
+
+ StudioControls.MenuItem {
+ text: qsTr("Clear Recent Project List")
+ onTriggered: projectModel.clearRecentProjects()
+ }
+ }
+ }
+
+ CustomGrid {
+ id: examplesGrid
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ hover: hoverHandler.hovered
+ model: ExamplesModel { id: examplesModel}
+ delegate: ThumbnailDelegate {
+ type: ThumbnailDelegate.Type.Example
+ downloadable: showDownload
+ hasUpdate: showUpdate
+ downloadUrl: url
+ thumbnailPlaceholderSource: examplesModel.resolveUrl(thumbnail)
+ onClicked: projectModel.openExample(targetPath,
+ projectName,
+ qmlFileName,
+ explicitQmlproject)
+ }
+ }
+
+ CustomGrid {
+ id: tutorialsGrid
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ hover: hoverHandler.hovered
+ model: TutorialsModel { id: tutorialsModel}
+ delegate: ThumbnailDelegate {
+ type: ThumbnailDelegate.Type.Tutorial
+ thumbnailPlaceholderSource: tutorialsModel.resolveUrl(thumbnail)
+ onClicked: Qt.openUrlExternally(url)
+ }
+ }
+
+ CustomGrid {
+ id: tourGrid
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ hover: hoverHandler.hovered
+ model: TourModel {}
+ delegate: TourThumbnailDelegate {
+ id: thumbnailDelegate
+ visible: !slidePlayer.visible
+ enabled: !slidePlayer.visible
+
+ Connections {
+ target: thumbnailDelegate
+ onClicked: tourGrid.startTour(qmlFileName)
+ }
+ }
+
+ function startTour(url) {
+ slidePlayer.visible = true
+ slidePlayer.slideSource = Qt.resolvedUrl(url)
+ }
+
+ SlidePlayer {
+ id: slidePlayer
+ anchors.fill: parent
+ visible: false
+ }
+
+ TourDialogButton {
+ id: closeButton
+ anchors.right: parent.right
+ anchors.top: parent.top
+ anchors.rightMargin: 16
+ anchors.topMargin: 16
+ visible: slidePlayer.visible
+
+ Connections {
+ target: closeButton
+ onButtonClicked: {
+ slidePlayer.visible = false
+ slidePlayer.loaderActive = false
+ slidePlayer.loaderActive = true
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/MainScreen.qml b/share/qtcreator/qmldesigner/welcomepage/MainScreen.qml
new file mode 100644
index 00000000000..b2e09d43081
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/MainScreen.qml
@@ -0,0 +1,318 @@
+// 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 projectmodel 1.0
+import DataModels 1.0
+
+Rectangle {
+ id: appBackground
+ height: Constants.height
+ color: Constants.currentThemeBackground
+ width: 1842
+ //anchors.fill: parent //this is required to make it responsive but commented out to force minimum size to work
+ property int pageIndex: 0
+ property bool designMode: !(typeof (Constants.projectModel.designMode) === "undefined")
+
+ signal openUiTour
+ signal closeUiTour
+
+ function uiTourClosed() {
+ recentProjects.checked = true
+ }
+
+ TestControlPanel {
+ id: controlPanel
+ x: 1644
+ width: 220
+ height: 127
+ visible: appBackground.designMode
+ anchors.right: parent.right
+ anchors.top: parent.top
+ anchors.topMargin: 15
+ anchors.rightMargin: 56
+ }
+
+ ColumnLayout {
+ id: openCreatelayout
+ y: 150
+ anchors.left: parent.left
+ anchors.right: thumbnails.left
+ anchors.rightMargin: 20
+ spacing: 15
+ anchors.leftMargin: 20
+
+ PushButton {
+ id: createProject
+ height: 50
+ text: qsTr("Create Project ...")
+
+ Layout.maximumHeight: 75
+ Layout.minimumHeight: 25
+ Layout.fillWidth: true
+ Layout.preferredHeight: 50
+ decorated: true
+ onClicked: Constants.projectModel.createProject()
+ }
+
+ PushButton {
+ id: openProject
+ height: 50
+ text: qsTr("Open Project ...")
+
+ Layout.maximumHeight: 75
+ Layout.minimumHeight: 25
+ Layout.fillWidth: true
+ Layout.preferredHeight: 50
+ decorated: true
+ onClicked: Constants.projectModel.openProject()
+ }
+
+ Text {
+ id: newQtLabel
+ width: 266
+ height: 40
+ color: Constants.currentGlobalText
+ text: qsTr("New to Qt?")
+ font.pixelSize: 24
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ Layout.fillWidth: true
+ }
+
+ PushButton {
+ id: getStarted
+ height: 50
+ text: qsTr("Get Started")
+ Layout.maximumHeight: 75
+ Layout.minimumHeight: 25
+ Layout.preferredHeight: 50
+ Layout.fillWidth: true
+ onClicked: Constants.projectModel.showHelp()
+ }
+ }
+
+ ColumnLayout {
+ id: currentPageMenuLayout
+ y: 422
+ anchors.left: parent.left
+ anchors.right: thumbnails.left
+ anchors.rightMargin: 20
+ anchors.leftMargin: 20
+ spacing: 15
+
+ CheckButton {
+ id: recentProjects
+ text: qsTr("Recent Projects")
+ autoExclusive: true
+ checked: true
+ Layout.fillWidth: true
+
+ Connections {
+ target: recentProjects
+ function onClicked(mouse) { appBackground.pageIndex = 0 }
+ }
+ }
+
+ CheckButton {
+ id: examples
+ text: qsTr("Examples")
+ autoExclusive: true
+ Layout.fillWidth: true
+
+ Connections {
+ target: examples
+ function onClicked(mouse) { appBackground.pageIndex = 1 }
+ }
+ }
+
+ CheckButton {
+ id: tutorials
+ text: qsTr("Tutorials")
+ autoExclusive: true
+ Layout.fillWidth: true
+
+ Connections {
+ target: tutorials
+ function onClicked(mouse) { appBackground.pageIndex = 2 }
+ }
+ }
+
+ CheckButton {
+ id: tours
+ text: qsTr("UI Tour")
+ autoExclusive: true
+ Layout.fillWidth: true
+
+ Connections {
+ target: tours
+ function onClicked(mouse) { appBackground.pageIndex = 3 }
+ }
+ }
+ }
+
+ BrandBar {
+ id: brandBar
+ y: 0
+ anchors.left: parent.left
+ anchors.leftMargin: 20
+
+ Rectangle {
+ id: loadProgress
+ x: 4
+ y: 120
+ width: Constants.loadingProgress * 10
+ height: 4
+ color: Constants.currentGlobalText
+ opacity: Constants.loadingProgress > 90 ? (100 - Constants.loadingProgress) / 10 : 1
+ }
+ }
+
+ MainGridStack {
+ id: thumbnails
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ anchors.topMargin: 150
+ anchors.rightMargin: 56
+ anchors.bottomMargin: 54
+ anchors.leftMargin: 290
+ stackLayoutCurrentIndex: appBackground.pageIndex
+ }
+
+ RowLayout {
+ id: linkRow
+ y: 1041
+ height: 25
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ anchors.leftMargin: 290
+ anchors.rightMargin: 55
+ anchors.bottomMargin: 14
+ spacing: 0
+
+ PushButton {
+ id: userGuide
+ text: qsTr("User Guide")
+ fontpixelSize: 12
+ Layout.minimumWidth: 100
+ Layout.fillWidth: true
+ Layout.preferredHeight: 25
+ Layout.preferredWidth: 200
+ decorated: true
+ onClicked: Qt.openUrlExternally("https://doc.qt.io/qtdesignstudio/")
+ }
+
+ Item {
+ width: 200
+ height: 200
+ Layout.fillWidth: true
+ Layout.preferredWidth: 50
+ Layout.preferredHeight: 25
+ }
+
+ PushButton {
+ id: blog
+ text: qsTr("Blog")
+ fontpixelSize: 12
+ Layout.minimumWidth: 100
+ Layout.fillWidth: true
+ Layout.preferredHeight: 25
+ Layout.preferredWidth: 200
+ decorated: true
+ onClicked: Qt.openUrlExternally("https://blog.qt.io/")
+ }
+
+ Item {
+ width: 200
+ height: 200
+ Layout.fillWidth: true
+ Layout.preferredWidth: 50
+ Layout.preferredHeight: 25
+ }
+
+ PushButton {
+ id: forums
+ text: qsTr("Forums")
+ fontpixelSize: 12
+ Layout.minimumWidth: 100
+ Layout.fillWidth: true
+ Layout.preferredHeight: 25
+ Layout.preferredWidth: 200
+ decorated: true
+ onClicked: Qt.openUrlExternally("https://forum.qt.io/")
+ }
+
+ Item {
+ width: 200
+ height: 200
+ Layout.fillWidth: true
+ Layout.preferredWidth: 50
+ Layout.preferredHeight: 25
+ }
+
+ PushButton {
+ id: account
+ text: qsTr("Account")
+ fontpixelSize: 12
+ Layout.minimumWidth: 100
+ Layout.fillWidth: true
+ Layout.preferredHeight: 25
+ Layout.preferredWidth: 200
+ decorated: true
+ onClicked: Qt.openUrlExternally("https://login.qt.io/login")
+ }
+
+ Item {
+ width: 200
+ height: 200
+ Layout.fillWidth: true
+ Layout.preferredWidth: 50
+ Layout.preferredHeight: 25
+ }
+
+ PushButton {
+ id: getQt
+ text: qsTr("Get Qt")
+ fontpixelSize: 12
+ Layout.minimumWidth: 100
+ Layout.fillWidth: true
+ Layout.preferredHeight: 25
+ Layout.preferredWidth: 200
+ decorated: true
+ onClicked: Qt.openUrlExternally("https://www.qt.io/pricing")
+ }
+
+ Item {
+ width: 200
+ height: 200
+ Layout.fillWidth: true
+ Layout.preferredWidth: 50
+ Layout.preferredHeight: 25
+ }
+
+ SocialButton {
+ id: social
+ text: ""
+ Layout.minimumWidth: 100
+ Layout.fillWidth: true
+ Layout.preferredHeight: 25
+ Layout.preferredWidth: 200
+ decorated: true
+ }
+ }
+
+ BlogBanner {
+ id: blogBanner
+ anchors.left: parent.left
+ anchors.leftMargin: 20
+ anchors.right: thumbnails.left
+ anchors.rightMargin: 20
+ y: 657
+ }
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/PushButton.ui.qml b/share/qtcreator/qmldesigner/welcomepage/PushButton.ui.qml
new file mode 100644
index 00000000000..a87c0241c6f
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/PushButton.ui.qml
@@ -0,0 +1,108 @@
+// 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.Templates
+import WelcomeScreen 1.0
+
+Button {
+ id: control
+
+ implicitWidth: Math.max(
+ buttonBackground ? buttonBackground.implicitWidth : 0,
+ textItem.implicitWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(
+ buttonBackground ? buttonBackground.implicitHeight : 0,
+ textItem.implicitHeight + topPadding + bottomPadding)
+ leftPadding: 4
+ rightPadding: 4
+
+ text: "My Button"
+ state: "normal"
+
+ property alias fontpixelSize: textItem.font.pixelSize
+ property bool decorated: false
+
+ background: Rectangle {
+ id: buttonBackground
+ color: "#00000000"
+ implicitWidth: 100
+ implicitHeight: 40
+ opacity: buttonBackground.enabled ? 1 : 0.3
+ radius: 2
+ border.color: "#047eff"
+ anchors.fill: parent
+ }
+
+ contentItem: Text {
+ id: textItem
+ text: control.text
+ font.pixelSize: 18
+ opacity: textItem.enabled ? 1.0 : 0.3
+ color: Constants.currentGlobalText
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+
+ Rectangle {
+ id: decoration
+ width: 10
+ visible: control.decorated
+ color: Constants.currentBrand
+ border.color: Constants.currentBrand
+ anchors.right: parent.right
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ anchors.rightMargin: 1
+ anchors.bottomMargin: 1
+ anchors.topMargin: 1
+ }
+
+ states: [
+ State {
+ name: "normal"
+ when: !control.down && !control.hovered
+
+ PropertyChanges {
+ target: buttonBackground
+ color: Constants.currentPushButtonNormalBackground
+ border.color: Constants.currentPushButtonNormalOutline
+ }
+
+ PropertyChanges {
+ target: textItem
+ color: Constants.currentGlobalText
+ }
+ },
+ State {
+ name: "hover"
+ when: control.hovered && !control.down
+
+ PropertyChanges {
+ target: textItem
+ color: Constants.currentGlobalText
+ }
+
+ PropertyChanges {
+ target: buttonBackground
+ color: Constants.currentPushButtonHoverBackground
+ border.color: Constants.currentPushButtonHoverOutline
+ }
+ },
+ State {
+ name: "press"
+ when: control.down
+
+ PropertyChanges {
+ target: textItem
+ color: Constants.darkActiveGlobalText
+ }
+
+ PropertyChanges {
+ target: buttonBackground
+ color: Constants.currentBrand
+ border.color: "#00000000"
+ }
+ }
+ ]
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/RangeMapper.qml b/share/qtcreator/qmldesigner/welcomepage/RangeMapper.qml
new file mode 100644
index 00000000000..76c67f719fd
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/RangeMapper.qml
@@ -0,0 +1,42 @@
+// 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
+
+QtObject {
+ id: object
+
+/*!
+ The input value.
+*/
+ property real input: 0
+
+/*!
+ The output value.
+*/
+ property real output: {
+ var slope = (object.outputMaximum - object.outputMinimum) / (object.inputMaximum - object.inputMinimum)
+ return object.outputMinimum + slope * (object.input - object.inputMinimum)
+ }
+
+/*!
+ The minimum input value.
+*/
+ property real inputMinimum: 0
+
+/*!
+ The maximum input value.
+*/
+ property real inputMaximum: 100
+
+/*!
+ The minimum output value.
+*/
+ property real outputMinimum: 0
+
+/*!
+ The maximum output value.
+*/
+ property real outputMaximum: 100
+
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/SocialButton.qml b/share/qtcreator/qmldesigner/welcomepage/SocialButton.qml
new file mode 100644
index 00000000000..864486966d3
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/SocialButton.qml
@@ -0,0 +1,129 @@
+// 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.Templates
+import QtQuick.Layouts
+import WelcomeScreen 1.0
+
+Button {
+ id: control
+
+ implicitWidth: Math.max(
+ buttonBackground ? buttonBackground.implicitWidth : 0,
+ textItem.implicitWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(
+ buttonBackground ? buttonBackground.implicitHeight : 0,
+ textItem.implicitHeight + topPadding + bottomPadding)
+ leftPadding: 4
+ rightPadding: 4
+
+ text: ""
+ visible: true
+ state: "normal"
+
+ property alias fontpixelSize: textItem.font.pixelSize
+ property bool decorated: false
+
+ background: Rectangle {
+ id: buttonBackground
+ color: "#fca4a4"
+ implicitWidth: 100
+ implicitHeight: 40
+ opacity: buttonBackground.enabled ? 1 : 0.3
+ radius: 2
+ border.color: "#047eff"
+ anchors.fill: parent
+ }
+
+ contentItem: Text {
+ id: textItem
+ visible: false
+ text: qsTr("Text")
+ font.pixelSize: 12
+ }
+
+ Rectangle {
+ id: decoration
+ width: 10
+ visible: control.decorated
+ color: Constants.currentBrand
+ border.color: Constants.currentBrand
+ anchors.right: parent.right
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ anchors.rightMargin: 1
+ anchors.bottomMargin: 1
+ anchors.topMargin: 1
+ }
+
+ RowLayout {
+ anchors.fill: parent
+
+ Item {
+ width: 200
+ height: 200
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ }
+
+ YoutubeButton {
+ id: youtubeButton
+ Layout.fillHeight: true
+ Layout.preferredWidth: 60
+ }
+
+ Item {
+ width: 200
+ height: 200
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+
+ TwitterButton {
+ id: twitterButton
+ Layout.maximumHeight: 15
+ Layout.minimumHeight: 15
+ Layout.preferredHeight: 15
+ Layout.fillHeight: false
+ Layout.preferredWidth: 25
+ }
+
+ Item {
+ width: 200
+ height: 200
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+ }
+
+ states: [
+ State {
+ name: "normal"
+ when: !youtubeButton.isHovered && !twitterButton.isHovered && !control.hovered
+
+ PropertyChanges {
+ target: buttonBackground
+ color: Constants.currentPushButtonNormalBackground
+ border.color: Constants.currentPushButtonNormalOutline
+ }
+ },
+ State {
+ name: "hover"
+ when: control.hovered || youtubeButton.isHovered || twitterButton.isHovered
+
+ PropertyChanges {
+ target: buttonBackground
+ color: Constants.currentPushButtonHoverBackground
+ border.color: Constants.currentPushButtonHoverOutline
+ }
+ }
+ ]
+}
+
+/*##^##
+Designer {
+ D{i:0;formeditorZoom:4;height:25;width:207}D{i:3;locked:true}D{i:7}D{i:9}
+}
+##^##*/
+
diff --git a/share/qtcreator/qmldesigner/welcomepage/StringMapper.qml b/share/qtcreator/qmldesigner/welcomepage/StringMapper.qml
new file mode 100644
index 00000000000..71d17117fb9
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/StringMapper.qml
@@ -0,0 +1,68 @@
+// 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 2.10
+
+/*!
+ \qmltype StringMapper
+ \inqmlmodule QtQuick.Studio.LogicHelper
+ \since QtQuick.Studio.LogicHelper 1.0
+ \inherits QtObject
+
+ \brief Converts numbers to strings with the defined precision.
+
+ The StringMapper type maps numbers to strings. The string mapper
+ \l input property is bound to the \c value property of a control that
+ provides the number and the \l text property of the string mapper is
+ mapped to the \c text property of type that displays the string.
+
+ Designers can use the String Mapper type in \QDS instead of writing
+ JavaScript expressions.
+
+ \section1 Example Usage
+
+ In the following example, we use \l Text type to display the numerical
+ value of a \l Slider type as a string:
+
+ \code
+ Rectangle {
+ Slider {
+ id: slider
+ value: 0.5
+ }
+ Text {
+ id: text1
+ text: stringMapper.text
+ }
+ StringMapper {
+ id: stringMapper
+ input: slider.value
+ }
+ }
+ \endcode
+*/
+
+QtObject {
+ id: object
+
+/*!
+ The value to convert to a string.
+*/
+ property real input: 0
+
+/*!
+ The number of digits after the decimal separator.
+*/
+ property int decimals: 2
+
+/*!
+ The \l input value as a string.
+*/
+ property string text: object.input.toFixed(object.decimals)
+}
+
+/*##^##
+Designer {
+ D{i:0;autoSize:true;height:480;width:640}
+}
+##^##*/
diff --git a/share/qtcreator/qmldesigner/welcomepage/Tag.qml b/share/qtcreator/qmldesigner/welcomepage/Tag.qml
new file mode 100644
index 00000000000..109cf435162
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/Tag.qml
@@ -0,0 +1,28 @@
+// 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 WelcomeScreen 1.0
+import QtQuick.Layouts 1.0
+
+Rectangle {
+ id: tagBackground
+ width: 84
+ height: 15
+ color: Constants.currentBrand
+ visible: tagLabel.text.length
+
+ property alias text: tagLabel.text
+
+ Text {
+ id: tagLabel
+ color: Constants.darkActiveGlobalText
+ text: qsTr("tag name")
+ anchors.fill: parent
+ font.pixelSize: 10
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ //font.weight: Font.ExtraLight
+ }
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/TagArea.qml b/share/qtcreator/qmldesigner/welcomepage/TagArea.qml
new file mode 100644
index 00000000000..04722d7ba85
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/TagArea.qml
@@ -0,0 +1,43 @@
+// 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 WelcomeScreen 1.0
+import QtQuick.Layouts
+
+Item {
+ id: root
+ height: (repeater.count > root.columnCount) ? root.tagHeight * 2 + root.tagSpacing
+ : root.tagHeight
+
+ property alias tags: repeater.model
+ // private
+ property int tagWidth: 75
+ property int tagHeight: 25
+ property int tagSpacing: 4
+
+ readonly property int columnCount: 3
+
+ Connections {
+ target: root
+ onWidthChanged: root.tagWidth = Math.floor((root.width - root.tagSpacing
+ * (root.columnCount - 1)) / root.columnCount)
+ }
+
+ Flow {
+ anchors.fill: parent
+ spacing: root.tagSpacing
+
+ Repeater {
+ id: repeater
+ model: ["Qt 6", "Qt for MCU", "3D"]
+
+ Tag {
+ text: modelData
+ width: root.tagWidth
+ height: root.tagHeight
+ }
+ }
+ }
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/TestControlPanel.qml b/share/qtcreator/qmldesigner/welcomepage/TestControlPanel.qml
new file mode 100644
index 00000000000..50ed31cab73
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/TestControlPanel.qml
@@ -0,0 +1,153 @@
+// 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 StudioTheme 1.0 as Theme
+
+Rectangle {
+ id: controlPanel
+ width: 220
+ height: 80
+ color: "#9b787878"
+ radius: 10
+
+ property bool closeOpen: true
+
+ Text {
+ id: closeOpen
+ x: 203
+ color: "#ffffff"
+ text: qsTr("X")
+ anchors.right: parent.right
+ anchors.top: parent.top
+ font.pixelSize: 12
+ horizontalAlignment: Text.AlignRight
+ anchors.rightMargin: 9
+ anchors.topMargin: 6
+
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+
+ Connections {
+ target: mouseArea
+ function onClicked(mouse) { controlPanel.closeOpen = !controlPanel.closeOpen }
+ }
+ }
+ }
+
+ Text {
+ id: themeSwitchLabel
+ x: 8
+ y: 50
+ color: "#ffffff"
+ text: qsTr("Theme")
+ font.pixelSize: 12
+ horizontalAlignment: Text.AlignRight
+ anchors.rightMargin: 6
+ }
+
+ Text {
+ id: lightLabel
+ x: 172
+ y: 26
+ color: "#ffffff"
+ text: qsTr("light")
+ font.pixelSize: 12
+ horizontalAlignment: Text.AlignRight
+ }
+
+ Text {
+ id: darkLabel
+ x: 65
+ y: 26
+ color: "#ffffff"
+ text: qsTr("dark")
+ font.pixelSize: 12
+ horizontalAlignment: Text.AlignRight
+ }
+
+ Slider {
+ id: themeSlider
+ x: 58
+ y: 44
+ width: 145
+ height: 28
+ snapMode: RangeSlider.SnapAlways
+ value: 0
+ from: 0
+ to: 1
+ stepSize: 1
+
+ Connections {
+ target: themeSlider
+ function onValueChanged(value) { Theme.Values.style = themeSlider.value }
+ }
+ }
+
+ CheckBox {
+ id: basicCheckBox
+ x: 60
+ y: 79
+ text: qsTr("")
+ checked: true
+ onToggled: { Constants.basic = !Constants.basic }
+ }
+
+ CheckBox {
+ id: communityCheckBox
+ x: 174
+ y: 79
+ text: qsTr("")
+ checked: false
+ onToggled: { Constants.communityEdition = !Constants.communityEdition }
+ }
+
+ Text {
+ id: basicEditionLabel
+ x: 8
+ y: 92
+ color: "#ffffff"
+ text: qsTr("Basic")
+ font.pixelSize: 12
+ horizontalAlignment: Text.AlignRight
+ anchors.rightMargin: 6
+ }
+
+ Text {
+ id: communityEditionLabel
+ x: 116
+ y: 92
+ color: "#ffffff"
+ text: qsTr("Community")
+ font.pixelSize: 12
+ horizontalAlignment: Text.AlignRight
+ anchors.rightMargin: 6
+ }
+
+ states: [
+ State {
+ name: "open"
+ when: controlPanel.closeOpen
+ },
+ State {
+ name: "close"
+ when: !controlPanel.closeOpen
+
+ PropertyChanges {
+ target: closeOpen
+ text: qsTr("<")
+ }
+
+ PropertyChanges {
+ target: controlPanel
+ width: 28
+ height: 26
+ clip: true
+ }
+ }
+ ]
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/ThumbnailDelegate.qml b/share/qtcreator/qmldesigner/welcomepage/ThumbnailDelegate.qml
new file mode 100644
index 00000000000..d50627d05e9
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/ThumbnailDelegate.qml
@@ -0,0 +1,630 @@
+// 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.
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 })
+ }
+ }
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/TourDialogButton.qml b/share/qtcreator/qmldesigner/welcomepage/TourDialogButton.qml
new file mode 100644
index 00000000000..35ace283ed2
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/TourDialogButton.qml
@@ -0,0 +1,69 @@
+// 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 WelcomeScreen 1.0
+import StudioTheme 1.0 as StudioTheme
+import UiTour
+
+Item {
+ id: tourButton
+ width: 40
+ height: 40
+ property alias dialogButtonText: dialogButton.text
+
+ signal buttonClicked
+
+ Text {
+ id: dialogButton
+ color: "#ffffff"
+ font.family: StudioTheme.Constants.iconFont.family
+ text: StudioTheme.Constants.closeFile_large
+ font.pixelSize: 32
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+ hoverEnabled: true
+
+ Connections {
+ target: mouseArea
+ onClicked: tourButton.buttonClicked()
+ }
+ }
+
+ states: [
+ State {
+ name: "normal"
+ when: !mouseArea.containsMouse && !mouseArea.pressed
+
+ PropertyChanges {
+ target: dialogButton
+ color: "#ecebeb"
+ font.pixelSize: 28
+ }
+ },
+ State {
+ name: "hover"
+ when: mouseArea.containsMouse && !mouseArea.pressed
+
+ PropertyChanges {
+ target: dialogButton
+ font.pixelSize: 29
+ }
+ },
+ State {
+ name: "press"
+ when: mouseArea.pressed
+
+ PropertyChanges {
+ target: dialogButton
+ font.pixelSize: 29
+ }
+ }
+ ]
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/TourModel.qml b/share/qtcreator/qmldesigner/welcomepage/TourModel.qml
new file mode 100644
index 00000000000..db6224f7d64
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/TourModel.qml
@@ -0,0 +1,73 @@
+// 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
+
+ListModel {
+ ListElement {
+ qmlFileName: "tours/welcomepage-tour/WelcomeSlideShow.ui.qml"
+ thumbnail: "images/welcome-page.png"
+ title: QT_TR_NOOP("Welcome Page")
+ subtitle: QT_TR_NOOP("The welcome page of Qt Design Studio.")
+ }
+ ListElement {
+ qmlFileName: "tours/workspace-tour/WorkspaceSlideShow.ui.qml"
+ thumbnail: "images/workspaces.png"
+ title: QT_TR_NOOP("Workspaces")
+ subtitle: QT_TR_NOOP("Introduction to the most important workspaces.")
+ }
+ ListElement {
+ qmlFileName: "tours/toolbar-tour/ToolbarSlideShow.ui.qml"
+ thumbnail: "images/top-toolbar.png"
+ title: QT_TR_NOOP("Top Toolbar")
+ subtitle: QT_TR_NOOP("Short explanation of the top toolbar.")
+ }
+ ListElement {
+ qmlFileName: "tours/states-tour/StatesSlideShow.ui.qml"
+ thumbnail: "images/states.png"
+ title: QT_TR_NOOP("States")
+ subtitle: QT_TR_NOOP("An introduction to states.")
+ }
+ ListElement {
+ qmlFileName: "tours/sortcomponents-tour/SortComponentsSlideShow.ui.qml"
+ thumbnail: "images/sorting-components.png"
+ title: QT_TR_NOOP("Sorting Components")
+ subtitle: QT_TR_NOOP("A way to organize multiple components.")
+ }
+ ListElement {
+ qmlFileName: "tours/connectcomponents-tour/ConnectComponentsSlideShow.ui.qml"
+ thumbnail: "images/connecting-components.png"
+ title: QT_TR_NOOP("Connecting Components")
+ subtitle: QT_TR_NOOP("A way to connect components with actions.")
+ }
+ ListElement {
+ qmlFileName: "tours/addassets-tour/AddAssetsSlideShow.ui.qml"
+ thumbnail: "images/adding-assets.png"
+ title: QT_TR_NOOP("Adding Assets")
+ subtitle: QT_TR_NOOP("A way to add new assets to the project.")
+ }
+ ListElement {
+ qmlFileName: "tours/animation-tour/AnimationSlideShow.ui.qml"
+ thumbnail: "images/animation-2d.png"
+ title: QT_TR_NOOP("Creating 2D Animation")
+ subtitle: QT_TR_NOOP("A way to create a 2D Animation.")
+ }
+ ListElement {
+ qmlFileName: "tours/studiocomponents-border-arc-tour/StudioComponentBorderArcSlideShow.ui.qml"
+ thumbnail: "images/border-arc.png"
+ title: QT_TR_NOOP("Border and Arc")
+ subtitle: QT_TR_NOOP("Work with Border and Arc Studio Components.")
+ }
+ ListElement {
+ qmlFileName: "tours/studiocomponents-ellipse-pie-tour/StudioComponentEllipsePieSlideShow.ui.qml"
+ thumbnail: "images/ellipse-pie.png"
+ title: QT_TR_NOOP("Ellipse and Pie")
+ subtitle: QT_TR_NOOP("Work with Ellipse and Pie Studio Components.")
+ }
+ ListElement {
+ qmlFileName: "tours/studiocomponents-polygon-triangle-rectangle-tour/StudioComponentPolygonTriangleRectangleSlideShow.ui.qml"
+ thumbnail: "images/complex-shapes.png"
+ title: QT_TR_NOOP("Complex Shapes")
+ subtitle: QT_TR_NOOP("Work with Polygon, Triangle and Rectangle Studio Components.")
+ }
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/TourProgressBar.qml b/share/qtcreator/qmldesigner/welcomepage/TourProgressBar.qml
new file mode 100644
index 00000000000..bae49c0fe43
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/TourProgressBar.qml
@@ -0,0 +1,41 @@
+// 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 WelcomeScreen 1.0
+
+Item {
+ id: progressBar
+
+ property int endSlide: 10
+ property int currentSlide: 1
+
+ Rectangle {
+ id: progressBarGroove
+ color: "#272727"
+ radius: 5
+ border.color: "#00000000"
+ anchors.fill: parent
+ }
+
+ Rectangle {
+ id: progressBarTrack
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: 1
+ anchors.topMargin: 1
+ width: (progressBarGroove.width / 100) * rangeMapper.output
+ color: "#57b9fc"
+ radius: 4.5
+ }
+
+ RangeMapper {
+ id: rangeMapper
+ inputMaximum: progressBar.endSlide
+ outputMaximum: 100
+ outputMinimum: 0
+ inputMinimum: 0
+ input: progressBar.currentSlide
+ }
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/TourRestartButton.qml b/share/qtcreator/qmldesigner/welcomepage/TourRestartButton.qml
new file mode 100644
index 00000000000..55f367ffb9c
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/TourRestartButton.qml
@@ -0,0 +1,84 @@
+// 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 WelcomeScreen 1.0
+
+Rectangle {
+ id: restart
+ height: 36
+ color: "#00ffffff"
+ radius: 18
+ border.color: "#f9f9f9"
+ border.width: 3
+ state: "normal"
+
+ signal restart()
+
+ Text {
+ id: text2
+ color: "#ffffff"
+ text: qsTrId("Restart")
+ anchors.verticalCenter: parent.verticalCenter
+ font.pixelSize: 12
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+ hoverEnabled: true
+
+ Connections {
+ target: mouseArea
+ onClicked: restart.restart()
+ }
+ }
+
+ states: [
+ State {
+ name: "normal"
+ when: !mouseArea.containsMouse && !mouseArea.pressed
+
+ PropertyChanges {
+ target: text2
+ color: "#dedede"
+ }
+
+ PropertyChanges {
+ target: restart
+ border.color: "#dedede"
+ }
+ },
+ State {
+ name: "hover"
+ when: mouseArea.containsMouse && !mouseArea.pressed
+
+ PropertyChanges {
+ target: restart
+ color: "#00ffffff"
+ border.color: "#ffffff"
+ }
+
+ PropertyChanges {
+ target: text2
+ color: "#ffffff"
+ }
+ },
+ State {
+ name: "press"
+ when: mouseArea.pressed
+
+ PropertyChanges {
+ target: restart
+ color: "#ffffff"
+ border.color: "#ffffff"
+ }
+
+ PropertyChanges {
+ target: text2
+ color: "#000000"
+ }
+ }
+ ]
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/TourThumbnailDelegate.qml b/share/qtcreator/qmldesigner/welcomepage/TourThumbnailDelegate.qml
new file mode 100644
index 00000000000..0f61a2a3c45
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/TourThumbnailDelegate.qml
@@ -0,0 +1,164 @@
+// 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 WelcomeScreen 1.0
+
+Item {
+ id: root
+ width: Constants.thumbnailSize
+ height: Constants.thumbnailSize
+ state: "normal"
+ clip: true
+
+ property bool complete: root.currentSlide === root.endSlide
+
+ // Needs to be set from the current slide show and user progress
+ property int currentSlide: 0
+ property int endSlide: 10
+
+ signal clicked()
+
+ Rectangle {
+ id: background
+ radius: 10
+ color: Constants.currentNormalThumbnailBackground
+ anchors.fill: parent
+
+ property bool multiline: (tourNameLabelMetric.width >= tourNameLabel.width)
+
+ TextMetrics {
+ id: tourNameLabelMetric
+ text: tourNameLabel.text
+ font: tourNameLabel.font
+ }
+
+ Image {
+ id: thumbnailPlaceholder
+ source: thumbnail
+ 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: tourNameBackground
+ height: background.multiline ? 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: tourNameLabel
+ color: Constants.currentGlobalText
+ font.pixelSize: 16
+ text: title
+ 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
+ }
+ }
+
+ Text {
+ id: subtitleCaption
+ color: Constants.currentGlobalText
+ text: subtitle
+ renderType: Text.NativeRendering
+ font.pixelSize: 14
+ wrapMode: Text.WordWrap
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.top: tourNameBackground.bottom
+ anchors.topMargin: 5
+ anchors.rightMargin: Constants.thumbnailMargin
+ anchors.leftMargin: Constants.thumbnailMargin
+ leftPadding: 5
+ rightPadding: 5
+ }
+
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+ hoverEnabled: true
+
+ Connections {
+ target: mouseArea
+ onClicked: root.clicked()
+ }
+ }
+ }
+
+ states: [
+ State {
+ name: "normal"
+ when: root.enabled && !mouseArea.containsMouse && !mouseArea.pressed && !root.complete
+
+ PropertyChanges {
+ target: background
+ color: Constants.currentNormalThumbnailBackground
+ border.width: 0
+ }
+ PropertyChanges {
+ target: tourNameBackground
+ color: Constants.currentNormalThumbnailLabelBackground
+ }
+ PropertyChanges {
+ target: mouseArea
+ enabled: true
+ }
+ },
+ State {
+ name: "hover"
+ when: root.enabled && mouseArea.containsMouse && !mouseArea.pressed && !root.complete
+
+ PropertyChanges {
+ target: background
+ color: Constants.currentHoverThumbnailBackground
+ border.width: 0
+ }
+ PropertyChanges {
+ target: tourNameBackground
+ color: Constants.currentHoverThumbnailLabelBackground
+ }
+ PropertyChanges {
+ target: mouseArea
+ enabled: true
+ }
+ },
+ State {
+ name: "press"
+ when: root.enabled && mouseArea.pressed && !root.complete
+
+ PropertyChanges {
+ target: background
+ color: Constants.currentHoverThumbnailBackground
+ border.color: Constants.currentBrand
+ border.width: 2
+ }
+ PropertyChanges {
+ target: tourNameBackground
+ color: Constants.currentBrand
+ }
+ PropertyChanges {
+ target: mouseArea
+ enabled: true
+ }
+ }
+ ]
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/TwirlButton.qml b/share/qtcreator/qmldesigner/welcomepage/TwirlButton.qml
new file mode 100644
index 00000000000..e9813ad9978
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/TwirlButton.qml
@@ -0,0 +1,118 @@
+// 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 WelcomeScreen 1.0
+import QtQuick.Layouts
+import StudioTheme 1.0 as StudioTheme
+
+Item {
+ id: twirlButton
+ width: 25
+ height: 25
+ state: "normal"
+
+ property bool parentHovered: false
+ property bool isHovered: mouseArea.containsMouse
+ signal triggerRelease()
+
+ Rectangle {
+ id: background
+ color: "#eab336"
+ border.width: 0
+ anchors.fill: parent
+ }
+
+ Text {
+ id: twirlIcon
+ width: 23
+ height: 23
+ color: Constants.currentGlobalText
+ font.family: StudioTheme.Constants.iconFont.family
+ text: StudioTheme.Constants.adsDropDown
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.bottom: parent.bottom
+ font.pixelSize: 14
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+ hoverEnabled: true
+
+ Connections {
+ target: mouseArea
+ onReleased: twirlButton.triggerRelease()
+ }
+ }
+
+ states: [
+ State {
+ name: "hidden"
+ when: !mouseArea.containsMouse && !mouseArea.pressed && !twirlButton.parentHovered
+
+ PropertyChanges {
+ target: background
+ visible: false
+ }
+ PropertyChanges {
+ target: twirlIcon
+ visible: false
+ }
+ },
+ State {
+ name: "normal"
+ when: !mouseArea.containsMouse && !mouseArea.pressed && twirlButton.parentHovered
+
+ PropertyChanges {
+ target: background
+ visible: false
+ }
+ PropertyChanges {
+ target: twirlIcon
+ visible: true
+ }
+ },
+ State {
+ name: "hover"
+ when: mouseArea.containsMouse && !mouseArea.pressed
+
+ PropertyChanges {
+ target: twirlIcon
+ scale: 1.4
+ }
+ PropertyChanges {
+ target: background
+ visible: true
+ color: Constants.currentHoverThumbnailLabelBackground
+ }
+ PropertyChanges {
+ target: twirlIcon
+ visible: true
+ }
+ },
+ State {
+ name: "press"
+ when: mouseArea.pressed
+
+ PropertyChanges {
+ target: twirlIcon
+ color: Constants.currentGlobalText
+ scale: 1.8
+ }
+ PropertyChanges {
+ target: background
+ visible: true
+ color: Constants.currentBrand
+ }
+ PropertyChanges {
+ target: twirlIcon
+ visible: true
+ }
+ }
+ ]
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/TwitterButton.qml b/share/qtcreator/qmldesigner/welcomepage/TwitterButton.qml
new file mode 100644
index 00000000000..9349fcd32c3
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/TwitterButton.qml
@@ -0,0 +1,125 @@
+// 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 WelcomeScreen 1.0
+import StudioTheme 1.0 as StudioTheme
+
+Item {
+ id: twitterButton
+ state: "darkNormal"
+
+ property bool isHovered: mouseArea.containsMouse
+
+ Image {
+ id: twitterDarkNormal
+ anchors.fill: parent
+ source: "images/twitterDarkNormal.png"
+ fillMode: Image.PreserveAspectFit
+ }
+
+ Image {
+ id: twitterLightNormal
+ anchors.fill: parent
+ source: "images/twitterLightNormal.png"
+ fillMode: Image.PreserveAspectFit
+ }
+
+ Image {
+ id: twitterHover
+ anchors.fill: parent
+ source: "images/twitterHover.png"
+ fillMode: Image.PreserveAspectFit
+ }
+
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+ hoverEnabled: true
+
+ Connections {
+ target: mouseArea
+ function onClicked(mouse) { Qt.openUrlExternally("https://twitter.com/qtproject/") }
+ }
+ }
+
+ states: [
+ State {
+ name: "darkNormal"
+ when: !StudioTheme.Values.isLightTheme && !mouseArea.containsMouse && !mouseArea.pressed
+
+ PropertyChanges {
+ target: twitterDarkNormal
+ visible: true
+ }
+
+ PropertyChanges {
+ target: twitterLightNormal
+ visible: false
+ }
+
+ PropertyChanges {
+ target: twitterHover
+ visible: false
+ }
+ },
+ State {
+ name: "lightNormal"
+ when: StudioTheme.Values.isLightTheme && !mouseArea.containsMouse && !mouseArea.pressed
+
+ PropertyChanges {
+ target: twitterHover
+ visible: false
+ }
+
+ PropertyChanges {
+ target: twitterLightNormal
+ visible: true
+ }
+
+ PropertyChanges {
+ target: twitterDarkNormal
+ visible: false
+ }
+ },
+ State {
+ name: "hover"
+ when: mouseArea.containsMouse && !mouseArea.pressed
+
+ PropertyChanges {
+ target: twitterHover
+ visible: true
+ }
+
+ PropertyChanges {
+ target: twitterLightNormal
+ visible: false
+ }
+
+ PropertyChanges {
+ target: twitterDarkNormal
+ visible: false
+ }
+ },
+ State {
+ name: "press"
+ when: (mouseArea.containsMouse || !mouseArea.containsMouse) && mouseArea.pressed
+
+ PropertyChanges {
+ target: twitterHover
+ visible: true
+ scale: 1.1
+ }
+
+ PropertyChanges {
+ target: twitterLightNormal
+ visible: false
+ }
+
+ PropertyChanges {
+ target: twitterDarkNormal
+ visible: false
+ }
+ }
+ ]
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/WelcomePage.qml b/share/qtcreator/qmldesigner/welcomepage/WelcomePage.qml
new file mode 100644
index 00000000000..2f8778f2f8f
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/WelcomePage.qml
@@ -0,0 +1,52 @@
+// 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 projectmodel 1.0
+
+Item {
+ id: appFrame
+ clip: true
+ width: Constants.width
+ height: Constants.height
+
+ property int loadingProgress: 50
+
+ onLoadingProgressChanged: Constants.loadingProgress = appFrame.loadingProgress
+
+ NumberAnimation {
+ target: appFrame
+ property: "loadingProgress"
+ from: 0
+ to: 100
+ loops: Animation.Infinite
+ running: false
+ duration: 1000
+ }
+
+ MainScreen {
+ id: screen
+ anchors.fill: parent
+ anchors.leftMargin: screen.designMode ? 0 : -45 // hide sidebar
+ }
+
+ property int pageIndex: 0
+ property int minimumWidth: 1200
+ property int minimumHeight: 720
+
+ onHeightChanged: {
+ if (appFrame.height > appFrame.minimumHeight)
+ appFrame.anchors.fill = parent
+ else if (appFrame.height < appFrame.minimumHeight)
+ appFrame.height = appFrame.minimumHeight
+ }
+ onWidthChanged: {
+ if (appFrame.width > appFrame.minimumWidth)
+ appFrame.anchors.fill = parent
+ else if (appFrame.width < appFrame.minimumWidth)
+ appFrame.width = appFrame.minimumWidth
+ }
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/WelcomeScreen.qmlproject b/share/qtcreator/qmldesigner/welcomepage/WelcomeScreen.qmlproject
new file mode 100644
index 00000000000..539db2133aa
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/WelcomeScreen.qmlproject
@@ -0,0 +1,49 @@
+/* File generated by Qt Creator */
+
+import QmlProject 1.1
+
+Project {
+ mainFile: "WelcomePage.qml"
+
+ /* Include .qml, .js, and image files from current directory and subdirectories */
+ QmlFiles {
+ directory: "."
+ }
+
+ JavaScriptFiles {
+ directory: "."
+ }
+
+ ImageFiles {
+ directory: "."
+ }
+
+ Files {
+ filter: "*.conf"
+ files: ["qtquickcontrols2.conf"]
+ }
+
+ Files {
+ filter: "qmldir"
+ directory: "."
+ }
+
+ Files {
+ filter: "*.ttf;*.otf"
+ }
+
+ Environment {
+ QT_QUICK_CONTROLS_CONF: "qtquickcontrols2.conf"
+ //QT_AUTO_SCREEN_SCALE_FACTOR: "1"
+ QT_SCALE_FACTOR: "0.8"
+ QT_LOGGING_RULES: "qt.qml.connections=false"
+ }
+
+ qt6Project: true
+
+ /* List of plugin directories passed to QML runtime */
+ importPaths: [ "imports", "studioImports", "asset_imports", "mockData", "dataImports" ]
+
+ /* Required for deployment */
+ targetDirectory: "/opt/WelcomeScreen"
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/YoutubeButton.qml b/share/qtcreator/qmldesigner/welcomepage/YoutubeButton.qml
new file mode 100644
index 00000000000..ec7eb54acee
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/YoutubeButton.qml
@@ -0,0 +1,201 @@
+// 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.Templates
+import WelcomeScreen 1.0
+import StudioTheme 1.0 as StudioTheme
+
+Item {
+ id: youtubeButton
+ state: "darkNormal"
+
+ property bool isHovered: mouseArea.containsMouse
+
+ Image {
+ id: youtubeDarkNormal
+ anchors.fill: parent
+ source: "images/youtubeDarkNormal.png"
+ fillMode: Image.PreserveAspectFit
+ }
+
+ Image {
+ id: youtubeLightNormal
+ anchors.fill: parent
+ source: "images/youtubeLightNormal.png"
+ fillMode: Image.PreserveAspectFit
+ }
+
+ Image {
+ id: youtubeLightHover
+ anchors.fill: parent
+ source: "images/youtubeLightHover.png"
+ fillMode: Image.PreserveAspectFit
+ }
+
+ Image {
+ id: youtubeDarkHover
+ anchors.fill: parent
+ source: "images/youtubeDarkHover.png"
+ fillMode: Image.PreserveAspectFit
+ }
+
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+ hoverEnabled: true
+
+ Connections {
+ target: mouseArea
+ function onClicked(mouse) { Qt.openUrlExternally("https://www.youtube.com/user/QtStudios/") }
+ }
+ }
+ states: [
+ State {
+ name: "darkNormal"
+ when: !StudioTheme.Values.isLightTheme && !mouseArea.containsMouse && !mouseArea.pressed
+
+ PropertyChanges {
+ target: youtubeDarkNormal
+ visible: true
+ }
+
+ PropertyChanges {
+ target: youtubeLightNormal
+ visible: false
+ }
+
+ PropertyChanges {
+ target: youtubeLightHover
+ visible: false
+ }
+
+ PropertyChanges {
+ target: youtubeDarkHover
+ visible: false
+ }
+ },
+ State {
+ name: "lightNormal"
+ when: StudioTheme.Values.isLightTheme && !mouseArea.containsMouse && !mouseArea.pressed
+
+ PropertyChanges {
+ target: youtubeDarkHover
+ visible: false
+ }
+
+ PropertyChanges {
+ target: youtubeLightHover
+ visible: false
+ }
+
+ PropertyChanges {
+ target: youtubeLightNormal
+ visible: true
+ }
+
+ PropertyChanges {
+ target: youtubeDarkNormal
+ visible: false
+ }
+ },
+ State {
+ name: "darkHover"
+ when: !StudioTheme.Values.isLightTheme && mouseArea.containsMouse && !mouseArea.pressed
+
+ PropertyChanges {
+ target: youtubeDarkNormal
+ visible: false
+ }
+
+ PropertyChanges {
+ target: youtubeLightNormal
+ visible: false
+ }
+
+ PropertyChanges {
+ target: youtubeLightHover
+ visible: false
+ }
+
+ PropertyChanges {
+ target: youtubeDarkHover
+ visible: true
+ }
+ },
+ State {
+ name: "lightHover"
+ when: StudioTheme.Values.isLightTheme && mouseArea.containsMouse && !mouseArea.pressed
+
+ PropertyChanges {
+ target: youtubeDarkHover
+ visible: false
+ }
+
+ PropertyChanges {
+ target: youtubeLightHover
+ visible: true
+ }
+
+ PropertyChanges {
+ target: youtubeLightNormal
+ visible: false
+ }
+
+ PropertyChanges {
+ target: youtubeDarkNormal
+ visible: false
+ }
+ },
+ State {
+ name: "darkPress"
+ when: !StudioTheme.Values.isLightTheme && mouseArea.pressed
+
+ PropertyChanges {
+ target: youtubeDarkHover
+ visible: true
+ scale: 1.1
+ }
+
+ PropertyChanges {
+ target: youtubeLightHover
+ visible: false
+ }
+
+ PropertyChanges {
+ target: youtubeLightNormal
+ visible: false
+ }
+
+ PropertyChanges {
+ target: youtubeDarkNormal
+ visible: false
+ }
+ },
+ State {
+ name: "lightPress"
+ when: StudioTheme.Values.isLightTheme && mouseArea.pressed
+
+ PropertyChanges {
+ target: youtubeDarkHover
+ visible: false
+ }
+
+ PropertyChanges {
+ target: youtubeLightHover
+ visible: true
+ scale: 1.1
+ }
+
+ PropertyChanges {
+ target: youtubeLightNormal
+ visible: false
+ }
+
+ PropertyChanges {
+ target: youtubeDarkNormal
+ visible: false
+ }
+ }
+ ]
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/fonts/fonts.txt b/share/qtcreator/qmldesigner/welcomepage/fonts/fonts.txt
new file mode 100644
index 00000000000..ab961220674
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/fonts/fonts.txt
@@ -0,0 +1 @@
+Fonts in this folder are loaded automatically.
diff --git a/share/qtcreator/qmldesigner/welcomepage/images/adding-assets.png b/share/qtcreator/qmldesigner/welcomepage/images/adding-assets.png
new file mode 100644
index 00000000000..099b8d3ec3f
Binary files /dev/null and b/share/qtcreator/qmldesigner/welcomepage/images/adding-assets.png differ
diff --git a/share/qtcreator/qmldesigner/welcomepage/images/animation-2d.png b/share/qtcreator/qmldesigner/welcomepage/images/animation-2d.png
new file mode 100644
index 00000000000..1a607e1fd9d
Binary files /dev/null and b/share/qtcreator/qmldesigner/welcomepage/images/animation-2d.png differ
diff --git a/share/qtcreator/qmldesigner/welcomepage/images/border-arc.png b/share/qtcreator/qmldesigner/welcomepage/images/border-arc.png
new file mode 100644
index 00000000000..d1575c49f53
Binary files /dev/null and b/share/qtcreator/qmldesigner/welcomepage/images/border-arc.png differ
diff --git a/share/qtcreator/qmldesigner/welcomepage/images/complex-shapes.png b/share/qtcreator/qmldesigner/welcomepage/images/complex-shapes.png
new file mode 100644
index 00000000000..371295b831c
Binary files /dev/null and b/share/qtcreator/qmldesigner/welcomepage/images/complex-shapes.png differ
diff --git a/share/qtcreator/qmldesigner/welcomepage/images/congratulations.png b/share/qtcreator/qmldesigner/welcomepage/images/congratulations.png
new file mode 100644
index 00000000000..816feb76b4b
Binary files /dev/null and b/share/qtcreator/qmldesigner/welcomepage/images/congratulations.png differ
diff --git a/share/qtcreator/qmldesigner/welcomepage/images/connecting-components.png b/share/qtcreator/qmldesigner/welcomepage/images/connecting-components.png
new file mode 100644
index 00000000000..9f8e45cd4ef
Binary files /dev/null and b/share/qtcreator/qmldesigner/welcomepage/images/connecting-components.png differ
diff --git a/share/qtcreator/qmldesigner/welcomepage/images/ds.png b/share/qtcreator/qmldesigner/welcomepage/images/ds.png
new file mode 100644
index 00000000000..e523ba40825
Binary files /dev/null and b/share/qtcreator/qmldesigner/welcomepage/images/ds.png differ
diff --git a/share/qtcreator/qmldesigner/welcomepage/images/ellipse-pie.png b/share/qtcreator/qmldesigner/welcomepage/images/ellipse-pie.png
new file mode 100644
index 00000000000..a081ea81bf9
Binary files /dev/null and b/share/qtcreator/qmldesigner/welcomepage/images/ellipse-pie.png differ
diff --git a/share/qtcreator/qmldesigner/welcomepage/images/newThumbnail.png b/share/qtcreator/qmldesigner/welcomepage/images/newThumbnail.png
new file mode 100644
index 00000000000..046c0535709
Binary files /dev/null and b/share/qtcreator/qmldesigner/welcomepage/images/newThumbnail.png differ
diff --git a/share/qtcreator/qmldesigner/welcomepage/images/noPreview.png b/share/qtcreator/qmldesigner/welcomepage/images/noPreview.png
new file mode 100644
index 00000000000..33641e6fb02
Binary files /dev/null and b/share/qtcreator/qmldesigner/welcomepage/images/noPreview.png differ
diff --git a/share/qtcreator/qmldesigner/welcomepage/images/place_holder.png b/share/qtcreator/qmldesigner/welcomepage/images/place_holder.png
new file mode 100644
index 00000000000..96e7e637964
Binary files /dev/null and b/share/qtcreator/qmldesigner/welcomepage/images/place_holder.png differ
diff --git a/share/qtcreator/qmldesigner/welcomepage/images/sorting-components.png b/share/qtcreator/qmldesigner/welcomepage/images/sorting-components.png
new file mode 100644
index 00000000000..19b2182d3f5
Binary files /dev/null and b/share/qtcreator/qmldesigner/welcomepage/images/sorting-components.png differ
diff --git a/share/qtcreator/qmldesigner/welcomepage/images/states.png b/share/qtcreator/qmldesigner/welcomepage/images/states.png
new file mode 100644
index 00000000000..41f1bbaddd8
Binary files /dev/null and b/share/qtcreator/qmldesigner/welcomepage/images/states.png differ
diff --git a/share/qtcreator/qmldesigner/welcomepage/images/thumbnailImage.png b/share/qtcreator/qmldesigner/welcomepage/images/thumbnailImage.png
new file mode 100644
index 00000000000..f54508029a6
Binary files /dev/null and b/share/qtcreator/qmldesigner/welcomepage/images/thumbnailImage.png differ
diff --git a/share/qtcreator/qmldesigner/welcomepage/images/thumbnail_test.png b/share/qtcreator/qmldesigner/welcomepage/images/thumbnail_test.png
new file mode 100644
index 00000000000..3c4834e6448
Binary files /dev/null and b/share/qtcreator/qmldesigner/welcomepage/images/thumbnail_test.png differ
diff --git a/share/qtcreator/qmldesigner/welcomepage/images/top-toolbar.png b/share/qtcreator/qmldesigner/welcomepage/images/top-toolbar.png
new file mode 100644
index 00000000000..33601d658b3
Binary files /dev/null and b/share/qtcreator/qmldesigner/welcomepage/images/top-toolbar.png differ
diff --git a/share/qtcreator/qmldesigner/welcomepage/images/twitterDarkNormal.png b/share/qtcreator/qmldesigner/welcomepage/images/twitterDarkNormal.png
new file mode 100644
index 00000000000..bd2349329c3
Binary files /dev/null and b/share/qtcreator/qmldesigner/welcomepage/images/twitterDarkNormal.png differ
diff --git a/share/qtcreator/qmldesigner/welcomepage/images/twitterHover.png b/share/qtcreator/qmldesigner/welcomepage/images/twitterHover.png
new file mode 100644
index 00000000000..a10316113d0
Binary files /dev/null and b/share/qtcreator/qmldesigner/welcomepage/images/twitterHover.png differ
diff --git a/share/qtcreator/qmldesigner/welcomepage/images/twitterLightNormal.png b/share/qtcreator/qmldesigner/welcomepage/images/twitterLightNormal.png
new file mode 100644
index 00000000000..b6ad88c5b62
Binary files /dev/null and b/share/qtcreator/qmldesigner/welcomepage/images/twitterLightNormal.png differ
diff --git a/share/qtcreator/qmldesigner/welcomepage/images/welcome-page.png b/share/qtcreator/qmldesigner/welcomepage/images/welcome-page.png
new file mode 100644
index 00000000000..4c072eb2a17
Binary files /dev/null and b/share/qtcreator/qmldesigner/welcomepage/images/welcome-page.png differ
diff --git a/share/qtcreator/qmldesigner/welcomepage/images/workspaces.png b/share/qtcreator/qmldesigner/welcomepage/images/workspaces.png
new file mode 100644
index 00000000000..ce4b5f61586
Binary files /dev/null and b/share/qtcreator/qmldesigner/welcomepage/images/workspaces.png differ
diff --git a/share/qtcreator/qmldesigner/welcomepage/images/youtubeDarkHover.png b/share/qtcreator/qmldesigner/welcomepage/images/youtubeDarkHover.png
new file mode 100644
index 00000000000..a58f1cd0cf3
Binary files /dev/null and b/share/qtcreator/qmldesigner/welcomepage/images/youtubeDarkHover.png differ
diff --git a/share/qtcreator/qmldesigner/welcomepage/images/youtubeDarkNormal.png b/share/qtcreator/qmldesigner/welcomepage/images/youtubeDarkNormal.png
new file mode 100644
index 00000000000..7c5a5cd918e
Binary files /dev/null and b/share/qtcreator/qmldesigner/welcomepage/images/youtubeDarkNormal.png differ
diff --git a/share/qtcreator/qmldesigner/welcomepage/images/youtubeLightHover.png b/share/qtcreator/qmldesigner/welcomepage/images/youtubeLightHover.png
new file mode 100644
index 00000000000..15a16b3bb1a
Binary files /dev/null and b/share/qtcreator/qmldesigner/welcomepage/images/youtubeLightHover.png differ
diff --git a/share/qtcreator/qmldesigner/welcomepage/images/youtubeLightNormal.png b/share/qtcreator/qmldesigner/welcomepage/images/youtubeLightNormal.png
new file mode 100644
index 00000000000..9ec959fc925
Binary files /dev/null and b/share/qtcreator/qmldesigner/welcomepage/images/youtubeLightNormal.png differ
diff --git a/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/Highlight.ui.qml b/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/Highlight.ui.qml
new file mode 100644
index 00000000000..a3bd85184a4
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/Highlight.ui.qml
@@ -0,0 +1,61 @@
+// 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.Timeline
+
+Rectangle {
+ id: root
+ width: 872
+ height: 860
+ radius: 4
+ color: "transparent"
+ border.color: "#1381e3"
+ border.width: 8
+ state: "off"
+
+ property bool active: true
+
+ states: [
+ State {
+ name: "on"
+ when: root.active
+
+ PropertyChanges {
+ target: root
+ }
+ },
+ State {
+ name: "off"
+ when: !root.active
+
+ PropertyChanges {
+ target: root
+ opacity: 0
+ }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ id: transition
+ to: "*"
+ from: "*"
+ ParallelAnimation {
+ SequentialAnimation {
+ PauseAnimation { duration: 0 }
+
+ PropertyAnimation {
+ target: root
+ property: "opacity"
+ duration: 150
+ }
+ }
+ }
+ }
+ ]
+}
+
+
+
diff --git a/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/Slide.qml b/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/Slide.qml
new file mode 100644
index 00000000000..cb94d05ad29
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/Slide.qml
@@ -0,0 +1,118 @@
+// 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.Timeline
+
+Item {
+ id: root
+ width: 1920
+ height: 1080
+
+ property string caption: "This is a string"
+ property string title: "this is a string"
+ property bool active: false
+
+ function prev() {
+ var states = root.stateNames()
+
+ if (states.length === 0)
+ return false
+
+ if (root.state === "")
+ return false
+
+ var index = states.indexOf(root.state)
+
+ // base state is not in the list
+ if (index > 0) {
+ root.state = states[index - 1]
+ return true
+ }
+
+ return false
+ }
+
+ function next() {
+ var states = root.stateNames()
+
+ if (states.length === 0)
+ return false
+
+ if (root.state === "") {
+ root.state = states[0]
+ return true
+ }
+
+ var index = states.indexOf(root.state)
+
+ if (index < (states.length - 1)) {
+ root.state = states[index + 1]
+ return true
+ }
+
+ return false
+ }
+
+ function stateNames() {
+ var states = []
+
+ for (var i = 0; i < root.states.length; i++) {
+ var state = root.states[i]
+ states.push(state.name)
+ }
+
+ return states
+ }
+
+ signal activated
+
+ function activate() {
+ root.active = true
+ stateGroup.state = "active"
+ root.activated()
+ }
+
+ function done() {
+ stateGroup.state = "done"
+ }
+
+ function init() {
+ root.active = false
+ stateGroup.state = "inactive"
+ }
+
+ StateGroup {
+ id: stateGroup
+ states: [
+ State {
+ name: "active"
+
+ PropertyChanges {
+ target: root
+ opacity: 1
+ visible: true
+ }
+ },
+ State {
+ name: "inactive"
+
+ PropertyChanges {
+ target: root
+ opacity: 0
+ visible: true
+ }
+ },
+ State {
+ name: "done"
+
+ PropertyChanges {
+ target: root
+ opacity: 1
+ visible: true
+ }
+ }
+ ]
+ }
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/SlideNavButton.qml b/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/SlideNavButton.qml
new file mode 100644
index 00000000000..07f744e300e
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/SlideNavButton.qml
@@ -0,0 +1,71 @@
+// 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 WelcomeScreen 1.0
+import StudioTheme 1.0 as StudioTheme
+import UiTour
+
+Item {
+ id: tourButton
+ width: 120
+ height: 120
+ property alias dialogButtonRotation: dialogButton.rotation
+ property alias dialogButtonFontpixelSize: dialogButton.font.pixelSize
+ property alias dialogButtonText: dialogButton.text
+
+ signal buttonClicked
+
+ Text {
+ id: dialogButton
+ color: "#ffffff"
+ text: StudioTheme.Constants.nextFile_large
+ font.family: StudioTheme.Constants.iconFont.family
+ font.pixelSize: 32
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+ hoverEnabled: true
+
+ Connections {
+ target: mouseArea
+ onClicked: tourButton.buttonClicked()
+ }
+ }
+
+ states: [
+ State {
+ name: "normal"
+ when: !mouseArea.containsMouse && !mouseArea.pressed
+
+ PropertyChanges {
+ target: dialogButton
+ color: "#ecebeb"
+ font.pixelSize: 92
+ }
+ },
+ State {
+ name: "hover"
+ when: mouseArea.containsMouse && !mouseArea.pressed
+
+ PropertyChanges {
+ target: dialogButton
+ font.pixelSize: 96
+ }
+ },
+ State {
+ name: "press"
+ when: mouseArea.pressed
+
+ PropertyChanges {
+ target: dialogButton
+ font.pixelSize: 98
+ }
+ }
+ ]
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/SlidePlayer.qml b/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/SlidePlayer.qml
new file mode 100644
index 00000000000..56642239902
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/SlidePlayer.qml
@@ -0,0 +1,132 @@
+// 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.Layouts
+import QtQuick.Shapes
+import UiTour
+
+Item {
+ id: root
+ width: 1920
+ height: 1080
+ visible: true
+
+ property alias slideSource: loader.source
+ property alias loaderActive: loader.active
+ property var mainScreen: loader.item
+
+ Image {
+ id: gradientRect
+ anchors.fill: parent
+ source: "gradientRect.webp"
+ mipmap: true
+ fillMode: Image.Stretch
+ }
+
+ RowLayout {
+ anchors.fill: parent
+
+ Item {
+ Layout.preferredWidth: 160
+ Layout.maximumWidth: 160
+ Layout.fillHeight: true
+
+ SlideNavButton {
+ id: prevSlideButton
+ dialogButtonRotation: 180
+ visible: ((mainScreen.currentSlide + 1) !== 1)
+ anchors.fill: parent
+
+ Connections {
+ target: prevSlideButton
+ onButtonClicked: mainScreen.prev()
+ }
+ }
+ }
+
+ Column {
+ id: content
+ Layout.fillWidth: true
+ Layout.preferredWidth: 120
+
+ Item {
+ id: titleFrame
+ width: content.width
+ height: 100
+
+ Text {
+ color: "#ffffff"
+ text: mainScreen.title
+ font.pixelSize: 40
+ font.bold: true
+ wrapMode: Text.WordWrap
+ anchors.centerIn: parent
+ }
+ }
+
+ Item {
+ id: slideFrame
+ width: content.width
+ height: Math.min(1080 * content.width / 1920,
+ root.height - (titleFrame.height + captionFrame.height + indicatorFrame.height))
+
+ Loader {
+ id: loader
+ source: "MySlideShow.ui.qml"
+ transformOrigin: Item.Center
+ scale: Math.min(slideFrame.width / 1920, slideFrame.height / 1080)
+ anchors.centerIn: parent
+ }
+ }
+
+ Item {
+ id: captionFrame
+ width: content.width
+ height: 140
+
+ Text {
+ id: captionText
+ color: "#ffffff"
+ text: mainScreen.caption
+ font.pixelSize: 20
+ font.bold: true
+ wrapMode: Text.WordWrap
+ anchors.fill: parent
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+ }
+
+ Item {
+ id: indicatorFrame
+ width: content.width
+ height: 100
+
+ Text {
+ color: "#ffffff"
+ text: (mainScreen.currentSlide + 1) + "/" + mainScreen.progress
+ font.pixelSize: 20
+ anchors.centerIn: parent
+ }
+ }
+ }
+
+ Item {
+ Layout.preferredWidth: 160
+ Layout.maximumWidth: 160
+ Layout.fillHeight: true
+
+ SlideNavButton {
+ id: nextSlideButton
+ visible: (mainScreen.progress !== (mainScreen.currentSlide + 1))
+ anchors.fill: parent
+
+ Connections {
+ target: nextSlideButton
+ onButtonClicked: mainScreen.next()
+ }
+ }
+ }
+ }
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/SlideShow.qml b/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/SlideShow.qml
new file mode 100644
index 00000000000..8e7195fcb1c
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/SlideShow.qml
@@ -0,0 +1,85 @@
+// 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
+
+Rectangle {
+ id: root
+ width: 1920
+ height: 1080
+ color: "#00000000"
+
+ property string caption
+ property string title
+
+ property int progress: 0
+ property int currentSlide: 0
+
+ function next() {
+ if (root.currentSlide === (root.progress - 1))
+ return
+
+ var index = root.findActive()
+ var current = root.children[index]
+
+ root.currentSlide++
+
+ if (current.next()) {
+ root.caption = current.caption
+ root.title = current.title
+ return
+ }
+
+ root.children[index].init()
+ root.children[index + 1].activate()
+
+ root.caption = root.children[index + 1].caption
+ root.title = root.children[index + 1].title
+ }
+
+ function prev() {
+ if (root.currentSlide === 0)
+ return
+
+ var index = root.findActive()
+ var current = root.children[index]
+
+ root.currentSlide--
+
+ if (current.prev()) {
+ root.caption = current.caption
+ root.title = current.title
+ return
+ }
+
+ root.children[index].init()
+ root.children[index - 1].activate()
+ root.caption = root.children[index - 1].caption
+ root.title = root.children[index - 1].title
+ }
+
+ function findActive() {
+ for (var i = 0; i < root.children.length; i++) {
+ var child = root.children[i]
+ if (child.active)
+ return i
+ }
+ return -1
+ }
+
+ Component.onCompleted: {
+ for (var i = 0; i < root.children.length; i++) {
+ var child = root.children[i]
+ child.init()
+ root.progress += child.states.length
+ if (i === 0) {
+ child.visible = true
+ child.activate()
+ }
+ }
+
+ root.caption = root.children[0].caption
+ root.title = root.children[0].title
+ }
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/StrongHighlight.ui.qml b/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/StrongHighlight.ui.qml
new file mode 100644
index 00000000000..7b9f315b68f
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/StrongHighlight.ui.qml
@@ -0,0 +1,107 @@
+// 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.Timeline
+
+Rectangle {
+ id: root
+ width: 600
+ height: 600
+ radius: 2
+ color: "transparent"
+ border.color: "#1381e3"
+ border.width: 8
+ state: "off"
+
+ property bool active: true
+
+ property color shadowColor: "#aa1b1b1b"
+
+ property int globalX: root.x //200
+ property int globalY: root.y //200
+ property int parentWidth: root.parent.width //1200
+ property int parentHeight: root.parent.height //1200
+
+ Rectangle {
+ z: -1
+ color: "transparent"
+ anchors.fill: parent
+ border.color: root.shadowColor
+ border.width: 3
+ }
+
+ Rectangle {
+ x: -width
+ z: -1
+ width: root.globalX
+ height: root.height
+ color: root.shadowColor
+ }
+
+ Rectangle {
+ x: root.width
+ z: -1
+ width: root.parentWidth - root.globalX - root.width
+ height: root.height
+ color: root.shadowColor
+ }
+
+ Rectangle {
+ x: -root.globalX
+ y: -root.globalY
+ z: -1
+ width: root.parentWidth
+ height: root.globalY
+ color: root.shadowColor
+ }
+
+ Rectangle {
+ x: -root.globalX
+ y: root.height
+ z: -1
+ width: root.parentWidth
+ height: root.parentHeight - root.globalY - root.height
+ color: root.shadowColor
+ }
+
+ states: [
+ State {
+ name: "on"
+ when: root.active
+
+ PropertyChanges {
+ target: root
+ }
+ },
+ State {
+ name: "off"
+ when: !root.active
+
+ PropertyChanges {
+ target: root
+ opacity: 0
+ }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ id: transition
+ to: "*"
+ from: "*"
+ ParallelAnimation {
+ SequentialAnimation {
+ PauseAnimation { duration: 0 }
+
+ PropertyAnimation {
+ target: root
+ property: "opacity"
+ duration: 150
+ }
+ }
+ }
+ }
+ ]
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/gradientRect.webp b/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/gradientRect.webp
new file mode 100644
index 00000000000..78c2be6dbe9
Binary files /dev/null and b/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/gradientRect.webp differ
diff --git a/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/qmldir b/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/qmldir
new file mode 100644
index 00000000000..cf5ba7db2f1
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/imports/UiTour/qmldir
@@ -0,0 +1,6 @@
+Highlight 1.0 Highlight.ui.qml
+StrongHighlight 1.0 StrongHighlight.ui.qml
+Slide 1.0 Slide.qml
+SlideShow 1.0 SlideShow.qml
+SlidePlayer 1.0 SlidePlayer.qml
+SlideNavButton 1.0 SlideNavButton.qml
diff --git a/share/qtcreator/qmldesigner/welcomepage/imports/WelcomeScreen/Constants.qml b/share/qtcreator/qmldesigner/welcomepage/imports/WelcomeScreen/Constants.qml
new file mode 100644
index 00000000000..2e4806cff5b
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/imports/WelcomeScreen/Constants.qml
@@ -0,0 +1,189 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+pragma Singleton
+
+import QtQuick
+import StudioTheme 1.0
+import projectmodel 1.0
+
+QtObject {
+ id: root
+
+ property int loadingProgress: 100
+ readonly property int width: 1842
+ readonly property int height: 1080
+ property bool communityEdition: projectModel.communityVersion
+ property bool enterpriseEdition: projectModel.enterpriseVersion
+
+ /* Edit this comment to add your custom font */
+ readonly property font font: Qt.font({
+ "family": Qt.application.font.family,
+ "pixelSize": Qt.application.font.pixelSize
+ })
+ readonly property font largeFont: Qt.font({
+ "family": Qt.application.font.family,
+ "pixelSize": Qt.application.font.pixelSize * 1.6
+ })
+
+ readonly property color backgroundColor: "#c2c2c2"
+
+ property var projectModel: ProjectModel {}
+
+ // Responsive grid stuff
+ readonly property int minColumnCount: 2
+ readonly property int minThumbnailSize: 244
+ readonly property int gridSpacing: 8
+ readonly property int scrollBarWidth: 10
+ readonly property int gridMargins: 20
+ readonly property int scrollBarTrackSize: 10
+
+ property int thumbnailSize: root.adaptiveThumbnailSize
+ property int gridCellSize: root.adaptiveThumbnailSize + root.gridSpacing
+ property int adaptiveThumbnailSize: root.minThumbnailSize // default to minimum size
+
+ function responsiveResize(width) {
+ var columnCount = Math.max(Math.floor(width / (root.minThumbnailSize + root.gridSpacing)),
+ root.minColumnCount)
+ root.adaptiveThumbnailSize = Math.floor((width + root.gridSpacing) / columnCount - root.gridSpacing)
+ }
+
+ // Thumbnail margins and sizes
+ property int thumbnailMargin: 10
+ property int imageBottomMargin: 90
+ property int titleBackgroundTopMargin: 5
+ property int titleHeight: 30
+ property int titleHeightMultiline: 52
+ property int titleMargin: 5
+
+ /// THEME
+
+ /// theme selector
+ property int currentTheme: 0
+ property bool defaultBrand: true
+ property bool basic: true
+
+ /// list view
+ property bool isListView: false
+
+ /// Current theme - USE THESE IN YOUR PROPERTY BINDINGS!
+
+ /// TRAFFIC LIGHT SYSTEM
+ property color greenLight: Values.themeGreenLight
+ property color amberLight: Values.themeAmberLight
+ property color redLight: Values.themeRedLight
+
+ /// BRAND
+ property string currentBrand: root.defaultBrand ? root.qdsBrand : root.creatorBrand
+
+ /// TEXT
+ property color currentGlobalText: Values.themeTextColor
+ property color currentActiveGlobalText: "#ffffff"
+ property string brandGlobalText: root.defaultBrand ? root.qdsGlobalText : root.creatorGlobalText
+
+ /// BACKGROUND
+ property color currentThemeBackground: Values.welcomeScreenBackground
+
+ /// DIALOG
+ property color currentDialogBackground: Values.themeThumbnailBackground
+ property color currentDialogBorder: root.currentBrand
+
+ /// BUTTONS
+ property color currentPushButtonNormalBackground: Values.themeControlBackground
+ property color currentPushButtonHoverBackground: Values.themeControlBackgroundHover
+
+ property color currentPushButtonNormalOutline: Values.themeControlOutline
+ property color currentPushButtonHoverOutline: Values.themeControlOutline
+
+ /// THUMBNAILS
+ property color currentThumbnailGridBackground: Values.themeSubPanelBackground
+
+ property color currentNormalThumbnailBackground: Values.themeThumbnailBackground
+ property color currentHoverThumbnailBackground: Values.themeControlBackgroundGlobalHover
+
+ property color currentNormalThumbnailLabelBackground: Values.themeThumbnailLabelBackground
+ property color currentHoverThumbnailLabelBackground: Values.themeControlBackgroundInteraction
+
+ /// TOOLTIP
+ property color currentToolTipBackground: Values.themeToolTipBackground
+ property color currentToolTipOutline: Values.themeToolTipOutline
+ property color currentToolTipText: Values.themeToolTipText
+
+ property color currentScrollBarTrack: Values.themeScrollBarTrack
+ property color currentScrollBarHandle: Values.themeScrollBarHandle
+ property color currentScrollBarHandle_idle: Values.themeScrollBarHandle_idle
+
+ /// GLOBAL COLORS
+
+ /// brand
+ property string creatorBrand: "#54D263"
+ property string qdsBrand: "#57B9FC"
+
+
+ /// DARK THEME COLORS
+ property string darkBackground: "#242424"
+ property string modeBarDark: "#414141"
+
+ /// globalText
+ property string darkGlobalText: "#ffffff"
+ property string darkActiveGlobalText: "#111111"
+ property string qdsGlobalText: "#ffffff"
+ property string creatorGlobalText: "#111111"
+
+ /// button
+ property string darkPushButtonNormalBackground: "#323232"
+ property string darkPushButtonNormalOutline: "#000000"
+ property string darkPushButtonHoverBackground: "#474747"
+ property string darkPushButtonHoverOutline: "#000000"
+
+ /// thumbnails
+ property string darkThumbnailGridBackground: "#040404"
+ property string darkNormalThumbnailBackground: "#292929"
+ property string darkNormalThumbnailLabelBackground: "#3D3D3D"
+ property string darkHoverThumbnailBackground: "#323232"
+ property string darkHoverThumbnailLabelBackground: "#474747"
+
+
+ /// MID THEME COLORS
+ property string midBackground: "#514e48"
+ property string modeBarMid: "#737068"
+
+ /// globalText
+ property string midGlobalText: "#ffffff"
+ property string midActiveGlobalText: "#111111"
+
+ /// button
+ property string midPushButtonNormalBackground: "#43413c"
+ property string midPushButtonNormalOutline: "#636058"
+ property string midPushButtonHoverBackground: "#504D47"
+ property string midPushButtonHoverOutline: "#737068"
+
+ /// thumbnails
+ property string midThumbnailGridBackground: "#383732"
+ property string midNormalThumbnailBackground: "#514e48"
+ property string midNormalThumbnailLabelBackground: "#43413c"
+ property string midHoverThumbnailBackground: "#5B5851"
+ property string midHoverThumbnailLabelBackground: "#43413c"
+
+
+ /// LIGHT THEME COLORS
+ property string lightBackground: "#EAEAEA"
+ property string modeBarLight: "#D1CFCF"
+
+ /// globalText
+ property string lightGlobalText: "#111111"
+ property string lightActiveGlobalText: "#ffffff"
+
+ /// button
+ property string lightPushButtonNormalBackground: "#eaeaea"
+ property string lightPushButtonNormalOutline: "#CACECE"
+ property string lightPushButtonHoverBackground: "#E5E5E5"
+ property string lightPushButtonHoverOutline: "#CACECE"
+
+ /// thumbnails
+ property string lightThumbnailGridBackground: "#EFEFEF"
+ property string lightNormalThumbnailBackground: "#F2F2F2"
+ property string lightNormalThumbnailLabelBackground: "#EBEBEB"
+ property string lightHoverThumbnailBackground: "#EAEAEA"
+ property string lightHoverThumbnailLabelBackground: "#E1E1E1"
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/imports/WelcomeScreen/designer/plugin.metainfo b/share/qtcreator/qmldesigner/welcomepage/imports/WelcomeScreen/designer/plugin.metainfo
new file mode 100644
index 00000000000..680b425c544
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/imports/WelcomeScreen/designer/plugin.metainfo
@@ -0,0 +1,13 @@
+MetaInfo {
+ Type {
+ name: "WelcomeScreen.EventListSimulator"
+ icon: ":/qtquickplugin/images/item-icon16.png"
+
+ Hints {
+ visibleInNavigator: true
+ canBeDroppedInNavigator: true
+ canBeDroppedInFormEditor: false
+ canBeDroppedInView3D: false
+ }
+ }
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/imports/WelcomeScreen/qmldir b/share/qtcreator/qmldesigner/welcomepage/imports/WelcomeScreen/qmldir
new file mode 100644
index 00000000000..69846237302
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/imports/WelcomeScreen/qmldir
@@ -0,0 +1,2 @@
+singleton Constants 1.0 Constants.qml
+EventListSimulator 1.0 EventListSimulator.qml
diff --git a/share/qtcreator/qmldesigner/welcomepage/main.qml b/share/qtcreator/qmldesigner/welcomepage/main.qml
new file mode 100644
index 00000000000..d76567b0352
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/main.qml
@@ -0,0 +1,22 @@
+// 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 WelcomeScreen 1.0
+
+Loader {
+ id: loader
+ asynchronous: false
+ source: "MainScreen.qml"
+
+ property int loadingProgress: 50
+
+ onLoadingProgressChanged: {
+ Constants.loadingProgress = loader.loadingProgress
+ }
+
+ Rectangle {
+ anchors.fill: parent
+ color: Constants.currentThemeBackground
+ }
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/main.qml.qml b/share/qtcreator/qmldesigner/welcomepage/main.qml.qml
new file mode 100644
index 00000000000..fdd65d5fb0c
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/main.qml.qml
@@ -0,0 +1,10 @@
+// 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
+
+MainScreen {
+ color: "#ffffff"
+ border.color: "#ffffff"
+
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/mockData/ExampleCheckout/FileDownloader.qml b/share/qtcreator/qmldesigner/welcomepage/mockData/ExampleCheckout/FileDownloader.qml
new file mode 100644
index 00000000000..28801f75974
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/mockData/ExampleCheckout/FileDownloader.qml
@@ -0,0 +1,16 @@
+// 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 2.0
+
+QtObject {
+ property url url
+ property bool finished
+ property bool error
+ property string name
+ property string completeBaseName
+ property int progress
+ property string outputFile
+ property date lastModified
+ property bool available
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/mockData/ExampleCheckout/FileExtractor.qml b/share/qtcreator/qmldesigner/welcomepage/mockData/ExampleCheckout/FileExtractor.qml
new file mode 100644
index 00000000000..ab6ea047fe7
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/mockData/ExampleCheckout/FileExtractor.qml
@@ -0,0 +1,21 @@
+// 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 2.0
+
+QtObject {
+
+ property string targetPath
+ property string archiveName
+ property string detailedText
+ property string currentFile
+ property string size
+ property string count
+ property string sourceFile
+
+ property bool finished
+ property bool targetFolderExists
+
+ property int progress
+ property date birthTime
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/mockData/ExampleCheckout/qmldir b/share/qtcreator/qmldesigner/welcomepage/mockData/ExampleCheckout/qmldir
new file mode 100644
index 00000000000..d4bbe253106
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/mockData/ExampleCheckout/qmldir
@@ -0,0 +1,2 @@
+FileExtractor 1.0 FileExtractor.qml
+FileDownloader 1.0 FileDownloader.qml
diff --git a/share/qtcreator/qmldesigner/welcomepage/mockData/projectmodel/ProjectModel.qml b/share/qtcreator/qmldesigner/welcomepage/mockData/projectmodel/ProjectModel.qml
new file mode 100644
index 00000000000..dc083056dc4
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/mockData/projectmodel/ProjectModel.qml
@@ -0,0 +1,117 @@
+// 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
+
+ListModel {
+ property bool communityVersion: true
+ property bool designMode: true
+
+ ListElement {
+ displayName: "Project 01"
+ prettyFilePath: "my_file_1"
+ thumbnail: "images/thumbnail_test.png"
+ }
+
+ ListElement {
+ displayName: "Project 02"
+ prettyFilePath: "my_file_2"
+ thumbnail: "images/thumbnail_test.png"
+ }
+
+ ListElement {
+ displayName: "Project 03"
+ prettyFilePath: "my_file_3"
+ thumbnail: "images/thumbnail_test.png"
+ }
+
+ ListElement {
+ displayName: "Project 04"
+ prettyFilePath: "my_file_4"
+ thumbnail: "images/thumbnail_test.png"
+ }
+
+ ListElement {
+ displayName: "Project 05"
+ prettyFilePath: "my_file_5"
+ thumbnail: "images/thumbnail_test.png"
+ }
+
+ ListElement {
+ displayName: "Project 06"
+ prettyFilePath: "my_file_6"
+ thumbnail: "images/thumbnail_test.png"
+ }
+
+ ListElement {
+ displayName: "Project 07"
+ prettyFilePath: "my_file_7"
+ thumbnail: "images/thumbnail_test.png"
+ }
+
+ ListElement {
+ displayName: "Project 08"
+ filename: "my_file_8"
+ thumbnail: "images/thumbnail_test.png"
+ }
+
+ ListElement {
+ displayName: "Project 09"
+ filename: "my_file_9"
+ thumbnail: "images/thumbnail_test.png"
+ }
+
+ ListElement {
+ displayName: "Project 10"
+ prettyFilePath: "my_file_10"
+ thumbnail: "images/thumbnail_test.png"
+ }
+
+ ListElement {
+ displayName: "Project 11"
+ filename: "my_file_11"
+ thumbnail: "images/thumbnail_test.png"
+ }
+
+ ListElement {
+ displayName: "Project 12"
+ prettyFilePath: "my_file_12"
+ thumbnail: "images/thumbnail_test.png"
+ }
+
+ ListElement {
+ displayName: "Project 13"
+ filename: "my_file_13"
+ thumbnail: "images/thumbnail_test.png"
+ }
+
+ ListElement {
+ displayName: "Project 14"
+ prettyFilePath: "my_file_14"
+ thumbnail: "images/thumbnail_test.png"
+ }
+
+ ListElement {
+ displayName: "Project 15"
+ filename: "my_file_15"
+ thumbnail: "images/thumbnail_test.png"
+ }
+
+ ListElement {
+ displayName: "Project 16"
+ filename: "my_file_16"
+ thumbnail: "images/thumbnail_test.png"
+ }
+
+ ListElement {
+ displayName: "Project 17"
+ filename: "my_file_17"
+ thumbnail: "images/thumbnail_test.png"
+ }
+
+ ListElement {
+ displayName: "Project 18"
+ prettyFilePath: "my_file_18"
+ thumbnail: "images/thumbnail_test.png"
+ }
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/mockData/projectmodel/qmldir b/share/qtcreator/qmldesigner/welcomepage/mockData/projectmodel/qmldir
new file mode 100644
index 00000000000..0d7bc345c2b
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/mockData/projectmodel/qmldir
@@ -0,0 +1 @@
+ProjectModel 1.0 ProjectModel.qml
diff --git a/share/qtcreator/qmldesigner/welcomepage/mockData/usagestatistics/UsageStatisticModel.qml b/share/qtcreator/qmldesigner/welcomepage/mockData/usagestatistics/UsageStatisticModel.qml
new file mode 100644
index 00000000000..583f80b690f
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/mockData/usagestatistics/UsageStatisticModel.qml
@@ -0,0 +1,8 @@
+// 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
+
+QtObject {
+ property bool usageStatisticEnabled: false
+}
diff --git a/share/qtcreator/qmldesigner/welcomepage/mockData/usagestatistics/qmldir b/share/qtcreator/qmldesigner/welcomepage/mockData/usagestatistics/qmldir
new file mode 100644
index 00000000000..c83a43a8ae7
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/mockData/usagestatistics/qmldir
@@ -0,0 +1 @@
+UsageStatisticModel 1.0 UsageStatisticModel.qml
diff --git a/share/qtcreator/qmldesigner/welcomepage/qtquickcontrols2.conf b/share/qtcreator/qmldesigner/welcomepage/qtquickcontrols2.conf
new file mode 100644
index 00000000000..db9486764e7
--- /dev/null
+++ b/share/qtcreator/qmldesigner/welcomepage/qtquickcontrols2.conf
@@ -0,0 +1,2 @@
+[Controls]
+Style=Basic