1// SPDX-FileCopyrightText: 2021 Nheko Contributors 2// 3// SPDX-License-Identifier: GPL-3.0-or-later 4 5import QtGraphicalEffects 1.0 6import QtQuick 2.10 7import QtQuick.Controls 2.3 8 9Item { 10 id: ripple 11 12 property alias clip: backgroundLayer.clip 13 property real radius: 0 14 property color color: "#22000000" 15 property real maxRadius: Math.max(width, height) 16 readonly property real radiusAnimationRate: 0.05 17 readonly property real radiusTailAnimationRate: 0.5 18 readonly property real opacityAnimationDuration: 300 19 readonly property real diameter: radius * 2 20 property real centerX 21 property real centerY 22 property var rippleTarget: parent 23 24 function start() { 25 console.log("Starting ripple animation"); 26 ripple.state = "ACTIVE"; 27 } 28 29 function stop() { 30 console.log("Stopping ripple animation"); 31 ripple.state = "NORMAL"; 32 } 33 34 anchors.fill: parent 35 state: "NORMAL" 36 states: [ 37 State { 38 name: "NORMAL" 39 }, 40 State { 41 name: "ACTIVE" 42 } 43 ] 44 transitions: [ 45 Transition { 46 from: "NORMAL" 47 to: "ACTIVE" 48 49 SequentialAnimation { 50 ScriptAction { 51 script: { 52 ripple.opacity = 1; 53 ripple.visible = true; 54 } 55 } 56 57 NumberAnimation { 58 id: radius_animation 59 60 target: ripple 61 properties: "radius" 62 from: 0 63 to: ripple.maxRadius 64 duration: ripple.maxRadius / ripple.radiusAnimationRate 65 66 easing { 67 type: Easing.OutQuad 68 } 69 70 } 71 72 } 73 74 }, 75 Transition { 76 from: "ACTIVE" 77 to: "NORMAL" 78 79 SequentialAnimation { 80 ParallelAnimation { 81 NumberAnimation { 82 id: radius_tail_animation 83 84 target: ripple 85 properties: "radius" 86 to: ripple.maxRadius 87 duration: ripple.maxRadius / ripple.radiusTailAnimationRate 88 89 easing { 90 type: Easing.Linear 91 } 92 93 } 94 95 NumberAnimation { 96 id: opacity_animation 97 98 target: ripple 99 properties: "opacity" 100 to: 0 101 duration: ripple.opacityAnimationDuration 102 103 easing { 104 type: Easing.InQuad 105 } 106 107 } 108 109 } 110 111 ScriptAction { 112 script: { 113 ripple.visible = false; 114 } 115 } 116 117 } 118 119 } 120 ] 121 122 Connections { 123 // Button 124 // Default to center 125 126 function onPressed(mouse) { 127 // MouseArea 128 if (mouse) { 129 ripple.centerX = mouse.x; 130 ripple.centerY = mouse.y; 131 } else if (rippleTarget.pressX) { 132 ripple.centerX = rippleTarget.pressX; 133 ripple.centerY = rippleTarget.pressY; 134 } else { 135 ripple.centerX = width / 2; 136 ripple.centerY = height / 2; 137 } 138 ripple.start(); 139 } 140 141 function onReleased() { 142 ripple.stop(); 143 } 144 145 function onExited() { 146 ripple.stop(); 147 } 148 149 function onCanceled() { 150 ripple.stop(); 151 } 152 153 function onClicked() { 154 ripple.stop(); 155 } 156 157 target: rippleTarget 158 ignoreUnknownSignals: true 159 } 160 161 Rectangle { 162 id: backgroundLayer 163 164 anchors.fill: parent 165 color: "transparent" 166 clip: true 167 168 Rectangle { 169 id: circle 170 171 x: ripple.centerX - ripple.radius 172 y: ripple.centerY - ripple.radius 173 height: ripple.diameter 174 width: ripple.diameter 175 radius: ripple.radius 176 color: ripple.color 177 } 178 179 } 180 181} 182