C
Qt Cluster: Rendering and Recovery from Main UI Failure
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
// This file is part of the Qt Safe Renderer module
pragma Singleton
import QtQuick
// comment ifndef QTIVIVEHICLEFUNCTIONS
//import QtIVIVehicleFunctions 1.0
import ClusterDemoData
Item {
id: valueSource
property real kph: 0
property real consumeKW: 0
property real maxConsumeKWValue: 90
property real maxChargeKWValue: 40
property real chargeKW: 0
property real maxRange: 600
property real range: (batteryLevel / 100) * maxRange
property bool runningInDesigner: false
property var consumption: [300, 600, 700, 800, 900, 700, 600, 300, 50, 50, -100, 50, -100, -150,
-200, 50, 150, 200, 300, 200, 300, 200, 500, 50, -100, -100, -150, -80, 50, 300, 600, 700, 800,
600, 700, 300, 50, 50]
property var turnSignal
property var currentDate: new Date()
//property string date: currentDate.toLocaleDateString(Qt.locale("fi_FI"), "ddd d. MMM")
//property string time: currentDate.toLocaleTimeString(Qt.locale("fi_FI"), "hh:mm")
property string date: currentDate.toLocaleDateString(Qt.locale("en_GB"))
property string time: currentDate.toLocaleTimeString(Qt.locale("en_GB"), "hh:mm")
ClusterData {
id: clusterDataSource
onVehicleSpeedChanged: {
kph = vehicleSpeed
if (carId === 0 && !fastBootDemo) {
oldSpeed.shift()
oldSpeed.push(vehicleSpeed)
speedChanged()
}
}
property int notLeft: ~Qt.LeftArrow
property int notRight: ~Qt.RightArrow
onLeftTurnLightChanged: leftTurnLight ? turnSignal |= Qt.LeftArrow
: turnSignal &= notLeft
onRightTurnLightChanged: rightTurnLight ? turnSignal |= Qt.RightArrow
: turnSignal &= notRight
}
// comment ifndef QTIVIVEHICLEFUNCTIONS
property real latitude: clusterDataSource.latitude
property real longitude: clusterDataSource.longitude
property real direction: clusterDataSource.direction
property bool lowBeam: clusterDataSource.headLight
property int carId: clusterDataSource.carId
property bool lightFailure: clusterDataSource.lightFailure
property bool flatTire: clusterDataSource.flatTire
property bool frontLeftOpen: false
property bool frontRightOpen: false
property bool rearLeftDoorOpen: false
property bool rearRighDoorOpen: false
property bool hoodOpen: false
property bool trunkOpen: false
property double batteryLevel: clusterDataSource.batteryPotential
property double fuelLevel: clusterDataSource.gasLevel
property int gear: clusterDataSource.gear
property bool parkingBrake: clusterDataSource.brake
// TODO: These two are hacks. View change messages might not come through CAN.
property bool viewChange: clusterDataSource.oilTemp
property bool rightViewChange: clusterDataSource.oilPressure
// New properties for custom view change and demo mode for CenterView
property bool customViewChange: false
// ENABLE FOR FAST BOOT DEMO (or otherwise with no CanController)
property bool fastBootDemo: false
// TODO: Park light used for automatic demo mode for now
property bool automaticDemoMode: fastBootDemo ? true : clusterDataSource.parkLight
// Speed animations for fast boot demo
Timer {
running: fastBootDemo
interval: 4000
onTriggered: animation.start()
}
Timer {
running: fastBootDemo
property bool turnLeft: true
repeat: true
interval: 5000
onTriggered: {
turnLeft = !turnLeft
if (turnLeft)
turnSignal = Qt.LeftArrow
else
turnSignal = Qt.RightArrow
stopSignaling.start()
}
}
Timer {
id: stopSignaling
running: false
interval: 2100
onTriggered: turnSignal = Qt.NoArrow
}
Behavior on fuelLevel {
enabled: fastBootDemo
PropertyAnimation {
duration: 18000
}
}
Behavior on batteryLevel {
enabled: fastBootDemo
PropertyAnimation {
duration: 18000
}
}
onFuelLevelChanged: {
if (fastBootDemo && fuelLevel <= 5)
fuelLevel = 100
}
onBatteryLevelChanged: {
if (fastBootDemo && batteryLevel <= 5)
batteryLevel = 100
}
SequentialAnimation {
id: animation
running: false
loops: Animation.Infinite
ScriptAction {
script: {
gear = 0
parkingBrake = true
consumeKW = 0
chargeKW = 0
}
}
PauseAnimation { duration: 2000 }
ScriptAction {
script: {
parkingBrake = false
gear = 1
fuelLevel -= 10.
batteryLevel -= 10.
}
}
ParallelAnimation {
PropertyAnimation {
target: valueSource
property: "kph"
from: 0
to: 150
duration: 10000
}
PropertyAnimation {
target: valueSource
property: "consumeKW"
from: 0
to: 75
duration: 10000
}
}
ParallelAnimation {
PropertyAnimation {
target: valueSource
property: "kph"
from: 150
to: 120
duration: 500
}
PropertyAnimation {
target: valueSource
property: "consumeKW"
from: 75
to: 0
duration: 100
}
PropertyAnimation {
target: valueSource
property: "chargeKW"
from: 0
to: 40
duration: 500
}
}
ParallelAnimation {
PropertyAnimation {
target: valueSource
property: "kph"
from: 120
to: 200
duration: 1500
}
PropertyAnimation {
target: valueSource
property: "consumeKW"
from: 0
to: 90
duration: 1500
}
PropertyAnimation {
target: valueSource
property: "chargeKW"
from: 40
to: 0
duration: 100
}
}
ParallelAnimation {
PropertyAnimation {
target: valueSource
property: "kph"
from: 200
to: 0
duration: 6000
}
PropertyAnimation {
target: valueSource
property: "consumeKW"
from: 90
to: 0
duration: 600
}
PropertyAnimation {
target: valueSource
property: "chargeKW"
from: 0
to: 40
duration: 3000
}
}
}
property int simuRpm: fastBootDemo ? kph * 40 : kph * 150
property double simuTemperature: fastBootDemo ? kph * .25 + 60. : kph * .5 + 50.
// In normal Car UI mode only speed is animated based on gps data
// In automatic demo mode rpm, turbo, consumption and engine temperature are based on speed
property int rpm: automaticDemoMode ? simuRpm : clusterDataSource.rpm
property double engineTemperature: automaticDemoMode ? simuTemperature
: clusterDataSource.engineTemp
property int totalDistance: 42300
property int kmSinceCharge: 8
property int avRangePerCharge: 425
property int energyPerKm: 324
property real totalDistanceSince: 0.
property string gearString: {
var g
if (gear === 0 || gear < -1)
return "N"
else if (gear === -1)
return "R"
else if (carId === 1) //sports car
return gear.toString()
else
return "D"
}
Timer {
id: timeTimer
interval: 15000
repeat: true
running: true
onTriggered: {
currentDate = new Date()
//date = currentDate.toLocaleDateString(Qt.locale("fi_FI"), "ddd d. MMM")
//time = currentDate.toLocaleTimeString(Qt.locale("fi_FI"), "hh:mm")
date = currentDate.toLocaleDateString(Qt.locale("en_GB"))
time = currentDate.toLocaleTimeString(Qt.locale("en_GB"), "hh:mm")
// Approximate total distance based on current speed
totalDistanceSince += kph / 240. // = km / 15 min
if (totalDistanceSince > 1.) {
var totalInt = Math.floor(totalDistanceSince)
totalDistance += totalInt
kmSinceCharge += totalInt
totalDistanceSince -= totalInt
}
}
}
Timer {
id: backCutTimer
interval: 1000
repeat: true
running: true
onTriggered: {
backCut = kph
}
}
property real temperature: 0.6
property alias musicTimer: musicTimer
property real backCut: 0 //For needle tail gradient
property real musicElapsed: 0
Timer {
id: musicTimer
interval: 2000
running: false
repeat: true
onTriggered: {
if (musicElapsed < 100)
musicElapsed++
else
musicElapsed = 0
}
}
Behavior on kph {
enabled: !fastBootDemo
PropertyAnimation { duration: 2000 }
}
//
// For electric car KwGauge animation
//
property var oldSpeed: [0, 0, 0]
signal speedChanged
SequentialAnimation {
id: reduceSpeedAnim
running: (carId === 0 && !fastBootDemo)
property alias chargeTo: charge.to
NumberAnimation {
target: valueSource
property: "consumeKW"
duration: 600
to: 0
}
NumberAnimation {
id: charge
target: valueSource
property: "chargeKW"
duration: 600
}
}
SequentialAnimation {
id: addSpeedAnim
running: (carId === 0 && !fastBootDemo)
property alias consumeTo: consume.to
NumberAnimation {
target: valueSource
property: "chargeKW"
duration: 600
to: 0
}
NumberAnimation {
id: consume
target: valueSource
property: "consumeKW"
duration: 600
}
}
onSpeedChanged: {
var speedChange = oldSpeed[1] - oldSpeed[0]
if (speedChange > 2) {
//"adding speed"
var newKW = Math.min(maxConsumeKWValue * 0.8, 10 * speedChange)
addSpeedAnim.consumeTo = newKW
addSpeedAnim.restart()
} else if (speedChange < -2) {
//"reducing speed"
newKW = Math.min(maxChargeKWValue * 0.8, 2 * Math.abs(speedChange))
reduceSpeedAnim.chargeTo = newKW
reduceSpeedAnim.restart()
} else if (Math.abs(speedChange) >= 0 && oldSpeed[1] !== 0) {
//Speed just about the same but still moving
addSpeedAnim.consumeTo = Math.min(maxConsumeKWValue * (kph / 100),
maxConsumeKWValue * 0.5)
addSpeedAnim.restart()
}
if (kph <= 0.1) {
addSpeedAnim.consumeTo = 0
reduceSpeedAnim.chargeTo = 0
addSpeedAnim.restart()
reduceSpeedAnim.restart()
}
}
}