498 lines
18 KiB
QML
498 lines
18 KiB
QML
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
** Contact: https://www.qt.io/licensing/
|
|
**
|
|
** This file is part of the Qt Quick Extras module of the Qt Toolkit.
|
|
**
|
|
** $QT_BEGIN_LICENSE:LGPL$
|
|
** Commercial License Usage
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
** accordance with the commercial license agreement provided with the
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
|
**
|
|
** GNU Lesser General Public License Usage
|
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
** General Public License version 3 as published by the Free Software
|
|
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
|
** packaging of this file. Please review the following information to
|
|
** ensure the GNU Lesser General Public License version 3 requirements
|
|
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
|
**
|
|
** GNU General Public License Usage
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
** General Public License version 2.0 or (at your option) the GNU General
|
|
** Public license version 3 or any later version approved by the KDE Free
|
|
** Qt Foundation. The licenses are as published by the Free Software
|
|
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
|
** included in the packaging of this file. Please review the following
|
|
** information to ensure the GNU General Public License requirements will
|
|
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
|
** https://www.gnu.org/licenses/gpl-3.0.html.
|
|
**
|
|
** $QT_END_LICENSE$
|
|
**
|
|
****************************************************************************/
|
|
|
|
import QtQuick 2.2
|
|
import QtGraphicalEffects 1.0
|
|
import QtQuick.Controls 1.4
|
|
import QtQuick.Controls.Styles 1.4
|
|
import QtQuick.Controls.Private 1.0
|
|
import QtQuick.Extras 1.4
|
|
import QtQuick.Extras.Private 1.0
|
|
|
|
/*!
|
|
\qmltype CircularGaugeStyle
|
|
\inqmlmodule QtQuick.Controls.Styles
|
|
\since 5.5
|
|
\ingroup controlsstyling
|
|
\brief Provides custom styling for CircularGauge.
|
|
|
|
You can create a custom circular gauge by replacing the following delegates:
|
|
\list
|
|
\li \l background
|
|
\li \l tickmark
|
|
\li \l minorTickmark
|
|
\li \l tickmarkLabel
|
|
\li \l needle
|
|
\li \l foreground
|
|
\endlist
|
|
|
|
Below is an example that changes the needle to a basic orange \l Rectangle:
|
|
\code
|
|
CircularGauge {
|
|
style: CircularGaugeStyle {
|
|
needle: Rectangle {
|
|
y: outerRadius * 0.15
|
|
implicitWidth: outerRadius * 0.03
|
|
implicitHeight: outerRadius * 0.9
|
|
antialiasing: true
|
|
color: Qt.rgba(0.66, 0.3, 0, 1)
|
|
}
|
|
}
|
|
}
|
|
\endcode
|
|
|
|
The result:
|
|
\image circulargauge-needle-example-2.png CircularGaugeStyle example
|
|
|
|
\section2 Direction
|
|
|
|
\l minimumValueAngle and \l maximumValueAngle determine not only the
|
|
position of the tickmarks, labels and needle, but the direction in which
|
|
they are displayed around the gauge. For example, if \l minimumValueAngle
|
|
is greater than \l maximumValueAngle, the gauge will be anti-clockwise.
|
|
Below, there are two gauges: the top gauge has a \l minimumValueAngle of
|
|
\c -90 degrees and a \l maximumValueAngle of \c 90 degrees, and the bottom
|
|
gauge has the opposite.
|
|
|
|
\image circulargauge-reversed.png Reversed CircularGauge
|
|
|
|
\sa {Styling CircularGauge}
|
|
*/
|
|
|
|
Style {
|
|
id: circularGaugeStyle
|
|
|
|
/*!
|
|
The \l CircularGauge that this style is attached to.
|
|
*/
|
|
readonly property CircularGauge control: __control
|
|
|
|
/*!
|
|
The distance from the center of the gauge to the outer edge of the
|
|
gauge.
|
|
|
|
This property is useful for determining the size of the various
|
|
components of the style, in order to ensure that they are scaled
|
|
proportionately when the gauge is resized.
|
|
*/
|
|
readonly property real outerRadius: Math.min(control.width, control.height) * 0.5
|
|
|
|
/*!
|
|
This property determines the angle at which the minimum value is
|
|
displayed on the gauge.
|
|
|
|
The angle set affects the following components of the gauge:
|
|
\list
|
|
\li The angle of the needle
|
|
\li The position of the tickmarks and labels
|
|
\endlist
|
|
|
|
The angle origin points north:
|
|
|
|
\image circulargauge-angles.png
|
|
|
|
There is no minimum or maximum angle for this property, but the default
|
|
style only supports angles whose absolute range is less than or equal
|
|
to \c 360 degrees. This is because ranges higher than \c 360 degrees
|
|
will cause the tickmarks and labels to overlap each other.
|
|
|
|
The default value is \c -145.
|
|
*/
|
|
property real minimumValueAngle: -145
|
|
|
|
/*!
|
|
This property determines the angle at which the maximum value is
|
|
displayed on the gauge.
|
|
|
|
The angle set affects the following components of the gauge:
|
|
\list
|
|
\li The angle of the needle
|
|
\li The position of the tickmarks and labels
|
|
\endlist
|
|
|
|
The angle origin points north:
|
|
|
|
\image circulargauge-angles.png
|
|
|
|
There is no minimum or maximum angle for this property, but the default
|
|
style only supports angles whose absolute range is less than or equal
|
|
to \c 360 degrees. This is because ranges higher than \c 360 degrees
|
|
will cause the tickmarks and labels to overlap each other.
|
|
|
|
The default value is \c 145.
|
|
*/
|
|
property real maximumValueAngle: 145
|
|
|
|
/*!
|
|
The range between \l minimumValueAngle and \l maximumValueAngle, in
|
|
degrees. This value will always be positive.
|
|
*/
|
|
readonly property real angleRange: control.__panel.circularTickmarkLabel.angleRange
|
|
|
|
/*!
|
|
This property holds the rotation of the needle in degrees.
|
|
*/
|
|
property real needleRotation: {
|
|
var percentage = (control.value - control.minimumValue) / (control.maximumValue - control.minimumValue);
|
|
minimumValueAngle + percentage * angleRange;
|
|
}
|
|
|
|
/*!
|
|
The interval at which tickmarks are displayed.
|
|
|
|
For example, if this property is set to \c 10 (the default),
|
|
control.minimumValue to \c 0, and control.maximumValue to \c 100,
|
|
the tickmarks displayed will be 0, 10, 20, etc., to 100,
|
|
around the gauge.
|
|
*/
|
|
property real tickmarkStepSize: 10
|
|
|
|
/*!
|
|
The distance in pixels from the outside of the gauge (outerRadius) at
|
|
which the outermost point of the tickmark line is drawn.
|
|
*/
|
|
property real tickmarkInset: 0
|
|
|
|
|
|
/*!
|
|
The amount of tickmarks displayed by the gauge, calculated from
|
|
\l tickmarkStepSize and the control's
|
|
\l {CircularGauge::minimumValue}{minimumValue} and
|
|
\l {CircularGauge::maximumValue}{maximumValue}.
|
|
|
|
\sa minorTickmarkCount
|
|
*/
|
|
readonly property int tickmarkCount: control.__panel.circularTickmarkLabel.tickmarkCount
|
|
|
|
/*!
|
|
The amount of minor tickmarks between each tickmark.
|
|
|
|
The default value is \c 4.
|
|
|
|
\sa tickmarkCount
|
|
*/
|
|
property int minorTickmarkCount: 4
|
|
|
|
/*!
|
|
The distance in pixels from the outside of the gauge (outerRadius) at
|
|
which the outermost point of the minor tickmark line is drawn.
|
|
*/
|
|
property real minorTickmarkInset: 0
|
|
|
|
/*!
|
|
The distance in pixels from the outside of the gauge (outerRadius) at
|
|
which the center of the value marker text is drawn.
|
|
*/
|
|
property real labelInset: __protectedScope.toPixels(0.19)
|
|
|
|
/*!
|
|
The interval at which tickmark labels are displayed.
|
|
|
|
For example, if this property is set to \c 10 (the default),
|
|
control.minimumValue to \c 0, and control.maximumValue to \c 100, the
|
|
tickmark labels displayed will be 0, 10, 20, etc., to 100,
|
|
around the gauge.
|
|
*/
|
|
property real labelStepSize: tickmarkStepSize
|
|
|
|
/*!
|
|
The amount of tickmark labels displayed by the gauge, calculated from
|
|
\l labelStepSize and the control's
|
|
\l {CircularGauge::minimumValue}{minimumValue} and
|
|
\l {CircularGauge::maximumValue}{maximumValue}.
|
|
|
|
\sa tickmarkCount, minorTickmarkCount
|
|
*/
|
|
readonly property int labelCount: control.__panel.circularTickmarkLabel.labelCount
|
|
|
|
/*! \qmlmethod real CircularGaugeStyle::valueToAngle(real value)
|
|
Returns \a value as an angle in degrees.
|
|
|
|
This function is useful for custom drawing or positioning of items in
|
|
the style's components. For example, it can be used to calculate the
|
|
angles at which to draw an arc around the gauge indicating the safe
|
|
area for the needle to be within.
|
|
|
|
For example, if minimumValueAngle is set to \c 270 and
|
|
maximumValueAngle is set to \c 90, this function will return \c 270
|
|
when passed minimumValue and \c 90 when passed maximumValue.
|
|
|
|
\sa {Styling CircularGauge#styling-circulargauge-background}{
|
|
Styling CircularGauge's background}
|
|
*/
|
|
function valueToAngle(value) {
|
|
return control.__panel.circularTickmarkLabel.valueToAngle(value);
|
|
}
|
|
|
|
property QtObject __protectedScope: QtObject {
|
|
/*!
|
|
Converts a value expressed as a percentage of \l outerRadius to
|
|
a pixel value.
|
|
*/
|
|
function toPixels(percentageOfOuterRadius) {
|
|
return percentageOfOuterRadius * outerRadius;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
The background of the gauge.
|
|
|
|
If set, the background determines the implicit size of the gauge.
|
|
|
|
By default, there is no background defined.
|
|
|
|
\sa {Styling CircularGauge#styling-circulargauge-background}{
|
|
Styling CircularGauge's background}
|
|
*/
|
|
property Component background
|
|
|
|
/*!
|
|
This component defines each individual tickmark. The position of each
|
|
tickmark is already set; only the
|
|
\l {Item::implicitWidth}{implicitWidth} and
|
|
\l {Item::implicitHeight}{implicitHeight} need to be specified.
|
|
|
|
Each instance of this component has access to the following properties:
|
|
|
|
\table
|
|
\row \li \c {readonly property int} \b styleData.index
|
|
\li The index of this tickmark.
|
|
\row \li \c {readonly property real} \b styleData.value
|
|
\li The value that this tickmark represents.
|
|
\endtable
|
|
|
|
To illustrate what these properties refer to, we can use the following
|
|
example:
|
|
|
|
\snippet circulargauge-tickmark-indices-values.qml tickmarks
|
|
|
|
We've replaced the conventional \e line tickmarks with \l Text items
|
|
and have hidden the tickmarkLabel component in order to make the
|
|
association clearer:
|
|
|
|
\image circulargauge-tickmark-indices-values.png Tickmarks
|
|
|
|
The index property can be useful if you have another model that
|
|
contains images to display for each index, for example.
|
|
|
|
The value property is useful for drawing lower and upper limits around
|
|
the gauge to indicate the recommended value ranges. For example, speeds
|
|
above 200 kilometers an hour in a car's speedometer could be indicated
|
|
as dangerous using this property.
|
|
|
|
\sa {Styling CircularGauge#styling-circulargauge-tickmark}{
|
|
Styling CircularGauge's tickmark}
|
|
*/
|
|
property Component tickmark: Rectangle {
|
|
implicitWidth: outerRadius * 0.02
|
|
antialiasing: true
|
|
implicitHeight: outerRadius * 0.06
|
|
color: "#c8c8c8"
|
|
}
|
|
|
|
/*!
|
|
This component defines each individual minor tickmark. The position of
|
|
each minor tickmark is already set; only the
|
|
\l {Item::implicitWidth}{implicitWidth} and
|
|
\l {Item::implicitHeight}{implicitHeight} need to be specified.
|
|
|
|
Each instance of this component has access to the following properties:
|
|
|
|
\table
|
|
\row \li \c {readonly property int} \b styleData.index
|
|
\li The index of this tickmark.
|
|
\row \li \c {readonly property real} \b styleData.value
|
|
\li The value that this tickmark represents.
|
|
\endtable
|
|
|
|
\sa {Styling CircularGauge#styling-circulargauge-minorTickmark}{
|
|
Styling CircularGauge's minorTickmark}
|
|
*/
|
|
property Component minorTickmark: Rectangle {
|
|
implicitWidth: outerRadius * 0.01
|
|
antialiasing: true
|
|
implicitHeight: outerRadius * 0.03
|
|
color: "#c8c8c8"
|
|
}
|
|
|
|
/*!
|
|
This defines the text of each tickmark label on the gauge.
|
|
|
|
Each instance of this component has access to the following properties:
|
|
|
|
\table
|
|
\row \li \c {readonly property int} \b styleData.index
|
|
\li The index of this label.
|
|
\row \li \c {readonly property real} \b styleData.value
|
|
\li The value that this label represents.
|
|
\endtable
|
|
|
|
\sa {Styling CircularGauge#styling-circulargauge-tickmarkLabel}{
|
|
Styling CircularGauge's tickmarkLabel}
|
|
*/
|
|
property Component tickmarkLabel: Text {
|
|
font.pixelSize: Math.max(6, __protectedScope.toPixels(0.12))
|
|
text: styleData.value
|
|
color: "#c8c8c8"
|
|
antialiasing: true
|
|
horizontalAlignment: Text.AlignHCenter
|
|
verticalAlignment: Text.AlignVCenter
|
|
}
|
|
|
|
/*!
|
|
The needle that points to the gauge's current value.
|
|
|
|
This component is drawn below the \l foreground component.
|
|
|
|
The style expects the needle to be pointing up at a rotation of \c 0,
|
|
in order for the rotation to be correct. For example:
|
|
|
|
\image circulargauge-needle.png CircularGauge's needle
|
|
|
|
When defining your own needle component, the only properties that the
|
|
style requires you to set are the
|
|
\l {Item::implicitWidth}{implicitWidth} and
|
|
\l {Item::implicitHeight}{implicitHeight}.
|
|
|
|
Optionally, you can set \l {Item::x}{x} and \l {Item::y}{y} to change
|
|
the needle's transform origin. Setting the \c x position can be useful
|
|
for needle images where the needle is not centered exactly
|
|
horizontally. Setting the \c y position allows you to make the base of
|
|
the needle hang over the center of the gauge.
|
|
|
|
\sa {Styling CircularGauge#styling-circulargauge-needle}{
|
|
Styling CircularGauge's needle}
|
|
*/
|
|
property Component needle: Item {
|
|
implicitWidth: __protectedScope.toPixels(0.08)
|
|
implicitHeight: 0.9 * outerRadius
|
|
|
|
Image {
|
|
anchors.fill: parent
|
|
source: "images/needle.png"
|
|
}
|
|
}
|
|
|
|
/*!
|
|
The foreground of the gauge. This component is drawn above all others.
|
|
|
|
Like \l background, the foreground component fills the entire gauge.
|
|
|
|
By default, the knob of the gauge is defined here.
|
|
|
|
\sa {Styling CircularGauge#styling-circulargauge-foreground}{
|
|
Styling CircularGauge's foreground}
|
|
*/
|
|
property Component foreground: Item {
|
|
Image {
|
|
source: "images/knob.png"
|
|
anchors.centerIn: parent
|
|
scale: {
|
|
var idealHeight = __protectedScope.toPixels(0.2);
|
|
var originalImageHeight = sourceSize.height;
|
|
idealHeight / originalImageHeight;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*! \internal */
|
|
property Component panel: Item {
|
|
id: panelItem
|
|
implicitWidth: backgroundLoader.item ? backgroundLoader.implicitWidth : TextSingleton.implicitHeight * 16
|
|
implicitHeight: backgroundLoader.item ? backgroundLoader.implicitHeight : TextSingleton.implicitHeight * 16
|
|
|
|
property alias background: backgroundLoader.item
|
|
property alias circularTickmarkLabel: circularTickmarkLabel_
|
|
|
|
Loader {
|
|
id: backgroundLoader
|
|
sourceComponent: circularGaugeStyle.background
|
|
width: outerRadius * 2
|
|
height: outerRadius * 2
|
|
anchors.centerIn: parent
|
|
}
|
|
|
|
CircularTickmarkLabel {
|
|
id: circularTickmarkLabel_
|
|
anchors.fill: backgroundLoader
|
|
|
|
minimumValue: control.minimumValue
|
|
maximumValue: control.maximumValue
|
|
stepSize: control.stepSize
|
|
tickmarksVisible: control.tickmarksVisible
|
|
minimumValueAngle: circularGaugeStyle.minimumValueAngle
|
|
maximumValueAngle: circularGaugeStyle.maximumValueAngle
|
|
tickmarkStepSize: circularGaugeStyle.tickmarkStepSize
|
|
tickmarkInset: circularGaugeStyle.tickmarkInset
|
|
minorTickmarkCount: circularGaugeStyle.minorTickmarkCount
|
|
minorTickmarkInset: circularGaugeStyle.minorTickmarkInset
|
|
labelInset: circularGaugeStyle.labelInset
|
|
labelStepSize: circularGaugeStyle.labelStepSize
|
|
|
|
style: CircularTickmarkLabelStyle {
|
|
tickmark: circularGaugeStyle.tickmark
|
|
minorTickmark: circularGaugeStyle.minorTickmark
|
|
tickmarkLabel: circularGaugeStyle.tickmarkLabel
|
|
}
|
|
}
|
|
|
|
Loader {
|
|
id: needleLoader
|
|
sourceComponent: circularGaugeStyle.needle
|
|
transform: [
|
|
Rotation {
|
|
angle: needleRotation
|
|
origin.x: needleLoader.width / 2
|
|
origin.y: needleLoader.height
|
|
},
|
|
Translate {
|
|
x: panelItem.width / 2 - needleLoader.width / 2
|
|
y: panelItem.height / 2 - needleLoader.height
|
|
}
|
|
]
|
|
}
|
|
|
|
Loader {
|
|
id: foreground
|
|
sourceComponent: circularGaugeStyle.foreground
|
|
anchors.fill: backgroundLoader
|
|
}
|
|
}
|
|
}
|