plasma-taskmanager-zoom/contents/ui/LaunchAnimation.qml

362 lines
10 KiB
QML

/*
SPDX-FileCopyrightText: 2024 User
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick
import QtQuick.Effects
import org.kde.plasma.components as PlasmaComponents3
import org.kde.plasma.core as PlasmaCore
import org.kde.kirigami as Kirigami
Item {
id: root
// Properties that can be set from the outside
property int animationType: 0 // 0=BusyIndicator, 1=PulsingIcon, 2=BouncingIcon, etc.
property int animationDuration: 1200
property real animationIntensity: 0.3
property bool active: false
property var iconSource: null
// Animation properties that external icon can bind to
property real iconScale: 1.0
property real iconRotation: 0
property real iconOpacity: 1.0
property real iconOffsetY: 0 // For bouncing
// Animation type constants for clarity
readonly property int typeBusyIndicator: 0
readonly property int typePulsingIcon: 1
readonly property int typeBouncingIcon: 2
readonly property int typeRotatingIcon: 3
readonly property int typeScalingIcon: 4
readonly property int typeFadingIcon: 5
readonly property int typeGlowEffect: 6
onActiveChanged: {
if (active) {
startAnimation();
} else {
stopAnimation();
}
}
onAnimationTypeChanged: {
if (active) {
stopAnimation();
startAnimation();
}
}
function startAnimation() {
switch(animationType) {
case typeBusyIndicator:
// Show busy indicator on top of icon (don't hide the icon)
iconScale = 1.0;
iconOpacity = 1.0;
iconRotation = 0;
iconOffsetY = 0;
break;
case typePulsingIcon:
// Reset to normal first, then start animation
iconScale = 1.0;
iconOpacity = 1.0;
iconRotation = 0;
iconOffsetY = 0;
pulseAnimation.restart();
break;
case typeBouncingIcon:
// Reset to normal first, then start animation
iconScale = 1.0;
iconOpacity = 1.0;
iconRotation = 0;
iconOffsetY = 0;
bounceAnimation.restart();
break;
case typeRotatingIcon:
// Reset to normal first, then start animation
iconScale = 1.0;
iconOpacity = 1.0;
iconRotation = 0;
iconOffsetY = 0;
rotateAnimation.restart();
break;
case typeScalingIcon:
// Reset to normal first, then start animation
iconScale = 1.0;
iconOpacity = 1.0;
iconRotation = 0;
iconOffsetY = 0;
scaleAnimation.restart();
break;
case typeFadingIcon:
// Reset to normal first, then start animation
iconScale = 1.0;
iconOpacity = 1.0;
iconRotation = 0;
iconOffsetY = 0;
fadeAnimation.restart();
break;
case typeGlowEffect:
// Reset to normal first, then start animation
iconScale = 1.0;
iconOpacity = 1.0;
iconRotation = 0;
iconOffsetY = 0;
glowAnimation.restart();
break;
}
}
function stopAnimation() {
pulseAnimation.stop();
bounceAnimation.stop();
rotateAnimation.stop();
scaleAnimation.stop();
fadeAnimation.stop();
glowAnimation.stop();
// Reset all animation properties
iconScale = 1.0;
iconRotation = 0;
iconOpacity = 1.0;
iconOffsetY = 0;
glowEffect.opacity = 0;
}
// Glow effect - Only additional visual element needed
Item {
id: glowEffect
anchors.centerIn: parent
width: parent.width * 1.2
height: parent.height * 1.2
visible: animationType === typeGlowEffect && active
opacity: 0
z: 5
Rectangle {
anchors.centerIn: parent
width: parent.width
height: parent.height
radius: width / 2
color: "transparent"
border.color: Kirigami.Theme.highlightColor
border.width: 2
}
Repeater {
model: 2
Rectangle {
anchors.centerIn: parent
width: parent.width + (index * 4)
height: parent.height + (index * 4)
radius: width / 2
color: "transparent"
border.color: Kirigami.Theme.highlightColor
border.width: 1
opacity: 0.4 / (index + 1)
}
}
}
// ANIMATION DEFINITIONS - These modify the exported properties
// 2. Pulsing Icon Animation - Smooth sine wave
SequentialAnimation {
id: pulseAnimation
loops: Animation.Infinite
running: false
NumberAnimation {
target: root
property: "iconScale"
from: 1.0
to: 1.0 + (animationIntensity * 0.6)
duration: animationDuration / 2
easing.type: Easing.InOutSine
}
NumberAnimation {
target: root
property: "iconScale"
from: 1.0 + (animationIntensity * 0.6)
to: 1.0
duration: animationDuration / 2
easing.type: Easing.InOutSine
}
}
// 3. Bouncing Icon Animation - REALISTIC PHYSICS with multiple bounces
SequentialAnimation {
id: bounceAnimation
loops: Animation.Infinite
running: false
// First big bounce
NumberAnimation {
target: root
property: "iconOffsetY"
from: 0
to: -(30 * animationIntensity) // Higher initial bounce
duration: animationDuration / 6
easing.type: Easing.OutQuad // Deceleration going up
}
NumberAnimation {
target: root
property: "iconOffsetY"
from: -(30 * animationIntensity)
to: 0
duration: animationDuration / 6
easing.type: Easing.InQuad // Acceleration going down
}
// Second smaller bounce
NumberAnimation {
target: root
property: "iconOffsetY"
from: 0
to: -(18 * animationIntensity) // 60% of original height
duration: animationDuration / 8
easing.type: Easing.OutQuad
}
NumberAnimation {
target: root
property: "iconOffsetY"
from: -(18 * animationIntensity)
to: 0
duration: animationDuration / 8
easing.type: Easing.InQuad
}
// Third tiny bounce
NumberAnimation {
target: root
property: "iconOffsetY"
from: 0
to: -(8 * animationIntensity) // 40% of second bounce
duration: animationDuration / 10
easing.type: Easing.OutQuad
}
NumberAnimation {
target: root
property: "iconOffsetY"
from: -(8 * animationIntensity)
to: 0
duration: animationDuration / 10
easing.type: Easing.InQuad
}
// Rest period
PauseAnimation { duration: animationDuration / 3 }
}
// 4. Rotating Icon Animation
RotationAnimation {
id: rotateAnimation
target: root
property: "iconRotation"
from: 0
to: 360
duration: animationDuration
loops: Animation.Infinite
running: false
easing.type: Easing.Linear
}
// 5. Scaling Icon Animation - Complex bounce-scale with elastic settle
SequentialAnimation {
id: scaleAnimation
loops: Animation.Infinite
running: false
// Quick shrink
NumberAnimation {
target: root
property: "iconScale"
from: 1.0
to: 1.0 - (animationIntensity * 0.4)
duration: animationDuration / 6
easing.type: Easing.InQuad
}
// Big bounce grow
NumberAnimation {
target: root
property: "iconScale"
from: 1.0 - (animationIntensity * 0.4)
to: 1.0 + (animationIntensity * 0.8)
duration: animationDuration / 3
easing.type: Easing.OutBack
easing.overshoot: 2.0
}
// Settle back
NumberAnimation {
target: root
property: "iconScale"
from: 1.0 + (animationIntensity * 0.8)
to: 1.0
duration: animationDuration / 2
easing.type: Easing.OutElastic
easing.amplitude: 1.5
}
}
// 6. Fading Icon Animation - Dramatic fade
SequentialAnimation {
id: fadeAnimation
loops: Animation.Infinite
running: false
NumberAnimation {
target: root
property: "iconOpacity"
from: 1.0
to: 0.1
duration: animationDuration / 2
easing.type: Easing.InOutQuad
}
NumberAnimation {
target: root
property: "iconOpacity"
from: 0.1
to: 1.0
duration: animationDuration / 2
easing.type: Easing.InOutQuad
}
}
// 7. Glow Effect Animation
SequentialAnimation {
id: glowAnimation
loops: Animation.Infinite
running: false
NumberAnimation {
target: glowEffect
property: "opacity"
from: 0
to: 0.8
duration: animationDuration / 3
easing.type: Easing.OutQuad
}
NumberAnimation {
target: glowEffect
property: "opacity"
from: 0.8
to: 0.3
duration: animationDuration / 3
easing.type: Easing.InOutQuad
}
NumberAnimation {
target: glowEffect
property: "opacity"
from: 0.3
to: 0
duration: animationDuration / 3
easing.type: Easing.InQuad
}
}
Component.onCompleted: {
}
}