Skip to content

Commit

Permalink
Implement tank gauge via clip instead of opacity mask
Browse files Browse the repository at this point in the history
The opacity mask shader effect sometimes didn't render properly
on device.  This commit adds a new clip-based tank gauge instead.
  • Loading branch information
chriadam committed May 17, 2024
1 parent a794af7 commit 7a5536d
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 4 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ set (VENUS_QML_MODULE_SOURCES
components/ButtonControlValue.qml
components/CircularMultiGauge.qml
components/CircularSingleGauge.qml
components/ClippingBarGauge.qml
components/ControlCard.qml
components/ControlValue.qml
components/CpuMonitor.qml
Expand Down
105 changes: 105 additions & 0 deletions components/ClippingBarGauge.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
** Copyright (C) 2024 Victron Energy B.V.
** See LICENSE.txt for license information.
*/

import QtQuick
import QtQuick.Effects as Effects
import Victron.VenusOS
import Victron.Gauges

Item {
id: root

property int valueType: VenusOS.Gauges_ValueType_NeutralPercentage
readonly property int valueStatus: Gauges.getValueStatus(_value * 100, valueType)
property color foregroundColor: Theme.statusColorValue(valueStatus)
property color backgroundColor: Theme.statusColorValue(valueStatus, true)
property color surfaceColor: Theme.color_levelsPage_gauge_separatorBarColor
property real value: 0.0
property int orientation: Qt.Vertical
property real radius: root.orientation === Qt.Vertical ? width / 2 : height / 2
property bool animationEnabled

width: orientation === Qt.Vertical ? Theme.geometry_barGauge_vertical_width_large : parent.width
height: orientation === Qt.Vertical ? parent.height : Theme.geometry_barGauge_horizontal_height
clip: true

readonly property real _value: isNaN(value) ? 0 : Math.min(1.0, Math.max(0, value))

// Only update the nextPos when the width/height have been initialized.
readonly property real _nextPos: (width !== Infinity && height !== Infinity)
? orientation === Qt.Vertical
? height - (height * _value) // slide in from bottom to top
: -width + (width * _value) // slide in from left to right
: 0

on_NextPosChanged: if (visible) _updateGauge()
onVisibleChanged: if (visible) _updateGauge()

function _updateGauge() {
if (animationEnabled) {
const animator = orientation === Qt.Vertical ? yAnimator : xAnimator
const currValue = orientation === Qt.Vertical ? fgRect.y : fgRect.x
if (!animator.running && currValue !== _nextPos) {
animator.from = currValue
animator.to = _nextPos
animator.start()
}
} else {
if (orientation === Qt.Vertical) {
fgRect.y = _nextPos
} else {
fgRect.x = _nextPos
}
}
}

Rectangle {
id: bgRect
anchors.fill: parent
color: root.backgroundColor
z: 1 // drawn below fg and below border
}

Rectangle {
id: fgRect

width: parent.width
height: parent.height
color: foregroundColor
z: 2 // drawn above bg and below border

// Use animators instead of a behavior on x/y. Otherwise, there can be a "jump" when
// receiving two value updates in close succession.
XAnimator {
id: xAnimator
target: fgRect
easing.type: Easing.InOutQuad
duration: Theme.animation_briefPage_sidePanel_sliderValueChange_duration
onRunningChanged: if (!running) Qt.callLater(_updateGauge) // if _nextPos changed during previous animation
}
YAnimator {
id: yAnimator
target: fgRect
easing.type: Easing.InOutQuad
duration: Theme.animation_briefPage_sidePanel_sliderValueChange_duration
onRunningChanged: if (!running) Qt.callLater(_updateGauge) // if _nextPos changed during previous animation
}
}

Rectangle {
id: borderRect
color: "transparent"
radius: root.radius + border.width // "exterior" radius = "internal" radius + border.width
width: parent.width + 2*border.width
height: parent.height + 2*border.width
x: -border.width
y: -border.width
z: 5 // drawn above everything else.
// wide enough to perfectly cover the "missing" pixels due to interior rounding.
border.width: Math.ceil(((Math.SQRT2*(2*root.radius)) - (2*root.radius))/2)
border.color: root.surfaceColor
}

}
1 change: 1 addition & 0 deletions components/ExpandedTanksView.qml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ Rectangle {
totalRemaining: model.device.remaining

gauge: TankGauge {
surfaceColor: root.color
width: Theme.geometry_levelsPage_groupedSubgauges_delegate_width
valueType: root._tankProperties.valueType
animationEnabled: root.animationEnabled
Expand Down
9 changes: 5 additions & 4 deletions components/TankGauge.qml
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,35 @@ import QtQuick
import Victron.VenusOS
import QtQuick.Controls.impl as CP

BarGauge {
ClippingBarGauge {
id: root

property bool isGrouped: false
property bool expanded

radius: Theme.geometry_levelsPage_tankGauge_radius
surfaceColor: Theme.color_levelsPage_gauge_separatorBarColor

Rectangle {
width: parent.width
height: 2
color: Theme.color_levelsPage_gauge_separatorBarColor
color: root.surfaceColor
y: parent.height/4
z: 5
}

Rectangle {
width: parent.width
height: 2
color: Theme.color_levelsPage_gauge_separatorBarColor
color: root.surfaceColor
y: 2*parent.height/4
z: 5
}

Rectangle {
width: parent.width
height: 2
color: Theme.color_levelsPage_gauge_separatorBarColor
color: root.surfaceColor
y: 3*parent.height/4
z: 5
}
Expand Down

0 comments on commit 7a5536d

Please sign in to comment.