C

Qt Quick Ultralite Motorcycle Cluster Demo

// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial
import QtQuick 2.4
import QtQuickUltralite.Extras 2.0

Item {
    id: root
    width: 228
    height: 228

    property bool active
    property bool isDayMode
    property real fuelLevel: 30
    property real fuelLevelForStartupAnimation: 0
    property real fuelLevelVisibleValue: (startUpAnimation.running
                                          || hideAnimation.running
                                          || dayModeAnimation.running
                                          || nightModeAnimation.running) ? fuelLevelForStartupAnimation : fuelLevel

    property color colorMode: fuelLevel < 20 ? Style.red : (fuelLevel < 40 ? Style.orange : Style.neutralGreen)

    property color imagesColors
    property image holeInBackgroundImg: "qrc:///images/fuelGauge/hole-in-bg.png"
    property real gradientCircleOpacityTarget: 1
    property real backgroundOpacityTarget: 1

    states: [
        State {
            name: "dayMode"
            when: isDayMode === true
            PropertyChanges {
                target: root
                imagesColors: Style.black
            }
            PropertyChanges {
                target: root
                holeInBackgroundImg: "qrc:///images/fuelGauge/hole-in-bg-day.png"
            }
            PropertyChanges {
                target: background
                opacity: 0
            }
            PropertyChanges {
                target: root
                gradientCircleOpacityTarget: 0
            }
            PropertyChanges {
                target: gradientCircle
                opacity: 0
            }
            PropertyChanges {
                target: root
                backgroundOpacityTarget: 0
            }
            PropertyChanges {
                target: holeInBackground
                opacity: 1
            }
        },
        State {
            name: "nightMode"
            when: isDayMode !== true
            PropertyChanges {
                target: root
                imagesColors: Style.white
            }
            PropertyChanges {
                target: root
                holeInBackgroundImg: "qrc:///images/fuelGauge/hole-in-bg.png"
            }
            PropertyChanges {
                target: background
                opacity: 1
            }
            PropertyChanges {
                target: root
                gradientCircleOpacityTarget: 1
            }
            PropertyChanges {
                target: gradientCircle
                opacity: 1
            }
            PropertyChanges {
                target: root
                backgroundOpacityTarget: 1
            }
        }
    ]

    transitions: [
        Transition {
            to: "dayMode"
            SequentialAnimation {
                id: dayModeAnimation
                ParallelAnimation {
                    ScriptAction {
                        script: {
                            fuelLevelForStartupAnimation = 0
                        }
                    }
                    NumberAnimation {
                        target: background
                        duration: 300
                        property: "opacity"
                        to: 0
                        easing.type: Easing.OutCubic
                    }
                    NumberAnimation {
                        target: gradientCircle
                        duration: 300
                        property: "opacity"
                        to: 0
                        easing.type: Easing.OutCubic
                    }
                }
                NumberAnimation {
                    target: holeInBackground
                    property: "opacity"
                    to: 0
                    duration: 300
                    easing.type: Easing.OutCubic
                }
                ScriptAction {
                    script: {
                        holeInBackground.source = holeInBackgroundImg
                    }
                }
                PauseAnimation {
                    duration: 1000
                }
                NumberAnimation {
                    target: holeInBackground
                    property: "opacity"
                    to: 1
                    duration: 300
                    easing.type: Easing.OutCubic
                }
                ScriptAction {
                    script: {
                        fuelLevelForStartupAnimation = fuelLevel
                    }
                }
                PauseAnimation {
                    duration: 300
                }
            }
        },
        Transition {
            to: "nightMode"
            SequentialAnimation {
                id: nightModeAnimation
                ScriptAction {
                    script: {
                        fuelLevelForStartupAnimation = 0
                    }
                }
                PauseAnimation {
                    duration: 300
                }
                NumberAnimation {
                    target: holeInBackground
                    property: "opacity"
                    to: 0
                    duration: 300
                    easing.type: Easing.OutCubic
                }
                ScriptAction {
                    script: {
                        holeInBackground.source = holeInBackgroundImg
                    }
                }
                PauseAnimation {
                    duration: 1000
                }
                NumberAnimation {
                    target: holeInBackground
                    property: "opacity"
                    to: 1
                    duration: 300
                    easing.type: Easing.OutCubic
                }
                ParallelAnimation {
                    ScriptAction {
                        script: {
                            fuelLevelForStartupAnimation = fuelLevel
                        }
                    }
                    NumberAnimation {
                        target: gradientCircle
                        duration: 300
                        easing.type: Easing.OutCubic
                    }
                    NumberAnimation {
                        target: background
                        duration: 300
                        property: "opacity"
                        to: 0
                        easing.type: Easing.OutCubic
                    }
                }
            }
        }
    ]

    Behavior on fuelLevelForStartupAnimation {
        NumberAnimation {
            duration: 800
            easing.type: Easing.OutCubic
        }
    }

    Image {
        id: background
        source: "qrc:///images/fuelGauge/fuel-colored-bg.png"
        anchors.centerIn: root
    }

    Item {
        id: hole
        width: 171
        height: 171
        anchors.centerIn: root
        clip: true

        property int wavesOffset: 0

        ColorizedImage {
            id: fuelLevelImage
            source: "qrc:///images/fuelGauge/wave-bottom-part.png"
            color: root.colorMode
            anchors.horizontalCenter: parent.horizontalCenter
            anchors.bottom: parent.bottom
            anchors.bottomMargin: MathAPI.clamp(
                                      root.fuelLevelVisibleValue / 80 * 135 - 135,
                                      -135, 0)
        }
        ColorizedImage {
            id: wave
            source: "qrc:///images/fuelGauge/wave-top-part.png"
            color: root.colorMode
            anchors.horizontalCenter: parent.horizontalCenter
            anchors.horizontalCenterOffset: hole.wavesOffset
            anchors.bottom: fuelLevelImage.top
        }
        ColorizedImage {
            id: wave_2
            source: "qrc:///images/fuelGauge/wave-top-part.png"
            color: root.colorMode
            anchors.horizontalCenter: parent.horizontalCenter
            anchors.horizontalCenterOffset: -60 - hole.wavesOffset
            anchors.bottom: fuelLevelImage.top
        }
        Image {
            id: wave_2_shadow
            source: "qrc:///images/fuelGauge/wave-shadow.png"
            anchors.horizontalCenter: parent.horizontalCenter
            anchors.horizontalCenterOffset: -60 - hole.wavesOffset
            anchors.bottom: fuelLevelImage.top
        }
        Image {
            id: holeInBackground
            anchors.centerIn: parent
            source: "qrc:///images/fuelGauge/hole-in-bg.png"
        }

        SequentialAnimation {
            id: wavesAnimation
            running: true
            loops: Animation.Infinite
            NumberAnimation {
                target: hole
                property: "wavesOffset"
                duration: 5000
                from: -90
                to: 90
            }
            NumberAnimation {
                target: hole
                property: "wavesOffset"
                duration: 5000
                from: 90
                to: -90
            }
        }
    }

    ColorizedImage {
        id: gradientCircle
        color: root.colorMode
        anchors.centerIn: root
        source: "qrc:///images/fuelGauge/fuel-colored-circle.png"
    }

    ColorizedImage {
        id: fuelScale
        source: "qrc:///images/fuelGauge/fuel-scale.png"
        anchors.centerIn: root
        color: imagesColors
        anchors.horizontalCenterOffset: 15
    }

    ColorizedImage {
        id: ring1
        source: "qrc:///images/fuelGauge/ring-2.png"
        anchors.centerIn: root
        width: 195
        height: 195
        color: imagesColors
    }

    ColorizedImage {
        id: ring2
        source: "qrc:///images/fuelGauge/ring-2.png"
        anchors.centerIn: root
        property int horizontalCenterOffsetValue
        anchors.horizontalCenterOffset: horizontalCenterOffsetValue
        color: imagesColors
    }

    function hideElements() {
        ring1.opacity = 0
        ring2.opacity = 0
        hole.opacity = 0
        fuelLevelForStartupAnimation = 0
        fuelScale.opacity = 0
        background.opacity = 0
        gradientCircle.opacity = 0
    }

    onActiveChanged: {
        if (active) {
            startAnimation()
        } else {
            hiddingAnimation()
        }
    }

    function startAnimation() {
        startUpAnimation.start()
    }

    function hiddingAnimation() {
        hideAnimation.start()
    }

    SequentialAnimation {
        id: hideAnimation
        ScriptAction {
            script: {
                root.fuelLevelForStartupAnimation = 0
            }
        }
        PauseAnimation {
            duration: 500
        }
        ScriptAction {
            script: {
                hole.opacity = 0
            }
        }
        NumberAnimation {
            target: root
            property: "opacity"
            to: 0
            duration: 500
            easing.type: Easing.OutCubic
        }
        ScriptAction {
            script: hideElements()
        }
    }

    SequentialAnimation {
        id: startUpAnimation

        ScriptAction {
            script: {
                hideElements()
                root.opacity = 1
            }
        }

        ParallelAnimation {
            NumberAnimation {
                target: ring2
                property: "horizontalCenterOffsetValue"
                from: StartupConfig.ring2TravelDistance
                to: 0
                duration: StartupConfig.ring2TravelDuration
                easing.type: Easing.OutCubic
            }
            NumberAnimation {
                target: ring2
                property: "opacity"
                from: 0
                to: 1
                duration: StartupConfig.ring2OpacityDuration
                easing.type: Easing.OutCubic
            }
        }
        ParallelAnimation {
            ScriptAction {
                script: {
                    hole.opacity = 1
                }
            }
            SequentialAnimation {
                PauseAnimation {
                    duration: 300
                }
                ScriptAction {
                    script: {
                        root.fuelLevelForStartupAnimation = 45
                    }
                }
                PauseAnimation {
                    duration: 600
                }
                ScriptAction {
                    script: {
                        root.fuelLevelForStartupAnimation = 30
                    }
                }
                PauseAnimation {
                    duration: 600
                }
                ScriptAction {
                    script: {
                        root.fuelLevelForStartupAnimation = root.fuelLevel
                    }
                }
                PauseAnimation {
                    duration: 600
                }
            }
            SequentialAnimation {
                NumberAnimation {
                    target: ring1
                    property: "opacity"
                    from: 0
                    to: 1
                    duration: 300
                    easing.type: Easing.OutQuad
                }
                NumberAnimation {
                    target: gradientCircle
                    property: "opacity"
                    to: gradientCircleOpacityTarget
                    duration: StartupConfig.backgroundOpacityDuration
                    easing.type: Easing.OutQuad
                }
                ParallelAnimation {
                    NumberAnimation {
                        target: fuelScale
                        property: "opacity"
                        to: 1
                        duration: StartupConfig.backgroundOpacityDuration
                        easing.type: Easing.OutQuad
                    }
                    NumberAnimation {
                        target: background
                        property: "opacity"
                        to: backgroundOpacityTarget
                        duration: StartupConfig.backgroundOpacityDuration
                        easing.type: Easing.OutQuad
                    }
                }
            }
        }
    }

    Component.onCompleted: {
        hideElements()
    }
}