/* Copyright 2018 - 2019 Benjamin Vedder benjamin@vedder.se This file is part of VESC Tool. VESC Tool is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. VESC Tool is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ import QtQuick 2.0 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import QtQuick.Extras 1.4 import QtGraphicalEffects 1.0 import QtQuick.Controls.Material 2.2 Item { property alias minimumValue: gauge.minimumValue property alias maximumValue: gauge.maximumValue property alias value: gauge.value property string unitText: "" property string typeText: "" property string tickmarkSuffix: "" property double labelStep: 10 property double tickmarkScale: 1 property color traceColor: "#606060" property double maxAngle: 144 property double minAngle: -144 CircularGauge { id: gauge anchors.fill: parent Behavior on value { NumberAnimation { easing.type: Easing.OutCirc duration: 100 } } style: CircularGaugeStyle { id: style labelStepSize: labelStep tickmarkStepSize: labelStep labelInset: outerRadius * 0.28 tickmarkInset: 2 minorTickmarkInset: 2 minimumValueAngle: minAngle maximumValueAngle: maxAngle background: Canvas { property double value: gauge.value anchors.fill: parent onValueChanged: requestPaint() function d2r(degrees) { return degrees * (Math.PI / 180.0); } onPaint: { var ctx = getContext("2d"); ctx.reset(); ctx.beginPath(); var gradient = ctx.createRadialGradient(outerRadius, outerRadius, 0, outerRadius, outerRadius, outerRadius) gradient.addColorStop(0.7, Material.background) gradient.addColorStop(1, traceColor) ctx.fillStyle = gradient ctx.arc(outerRadius, outerRadius, outerRadius, 0, Math.PI * 2) ctx.fill() ctx.beginPath(); ctx.strokeStyle = Material.background ctx.lineWidth = outerRadius ctx.arc(outerRadius, outerRadius, outerRadius / 2, d2r(valueToAngle(Math.max(gauge.value, 0)) - 90), d2r(valueToAngle(gauge.maximumValue + 1) - 90)); ctx.arc(outerRadius, outerRadius, outerRadius / 2, d2r(valueToAngle(gauge.minimumValue) - 90), d2r(valueToAngle(Math.min(gauge.value, 0)) - 90)); ctx.stroke(); ctx.beginPath(); ctx.arc(outerRadius, outerRadius, outerRadius / 2, d2r(valueToAngle(gauge.maximumValue) - 90), d2r(valueToAngle(gauge.minimumValue) - 90)); ctx.stroke(); ctx.beginPath(); ctx.strokeStyle = "darkGray" ctx.lineWidth = 1 ctx.arc(outerRadius, outerRadius, outerRadius - 0.5, 0, 2 * Math.PI); ctx.stroke(); } } needle: Item { y: -outerRadius * 0.82 height: outerRadius * 0.18 Rectangle { id: needle height: parent.height color: "red" width: height * 0.13 antialiasing: true radius: 10 } Glow { anchors.fill: needle radius: 5 samples: 10 spread: 0.6 color: "darkred" source: needle } } foreground: Item { Text { id: speedLabel anchors.centerIn: parent text: gauge.value.toFixed(0) horizontalAlignment: Text.AlignHCenter font.pixelSize: outerRadius * 0.3 color: "white" antialiasing: true } Text { id: speedLabelUnit text: unitText anchors.horizontalCenter: parent.horizontalCenter anchors.top: speedLabel.bottom horizontalAlignment: Text.AlignHCenter font.pixelSize: outerRadius * 0.15 color: "white" antialiasing: true } Text { id: typeLabel text: typeText verticalAlignment: Text.AlignVCenter anchors.horizontalCenter: parent.horizontalCenter anchors.bottom: speedLabel.top anchors.bottomMargin: outerRadius * 0.1 horizontalAlignment: Text.AlignHCenter font.pixelSize: outerRadius * 0.15 color: "white" antialiasing: true } } function isCovered(value) { var res = false if (gauge.value > 0) { if (value <= gauge.value && value >= 0) { res = true } } else { if (value >= gauge.value && value <= 0) { res = true } } return res } tickmarkLabel: Text { font.pixelSize: outerRadius * 0.15 text: parseFloat(styleData.value * tickmarkScale).toFixed(0) + tickmarkSuffix color: isCovered(styleData.value) ? "white" : "darkGray" antialiasing: true } tickmark: Rectangle { implicitWidth: 2 implicitHeight: outerRadius * 0.09 antialiasing: true smooth: true color: isCovered(styleData.value) ? "white" : "darkGray" } minorTickmark: Rectangle { implicitWidth: 1.5 implicitHeight: outerRadius * 0.05 antialiasing: true smooth: true color: isCovered(styleData.value) ? "white" : "darkGray" } } } }