2023-08-16 12:57:41 +03:00
|
|
|
// Copyright (C) 2023 The Qt Company Ltd.
|
|
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
|
|
|
|
|
|
|
|
|
import QtQuick
|
|
|
|
|
import QtQuickDesignerTheme
|
|
|
|
|
import HelperWidgets as HelperWidgets
|
|
|
|
|
import StudioControls as StudioControls
|
|
|
|
|
import StudioTheme 1.0 as StudioTheme
|
|
|
|
|
import EffectMakerBackend
|
|
|
|
|
|
|
|
|
|
Column {
|
|
|
|
|
id: root
|
|
|
|
|
|
2023-11-06 14:41:31 +02:00
|
|
|
property real animatedTime: previewFrameTimer.elapsedTime
|
|
|
|
|
property int animatedFrame: previewFrameTimer.currentFrame
|
|
|
|
|
property bool timeRunning: previewAnimationRunning
|
2023-10-19 16:39:21 +03:00
|
|
|
|
2023-08-16 12:57:41 +03:00
|
|
|
width: parent.width
|
|
|
|
|
|
2023-09-19 14:10:39 +03:00
|
|
|
required property Item mainRoot
|
2023-10-02 14:20:11 +03:00
|
|
|
property var effectMakerModel: EffectMakerBackend.effectMakerModel
|
2023-10-02 11:33:15 +03:00
|
|
|
property alias source: source
|
2023-10-03 10:34:50 +03:00
|
|
|
// The delay in ms to wait until updating the effect
|
2023-10-11 18:59:03 +03:00
|
|
|
readonly property int updateDelay: 100
|
2023-10-02 11:33:15 +03:00
|
|
|
|
2023-10-09 13:46:08 +03:00
|
|
|
// Create a dummy parent to host the effect qml object
|
|
|
|
|
function createNewComponent() {
|
|
|
|
|
var oldComponent = componentParent.children[0];
|
|
|
|
|
if (oldComponent)
|
|
|
|
|
oldComponent.destroy();
|
|
|
|
|
try {
|
|
|
|
|
const newObject = Qt.createQmlObject(
|
|
|
|
|
effectMakerModel.qmlComponentString,
|
|
|
|
|
componentParent,
|
|
|
|
|
""
|
|
|
|
|
);
|
|
|
|
|
effectMakerModel.resetEffectError(0);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
let errorString = "QML: ERROR: ";
|
|
|
|
|
let errorLine = -1;
|
|
|
|
|
if (error.qmlErrors.length > 0) {
|
|
|
|
|
// Show the first QML error
|
|
|
|
|
let e = error.qmlErrors[0];
|
|
|
|
|
errorString += e.lineNumber + ": " + e.message;
|
|
|
|
|
errorLine = e.lineNumber;
|
|
|
|
|
}
|
|
|
|
|
effectMakerModel.setEffectError(errorString, 0, errorLine);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-16 12:57:41 +03:00
|
|
|
Rectangle { // toolbar
|
|
|
|
|
width: parent.width
|
|
|
|
|
height: StudioTheme.Values.toolbarHeight
|
|
|
|
|
color: StudioTheme.Values.themeToolbarBackground
|
|
|
|
|
|
2023-11-09 19:52:58 +02:00
|
|
|
Row {
|
2023-08-16 12:57:41 +03:00
|
|
|
spacing: 5
|
2023-08-29 23:08:43 +03:00
|
|
|
anchors.leftMargin: 5
|
2023-11-09 19:52:58 +02:00
|
|
|
anchors.left: parent.left
|
2023-11-10 16:17:43 +02:00
|
|
|
anchors.verticalCenter: parent.verticalCenter
|
2023-08-29 23:08:43 +03:00
|
|
|
|
2023-09-19 14:10:39 +03:00
|
|
|
PreviewImagesComboBox {
|
|
|
|
|
id: imagesComboBox
|
|
|
|
|
|
|
|
|
|
mainRoot: root.mainRoot
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-09 19:52:58 +02:00
|
|
|
StudioControls.ColorEditor {
|
|
|
|
|
id: colorEditor
|
|
|
|
|
|
|
|
|
|
actionIndicatorVisible: false
|
|
|
|
|
showHexTextField: false
|
|
|
|
|
color: "#dddddd"
|
2023-08-29 23:08:43 +03:00
|
|
|
}
|
2023-11-09 19:52:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Row {
|
|
|
|
|
spacing: 5
|
|
|
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
2023-11-10 16:17:43 +02:00
|
|
|
anchors.verticalCenter: parent.verticalCenter
|
2023-08-16 12:57:41 +03:00
|
|
|
|
|
|
|
|
HelperWidgets.AbstractButton {
|
2023-10-02 11:33:15 +03:00
|
|
|
enabled: sourceImage.scale > .4
|
2023-08-16 12:57:41 +03:00
|
|
|
style: StudioTheme.Values.viewBarButtonStyle
|
|
|
|
|
buttonIcon: StudioTheme.Constants.zoomOut_medium
|
|
|
|
|
tooltip: qsTr("Zoom out")
|
|
|
|
|
|
2023-08-29 23:08:43 +03:00
|
|
|
onClicked: {
|
2023-10-02 11:33:15 +03:00
|
|
|
sourceImage.scale -= .2
|
2023-08-29 23:08:43 +03:00
|
|
|
}
|
2023-08-16 12:57:41 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HelperWidgets.AbstractButton {
|
2023-10-02 11:33:15 +03:00
|
|
|
enabled: sourceImage.scale < 2
|
2023-08-16 12:57:41 +03:00
|
|
|
style: StudioTheme.Values.viewBarButtonStyle
|
|
|
|
|
buttonIcon: StudioTheme.Constants.zoomIn_medium
|
|
|
|
|
tooltip: qsTr("Zoom In")
|
|
|
|
|
|
2023-08-29 23:08:43 +03:00
|
|
|
onClicked: {
|
2023-10-02 11:33:15 +03:00
|
|
|
sourceImage.scale += .2
|
2023-08-29 23:08:43 +03:00
|
|
|
}
|
2023-08-16 12:57:41 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HelperWidgets.AbstractButton {
|
2023-10-02 11:33:15 +03:00
|
|
|
enabled: sourceImage.scale !== 1
|
2023-08-16 12:57:41 +03:00
|
|
|
style: StudioTheme.Values.viewBarButtonStyle
|
2023-09-05 18:03:05 +03:00
|
|
|
buttonIcon: StudioTheme.Constants.fitAll_medium
|
2023-08-16 12:57:41 +03:00
|
|
|
tooltip: qsTr("Zoom Fit")
|
|
|
|
|
|
2023-08-29 23:08:43 +03:00
|
|
|
onClicked: {
|
2023-10-02 11:33:15 +03:00
|
|
|
sourceImage.scale = 1
|
2023-08-29 23:08:43 +03:00
|
|
|
}
|
|
|
|
|
}
|
2023-11-09 19:52:58 +02:00
|
|
|
}
|
2023-08-29 23:08:43 +03:00
|
|
|
|
2023-11-09 19:52:58 +02:00
|
|
|
Row {
|
|
|
|
|
spacing: 5
|
|
|
|
|
anchors.rightMargin: 5
|
|
|
|
|
anchors.right: parent.right
|
2023-11-10 16:17:43 +02:00
|
|
|
anchors.verticalCenter: parent.verticalCenter
|
2023-08-16 12:57:41 +03:00
|
|
|
|
|
|
|
|
Column {
|
|
|
|
|
Text {
|
2023-11-06 14:41:31 +02:00
|
|
|
text: animatedTime >= 100
|
|
|
|
|
? animatedTime.toFixed(1) + " s" : animatedTime.toFixed(3) + " s"
|
2023-08-16 12:57:41 +03:00
|
|
|
color: StudioTheme.Values.themeTextColor
|
|
|
|
|
font.pixelSize: 10
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Text {
|
2023-11-06 14:41:31 +02:00
|
|
|
text: (animatedFrame).toString().padStart(6, '0')
|
2023-08-16 12:57:41 +03:00
|
|
|
color: StudioTheme.Values.themeTextColor
|
|
|
|
|
font.pixelSize: 10
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HelperWidgets.AbstractButton {
|
|
|
|
|
style: StudioTheme.Values.viewBarButtonStyle
|
|
|
|
|
buttonIcon: StudioTheme.Constants.toStartFrame_medium
|
|
|
|
|
tooltip: qsTr("Restart Animation")
|
|
|
|
|
|
2023-11-06 14:41:31 +02:00
|
|
|
onClicked: {
|
|
|
|
|
previewFrameTimer.reset()
|
|
|
|
|
}
|
2023-08-16 12:57:41 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HelperWidgets.AbstractButton {
|
|
|
|
|
style: StudioTheme.Values.viewBarButtonStyle
|
2023-11-08 16:03:23 +02:00
|
|
|
buttonIcon: previewAnimationRunning ? StudioTheme.Constants.pause_medium
|
|
|
|
|
: StudioTheme.Constants.playOutline_medium
|
2023-08-16 12:57:41 +03:00
|
|
|
tooltip: qsTr("Play Animation")
|
|
|
|
|
|
2023-11-06 14:41:31 +02:00
|
|
|
onClicked: {
|
|
|
|
|
previewAnimationRunning = !previewAnimationRunning
|
|
|
|
|
}
|
2023-08-16 12:57:41 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Rectangle { // preview image
|
2023-10-02 11:33:15 +03:00
|
|
|
id: preview
|
2023-08-16 12:57:41 +03:00
|
|
|
|
2023-11-09 19:52:58 +02:00
|
|
|
color: colorEditor.color
|
2023-08-16 12:57:41 +03:00
|
|
|
width: parent.width
|
|
|
|
|
height: 200
|
2023-08-29 23:08:43 +03:00
|
|
|
clip: true
|
2023-08-16 12:57:41 +03:00
|
|
|
|
2023-10-02 14:20:11 +03:00
|
|
|
Item { // Source item as a canvas (render target) for effect
|
2023-10-02 11:33:15 +03:00
|
|
|
id: source
|
2023-08-16 12:57:41 +03:00
|
|
|
anchors.fill: parent
|
2023-10-02 11:33:15 +03:00
|
|
|
layer.enabled: true
|
|
|
|
|
layer.mipmap: true
|
|
|
|
|
layer.smooth: true
|
|
|
|
|
|
|
|
|
|
Image {
|
|
|
|
|
id: sourceImage
|
|
|
|
|
anchors.margins: 5
|
|
|
|
|
anchors.fill: parent
|
|
|
|
|
fillMode: Image.PreserveAspectFit
|
|
|
|
|
source: imagesComboBox.selectedImage
|
|
|
|
|
smooth: true
|
|
|
|
|
|
|
|
|
|
Behavior on scale {
|
|
|
|
|
NumberAnimation {
|
|
|
|
|
duration: 200
|
|
|
|
|
easing.type: Easing.OutQuad
|
|
|
|
|
}
|
2023-08-29 23:08:43 +03:00
|
|
|
}
|
|
|
|
|
}
|
2023-08-16 12:57:41 +03:00
|
|
|
}
|
2023-10-02 14:20:11 +03:00
|
|
|
|
|
|
|
|
Item {
|
|
|
|
|
id: componentParent
|
|
|
|
|
width: source.width
|
|
|
|
|
height: source.height
|
2023-10-11 18:59:03 +03:00
|
|
|
anchors.centerIn: parent
|
2023-10-02 14:20:11 +03:00
|
|
|
// Cache the layer. This way heavy shaders rendering doesn't
|
|
|
|
|
// slow down code editing & rest of the UI.
|
|
|
|
|
layer.enabled: true
|
|
|
|
|
layer.smooth: true
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-03 10:34:50 +03:00
|
|
|
Connections {
|
|
|
|
|
target: effectMakerModel
|
|
|
|
|
function onShadersBaked() {
|
|
|
|
|
console.log("Shaders Baked!")
|
2023-10-11 18:59:03 +03:00
|
|
|
updateTimer.restart()
|
2023-10-03 10:34:50 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-02 14:20:11 +03:00
|
|
|
Timer {
|
|
|
|
|
id: updateTimer
|
2023-10-11 18:59:03 +03:00
|
|
|
interval: updateDelay
|
2023-10-02 14:20:11 +03:00
|
|
|
onTriggered: {
|
2023-10-11 18:59:03 +03:00
|
|
|
effectMakerModel.updateQmlComponent()
|
|
|
|
|
createNewComponent()
|
2023-10-02 14:20:11 +03:00
|
|
|
}
|
|
|
|
|
}
|
2023-08-16 12:57:41 +03:00
|
|
|
}
|
|
|
|
|
}
|