Index: leahi.pro =================================================================== diff -u -rcb9c48c7c307690dcafcfd16ef412fe660291692 -r1aec139f8de0f0ccc5c6a3c4c3d2c479e054b0f9 --- leahi.pro (.../leahi.pro) (revision cb9c48c7c307690dcafcfd16ef412fe660291692) +++ leahi.pro (.../leahi.pro) (revision 1aec139f8de0f0ccc5c6a3c4c3d2c479e054b0f9) @@ -60,6 +60,7 @@ sources/model/td \ sources/model/td/data \ sources/model/td/data/treatment \ + sources/model/td/data/treatmentlog \ sources/model/td/alarm \ sources/model/td/adjustment \ sources/model/td/adjustment/settings \ @@ -204,6 +205,9 @@ sources/device/DeviceModels.h \ \ # ---------- Models - TD - Data //// ----- @LEAHIZED sources/model/td/data/MTDOpModeData.h \ + \ # ---------- Models - TD - Data - Treatment Log + sources/model/td/data/treatmentlog/MTreatmentLogAlarmData.h \ + sources/model/td/data/treatmentlog/MTreatmentLogEventData.h \ \ # ---------- Models - TD - Adjustment - In-Treatment //// ----- @LEAHIZED sources/model/td/adjustment/treatment/MTreatmentAdjustUltrafiltrationStateResponse.h \ sources/model/td/adjustment/treatment/MTreatmentAdjustUltrafiltrationEditResponse.h \ @@ -324,9 +328,7 @@ sources/model/hd/data/post/MHDRTCEpochData.h \ sources/model/hd/data/MHDUsageInfoResponse.h \ \ # ---------- Models - HD - Data - Treatment Log - sources/model/hd/data/treatmentlog/MTreatmentLogAlarmData.h \ sources/model/hd/data/treatmentlog/MTreatmentLogAvrgeData.h \ - sources/model/hd/data/treatmentlog/MTreatmentLogEventData.h \ \ # ---------- Models - DG - Adjustment sources/model/dg/adjustment/settings/MAdjustDGRequests.h \ sources/model/dg/adjustment/settings/MAdjustDGCleaningUsageResponse.h \ @@ -466,6 +468,7 @@ sources/view/td/data/treatment/VTreatmentPressureOcclusion.h \ sources/view/td/data/treatment/VTreatmentSalineData.h \ sources/view/td/data/treatment/VTreatmentTime.h \ + sources/view/td/data/treatment/VTreatmentTrends.h \ sources/view/td/data/treatment/VTreatmentUltrafiltrationData.h SOURCES += \ @@ -553,6 +556,9 @@ sources/device/DeviceModels.cpp \ \ # ---------- Models - TD - Data - States sources/model/td/data/MTDOpModeData.cpp \ + \ # ---------- Models - TD - Data - Treatment Log + sources/model/td/data/treatmentlog/MTreatmentLogAlarmData.cpp \ + sources/model/td/data/treatmentlog/MTreatmentLogEventData.cpp \ \ # ---------- Models - TD - Adjustment - In-Treatment sources/model/td/adjustment/treatment/MTreatmentAdjustUltrafiltrationStateResponse.cpp \ sources/model/td/adjustment/treatment/MTreatmentAdjustUltrafiltrationEditResponse.cpp \ @@ -636,9 +642,7 @@ sources/model/hd/data/pretreatment/MPreTreatmentSelfTestNoCartridgeData.cpp \ sources/model/hd/data/pretreatment/MPreTreatmentSelfTestDryData.cpp \ \ # ---------- Models - HD - Data - Treatment Log - sources/model/hd/data/treatmentlog/MTreatmentLogAlarmData.cpp \ sources/model/hd/data/treatmentlog/MTreatmentLogAvrgeData.cpp \ - sources/model/hd/data/treatmentlog/MTreatmentLogEventData.cpp \ \ # ---------- Models - DG - Adjustment \ # ---------- Models - DG - Adjustment - Settings sources/model/dg/adjustment/settings/MAdjustDGDateTimeResponse.cpp \ @@ -786,6 +790,7 @@ sources/view/td/data/treatment/VTreatmentPressureOcclusion.cpp \ sources/view/td/data/treatment/VTreatmentSalineData.cpp \ sources/view/td/data/treatment/VTreatmentTime.cpp \ + sources/view/td/data/treatment/VTreatmentTrends.cpp \ sources/view/td/data/treatment/VTreatmentUltrafiltrationData.cpp RESOURCES += \ Index: leahi.qrc =================================================================== diff -u -rf2aa3ee850de1023cfc011b845ed0364d251b749 -r1aec139f8de0f0ccc5c6a3c4c3d2c479e054b0f9 --- leahi.qrc (.../leahi.qrc) (revision f2aa3ee850de1023cfc011b845ed0364d251b749) +++ leahi.qrc (.../leahi.qrc) (revision 1aec139f8de0f0ccc5c6a3c4c3d2c479e054b0f9) @@ -151,6 +151,7 @@ sources/gui/qml/components/Footer.qml sources/gui/qml/components/TextEntry.qml sources/gui/qml/components/ScrollBar.qml + sources/gui/qml/components/ScrollBar2.qml sources/gui/qml/components/FooterStatic.qml sources/gui/qml/components/TimeEntry.qml sources/gui/qml/components/Label.qml @@ -252,6 +253,7 @@ sources/gui/qml/pages/treatment/TreatmentBloodPrime.qml sources/gui/qml/pages/treatment/TreatmentSection.qml sources/gui/qml/pages/treatment/TreatmentSectionHeader.qml + sources/gui/qml/pages/treatment/TreatmentTrends.qml sources/gui/qml/pages/treatment/sections/TreatmentFlows.qml Index: sources/gui/GuiGlobals.h =================================================================== diff -u -rcb9c48c7c307690dcafcfd16ef412fe660291692 -r1aec139f8de0f0ccc5c6a3c4c3d2c479e054b0f9 --- sources/gui/GuiGlobals.h (.../GuiGlobals.h) (revision cb9c48c7c307690dcafcfd16ef412fe660291692) +++ sources/gui/GuiGlobals.h (.../GuiGlobals.h) (revision 1aec139f8de0f0ccc5c6a3c4c3d2c479e054b0f9) @@ -293,8 +293,8 @@ ID_AdjustTreatmentLogRsp = 0x7600, // 118 // Treatment Log Data ID_TreatmentLogAvrgeData = 0x940F, // 148 //// ----- @CRAPIZED: had to change to avoid duplication - ID_TreatmentLogAlarmData = 0x950F, // 149 //// ----- @CRAPIZED: had to change to avoid duplication - ID_TreatmentLogEventData = 0x960F, // 150 //// ----- @CRAPIZED: had to change to avoid duplication + ID_TreatmentLogAlarmData = 0x6A00, // 106 //// ----- @LEAHIZED + ID_TreatmentLogEventData = 0x6B00, // 107 //// ----- @LEAHIZED // Disinfect ID_AdjustDisinfectModeReq = 0x9A00, // 154 Index: sources/gui/qml/components/ScrollBar2.qml =================================================================== diff -u --- sources/gui/qml/components/ScrollBar2.qml (revision 0) +++ sources/gui/qml/components/ScrollBar2.qml (revision 1aec139f8de0f0ccc5c6a3c4c3d2c479e054b0f9) @@ -0,0 +1,71 @@ +/*! + * + * Copyright (c) 2021-2024 Diality Inc. - All Rights Reserved. + * \copyright + * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN + * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. + * + * \file ScrollBar2.qml + * \author (last) Vy + * \date (last) 04-Apr-2023 + * \author (original) Behrouz NematiPour + * \date (original) 06-May-2021 + * + */ + +// Qt +import QtQuick 2.12 + + +// Project +// Qml imports +import "qrc:/globals" +import "qrc:/components" + +/*! + * \brief the ScrollBar Component + */ + +Rectangle { id: _root + enum Direction { Vertical, Horizontal } + + property int direction : ScrollBar2.Vertical + property Flickable flickable: undefined + property alias scrollColor : _scrollbar.color + property alias backColor : _root.color + property real scrollMargin : 0 + property alias handleWidth : _scrollbar.width + + width : Variables.dialogRadius + height : Variables.dialogRadius + radius : direction === ScrollBar2.Horizontal ? height : width + clip : true + color : "transparent" + + Rectangle { id: _scrollbar + readonly property real xPos: (flickable instanceof Flickable) ? flickable.visibleArea.xPosition * parent.width : 0 + readonly property real yPos: (flickable instanceof Flickable) ? flickable.visibleArea.yPosition * parent.height : 0 + readonly property int barWidth: (flickable instanceof Flickable) ? parent.width * flickable.visibleArea.widthRatio : 0 + readonly property int barHeight: (flickable instanceof Flickable) ? parent.height * flickable.visibleArea.heightRatio : 0 + readonly property int minSize: parent.radius * 2 + readonly property int deltaWidth: direction === ScrollBar2.Horizontal + ? xPos < 0 ? Math.abs(xPos) : Math.max(0, xPos - (parent.width - barWidth)) + : 0 + readonly property int deltaHeight: direction === ScrollBar2.Vertical + ? yPos < 0 ? Math.abs(yPos) : Math.max(0, yPos - (parent.height - barHeight)) + : 0 + + anchors { + bottom : direction === ScrollBar2.Horizontal ? parent.bottom : undefined + bottomMargin : direction === ScrollBar2.Horizontal ? parent.scrollMargin : 0 + right : direction === ScrollBar2.Horizontal ? undefined : parent.right + rightMargin : direction === ScrollBar2.Horizontal ? 0 : parent.scrollMargin + } + x : direction === ScrollBar2.Horizontal ? Math.min(Math.max(0, xPos), parent.width - minSize) : 0 + y : direction === ScrollBar2.Horizontal ? 0 : Math.min(Math.max(0, yPos), parent.height - minSize) + width : direction === ScrollBar2.Horizontal ? Math.max(minSize, barWidth - deltaWidth) : parent.width + height : direction === ScrollBar2.Horizontal ? parent.height : Math.max(minSize, barHeight - deltaHeight) + radius : parent.radius + color : Colors.scrollBarBgColor + } +} Index: sources/gui/qml/globals/Colors.qml =================================================================== diff -u -rcb9c48c7c307690dcafcfd16ef412fe660291692 -r1aec139f8de0f0ccc5c6a3c4c3d2c479e054b0f9 --- sources/gui/qml/globals/Colors.qml (.../Colors.qml) (revision cb9c48c7c307690dcafcfd16ef412fe660291692) +++ sources/gui/qml/globals/Colors.qml (.../Colors.qml) (revision 1aec139f8de0f0ccc5c6a3c4c3d2c479e054b0f9) @@ -92,6 +92,8 @@ readonly property color panelBackgroundColor : "#12FFFFFF" readonly property color panelBorderColor : "#4DB5B5B5" readonly property color panelInvalidBorderColor : "#FFA500" + readonly property color panelBackground : "#2A3F53" + readonly property color panelBorder : "#324C65" readonly property color touchTextAreaTitle : "#a0b6d0" Index: sources/gui/qml/globals/Variables.qml =================================================================== diff -u -r8672e62f205231b08dd7d4a4f6f7f3a60b2c677b -r1aec139f8de0f0ccc5c6a3c4c3d2c479e054b0f9 --- sources/gui/qml/globals/Variables.qml (.../Variables.qml) (revision 8672e62f205231b08dd7d4a4f6f7f3a60b2c677b) +++ sources/gui/qml/globals/Variables.qml (.../Variables.qml) (revision 1aec139f8de0f0ccc5c6a3c4c3d2c479e054b0f9) @@ -292,6 +292,8 @@ readonly property string unitTextDispensingRate : qsTr("mL/hr") readonly property string unitTextRate : qsTr("L/h") readonly property string unitTextDialCond : qsTr("mS/cm") + // - Pressures + readonly property string unitPressure : qsTr("mmHg") // - Vitals readonly property string unitTextBloodPressure : qsTr("mmHg") readonly property string unitTextHeartBeat : qsTr("BPM" ) Index: sources/gui/qml/main.qml =================================================================== diff -u -rb12853c86ef9e517667516dc3e47bca07349cedf -r1aec139f8de0f0ccc5c6a3c4c3d2c479e054b0f9 --- sources/gui/qml/main.qml (.../main.qml) (revision b12853c86ef9e517667516dc3e47bca07349cedf) +++ sources/gui/qml/main.qml (.../main.qml) (revision 1aec139f8de0f0ccc5c6a3c4c3d2c479e054b0f9) @@ -75,6 +75,7 @@ import VTreatmentBloodPrime 0.1 import VTreatmentStop 0.1 import VTreatmentRanges 0.1 +import VTreatmentTrends 0.1 // Pre-Treatment import VPreTreatmentAdjustmentInitTreatment 0.1 import VDGFilterFlush 0.1 @@ -272,6 +273,7 @@ VTreatmentCreate { id: vTreatmentCreate } VTreatmentRanges { id: vTreatmentRanges } + VTreatmentTrends { id: vTreatmentTrends } VTreatmentAdjustmentSaline { id: vTreatmentAdjustmentSaline } VTreatmentAdjustmentVitals { id: vTreatmentAdjustmentVitals } VTreatmentAdjustmentUltrafiltrationState { id: vTreatmentAdjustmentUltrafiltrationState } Index: sources/gui/qml/pages/treatment/TreatmentStack.qml =================================================================== diff -u -r975e1964b60365b24c74be139c6b84369a7248ce -r1aec139f8de0f0ccc5c6a3c4c3d2c479e054b0f9 --- sources/gui/qml/pages/treatment/TreatmentStack.qml (.../TreatmentStack.qml) (revision 975e1964b60365b24c74be139c6b84369a7248ce) +++ sources/gui/qml/pages/treatment/TreatmentStack.qml (.../TreatmentStack.qml) (revision 1aec139f8de0f0ccc5c6a3c4c3d2c479e054b0f9) @@ -82,7 +82,7 @@ } } - ScreenItem { id: _treatmentTrends } // TODO: make me! + TreatmentTrends { id: _treatmentTrends } ScreenItem { id: _treatmentHeparin } // TODO: make me! //// Treatment Adjustment Dialogs Index: sources/gui/qml/pages/treatment/TreatmentTrends.qml =================================================================== diff -u --- sources/gui/qml/pages/treatment/TreatmentTrends.qml (revision 0) +++ sources/gui/qml/pages/treatment/TreatmentTrends.qml (revision 1aec139f8de0f0ccc5c6a3c4c3d2c479e054b0f9) @@ -0,0 +1,705 @@ +/*! + * + * Copyright (c) 2021-2025 Diality Inc. - All Rights Reserved. + * \copyright + * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN + * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. + * + * \file TreatmentTrends.qml + * \author (last) Stephen Quong + * \date (last) 01-Oct-2025 + * \author (original) Stephen Quong + * \date (original) 01-Oct-2025 + * + */ + +// Qt +import QtQuick 2.12 +import QtGraphicalEffects 1.12 + +// Project +// Qml imports +import "qrc:/globals" +import "qrc:/components" +import "qrc:/pages/treatment/sections" + +/*! + * \brief the in-treatment Blood Prime screen + */ +ScreenItem { id: _root + objectName: "_TreatmentTrends" + + onVisibleChanged: { + _paramArea.isExpanded = false + _paramList.positionViewAtBeginning() + _historyList.positionViewAtBeginning() + } + + QtObject { id: _private + objectName : "_private" + readonly property int cellHeight : 72 + readonly property int topHeaderHeight : 80 + readonly property int labelWidth : 300 + readonly property int scrollButtonWidth : 40 + readonly property int paramAreaRightMargin : 5 + // readonly property int paramWidth: 211 + readonly property int paramWidth : + (_root.width - Variables.defaultMargin - labelWidth - scrollButtonWidth - paramAreaRightMargin - _expandButton.width) / 7 + } + + component ScrollButton: TouchRect { id: _scrollButton + objectName : "_scrollButton" + property alias iconSource : _iconImage.source + anchors.verticalCenter : parent.verticalCenter + width : _private.scrollButtonWidth + height : _private.scrollButtonWidth + border.color : Colors.transparent + backgroundColor : Colors.transparent + + Image { id: _iconImage + objectName : "_iconImage" + anchors.centerIn : parent + height : 35 + width : 35 + fillMode : Image.PreserveAspectFit + source : "qrc:/images/iArrowLeft" + } + } + + component Header: Rectangle { id: _header + objectName : "_header" + property alias label : _labelText.text + property alias labelFontWeight : _labelText.font.weight + height : _private.topHeaderHeight + radius : 10 + color : Colors.treatmentSectionHeader + layer { + enabled: true + effect: DropShadow { id: _topHeaderShadow + objectName : "_topHeaderShadow" + horizontalOffset: 2 + verticalOffset : 2 + radius : 12 + samples : 32 + color : "#50000000" + source : _header + } + } + + Text { id: _labelText + objectName : "_labelText" + anchors { + left : parent.left + leftMargin : Variables.defaultMargin + verticalCenter : parent.verticalCenter + } + width : _private.labelWidth + height : contentHeight + color : Colors.offWhite + font { + pixelSize : 22 + weight : Font.Medium + } + horizontalAlignment : Text.AlignLeft + } + } + + component ParameterLabel: Item { id: _labelItem + objectName : "_labelItem" + property alias label : _labelText.text + property alias labelFontWeight : _labelText.font.weight + property string unit : "" + property string subLabel : "" + property bool showDivider : true + anchors.left : parent.left + width : _private.labelWidth + height : _private.cellHeight + + Item { id: _labelArea + objectName : "_labelArea" + anchors { + left : parent.left + right : parent.right + verticalCenter : parent.verticalCenter + } + height : childrenRect.height + + Text { id: _labelText + objectName : "_labelText" + anchors.left : parent.left + width : contentWidth + height : contentHeight + color : Colors.offWhite + font { + pixelSize : 20 + weight : Font.Medium + } + horizontalAlignment : Text.AlignLeft + } + Text { id: _unitText + objectName : "_unitText" + anchors { + left : _labelText.right + baseline: _labelText.baseline + } + font { + pixelSize : 18 + weight : Font.Thin + } + width : text.length === 0 ? 0 : contentWidth + height : text.length === 0 ? 0 : contentHeight + color : Colors.textProgressBar + horizontalAlignment : Text.AlignLeft + text : (_labelItem.unit.length !== 0) ? " (%1)".arg(_labelItem.unit) : "" + } + Text { id: _subLabelText + objectName : "_subLabelText" + anchors { + top : _labelText.bottom + left : _labelText.left + } + font { + pixelSize : 18 + weight : Font.Thin + italic : true + } + width : text.length === 0 ? 0 : contentWidth + height : text.length === 0 ? 0 : contentHeight + color : Colors.textProgressBar + horizontalAlignment : Text.AlignLeft + text : (_labelItem.subLabel.length !== 0) ? "(%1)".arg(_labelItem.subLabel) : "" + } + } + + Rectangle { id: _horizontalDivider + objectName : "_horizontalDivider" + anchors { + bottom : parent.bottom + left : parent.left + right : parent.right + } + height : 1 + color : Colors.panelBorder + visible : _labelItem.showDivider + } + } + + component ValueText: Item { id: _valueItem + objectName : "_valueItem" + property alias value : _valueText.text + property alias valueFontWeight : _valueText.font.weight + property alias valueText : _valueText + property bool showDivider : true + width : _private.paramWidth + height : _private.cellHeight + enabled : true + + Text { id: _valueText + objectName : "_valueText" + anchors.centerIn : parent + width : contentWidth + height : contentHeight + color : Colors.offWhite + font { + pixelSize : 24 + weight : Font.DemiBold + } + horizontalAlignment : Text.AlignHCenter + verticalAlignment : Text.AlignVCenter + } + + Rectangle { id: _horizontalDivider + objectName : "_horizontalDivider" + anchors { + bottom : parent.bottom + left : parent.left + right : parent.right + } + height : 1 + color : Colors.panelBorder + visible : _valueItem.showDivider + } + } + + component LabelTime: Item { id: _labelTime + objectName: "_labelTime" + property string labelText: "" + property string timeText: "" + width: childrenRect.width + + Text { id: _label + objectName: "_label" + anchors{ + left : parent.left + verticalCenter : parent.verticalCenter + } + width : contentWidth + color : Colors.textProgressBar + font.pixelSize : 16 + text: _labelTime.labelText + } + + Text { id: _timeText + objectName: "_timeText" + anchors{ + left : _label.right + baseline : _label.baseline + } + width : Math.max(50, contentWidth) + color : Colors.offWhite + font { + pixelSize : 18 + weight : Font.DemiBold + } + text: _labelTime.timeText + } + } + + Item { id: _contentArea + objectName : "_contentArea" + anchors { + fill : parent + margins : Variables.defaultMargin + } + + Rectangle { id: _paramArea + objectName : "_paramArea" + property bool isExpanded: false + anchors { + top : parent.top + bottom : parent.bottom + left : parent.left + } + z : parent.z + 2 + width : _private.labelWidth + (_private.paramWidth * _paramList.visibleParamCount) + + _private.scrollButtonWidth + (Variables.defaultMargin * 2) + color : Colors.treatmentSectionMain + radius : 10 + + Behavior on width { NumberAnimation { duration: 200 } } + + Rectangle { id: _paramListBackground + objectName: "_paramListBackground" + anchors { + top : parent.top + bottom : _paramSideHeader.bottom + left : _paramSideHeader.right + right : parent.right + } + color : Colors.panelBackground + radius : parent.radius + + Rectangle { id: _radiusCover + objectName: "_radiusCover" + anchors { + bottom : parent.bottom + left : parent.left + } + color : parent.color + width : parent.radius + 1 + height : width + } + + Rectangle { id: _verticalDivider + objectName: "_verticalDivider" + anchors { + top : parent.top + bottom : parent.bottom + left : parent.left + } + width: 1 + color: Colors.panelBorder + } + } + + Header { id: _paramTopHeader + objectName: "_paramTopHeader" + anchors { + top : parent.top + left : parent.left + right : parent.right + } + label : qsTr("Parameters") + labelFontWeight : Font.DemiBold + } + + Column { id: _paramSideHeader + objectName: "_paramSideHeader" + anchors { + top : _paramTopHeader.bottom + bottom : parent.bottom + left : parent.left + leftMargin : Variables.defaultMargin + } + width: _private.labelWidth + ParameterLabel { label: qsTr("Blood Pressure"); unit: Variables.unitPressure } + ParameterLabel { label: qsTr("Heart Rate"); unit: Variables.unitTextHeartBeat } + ParameterLabel { label: qsTr("UF Volume"); unit: Variables.unitVolume; subLabel: qsTr("Cumulative Removed") } + ParameterLabel { label: qsTr("UF Rate"); unit: Variables.unitTextRate } + ParameterLabel { label: qsTr("Arterial Pressure"); unit: Variables.unitPressure } + ParameterLabel { label: qsTr("Venous Pressure"); unit: Variables.unitPressure } + ParameterLabel { label: qsTr("TMP"); unit: Variables.unitPressure } + ParameterLabel { label: qsTr("Fluid Delivered"); unit: Variables.unitTextFluid; subLabel: qsTr("Cumulative") } + ParameterLabel { label: qsTr("Blood Flow Rate"); unit: Variables.unitTextFlowRate } + ParameterLabel { label: qsTr("Dialysate Flow Rate"); unit: Variables.unitTextFlowRate } + ParameterLabel { label: qsTr("Temperature"); unit: Variables.unitTextTemperature } + ParameterLabel { + label : qsTr("Conductivity") + unit : Variables.unitTextDialCond + showDivider : false + } + } + + Item { id: _paramListArea + objectName: "_paramListArea" + anchors { + top : parent.top + bottom : parent.bottom + left : _paramSideHeader.right + right : _rightScrollButton.left + } + clip: true + + Behavior on width { NumberAnimation { duration: 200 } } + + ListView { id: _paramList + objectName: "_paramList" + readonly property int visibleParamCount: _paramArea.isExpanded ? 7 : 5 + + anchors { + fill : parent + rightMargin : (Math.max(0, visibleParamCount - model.count) * _private.paramWidth) + } + orientation : ListView.Horizontal + layoutDirection : Qt.RightToLeft + snapMode : ListView.SnapToItem + model : vTreatmentTrends.data + displayMarginBeginning : visibleParamCount * _private.paramWidth + preferredHighlightBegin : 0 + preferredHighlightEnd : _private.paramWidth + highlightRangeMode : ListView.ApplyRange + highlightFollowsCurrentItem : true + addDisplaced : Transition { NumberAnimation { properties: "x"; duration: 200 } } + delegate: Column { id: _paramListDelegate + ValueText { id: _timestampValue + objectName : "_timestampValue" + height : _private.topHeaderHeight + value : Qt.formatTime(timestamp, "hh:mm:ss") + valueFontWeight : Font.Bold + showDivider : false + + Text { id: _lastTimeText + objectName: "_lastTimeText" + anchors { + top : parent.top + topMargin : 10 + horizontalCenter: parent.horizontalCenter + } + font.pixelSize : 14 + color : Colors.ufVolumeGoalText + height : contentHeight + text : qsTr("Last Time") + visible : model.index === 0 + } + } + ValueText { id: _bloodpressureValue + objectName : "_bloodpressureValue" + value : "%1/%2".arg(systolic ?? "--").arg(diastolic ?? "--") + } + ValueText { id: _pulseRateValue + objectName : "_pulseRateValue" + value : pulseRate ?? "--" + } + ValueText { id: _ufVolumeRemovedValue + objectName : "_ufVolumeRemovedValue" + value : ufVolumeRemoved.toFixed(Variables.ultrafiltrationPrecision) ?? "--" + } + ValueText { id: _ufRateValue + objectName : "_ufRateValue" + value : ufRate.toFixed(Variables.ultrafiltrationPrecision) ?? "--" + } + ValueText { id: _arterialPressureValue + objectName : "_arterialPressureValue" + value : arterialPressure ?? "--" + } + ValueText { id: _venousPressureValue + objectName : "_venousPressureValue" + value : venousPressure ?? "--" + } + ValueText { id: _tmpValue + objectName : "_tmpValue" + value : tmp ?? "--" + } + ValueText { id: _bolusCumulativeDeliveredValue + objectName : "_bolusCumulativeDeliveredValue" + value : bolusCumulativeDelivered ?? "--" + } + ValueText { id: _bloodFlowRateValue + objectName : "_bloodFlowRateValue" + value : bloodFlowRate.toFixed(Variables.bloodFlowPrecision) ?? "--" + } + ValueText { id: _dialysateFlowRateValue + objectName : "_dialysateFlowRateValue" + value : dialysateFlowRate.toFixed(Variables.dialysateFlowPrecision) ?? "--" + } + ValueText { id: _dialysateTemperatureValue + objectName : "_dialysateTemperatureValue" + value : dialysateTemperature.toFixed(Variables.dialysateTempPrecision) ?? "--" + } + ValueText { id: _conductivityValue + objectName : "_conductivityValue" + value : conductivity.toFixed(Variables.dialysateCondPrecision) ?? "--" + showDivider : false + } + } + + Behavior on contentX { NumberAnimation { duration: 200 } } + } + } + + ScrollBar2 { id: _scrollbar + objectName: "_scrollbar" + anchors { + bottom : parent.bottom + bottomMargin : 10 + left : _paramListArea.left + leftMargin : Variables.defaultMargin + right : parent.right + rightMargin : Variables.defaultMargin + } + height : 5 + direction : ScrollBar2.Horizontal + scrollColor : "#606060" + flickable : _paramList + opacity : _paramList.model.count > _paramList.visibleParamCount + || _paramList.flicking || _paramList.dragging ? 1 : 0 + + Behavior on opacity { NumberAnimation { duration: 200 } } + } + + ScrollButton { id: _leftScrollButton + objectName: "_leftScrollButton" + anchors { + right : _paramListArea.left + verticalCenter : _paramTopHeader.verticalCenter + } + touchable : _paramList.atXBeginning === false + iconSource : touchable ? "qrc:/images/iArrowLeft" : "qrc:/images/iArrowLeftDisabled" + + onClicked: { + if (_paramList.atXBeginning === false) { + _paramList.contentX = Math.max(-(_paramList.contentWidth), _paramList.contentX - _private.paramWidth) + } + } + } + + ScrollButton { id: _rightScrollButton + objectName: "_rightScrollButton" + anchors { + right : parent.right + rightMargin : _private.paramAreaRightMargin // Variables.defaultMargin + verticalCenter : _paramTopHeader.verticalCenter + } + touchable : _paramList.atXEnd === false + iconSource : touchable ? "qrc:/images/iArrowRight" : "qrc:/images/iArrowRightDisabled" + + onClicked: { + if (_paramList.atXEnd === false) { + _paramList.contentX = Math.min(-(_paramList.visibleParamCount * _private.paramWidth), _paramList.contentX + _private.paramWidth) + } + } + } + } + + TouchRect { id: _expandButton + objectName: "_expandButton" + anchors { + left : _paramArea.right + leftMargin : -(width / 2) + verticalCenter : _paramArea.verticalCenter + } + z : _paramArea.z - 1 + width : 80 + height : width + radius : height + border.color : Colors.transparent + backgroundColor : Colors.backgroundButtonSelect + + onPressed: { + _paramArea.isExpanded = ! _paramArea.isExpanded + } + + Image { id: _iconImage + objectName: "_iconImage" + anchors { + horizontalCenter : parent.horizontalCenter + horizontalCenterOffset : (parent.width/4) - (width/8) + verticalCenter : parent.verticalCenter + } + height : 35 + width : 35 + fillMode: Image.PreserveAspectFit + source : _paramArea.isExpanded ? "qrc:/images/iChevronLeft" : "qrc:/images/iChevronRight" + } + } + + Rectangle { id: _historyArea + objectName: "_historyArea" + anchors { + top : _paramArea.top + bottom : _paramArea.bottom + left : _expandButton.right + leftMargin : Variables.defaultMargin + } + width : _private.paramWidth * 2 - Variables.defaultMargin + radius : _paramListBackground.radius + color : _paramListBackground.color + opacity : _paramArea.isExpanded ? 0 : 1 + + Behavior on opacity { NumberAnimation { duration: 200 } } + + Header { id: _historyHeader + objectName: "_historyHeader" + anchors { + top : parent.top + left : parent.left + right : parent.right + } + label : qsTr("Treatment History") + labelFontWeight : Font.DemiBold + } + + Rectangle { id: _timeArea + objectName: "_timeArea" + anchors { + top : _historyHeader.bottom + topMargin : Variables.defaultMargin + left : parent.left + leftMargin : 10 + right : parent.right + rightMargin : anchors.leftMargin + } + height : 60 + color : Colors.panelBackgroundColor + border { + width: 1 + color: Colors.panelBorderColor + } + radius : 8.5 + + Item { id: _timeContainer + anchors { + top: parent.top + bottom: parent.bottom + horizontalCenter: parent.horizontalCenter + } + width: childrenRect.width + + LabelTime { id: _startTime + objectName: "_startTime" + anchors.left: parent.left + height: parent.height + labelText: qsTr("Start Time: ") + timeText: Qt.formatDateTime(vTreatmentTrends.time_Start, "hh:mm") + } + + LabelTime { id: _elapsedTime + objectName: "_elapsedTime" + readonly property int hours: vTreatmentTrends.time_Elapsed / 3600 + readonly property int mins: (vTreatmentTrends.time_Elapsed % 3600) / 60 + anchors { + left: _startTime.right + leftMargin: Variables.defaultMargin + } + height: parent.height + labelText: qsTr("Time Elapsed (hrs): ") + timeText: "%1:%2".arg(hours < 10 ? "0" + hours : hours).arg(mins < 10 ? "0" + mins : mins) + } + } + } + + ListView { id: _historyList + objectName: "_historyList" + anchors { + top : _timeArea.bottom + topMargin : 10 + bottom : parent.bottom + bottomMargin: Variables.defaultMargin + left : _timeArea.left + right : _timeArea.right + } + model: vTreatmentTrends.history + clip: true + addDisplaced: Transition { NumberAnimation { properties: "y"; duration: 200 } } + delegate: Item { id: _historyItem + objectName: "_historyItem" + width: _historyList.width + height: 50 + + Text { id: _time + objectName: "_time" + anchors { + top: parent.top + bottom: parent.bottom + } + width: 50 + font.pixelSize: 20 + font.weight: Font.Medium + color: _historyText.color + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + text: Qt.formatDateTime(timestamp, "hh:mm") + } + + Rectangle { id: _historyDivider + objectName: "_historyDivider" + anchors { + top: parent.top + bottom: parent.bottom + left: _time.right + leftMargin: 10 + } + width: 1 + color: Colors.panelBorder + } + + Text { id: _historyText + objectName: "_historyText" + anchors { + top: parent.top + bottom: parent.bottom + left: _historyDivider.right + leftMargin: 10 + right: parent.right + rightMargin: 5 + } + font.pixelSize: 18 + color: Colors.offWhite + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + text: entryID ? "%1 (%2: %3)".arg(message).arg(qsTr("ID")).arg(entryID) : message + } + } + } + + ScrollBar2 { id: _historyScrollbar + objectName: "_historyScrollbar" + anchors { + top : _historyList.top + bottom : _historyList.bottom + right : parent.right + rightMargin : 5 + } + width : 5 + scrollColor : "#606060" + direction : ScrollBar2.Vertical + flickable : _historyList + opacity : _historyList.contentHeight > _historyList.height + || _historyList.flicking || _historyList.dragging ? 1 : 0 + + Behavior on opacity { NumberAnimation { duration: 200 } } + } + } + } +} Index: sources/model/MListModel.cpp =================================================================== diff -u -r53f7433638ec721d4f687fe8a4ed5d98c03c2fe7 -r1aec139f8de0f0ccc5c6a3c4c3d2c479e054b0f9 --- sources/model/MListModel.cpp (.../MListModel.cpp) (revision 53f7433638ec721d4f687fe8a4ed5d98c03c2fe7) +++ sources/model/MListModel.cpp (.../MListModel.cpp) (revision 1aec139f8de0f0ccc5c6a3c4c3d2c479e054b0f9) @@ -1,6 +1,32 @@ #include "MListModel.h" /*! + * \brief Constructor + * \param[in] parent - Parent of this object. + */ +View::MListModel::MListModel(QObject *parent) + : QAbstractListModel(parent) +{ + connect(this, &MListModel::rowsInserted, this, &MListModel::countChanged); + connect(this, &MListModel::rowsRemoved, this, &MListModel::countChanged); +} + +/*! + * \brief Inserts data into the model at a given position. + * \param[in] pos - The position where the data will be inserted. + * If row is less than 0, then data will be prepended to the model. + * If row is greater than or equal to rowCount(), then data will be appeneded to the model. + * \param[in] data - The data to insert into the model. + */ +void View::MListModel::insertRow(const int pos, const QHash &vData) +{ + const int index = std::clamp(pos, 0, rowCount()); + beginInsertRows(QModelIndex(), index, index); + _data.insert(index, vData); + endInsertRows(); +} + +/*! * \brief Retrieve the role names set for this list model. * \return Role names used for this model. */ Index: sources/model/MListModel.h =================================================================== diff -u -r8c7b9550b05f223be9d094e850e06f9ed80adb70 -r1aec139f8de0f0ccc5c6a3c4c3d2c479e054b0f9 --- sources/model/MListModel.h (.../MListModel.h) (revision 8c7b9550b05f223be9d094e850e06f9ed80adb70) +++ sources/model/MListModel.h (.../MListModel.h) (revision 1aec139f8de0f0ccc5c6a3c4c3d2c479e054b0f9) @@ -17,9 +17,12 @@ { Q_OBJECT + Q_PROPERTY(int count READ rowCount NOTIFY countChanged STORED false) + public: - explicit MListModel(QObject *parent = nullptr) : QAbstractListModel (parent) { } + explicit MListModel(QObject *parent = nullptr); + void insertRow (const int pos, const QHash &vData ); QHash roleNames ( ) const override; int rowCount (const QModelIndex & = QModelIndex() ) const override; QVariant data (const QModelIndex &vIndex, int vRole = Qt::DisplayRole ) const override; @@ -28,9 +31,12 @@ void setRoleNames(const QHash& vRoleNames ); MListModel &operator = (const QList> &src ); -public slots: +public Q_SLOTS: QVariantMap get (int vRow ) const; // Exposed to QML +Q_SIGNALS: + void countChanged(); + private: QList> _data; QHash _roleNames; Fisheye: Tag 1aec139f8de0f0ccc5c6a3c4c3d2c479e054b0f9 refers to a dead (removed) revision in file `sources/model/hd/data/treatmentlog/MTreatmentLogAlarmData.cpp'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1aec139f8de0f0ccc5c6a3c4c3d2c479e054b0f9 refers to a dead (removed) revision in file `sources/model/hd/data/treatmentlog/MTreatmentLogAlarmData.h'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1aec139f8de0f0ccc5c6a3c4c3d2c479e054b0f9 refers to a dead (removed) revision in file `sources/model/hd/data/treatmentlog/MTreatmentLogEventData.cpp'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1aec139f8de0f0ccc5c6a3c4c3d2c479e054b0f9 refers to a dead (removed) revision in file `sources/model/hd/data/treatmentlog/MTreatmentLogEventData.h'. Fisheye: No comparison available. Pass `N' to diff? Index: sources/model/td/data/treatmentlog/MTreatmentLogAlarmData.cpp =================================================================== diff -u --- sources/model/td/data/treatmentlog/MTreatmentLogAlarmData.cpp (revision 0) +++ sources/model/td/data/treatmentlog/MTreatmentLogAlarmData.cpp (revision 1aec139f8de0f0ccc5c6a3c4c3d2c479e054b0f9) @@ -0,0 +1,56 @@ +/*! + * + * Copyright (c) 2021-2024 Diality Inc. - All Rights Reserved. + * \copyright + * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN + * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. + * + * \file MTreatmentLogAlarmData.cpp + * \author (last) Behrouz NematiPour + * \date (last) 19-May-2021 + * \author (original) Behrouz NematiPour + * \date (original) 15-May-2021 + * + */ +#include "MTreatmentLogAlarmData.h" + +// Qt +#include + +using namespace Model; + +QVariantList MTreatmentLogAlarmData::parameters() const { + return { + _data.mAlarmID .value, + _data.mParam1 .value, + _data.mParam2 .value, + }; +} + +bool MTreatmentLogAlarmData::fromByteArray(const QByteArray &vByteArray, int *vIndex) { + int index = 0; // message data start position + if ( ! GetValue(vByteArray, index, _data.mAlarmID )) goto lError; + if ( ! GetValue(vByteArray, index, _data.mParam1 )) goto lError; + if ( ! GetValue(vByteArray, index, _data.mParam2 )) goto lError; + + return true ; + +lError: + if(vIndex) { *vIndex = index; } + + return false ; +} + +/*! + * \brief MTreatmentLogAlarmData::data + * \details Provides model's Data from the received messages data values + * \return Data + */ +TreatmentLogAlarmData MTreatmentLogAlarmData::data() const { + Data data; + data.mTimeStamp = QDateTime::currentDateTime().toSecsSinceEpoch(); + data.mAlarmID = _data.mAlarmID .value; + data.mParam1 = _data.mParam1 .value; + data.mParam2 = _data.mParam2 .value; + return data; +} Index: sources/model/td/data/treatmentlog/MTreatmentLogAlarmData.h =================================================================== diff -u --- sources/model/td/data/treatmentlog/MTreatmentLogAlarmData.h (revision 0) +++ sources/model/td/data/treatmentlog/MTreatmentLogAlarmData.h (revision 1aec139f8de0f0ccc5c6a3c4c3d2c479e054b0f9) @@ -0,0 +1,88 @@ +/*! + * + * Copyright (c) 2021-2024 Diality Inc. - All Rights Reserved. + * \copyright + * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN + * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. + * + * \file MTreatmentLogAlarmData.h + * \author (last) Behrouz NematiPour + * \date (last) 22-Mar-2023 + * \author (original) Behrouz NematiPour + * \date (original) 15-May-2021 + * + */ +#pragma once + +// Qt +#include + +// Project +#include "MAbstract.h" +#include "types.h" + +// forward declarations +class tst_models; + +namespace Model { + +/*! + * \brief The MTreatmentLogAlarmData class + * \details The post treatment states data model + * These are states of the post treatment. + * + * | MSG | CAN ID | Type | Ack | Src | Dst | Description | + * |:----:|:------:|:------:|:---:|:---:|:---:|:-----------:| + * |0x6A00| 0x040 | Event | Y | HD | UI | Treatment Log Alarm Data | + * + * | Payload || + * | || + * | #1:(U32) | \ref Data::mAlarmID | + * | #2:(F32) | \ref Data::mParam1 | + * | #3:(F32) | \ref Data::mParam2 | + * + * \sa Data + * \sa HD_Post_Treatment_Mode_States + * + *

Logging info

+ * | || + * | || + * | typeText | Datum | + * | unitText | HD | + * | infoText | TreatmentLogAlarm | + * + */ +class MTreatmentLogAlarmData : public MAbstract { + + // friends + friend class ::tst_models; + + QVariantList parameters() const override; + + struct { + Types::U32 mAlarmID ; ///< Alarm ID + Types::F32 mParam1 ; ///< Alarm Parameter 1 // may need more than 1 parameter but defined one so it would be easier to add more later. + Types::F32 mParam2 ; ///< Alarm Parameter 2 // may need more than 1 parameter but defined one so it would be easier to add more later. + } _data; + +public: + + Type_Enum typeText () const override { return Type_Enum::eDatum ; } + Unit_Enum unitText () const override { return Unit_Enum::eTD ; } + QString infoText () const override { return QString("TreatmentLogAlarm") ; } + + struct Data { + quint64 mTimeStamp ; ///< Timestamp of the received message in secs since epoch + quint32 mAlarmID ; ///< Alarm ID + float mParam1 ; ///< Alarm Parameter 1 + float mParam2 ; ///< Alarm Parameter 2 + }; + + MTreatmentLogAlarmData() { } + + bool fromByteArray (const QByteArray &vByteArray , int *vIndex = nullptr) override; + Data data ( ) const ; +}; +} + +typedef Model::MTreatmentLogAlarmData::Data TreatmentLogAlarmData; Index: sources/model/td/data/treatmentlog/MTreatmentLogEventData.cpp =================================================================== diff -u --- sources/model/td/data/treatmentlog/MTreatmentLogEventData.cpp (revision 0) +++ sources/model/td/data/treatmentlog/MTreatmentLogEventData.cpp (revision 1aec139f8de0f0ccc5c6a3c4c3d2c479e054b0f9) @@ -0,0 +1,56 @@ +/*! + * + * Copyright (c) 2021-2024 Diality Inc. - All Rights Reserved. + * \copyright + * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN + * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. + * + * \file MTreatmentLogEventData.cpp + * \author (last) Behrouz NematiPour + * \date (last) 19-May-2021 + * \author (original) Behrouz NematiPour + * \date (original) 15-May-2021 + * + */ +#include "MTreatmentLogEventData.h" + +// Qt +#include + +using namespace Model; + +QVariantList MTreatmentLogEventData::parameters() const { + return { + _data.mEventID .value, + _data.mOldValue .value, + _data.mNewValue .value, + }; +} + +bool MTreatmentLogEventData::fromByteArray(const QByteArray &vByteArray, int *vIndex) { + int index = 0; // message data start position + if ( ! GetValue(vByteArray, index, _data.mEventID )) goto lError; + if ( ! GetValue(vByteArray, index, _data.mOldValue )) goto lError; + if ( ! GetValue(vByteArray, index, _data.mNewValue )) goto lError; + + return true ; + +lError: + if(vIndex) { *vIndex = index; } + + return false ; +} + +/*! + * \brief MTreatmentLogEventData::data + * \details Provides model's Data from the received messages data values + * \return Data + */ +TreatmentLogEventData MTreatmentLogEventData::data() const { + Data data; + data.mTimeStamp = QDateTime::currentDateTime().toSecsSinceEpoch(); + data.mEventID = _data.mEventID .value; + data.mOldValue = _data.mOldValue .value; + data.mNewValue = _data.mNewValue .value; + return data; +} Index: sources/model/td/data/treatmentlog/MTreatmentLogEventData.h =================================================================== diff -u --- sources/model/td/data/treatmentlog/MTreatmentLogEventData.h (revision 0) +++ sources/model/td/data/treatmentlog/MTreatmentLogEventData.h (revision 1aec139f8de0f0ccc5c6a3c4c3d2c479e054b0f9) @@ -0,0 +1,88 @@ +/*! + * + * Copyright (c) 2021-2024 Diality Inc. - All Rights Reserved. + * \copyright + * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN + * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. + * + * \file MTreatmentLogEventData.h + * \author (last) Behrouz NematiPour + * \date (last) 24-Mar-2023 + * \author (original) Behrouz NematiPour + * \date (original) 15-May-2021 + * + */ +#pragma once + +// Qt +#include + +// Project +#include "MAbstract.h" +#include "types.h" + +// forward declarations +class tst_models; + +namespace Model { + +/*! + * \brief The MTreatmentLogEventData class + * \details The post treatment states data model + * These are states of the post treatment. + * + * | MSG | CAN ID | Type | Ack | Src | Dst | Description | + * |:----:|:------:|:------:|:---:|:---:|:---:|:-----------:| + * |0x6B00| 0x040 | Event | Y | HD | UI | Treatment Log Event Data | + * + * | Payload || + * | || + * | #1:(U32) | \ref Data::mEventID | + * | #2:(F32) | \ref Data::mOldValue | + * | #3:(F32) | \ref Data::mNewValue | + * + * \sa Data + * \sa HD_Post_Treatment_Mode_States + * + *

Logging info

+ * | || + * | || + * | typeText | Datum | + * | unitText | HD | + * | infoText | TreatmentLogEvent | + * + */ +class MTreatmentLogEventData : public MAbstract { + + // friends + friend class ::tst_models; + + QVariantList parameters() const override; + + struct { + Types::U32 mEventID ; ///< Event ID + Types::F32 mOldValue ; ///< Event Old Value + Types::F32 mNewValue ; ///< Event New Value + } _data; + +public: + + Type_Enum typeText () const override { return Type_Enum::eDatum ; } + Unit_Enum unitText () const override { return Unit_Enum::eTD ; } + QString infoText () const override { return QString("TreatmentLogEvent") ; } + + struct Data { + quint64 mTimeStamp ; ///< Timestamp of the received message in secs since epoch + quint32 mEventID ; ///< Event ID + float mOldValue ; ///< Event Old Value + float mNewValue ; ///< Event New Value + }; + + MTreatmentLogEventData() { } + + bool fromByteArray (const QByteArray &vByteArray , int *vIndex = nullptr) override; + Data data ( ) const ; +}; +} + +typedef Model::MTreatmentLogEventData::Data TreatmentLogEventData; Index: sources/view/td/data/treatment/VTreatmentTrends.cpp =================================================================== diff -u --- sources/view/td/data/treatment/VTreatmentTrends.cpp (revision 0) +++ sources/view/td/data/treatment/VTreatmentTrends.cpp (revision 1aec139f8de0f0ccc5c6a3c4c3d2c479e054b0f9) @@ -0,0 +1,205 @@ +/*! + * + * Copyright (c) 2021-2025 Diality Inc. - All Rights Reserved. + * \copyright + * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN + * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. + * + * \file VTreatmentTrends.cpp + * \author (last) Stephen Quong + * \date (last) 01-Oct-2025 + * \author (original) Stephen Quong + * \date (original) 01-Oct-2025 + * + */ +#include "VTreatmentTrends.h" + +#include +#include + +// Project +#include "GuiController.h" + +using namespace View; + +static void qRegister() +{ + qmlRegisterType ("VTreatmentTrends", 0, 1, "VTreatmentTrends"); +} +Q_COREAPP_STARTUP_FUNCTION(qRegister) + +VTreatmentTrends::VTreatmentTrends(QObject *parent) : + QObject(parent), + _data(this), + _history(this) +{ + QQmlEngine::setObjectOwnership(&_data, QQmlEngine::CppOwnership); + _data.setRoleNames({ + { eDataRole_Timestamp, "timestamp" }, + { eDataRole_Systolic, "systolic" }, + { eDataRole_Diastolic, "diastolic" }, + { eDataRole_PulseRate, "pulseRate" }, + { eDataRole_UFVolumeRemoved, "ufVolumeRemoved" }, + { eDataRole_UFRate, "ufRate" }, + { eDataRole_ArterialPressure, "arterialPressure" }, + { eDataRole_VenousPressure, "venousPressure" }, + { eDataRole_TMP, "tmp" }, + { eDataRole_BolusCumulativeDelivered, "bolusCumulativeDelivered" }, + { eDataRole_BloodFlowRate, "bloodFlowRate" }, + { eDataRole_DialysateFlowRate, "dialysateFlowRate" }, + { eDataRole_DialysateTemperature, "dialysateTemperature" }, + { eDataRole_Conductivity, "conductivity" }, + }); + + QQmlEngine::setObjectOwnership(&_history, QQmlEngine::CppOwnership); + _history.setRoleNames({ + { eHistoryRole_Timestamp, "timestamp" }, + { eHistoryRole_EntryID, "entryID" }, + { eHistoryRole_Priority, "priority" }, + { eHistoryRole_Message, "message" }, + }); + + initConnections(); +} + +MListModel* VTreatmentTrends::data() +{ + return &_data; +} + +MListModel* VTreatmentTrends::history() +{ + return &_history; +} + +void VTreatmentTrends::initConnections() +{ + ACTION_VIEW_CONNECTION(DDConductivityData ) + ACTION_VIEW_CONNECTION(PressureOcclusionData ) + ACTION_VIEW_CONNECTION(TreatmentParametersSetPointData ) + ACTION_VIEW_CONNECTION(TreatmentSalineData ) + ACTION_VIEW_CONNECTION(TreatmentStatesData ) + ACTION_VIEW_CONNECTION(TreatmentTimeData ) + ACTION_VIEW_CONNECTION(TreatmentUltrafiltrationData ) + ACTION_VIEW_CONNECTION(TreatmentVitalsData ) + + ACTION_VIEW_CONNECTION(TreatmentLogAlarmData ) + ACTION_VIEW_CONNECTION(TreatmentLogEventData ) +} + +void VTreatmentTrends::onActionReceive(const DDConductivityData &vData) +{ + _latestData[eDataRole_Conductivity] = vData.mAcidBicarbCondutivity2; +} + +void VTreatmentTrends::onActionReceive(const PressureOcclusionData &vData) +{ + _latestData[eDataRole_ArterialPressure ] = vData.mArterialPressure; + _latestData[eDataRole_VenousPressure ] = vData.mVenousPressure; + _latestData[eDataRole_TMP ] = vData.mTmpPressure; +} + +void VTreatmentTrends::onActionReceive(const TreatmentParametersSetPointData &vData) +{ + _latestData[eDataRole_BloodFlowRate ] = vData.mBloodFlow; + _latestData[eDataRole_DialysateFlowRate ] = vData.mDialysateFlow; + _latestData[eDataRole_DialysateTemperature ] = vData.mDialysateTemp; +} + +void VTreatmentTrends::onActionReceive(const TreatmentSalineData &vData) +{ + _latestData[eDataRole_BolusCumulativeDelivered] = vData.mCumulative; +} + +void VTreatmentTrends::onActionReceive(const TreatmentStatesData &vData) +{ + static GuiTreatmentStates currentSubMode = GuiActions::NUM_OF_TREATMENT_STATES; + if (vData.mSubMode != currentSubMode) { + TrendEntry entry; + entry[eHistoryRole_Timestamp] = QDateTime::currentDateTime(); + entry[eHistoryRole_EntryID] = QVariant(); + entry[eHistoryRole_Priority] = 0; + + switch (vData.mSubMode) { + case GuiActions::TREATMENT_START_STATE: + time_Start(QTime::currentTime()); + entry[eHistoryRole_Message] = tr("Start Treatment"); + _history.insertRow(0, entry); + break; + case GuiActions::TREATMENT_PAUSED_STATE: + entry[eHistoryRole_Message] = tr("Treatment Paused"); + _history.insertRow(0, entry); + break; + case GuiActions::TREATMENT_END_STATE: { + entry[eHistoryRole_Message] = tr("End Treatment"); + _history.insertRow(0, entry); + break; + } + } + + currentSubMode = GuiTreatmentStates(vData.mSubMode); + } +} + +void VTreatmentTrends::onActionReceive(const TreatmentTimeData &vData) +{ + time_Elapsed(vData.mElapsed); +} + +void VTreatmentTrends::onActionReceive(const TreatmentUltrafiltrationData &vData) +{ + _latestData[eDataRole_UFVolumeRemoved ] = vData.mVolumeRemoved; + _latestData[eDataRole_UFRate ] = vData.mTargetRate; +} + +void VTreatmentTrends::onActionReceive(const TreatmentVitalsData &vData) +{ + _latestData[eDataRole_Timestamp ] = QDateTime::currentDateTime(); + _latestData[eDataRole_Systolic ] = vData.mSystolic; + _latestData[eDataRole_Diastolic ] = vData.mDiastolic; + _latestData[eDataRole_PulseRate ] = vData.mHeartRate; + + _data.insertRow(0, _latestData); + _latestData.clear(); +} + +void VTreatmentTrends::onRequestVitals() +{ + _savedData = _latestData; + _savedData[eDataRole_Timestamp] = QDateTime::currentDateTime(); + _savedData[eDataRole_Systolic ] = QVariant(); + _savedData[eDataRole_Diastolic ] = QVariant(); + _savedData[eDataRole_PulseRate ] = QVariant(); +} + +void VTreatmentTrends::onReceiveVitals() +{ +} + +void VTreatmentTrends::onTimeoutVitals() +{ + _data.insertRow(0, _latestData); + _latestData.clear(); +} + +void View::VTreatmentTrends::onActionReceive(const TreatmentLogAlarmData &vData) +{ + TrendEntry entry; + entry[eHistoryRole_Timestamp] = QDateTime::currentDateTime(); + entry[eHistoryRole_EntryID] = vData.mAlarmID; + entry[eHistoryRole_Priority] = 0; + entry[eHistoryRole_Message] = _TreatmentLog.alarmTitle(vData.mAlarmID, false); + + _history.insertRow(0, entry); +} + +void View::VTreatmentTrends::onActionReceive(const TreatmentLogEventData &vData) +{ + TrendEntry entry; + entry[eHistoryRole_Timestamp] = QDateTime::currentDateTime(); + entry[eHistoryRole_EntryID] = vData.mEventID; + entry[eHistoryRole_Priority] = 0; + entry[eHistoryRole_Message] = _TreatmentLog.eventTitle(vData.mEventID, false); + + _history.insertRow(0, entry); +} Index: sources/view/td/data/treatment/VTreatmentTrends.h =================================================================== diff -u --- sources/view/td/data/treatment/VTreatmentTrends.h (revision 0) +++ sources/view/td/data/treatment/VTreatmentTrends.h (revision 1aec139f8de0f0ccc5c6a3c4c3d2c479e054b0f9) @@ -0,0 +1,110 @@ +/*! + * + * Copyright (c) 2021-2025 Diality Inc. - All Rights Reserved. + * \copyright + * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN + * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. + * + * \file VTreatmentTrends.h + * \author (last) Stephen Quong + * \date (last) 01-Oct-2025 + * \author (original) Stephen Quong + * \date (original) 01-Oct-2025 + * + */ +#pragma once + +// Qt +#include +#include + +// Project +#include "main.h" // Doxygen : do not remove +#include "MDDConductivityData.h" +#include "MListModel.h" +#include "MTreatmentParametersSetPointData.h" +#include "MTreatmentPressureOcclusionData.h" +#include "MTreatmentSalineData.h" +#include "MTreatmentStatesData.h" +#include "MTreatmentTimeData.h" +#include "MTreatmentUltrafiltrationData.h" +#include "MTreatmentVitalsData.h" +#include "TreatmentLog.h" +#include "VView.h" + +// namespace +namespace View { + +/*! + * \brief The VTreatmentTrends class + * \details View for Trends Models' data representation. + * + * \sa Model::MTreatmentTrends + * + */ +class VTreatmentTrends : public QObject +{ + Q_OBJECT + + READONLY (QTime, time_Start, QTime() ) + READONLY (quint32, time_Elapsed, 0 ) + + Q_PROPERTY (MListModel *data READ data CONSTANT) + Q_PROPERTY (MListModel *history READ history CONSTANT) + + VIEW_DEC_CLASS ( VTreatmentTrends ) + + VIEW_DEC_SLOT ( PressureOcclusionData ) + VIEW_DEC_SLOT ( TreatmentParametersSetPointData ) + VIEW_DEC_SLOT ( TreatmentSalineData ) + VIEW_DEC_SLOT ( TreatmentStatesData ) + VIEW_DEC_SLOT ( TreatmentTimeData ) + VIEW_DEC_SLOT ( TreatmentUltrafiltrationData ) + VIEW_DEC_SLOT ( TreatmentVitalsData ) + VIEW_DEC_SLOT ( DDConductivityData ) + VIEW_DEC_SLOT ( TreatmentLogAlarmData ) + VIEW_DEC_SLOT ( TreatmentLogEventData ) + +public: + enum { + eDataRole_Timestamp = Qt::UserRole , + eDataRole_Systolic , + eDataRole_Diastolic , + eDataRole_PulseRate , + eDataRole_UFVolumeRemoved , + eDataRole_UFRate , + eDataRole_ArterialPressure , + eDataRole_VenousPressure , + eDataRole_TMP , + eDataRole_BolusCumulativeDelivered , + eDataRole_BloodFlowRate , + eDataRole_DialysateFlowRate , + eDataRole_DialysateTemperature , + eDataRole_Conductivity , + } DataRole; + + enum { + eHistoryRole_Timestamp = Qt::UserRole , + eHistoryRole_EntryID , + eHistoryRole_Priority , + eHistoryRole_Message , + } HistoryRole; + + MListModel* data(); + MListModel* history(); + +public Q_SLOTS: + void onRequestVitals(); + void onReceiveVitals(); + void onTimeoutVitals(); + +private: + typedef QHash TrendEntry; + + MListModel _data; + MListModel _history; + TrendEntry _latestData; + TrendEntry _savedData; +}; + +} // namespace View