mirror of
https://github.com/Serial-Studio/Serial-Studio.git
synced 2025-01-31 17:42:55 +08:00
254 lines
7.0 KiB
QML
254 lines
7.0 KiB
QML
/*
|
|
* Copyright (c) 2021 Arun Pk
|
|
* Copyright (c) 2024 Alex Spataru <https://github.com/alex-spataru>
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*/
|
|
|
|
import QtQml
|
|
import QtQuick
|
|
import QtQuick.Shapes
|
|
|
|
Item {
|
|
id: control
|
|
|
|
property int trackWidth: 20
|
|
property int progressWidth: 20
|
|
|
|
property real startAngle: 0
|
|
property real endAngle: 360
|
|
|
|
property real value: 0.0
|
|
property real minValue: 0.0
|
|
property real maxValue: 1.0
|
|
property real alarmValue: 0.5
|
|
|
|
property int capStyle: Qt.RoundCap
|
|
|
|
property color alarmColor: "#ff0000"
|
|
property color trackColor: "#505050"
|
|
property color handleColor: "#fefefe"
|
|
property color progressColor: "#3a4ec4"
|
|
|
|
property real stepSize: 0.1
|
|
|
|
property Component alarmMarker: null
|
|
property Component valueMarker: null
|
|
|
|
property bool snap: false
|
|
property bool hideTrack: false
|
|
property bool hideProgress: false
|
|
property bool alarmEnabled: false
|
|
|
|
property int valueMarkerWidth: 22
|
|
property int valueMarkerHeight: 22
|
|
property int valueMarkerVerticalOffset: 0
|
|
|
|
property int alarmMarkerWidth: 22
|
|
property int alarmMarkerHeight: 22
|
|
property int alarmMarkerVerticalOffset: 0
|
|
|
|
readonly property alias angle: internal.angle
|
|
readonly property alias baseRadius: internal.baseRadius
|
|
readonly property alias alarmStartAngle: internal.alarmStartAngle
|
|
|
|
implicitWidth: 250
|
|
implicitHeight: 250
|
|
|
|
Binding {
|
|
target: control
|
|
property: "value"
|
|
when: internal.setUpdatedValue
|
|
restoreMode: Binding.RestoreBinding
|
|
value: control.snap ? internal.snappedValue : internal.mapFromValue(startAngle, endAngle, minValue, maxValue, internal.angleProxy)
|
|
}
|
|
|
|
QtObject {
|
|
id: internal
|
|
|
|
property real snappedValue: 0.0
|
|
property bool setUpdatedValue: false
|
|
property real angleProxy: control.startAngle
|
|
property color trackColor: control.trackColor
|
|
property color transparentColor: "transparent"
|
|
property real actualSpanAngle: control.endAngle - control.startAngle
|
|
property var centerPt: Qt.point(control.width / 2, control.height / 2)
|
|
property real baseRadius: Math.min(control.width, control.height) / 2 - Math.max(control.trackWidth, control.progressWidth) / 2
|
|
readonly property real angle: internal.mapFromValue(control.minValue, control.maxValue, control.startAngle, control.endAngle, control.value)
|
|
property real alarmStartAngle: internal.mapFromValue(control.minValue, control.maxValue, control.startAngle, control.endAngle, control.alarmValue)
|
|
|
|
function mapFromValue(inMin, inMax, outMin, outMax, inValue) {
|
|
return (inValue - inMin) * (outMax - outMin) / (inMax - inMin) + outMin;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Track Shape
|
|
//
|
|
Shape {
|
|
id: trackShape
|
|
|
|
layer.samples: 8
|
|
layer.enabled: true
|
|
width: control.width
|
|
height: control.height
|
|
visible: !control.hideTrack
|
|
|
|
ShapePath {
|
|
id: trackShapePath
|
|
|
|
capStyle: control.capStyle
|
|
strokeColor: control.trackColor
|
|
strokeWidth: control.trackWidth
|
|
fillColor: internal.transparentColor
|
|
|
|
PathAngleArc {
|
|
centerX: control.width / 2
|
|
centerY: control.height / 2
|
|
radiusX: internal.baseRadius
|
|
radiusY: internal.baseRadius
|
|
startAngle: control.startAngle - 90
|
|
sweepAngle: internal.actualSpanAngle
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Progress Shape
|
|
//
|
|
Shape {
|
|
id: progressShape
|
|
|
|
layer.samples: 8
|
|
layer.enabled: true
|
|
width: control.width
|
|
height: control.height
|
|
visible: !control.hideProgress
|
|
|
|
ShapePath {
|
|
id: progressShapePath
|
|
|
|
capStyle: control.capStyle
|
|
strokeWidth: control.progressWidth
|
|
strokeColor: control.progressColor
|
|
fillColor: internal.transparentColor
|
|
|
|
PathAngleArc {
|
|
centerX: control.width / 2
|
|
centerY: control.height / 2
|
|
radiusX: internal.baseRadius
|
|
radiusY: internal.baseRadius
|
|
startAngle: control.startAngle - 90
|
|
sweepAngle: control.angle - control.startAngle
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Alarm Progress Shape
|
|
//
|
|
Shape {
|
|
id: alarmShape
|
|
|
|
layer.samples: 8
|
|
layer.enabled: true
|
|
width: control.width
|
|
height: control.height
|
|
visible: control.alarmEnabled && control.value > control.alarmValue
|
|
|
|
ShapePath {
|
|
id: alarmShapePath
|
|
|
|
capStyle: control.capStyle
|
|
strokeWidth: control.progressWidth
|
|
strokeColor: control.alarmColor
|
|
fillColor: internal.transparentColor
|
|
|
|
PathAngleArc {
|
|
centerX: control.width / 2
|
|
centerY: control.height / 2
|
|
radiusX: internal.baseRadius
|
|
radiusY: internal.baseRadius
|
|
startAngle: internal.alarmStartAngle - 90
|
|
sweepAngle: control.angle - internal.alarmStartAngle
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Alarm Marker
|
|
//
|
|
Item {
|
|
id: alarmMarkerItem
|
|
|
|
z: 3
|
|
antialiasing: true
|
|
width: control.alarmMarkerWidth
|
|
height: control.alarmMarkerHeight
|
|
x: control.width / 2 - width / 2
|
|
y: control.height / 2 - height / 2
|
|
visible: control.alarmEnabled && control.alarmMarker != null
|
|
|
|
transform: [
|
|
Translate {
|
|
y: -(Math.min(control.width, control.height) / 2) + Math.max(control.trackWidth, control.progressWidth) / 2 + control.alarmMarkerVerticalOffset
|
|
},
|
|
Rotation {
|
|
angle: internal.alarmStartAngle
|
|
origin.x: alarmMarkerItem.width / 2
|
|
origin.y: alarmMarkerItem.height / 2
|
|
}
|
|
]
|
|
|
|
Loader {
|
|
sourceComponent: control.alarmMarker
|
|
}
|
|
}
|
|
|
|
//
|
|
// Value Marker
|
|
//
|
|
Item {
|
|
id: valueMarkerItem
|
|
|
|
z: 3
|
|
antialiasing: true
|
|
width: control.valueMarkerWidth
|
|
height: control.valueMarkerHeight
|
|
x: control.width / 2 - width / 2
|
|
y: control.height / 2 - height / 2
|
|
visible: control.valueMarker != null
|
|
|
|
transform: [
|
|
Translate {
|
|
y: -(Math.min(control.width, control.height) / 2) + Math.max(control.trackWidth, control.progressWidth) / 2 + control.valueMarkerVerticalOffset
|
|
},
|
|
Rotation {
|
|
angle: internal.angle
|
|
origin.x: valueMarkerItem.width / 2
|
|
origin.y: valueMarkerItem.height / 2
|
|
}
|
|
]
|
|
|
|
Loader {
|
|
sourceComponent: control.valueMarker
|
|
}
|
|
}
|
|
}
|