218 lines
7.4 KiB
QML
218 lines
7.4 KiB
QML
/*
|
|
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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
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"
|
|
}
|
|
}
|
|
}
|
|
}
|