import QtQuick 2.15 import QtQml 2.15 Behavior { id: root property QtObject fadeTarget: targetProperty.object property string fadeProperty: "opacity" property var fadeProperties: [fadeProperty] property var exitValue: 0 property var enterValue: 0 property int fadeDuration: 300 property string easingType: "Quad" property bool delayWhile: false onDelayWhileChanged: { if (!delayWhile) sequentialAnimation.finished(); } readonly property Component shaderEffectSourceWrapperComponent: Item { id: ses property alias shaderEffectSource: shaderEffectSource property alias sourceItem: shaderEffectSource.sourceItem parent: sourceItem.parent x: sourceItem.x y: sourceItem.y ShaderEffectSource { id: shaderEffectSource transformOrigin: sourceItem.transformOrigin hideSource: true live: false width: sourceItem.width height: sourceItem.height } } readonly property Component defaultExitAnimation: NumberAnimation { properties: root.fadeProperties.join(',') duration: root.fadeDuration to: root.exitValue easing.type: root.easingType === "Linear" ? Easing.Linear : Easing["In"+root.easingType] } property Component exitAnimation: defaultExitAnimation readonly property Component defaultEnterAnimation: NumberAnimation { properties: root.fadeProperties.join(',') duration: root.fadeDuration from: root.enterValue to: root.fadeTarget[root.fadeProperties[0]] easing.type: root.easingType === "Linear" ? Easing.Linear : Easing["Out"+root.easingType] } property Component enterAnimation: defaultEnterAnimation SequentialAnimation { id: sequentialAnimation ScriptAction { script: { const exitItem = shaderEffectSourceWrapperComponent.createObject(null, { sourceItem: root.fadeTarget }); const exitShaderEffectSource = exitItem.shaderEffectSource; if (exitAnimation === root.defaultExitAnimation) root.fadeProperties.forEach(p => exitShaderEffectSource[p] = root.fadeTarget[p]); exitShaderEffectSource.width = root.fadeTarget.width; exitShaderEffectSource.height = root.fadeTarget.height; const exitAnimationInstance = exitAnimation.createObject(root, { target: exitItem.shaderEffectSource }); exitAnimationInstance.finished.connect(() => { sequentialAnimation.finished.disconnect(exitAnimationInstance.start); exitAnimationInstance.target = null; exitItem.destroy(); exitAnimationInstance.destroy(); }); sequentialAnimation.finished.connect(exitAnimationInstance.start); } } PauseAnimation { duration: 5 // figure out how to wait on a signal in an animation (for ShaderEffectSource update) } PropertyAction {} ScriptAction { script: { const enterItem = shaderEffectSourceWrapperComponent.createObject(null, { sourceItem: root.fadeTarget }); const enterShaderEffectSource = enterItem.shaderEffectSource; if (enterAnimation === root.defaultEnterAnimation) root.fadeProperties.forEach(p => enterShaderEffectSource[p] = root.enterValue); enterShaderEffectSource.live = true; const enterAnimationInstance = enterAnimation.createObject(root, { target: enterItem.shaderEffectSource }); enterAnimationInstance.finished.connect(() => { sequentialAnimation.finished.disconnect(enterAnimationInstance.start); enterAnimationInstance.target = null; enterItem.destroy(); enterAnimationInstance.destroy(); }) sequentialAnimation.finished.connect(enterAnimationInstance.start); if (!root.delayWhile) sequentialAnimation.finished(); } } } }