From f713a77e670aea28f560f0459ee78cf39f8e3c45 Mon Sep 17 00:00:00 2001 From: David Edmundson Date: Thu, 29 Mar 2018 13:41:07 +0100 Subject: [PATCH] Vastly simplify image wallpaper code Summary: The image wallpaper is a mess of 4 different fade functions, some not in sync, and very complicated swapping images about. This simplifies the whole thing by using a StackView, we just pop our setup with a new configuration on and it handles deleting old objects when the transition ends. Code is 1/3 the size, whilst doing the same thing and should result in having fewer items about. In addition with this patch changing the transition effect in future would be super trivial. Test Plan: Set as both image and wallpaper Renders stuff as before Reviewers: #plasma, broulik Reviewed By: #plasma, broulik Subscribers: broulik, mart, plasma-devel Tags: #plasma Differential Revision: https://phabricator.kde.org/D11726 --- .../image/imagepackage/contents/ui/main.qml | 310 ++++-------------- 1 file changed, 70 insertions(+), 240 deletions(-) diff --git a/wallpapers/image/imagepackage/contents/ui/main.qml b/wallpapers/image/imagepackage/contents/ui/main.qml index e6d4551ed..93f245342 100644 --- a/wallpapers/image/imagepackage/contents/ui/main.qml +++ b/wallpapers/image/imagepackage/contents/ui/main.qml @@ -19,22 +19,21 @@ */ import QtQuick 2.5 +import QtQuick.Controls 2.1 as QQC2 import QtQuick.Window 2.2 import QtGraphicalEffects 1.0 import org.kde.plasma.wallpapers.image 2.0 as Wallpaper import org.kde.plasma.core 2.0 as PlasmaCore -Item { +QQC2.StackView { id: root - readonly property string configuredImage: wallpaper.configuration.Image readonly property string modelImage: imageWallpaper.wallpaperPath - property Item currentImage: imageB - property Item currentBlurBackground: blurBackgroundB - property Item otherImage: imageA - property Item otherBlurBackground: blurBackgroundA + readonly property string configuredImage: wallpaper.configuration.Image readonly property int fillMode: wallpaper.configuration.FillMode - property size sourceSize: Qt.size(root.width * Screen.devicePixelRatio, root.height * Screen.devicePixelRatio) + readonly property string configColor: wallpaper.configuration.Color + readonly property bool blur: wallpaper.configuration.Blur + readonly property size sourceSize: Qt.size(root.width * Screen.devicePixelRatio, root.height * Screen.devicePixelRatio) //public API, the C++ part will look for those function setUrl(url) { @@ -51,128 +50,10 @@ Item { } //private - function setupImage() { - currentImage.sourceSize = root.sourceSize; - currentImage.fillMode = root.fillMode; - currentImage.source = modelImage; - } - - function fadeWallpaper() { - if (startupTimer.running) { - setupImage(); - return; - } - - fadeAnim.running = false - swapImages() - currentImage.source = modelImage - currentImage.sourceSize = root.sourceSize - // Prevent source size change when image has just been setup anyway - sourceSizeTimer.stop() - currentImage.opacity = 0 - currentBlurBackground.opacity = 0 - otherImage.z = 0 - currentImage.z = 1 - - // only cross-fade if the new image could be smaller than the old one - fadeOtherAnimator.enabled = Qt.binding(function() { - return currentImage.paintedWidth < otherImage.paintedWidth || currentImage.paintedHeight < otherImage.paintedHeight - }) - - // Alleviate stuttering by waiting with the fade animation until the image is loaded (or failed to) - fadeAnim.running = Qt.binding(function() { - return currentImage.status !== Image.Loading && otherImage.status !== Image.Loading - }) - } - - function fadeFillMode() { - if (startupTimer.running) { - setupImage(); - return; - } - - fadeAnim.running = false - swapImages() - currentImage.sourceSize = root.sourceSize - sourceSizeTimer.stop() - currentImage.source = modelImage - currentImage.opacity = 0 - currentBlurBackground.opacity = 0 - otherImage.z = 0 - currentImage.fillMode = fillMode - currentImage.z = 1 - - // only cross-fade if the new image could be smaller than the old one - fadeOtherAnimator.enabled = Qt.binding(function() { - return currentImage.paintedWidth < otherImage.paintedWidth || currentImage.paintedHeight < otherImage.paintedHeight - }) - - fadeAnim.running = Qt.binding(function() { - return currentImage.status !== Image.Loading && otherImage.status !== Image.Loading - }) - } - function fadeSourceSize() { - if (currentImage.sourceSize === root.sourceSize) { - return - } - - if (startupTimer.running) { - setupImage(); - return; - } - - fadeAnim.running = false - swapImages() - currentImage.sourceSize = root.sourceSize - currentImage.opacity = 0 - currentBlurBackground.opacity = 0 - currentImage.source = otherImage.source - otherImage.z = 0 - currentImage.z = 1 - - fadeOtherAnimator.enabled = false // the image size didn't change, avoid cross-dissolve - fadeAnim.running = Qt.binding(function() { - return currentImage.status !== Image.Loading && otherImage.status !== Image.Loading - }) - } - - function startFadeSourceTimer() { - if (width > 0 && height > 0 && (imageA.status !== Image.Null || imageB.status !== Image.Null)) { - sourceSizeTimer.restart() - } - } - - function swapImages() { - if (currentImage == imageA) { - currentImage = imageB - currentBlurBackground = blurBackgroundB - otherImage = imageA - otherBlurBackground = blurBackgroundA - } else { - currentImage = imageA - currentBlurBackground = blurBackgroundA - otherImage = imageB - otherBlurBackground = blurBackgroundB - } - } - - onWidthChanged: startFadeSourceTimer() - onHeightChanged: startFadeSourceTimer() - - // HACK prevent fades and transitions during startup - Timer { - id: startupTimer - interval: 100 - running: true - } - - Timer { - id: sourceSizeTimer - interval: 1000 // always delay reloading the image even when animations are turned off - onTriggered: fadeSourceSize() + onConfiguredImageChanged: { + imageWallpaper.addUrl(configuredImage) } - Component.onCompleted: { if (wallpaper.pluginName == "org.kde.slideshow") { wallpaper.setAction("open", i18n("Open Wallpaper Image"), "document-open"); @@ -189,130 +70,79 @@ Item { slideTimer: wallpaper.configuration.SlideInterval } - onFillModeChanged: { - fadeFillMode(); - } - onConfiguredImageChanged: { - imageWallpaper.addUrl(configuredImage) - } - onModelImageChanged: { - fadeWallpaper(); + onFillModeChanged: Qt.callLater(loadImage); + onModelImageChanged: Qt.callLater(loadImage); + onConfigColorChanged: Qt.callLater(loadImage); + onBlurChanged: Qt.callLater(loadImage); + onWidthChanged: Qt.callLater(loadImage); + onHeightChanged: Qt.callLater(loadImage); + + function loadImage() { + var isFirst = (root.currentItem == undefined); + var pendingImage = baseImage.createObject(root, { "source": root.modelImage, + "fillMode": root.fillMode, + "sourceSize": root.sourceSize, + "color": root.configColor, + "blur": root.blur, + "opacity": isFirst ? 1: 0}); + + function replaceWhenLoaded() { + if (pendingImage.status != Image.Loading) { + root.replace(pendingImage, {}, + isFirst ? QQC2.StackView.Immediate : QQC2.StackView.Transition);//dont' animate first show + pendingImage.statusChanged.disconnect(replaceWhenLoaded); + } + } + pendingImage.statusChanged.connect(replaceWhenLoaded); + replaceWhenLoaded(); } - SequentialAnimation { - id: fadeAnim - running: false + Component { + id: baseImage - ParallelAnimation { - OpacityAnimator { - target: currentBlurBackground - from: 0 - to: 1 - duration: fadeOtherAnimator.duration - } - OpacityAnimator { - target: otherBlurBackground - from: 1 - // cannot disable an animation individually, so we just fade from 1 to 1 - to: enabled ? 0 : 1 + Image { + id: mainImage - //use configured duration if animations are enabled - duration: units.longDuration && wallpaper.configuration.TransitionAnimationDuration - } - OpacityAnimator { - target: currentImage - from: 0 - to: 1 - duration: fadeOtherAnimator.duration - } - OpacityAnimator { - id: fadeOtherAnimator - property bool enabled: true - target: otherImage - from: 1 - // cannot disable an animation individually, so we just fade from 1 to 1 - to: enabled ? 0 : 1 + property alias color: backgroundColor.color + property alias blur: blurEffect.visible + + asynchronous: true + cache: false + autoTransform: true + z: -1 + + QQC2.StackView.onRemoved: destroy() - //use configured duration if animations are enabled - duration: units.longDuration && wallpaper.configuration.TransitionAnimationDuration + Rectangle { + id: backgroundColor + anchors.fill: parent + visible: mainImage.status === Image.Ready + z: -2 } - } - ScriptAction { - script: { - otherImage.source = ""; - otherImage.fillMode = fillMode; + + GaussianBlur { + id: blurEffect + anchors.fill: parent + source: mainImage + radius: 32 + samples: 65 + z: mainImage.z } } } - Rectangle { - id: backgroundColor - anchors.fill: parent - visible: currentImage.status === Image.Ready || otherImage.status === Image.Ready - color: wallpaper.configuration.Color - Behavior on color { - ColorAnimation { duration: units.longDuration } - enabled: !startupTimer.running + replaceEnter: Transition { + OpacityAnimator { + from: 0 + to: 1 + duration: wallpaper.configuration.TransitionAnimationDuration } } - - Image { - id: blurBackgroundSourceA - visible: wallpaper.configuration.Blur - anchors.fill: parent - asynchronous: true - cache: false - fillMode: Image.PreserveAspectCrop - source: imageA.source - z: -1 - } - - GaussianBlur { - id: blurBackgroundA - visible: wallpaper.configuration.Blur - anchors.fill: parent - source: blurBackgroundSourceA - radius: 32 - samples: 65 - z: imageA.z - } - - Image { - id: blurBackgroundSourceB - visible: wallpaper.configuration.Blur - anchors.fill: parent - asynchronous: true - cache: false - fillMode: Image.PreserveAspectCrop - source: imageB.source - z: -1 - } - - GaussianBlur { - id: blurBackgroundB - visible: wallpaper.configuration.Blur - anchors.fill: parent - source: blurBackgroundSourceB - radius: 32 - samples: 65 - z: imageB.z - } - - Image { - id: imageA - anchors.fill: parent - asynchronous: true - cache: false - fillMode: wallpaper.configuration.FillMode - autoTransform: true //new API in Qt 5.5, do not backport into Plasma 5.4. - } - - Image { - id: imageB - anchors.fill: parent - asynchronous: true - cache: false - fillMode: wallpaper.configuration.FillMode - autoTransform: true //new API in Qt 5.5, do not backport into Plasma 5.4. + // Keep the old image around till the new one is fully faded in + // If we fade both at the same time you can see the background behind glimpse through + replaceExit: Transition{ + PauseAnimation { + duration: wallpaper.configuration.TransitionAnimationDuration + } } }