Various changes have been made as a result of the discussion of the first version

This commit is contained in:
Yury Shuvakin
2022-09-09 16:36:44 +03:00
parent 1fc06361f8
commit 3d0f39f846
13 changed files with 259 additions and 68 deletions

View File

@@ -173,6 +173,8 @@ TRANSLATIONS = translations/cubo_en.ts \
translations/cubo_ru.ts \
translations/cubo_it.ts
RC_ICONS = qml/Icons/cubo-icon.ico
DISTFILES += \
android/AndroidManifest.xml \
android/gradle/wrapper/gradle-wrapper.jar \

View File

@@ -1,6 +1,8 @@
import QtQuick 2.12
import QtCharts 2.3
import QtQuick.Shapes 1.12
import Controls 1.0 as Controls
import Utils 1.0
ChartView {
@@ -20,6 +22,7 @@ ChartView {
property int defaultXMax: 10
property int defaultYMax: 1
property bool autoScaling: true
property int selectedSeriesIndex: 0
ValueAxis {
id: valueAxisX
@@ -45,10 +48,47 @@ ChartView {
titleVisible: false
}
Shape {
id: currentPointLine
implicitWidth: 1
implicitHeight: chart.plotArea.height
x: chart.plotArea.x
y: chart.plotArea.y
ShapePath {
strokeColor: Palette.borderColor
strokeStyle: ShapePath.SolidLine
startX: 0
startY: 0
PathLine { x: 0; y: currentPointLine.height }
}
}
Rectangle {
id: currentPointInfo
width: currentPointInfoLabel.width
height: currentPointInfoLabel.height
color: Palette.backgroundColor
border.width: 1
border.color: Palette.borderColor
opacity: 0.9
radius: 6
visible: false
Controls.SubtitleLabel {
id: currentPointInfoLabel
horizontalAlignment: Text.AlignHCenter
anchors.centerIn: parent
padding: 10
}
}
MouseArea {
id: chartMouseAreaA
id: chartMouseArea
anchors.fill: parent
acceptedButtons: Qt.LeftButton
hoverEnabled: true
property real lastMouseX: 0
property real lastMouseY: 0
@@ -59,27 +99,28 @@ ChartView {
if ((mouse.buttons & Qt.LeftButton) == Qt.LeftButton) {
if (mouseX - lastMouseX > scrollThreshold) {
chart.scrollLeft(mouseX - lastMouseX)
lastMouseX = mouseX
chart.autoScaling = false
} else if (mouseX - lastMouseX < scrollThreshold) {
chart.scrollRight(lastMouseX - mouseX)
}
lastMouseX = mouseX
chart.autoScaling = false
}
}
updatePointInfo()
}
onMouseYChanged: {
if ((mouse.buttons & Qt.LeftButton) == Qt.LeftButton) {
if (mouseY - lastMouseY > scrollThreshold) {
chart.scrollUp(mouseY - lastMouseY)
lastMouseY = mouseY
chart.autoScaling = false
} else if (mouseY - lastMouseY < scrollThreshold) {
chart.scrollDown(lastMouseY - mouseY)
}
lastMouseY = mouseY
chart.autoScaling = false
}
}
updatePointInfo()
}
onPressed: {
if (mouse.button === Qt.LeftButton) {
@@ -88,13 +129,71 @@ ChartView {
}
}
onWheel: {
var scaleFactor = 0.75
var area = chart.plotArea
chart.autoScaling = false
var yAxisPosition = mouseX <= chart.plotArea.x
if (yAxisPosition) {
if (wheel.angleDelta.y > 0) {
chart.zoomIn()
chart.autoScaling = false
chart.zoomIn(Qt.rect(area.x, area.y + Math.round(area.height * (1 - scaleFactor) / 2), area.width, Math.round(area.height * scaleFactor)))
} else {
chart.zoomOut()
chart.autoScaling = false
chart.zoomIn(Qt.rect(area.x, area.y - Math.round((area.height / scaleFactor) * (1 - scaleFactor) / 2), area.width, Math.round(area.height / scaleFactor)))
}
return
}
var xAxisPosition = mouseY >= (chart.plotArea.y + chart.plotArea.height)
if (xAxisPosition) {
if (wheel.angleDelta.y > 0) {
chart.zoomIn(Qt.rect(area.x + area.width * (1 - scaleFactor) / 2, area.y, Math.round(area.width * scaleFactor), area.height))
} else {
chart.zoomIn(Qt.rect(area.x - (area.width / scaleFactor) * (1 - scaleFactor) / 2, area.y, Math.round(area.width / scaleFactor), area.height))
}
return
}
if (wheel.angleDelta.y > 0) {
let zoomedInArea = Qt.rect(area.x + Math.round((mouseX - area.x) * (1 - scaleFactor)),
area.y + Math.round((mouseY - area.y) * (1 - scaleFactor)),
Math.round(area.width * scaleFactor),
Math.round(area.height * scaleFactor))
chart.zoomIn(zoomedInArea)
} else {
let zoomedOutArea = Qt.rect(area.x - Math.floor((mouseX - area.x) * (1 - scaleFactor)),
area.y - Math.floor((mouseY - area.y) * (1 - scaleFactor)),
Math.round(area.width * (1 + (1 - scaleFactor))),
Math.round(area.height * (1 + (1 - scaleFactor))))
chart.zoomIn(zoomedOutArea)
}
updatePointInfo()
}
function updatePointInfo() {
var currentPointVisibility = mouseX >= chart.plotArea.x && mouseX <= chart.plotArea.x + chart.plotArea.width &&
mouseY >= chart.plotArea.y && mouseY <= chart.plotArea.y + chart.plotArea.height
currentPointInfo.visible = currentPointVisibility
currentPointInfo.x = mouseX + 5
currentPointInfo.y = mouseY - currentPointInfo.height - 5
var currentX = Math.ceil(mapToValue(Qt.point(mouseX, mouseY), chart.series(selectedSeriesIndex)).x)
var selectedPoint = Qt.point(0, 0)
if (currentX < chart.series(selectedSeriesIndex).count && currentX > 0) {
selectedPoint = chart.series(selectedSeriesIndex).at(currentX)
currentPointInfoLabel.text = selectedPoint.x + ", " +selectedPoint.y
} else {
currentPointInfo.visible = false
}
currentPointLine.visible = currentPointVisibility
currentPointLine.x = mouseX
}
}
onSeriesAdded: if (count === 1) {
series.pointAdded.connect(function (index){ chartMouseArea.updatePointInfo() })
}
}

View File

@@ -0,0 +1,27 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import Utils 1.0
Button {
id: control
icon.width: 24
icon.height: 24
contentItem: Image {
source: control.icon.source
sourceSize.width: control.icon.width
sourceSize.height: control.icon.height
fillMode: Image.PreserveAspectFit
}
background: Rectangle {
implicitWidth: 44
implicitHeight: 44
opacity: enabled ? 1 : 0.3
color: control.pressed ? Palette.pressedButtonColor :
control.hovered ? Palette.hoveredButtonColor : Palette.buttonColor
radius: 5
}
}

View File

@@ -9,6 +9,8 @@ TextField {
color: Palette.textColor
selectByMouse: true
selectionColor: Palette.selectedTextBackgroundColor
leftPadding: 16
rightPadding: 16
background: Rectangle {
color: enabled ? Palette.backgroundColor : Palette.hoveredBackgroundColor

View File

@@ -24,3 +24,4 @@ BusyIndicator 1.0 BusyIndicator.qml
MenuItemDelegate 1.0 MenuItemDelegate.qml
ScrollIndicator 1.0 ScrollIndicator.qml
OutlineImageButton 1.0 OutlineImageButton.qml
ImageButton 1.0 ImageButton.qml

BIN
qml/Icons/cubo-icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

View File

@@ -9,7 +9,7 @@ import Utils 1.0
ApplicationWindow {
id: window
title: qsTr("Cubo Verde BMS tool")
title: qsTr("Cubo Verde BMS")
width: 1366
height: 768
visible: true

View File

@@ -6,6 +6,8 @@ import Cubo 1.0
import Utils 1.0
Item {
id: root
ColumnLayout {
spacing: 15
anchors.fill: parent
@@ -298,6 +300,8 @@ Item {
Connections {
target: BmsInterface.commands()
enabled: root.visible
onValuesReceived: {
batteryChargeLevelLabel.text = values.soC
batteryVoltageLabel.text = MathHelper.roundDouble(values.packVoltage)
@@ -334,7 +338,7 @@ Item {
Timer {
id: refreshValuesTimer
interval: 5000
interval: 1000
onTriggered: getValues()
}

View File

@@ -15,13 +15,15 @@ RowLayout {
signal needWait(bool active, string text)
spacing: contentColumnSpacing
spacing: contentColumnSpacing - 10
Flickable {
id: settingsFlickable
clip: true
contentWidth: width - rightMargin - leftMargin
contentHeight: configLayout.height
boundsBehavior: Flickable.StopAtBounds
rightMargin: 10
ColumnLayout {
id: configLayout

View File

@@ -8,6 +8,8 @@ import Cubo 1.0
import Utils 1.0
Item {
id: root
Component {
id: cellListHeader
@@ -22,6 +24,7 @@ Item {
Layout.fillWidth: true
Controls.SubtitleLabel {
id: indexTitleLabel
text: qsTr("#")
color: Palette.tableHeaderTextColor
anchors.centerIn: parent
@@ -35,6 +38,7 @@ Item {
Layout.fillWidth: true
Controls.SubtitleLabel {
id: voltageTitleLabel
text: qsTr("Voltage")
color: Palette.tableHeaderTextColor
anchors.centerIn: parent
@@ -48,6 +52,7 @@ Item {
Layout.fillWidth: true
Controls.SubtitleLabel {
id: balancingTitleLabel
text: qsTr("Balancing")
color: Palette.tableHeaderTextColor
anchors.centerIn: parent
@@ -64,15 +69,16 @@ Item {
RowLayout {
spacing: 10
width: ListView.view.width
height: 38
height: 36
Item {
Layout.preferredWidth: parent.width / 6 - 20
Layout.preferredWidth: parent.width / 6 - 24
}
Controls.SubtitleLabel {
id: indexLabel
color: Palette.tableHeaderTextColor
horizontalAlignment: Text.AlignHCenter
Layout.preferredWidth: 25
Layout.alignment: Qt.AlignCenter
}
@@ -96,7 +102,7 @@ Item {
}
Item {
Layout.preferredWidth: parent.width / 6 - 20
Layout.preferredWidth: parent.width / 6 - 24
}
Component.onCompleted: {
@@ -157,12 +163,14 @@ Item {
Connections {
target: BmsInterface.commands()
enabled: root.visible
onCellsReceived: {
firstCellGroup.model = []
var firstModel = []
for (var i = 0; i < Math.min(cellCount, 16); ++i) {
firstModel.push({"voltage": MathHelper.roundDouble(cellVoltageArray[i]), "balancing": cellVoltageArray[i] < 0})
firstModel.push({"voltage": Math.abs(MathHelper.roundDouble(cellVoltageArray[i], 3)), "balancing": cellVoltageArray[i] < 0})
}
firstCellGroup.model = firstModel
@@ -171,7 +179,7 @@ Item {
var secondModel = []
for (var j = 16; j < Math.min(cellCount, 32); ++j) {
secondModel.push({"voltage": MathHelper.roundDouble(cellVoltageArray[j]), "balancing": cellVoltageArray[i] < 0})
secondModel.push({"voltage": Math.abs(MathHelper.roundDouble(cellVoltageArray[j], 3)), "balancing": cellVoltageArray[i] < 0})
}
secondCellGroup.model = secondModel
}
@@ -187,7 +195,7 @@ Item {
Timer {
id: refreshValuesTimer
interval: 5000
interval: 1000
onTriggered: getValues()
}

View File

@@ -8,9 +8,10 @@ import Cubo 1.0
import Utils 1.0
ColumnLayout {
id: root
spacing: 20
property int currentTime: 0
property real currentTime: 0
property var voltageData: []
property var currentData: []
@@ -86,6 +87,7 @@ ColumnLayout {
property Controls.ChartView chartItem: undefined
property color seriesColor: "black"
property bool horizontal: true
property bool selected: false
Controls.CheckBox {
id: checkSeries
@@ -114,9 +116,17 @@ ColumnLayout {
Rectangle {
color: seriesColor
radius: width / 2
Layout.preferredWidth: 18
Layout.preferredHeight: 18
border.width: selected ? 2 : 0
border.color: "black"
Layout.preferredWidth: selected ? 21 : 18
Layout.preferredHeight: selected ? 21 : 18
Layout.rightMargin: 20
Layout.alignment: Qt.AlignCenter
MouseArea {
anchors.fill: parent
onClicked: if (!selected) selected = true
}
}
Component.onCompleted: {
@@ -124,6 +134,10 @@ ColumnLayout {
horizontal = !ListView.view
seriesColor = chartItem.series(modelData).color
checkSeries.text = Qt.binding(function(){ return chartItem.series(modelData).name })
selectedChanged.connect(function (){ if (selected) chartItem.selectedSeriesIndex = index })
chartItem.selectedSeriesIndexChanged.connect(function (){ if (typeof(selected) != "undefined") selected = chartItem.selectedSeriesIndex === index })
selected = chartItem.selectedSeriesIndex === index
}
}
}
@@ -289,44 +303,6 @@ ColumnLayout {
RowLayout {
spacing: 20
Controls.Button {
text: timer.running ? qsTr("Pause data collection") : qsTr("Resume data collection")
onClicked: {
if (timer.running)
timer.stop()
else
timer.start()
}
}
Controls.Button {
text: qsTr("Clear data")
onClicked: {
currentTime = 0
clearData(voltageData, voltageLoader)
clearData(currentData, currentLoader)
clearData(batteryTemperatureData, batteryTemperatureLoader)
clearData(bmsTemperatureData, bmsTemperatureLoader)
clearData(cellVoltageData, cellVoltageLoader)
clearData(cellListData, cellListLoader)
resetZoomButton.clicked()
}
function clearData(dataObject, chartObject) {
for (var i = 0; i < dataObject.length; ++i) {
dataObject[i].splice(0, dataObject[i].length)
var series = chartObject.item.chart.series(i)
series.removePoints(0, series.count)
}
}
}
Item {
Layout.fillWidth: true
}
Controls.Button {
id: resetZoomButton
text: qsTr("Reset zoom")
@@ -382,6 +358,73 @@ ColumnLayout {
return min
}
}
Controls.Button {
property string pauseText: qsTr("Pause data collection")
property string resumeText: qsTr("Resume data collection")
text: pauseText
onClicked: {
if (timer.running) {
text = resumeText
timer.stop()
} else {
text = pauseText
timer.start()
}
}
}
Controls.Button {
text: qsTr("Clear data")
onClicked: {
currentTime = 0
clearData(voltageData, voltageLoader)
clearData(currentData, currentLoader)
clearData(batteryTemperatureData, batteryTemperatureLoader)
clearData(bmsTemperatureData, bmsTemperatureLoader)
clearData(cellVoltageData, cellVoltageLoader)
clearData(cellListData, cellListLoader)
resetZoomButton.clicked()
}
function clearData(dataObject, chartObject) {
for (var i = 0; i < dataObject.length; ++i) {
dataObject[i].splice(0, dataObject[i].length)
var series = chartObject.item.chart.series(i)
series.removePoints(0, series.count)
}
}
}
Item {
Layout.fillWidth: true
}
RowLayout {
spacing: 10
Controls.SubtitleLabel {
text: qsTr("Interval, s")
}
Controls.TextField {
id: intervalField
validator: DoubleValidator { bottom: 0.1; top: 100; decimals: 1; locale: "en-US" }
text: "1"
onEditingFinished: timer.interval = parseFloat(text) * 1000
Layout.preferredHeight: 44
}
Controls.ImageButton {
icon.source: "qrc:/Icons/check-indicator.svg"
icon.width: 32
icon.height: 32
Layout.preferredWidth: 42
Layout.preferredHeight: 42
}
}
}
Connections {
@@ -395,6 +438,7 @@ ColumnLayout {
Connections {
target: BmsInterface.commands()
enabled: root.visible
onValuesReceived: {
addValueToChart(values.packVoltage, voltageData, voltageLoader, 0, 0.05)
@@ -428,7 +472,7 @@ ColumnLayout {
addValueToChart(cellVoltageArray[j], cellListData, cellListLoader, j, 0.05)
}
currentTime += 1
currentTime = Math.round((timer.interval / 1000 + currentTime + Number.EPSILON) * 10) / 10
}
}

View File

@@ -2,7 +2,8 @@ pragma Singleton
import QtQuick 2.12
QtObject {
function roundDouble(value) {
return Math.round((value + Number.EPSILON) * 100) / 100
function roundDouble(value, decimals = 2) {
var factor = Math.pow(10, decimals)
return Math.round((value + Number.EPSILON) * factor) / factor
}
}

View File

@@ -40,5 +40,6 @@
<file>Controls/MenuItemDelegate.qml</file>
<file>Controls/ScrollIndicator.qml</file>
<file>Controls/OutlineImageButton.qml</file>
<file>Controls/ImageButton.qml</file>
</qresource>
</RCC>