import QtQuick 2.0 Rectangle { id: control property color successColor: "green" property color warningColor: "orange" property color errorColor: "red" property color unknownColor: "grey" property color backgroundColor: "white" property color workingColor: "grey" property double indicatorSize: 1 height: app.height * 0.9 width: height * 0.8 color: backgroundColor border.width: Math.min(width * 0.1, height * 0.1) * control.indicatorSize border.color: "green" radius: border.width * 0.5 state: "success" clip: true Rectangle { id: higherRect property int totalWidth: Math.abs(Math.sin(rotation * Math.PI / 180) * (height)) property int totalHeight: Math.abs(Math.cos(rotation * Math.PI / 180) * (height)) radius: width * 0.5 border.width: 0 border.color: control.workingColor color: "green" } Rectangle { id: lowerRect property int totalWidth: Math.abs(Math.sin(rotation * Math.PI / 180) * (height)) property int totalHeight: Math.abs(Math.cos(rotation * Math.PI / 180) * (height)) radius: width * 0.5 border.width: 0 border.color: control.workingColor color: "green" } ParallelAnimation { id: workingAnimation property int from: lowerRect.height property int to: Math.max(control.width * 1.1, control.height * 1.1) property bool shouldBeRunning: false running: false loops: Animation.Infinite onShouldBeRunningChanged: { pauseAnimation.start() } NumberAnimation { target: higherRect properties: "height" from: workingAnimation.from to: workingAnimation.to duration: 1000 easing.type: Easing.InQuad } NumberAnimation { target: higherRect properties: "opacity" from: 1 to: 0.3 duration: 1000 easing.type: Easing.InQuad } } PauseAnimation { id: pauseAnimation duration: 400 onStopped: { workingAnimation.running = workingAnimation.shouldBeRunning higherRect.opacity = 1 } } states: [ State { name: "working" PropertyChanges { target: control border.color: control.workingColor } PropertyChanges { target: higherRect x: (parent.width - width) / 2 y: (parent.height - height) / 2 width: height height: Math.min(parent.width * 0.1, parent.height * 0.1) * control.indicatorSize color: "transparent" border.color: control.workingColor border.width: control.border.width } PropertyChanges { target: lowerRect x: (parent.width - width) / 2 y: (parent.height - height) / 2 width: height height: Math.min(parent.width * 0.2, parent.height * 0.2) * control.indicatorSize color: control.workingColor } PropertyChanges { target: workingAnimation shouldBeRunning: true } }, State { name: "unknown" PropertyChanges { target: control border.color: control.unknownColor } PropertyChanges { target: higherRect x: (parent.width - width) / 2 y: (parent.height - height) / 2 width: control.border.width height: Math.min(parent.width * 0.7, parent.height * 0.7) * control.indicatorSize color: control.unknownColor rotation: 90 } PropertyChanges { target: lowerRect x: (parent.width - width) / 2 y: (parent.height - height) / 2 width: control.border.width height: Math.min(parent.width * 0.7, parent.height * 0.7) * control.indicatorSize color: control.unknownColor rotation: -90 } }, State { id: errorState name: "error" property int distance: control.height * 0.1 PropertyChanges { target: control border.color: control.errorColor } PropertyChanges { target: higherRect x: (parent.width - width) / 2 y: control.border.width + parent.height * 0.15 width: control.border.width height: parent.height * 0.4 * control.indicatorSize color: control.errorColor } PropertyChanges { target: lowerRect x: (parent.width - width) / 2 y: higherRect.y + higherRect.height + errorState.distance width: control.border.width * 1.3 height: width color: control.errorColor } }, State { name: "warn" PropertyChanges { target: control border.color: control.warningColor } PropertyChanges { target: higherRect x: (parent.width - width) / 2 y: (parent.height - height) / 2 width: control.border.width height: Math.min(parent.width * 0.7, parent.height * 0.7) * control.indicatorSize color: control.warningColor rotation: 45 } PropertyChanges { target: lowerRect x: (parent.width - width) / 2 y: (parent.height - height) / 2 width: control.border.width height: Math.min(parent.width * 0.7, parent.height * 0.7) * control.indicatorSize color: control.warningColor rotation: -45 } }, State { id: tickState property int bottomX: ((control.width) / 2 - (higherRect.totalWidth - (lowerRect.totalWidth + higherRect.totalWidth) / 2 )) * 1.055 property int bottomY: ((control.height + higherRect.totalHeight) / 2 - lowerRect.radius) * 1.05 name: "success" PropertyChanges { target: control border.color: control.successColor } PropertyChanges { target: higherRect x: tickState.bottomX - width / 2 + (Math.sin(rotation * Math.PI / 180) * (height / 2 - radius)) y: tickState.bottomY - height / 2 - (Math.cos(rotation * Math.PI / 180) * (height / 2 - radius)) width: control.border.width height: Math.min(parent.width * 0.6, parent.height * 0.6) * control.indicatorSize rotation: 40 color: control.successColor } PropertyChanges { target: lowerRect x: tickState.bottomX - width / 2 + (Math.sin(rotation * Math.PI / 180) * (height / 2 - radius)) y: tickState.bottomY - height / 2 - (Math.cos(rotation * Math.PI / 180) *(height / 2 - radius)) width: control.border.width height: Math.min(parent.width * 0.3, parent.height * 0.3) * control.indicatorSize rotation: -40 color: control.successColor } } ] transitions: [ Transition { NumberAnimation { properties: "height,width,rotation,x,y" duration: 400 easing.type: Easing.InOutQuad } ColorAnimation { properties: "color,border.color" duration: 400 easing.type: Easing.InOutQuad } } ] }