Index: leahi.qrc =================================================================== diff -u -ra6ad83a73eb80978261a408ee5a92fbc8f7faa4e -r4746b6bcbf4def7888f7b29d72431b28e6672f12 --- leahi.qrc (.../leahi.qrc) (revision a6ad83a73eb80978261a408ee5a92fbc8f7faa4e) +++ leahi.qrc (.../leahi.qrc) (revision 4746b6bcbf4def7888f7b29d72431b28e6672f12) @@ -162,6 +162,7 @@ sources/gui/qml/components/HeaderBar.qml sources/gui/qml/components/HeaderBarPopup.qml sources/gui/qml/components/AlarmButtonRow.qml + sources/gui/qml/components/SliderUfAdjustment.qml sources/gui/qml/compounds/PressureRangeSlider.qml Index: sources/gui/qml/components/ProgressBarEx.qml =================================================================== diff -u -r23f8a6036e22f80c3c5fd2834a2980bb62d2a34d -r4746b6bcbf4def7888f7b29d72431b28e6672f12 --- sources/gui/qml/components/ProgressBarEx.qml (.../ProgressBarEx.qml) (revision 23f8a6036e22f80c3c5fd2834a2980bb62d2a34d) +++ sources/gui/qml/components/ProgressBarEx.qml (.../ProgressBarEx.qml) (revision 4746b6bcbf4def7888f7b29d72431b28e6672f12) @@ -43,6 +43,7 @@ minimum : _root.minimum maximum : _root.maximum value : _root.valueEx + radius : _root.radius color : Colors.highlightMedProgressBar margin : 0 maxText.visible : visible Index: sources/gui/qml/components/Slider.qml =================================================================== diff -u -rc65859e54930664100dfdff13afa019e05ae23b6 -r4746b6bcbf4def7888f7b29d72431b28e6672f12 --- sources/gui/qml/components/Slider.qml (.../Slider.qml) (revision c65859e54930664100dfdff13afa019e05ae23b6) +++ sources/gui/qml/components/Slider.qml (.../Slider.qml) (revision 4746b6bcbf4def7888f7b29d72431b28e6672f12) @@ -25,6 +25,7 @@ */ RangeRect { id: _root property real value : _progressRect.value + property real minStop : undefined property real defaultValue : _root.minimum property real step : 1 @@ -55,6 +56,7 @@ property bool hasBorder : true property bool showMinMaxText : true property color borderColor : Colors.borderDisableButton + property color highlightColor : Colors.sliderHighlightColor signal activeChanged() signal handleSelected() @@ -105,7 +107,7 @@ function setActiveVisuals(active) { if (active) { - color = Colors.sliderHighlightColor + color = _root.highlightColor handlerColor = Colors.createTreatmentActive } else { color = Colors.createTreatmentInactive @@ -191,6 +193,11 @@ let mMinimum = Number(_root.minimum.toFixed(decimal)) let mMaximum = Number(_root.maximum.toFixed(decimal)) + // if there is a minimum stop, then adjust the slider minimum to that value + if (minStop && mMinimum < minStop) { + mMinimum = minStop + } + // the center of the handler is aligned on the snap point and half width shall be used to set as min not the entire width. // also half of the hadler is out of slider min position when set on min, which proves the same as above. if(x < ( _handler.width / 2 ) ) { @@ -260,7 +267,7 @@ ProgressRect { id: _progressRect property real previousSliderValue: Number.NaN value : minimum - color : Colors.sliderHighlightColor + color : _root.highlightColor decimal : _root.decimal minimum : _root.minimum Index: sources/gui/qml/components/SliderUfAdjustment.qml =================================================================== diff -u --- sources/gui/qml/components/SliderUfAdjustment.qml (revision 0) +++ sources/gui/qml/components/SliderUfAdjustment.qml (revision 4746b6bcbf4def7888f7b29d72431b28e6672f12) @@ -0,0 +1,229 @@ +/*! + * + * Copyright (c) 2020-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 SliderUfAdjustment.qml + * \author (last) Stephen Quong + * \date (last) 20-Aug-2025 + * \author (original) Stephen Quong + * \date (original) 20-Aug-2025 + * + */ + +// Qt +import QtQuick 2.12 + +// Project +// Qml imports +import "qrc:/globals" +import "qrc:/components" + +/*! + * \brief Slider component with a title and the currently selected value + */ +Rectangle { id: _root + property Flickable flickable: null + + property var toggleSwich : null // it is the treatment slider custom Switch bu it will be defined outside of this component and the var type would suffice. + + property bool adjustable : true + property alias decimal : _slider.decimal + property alias minimum : _slider.minimum + property alias maximum : _slider.maximum + property alias minStop : _slider.minStop + property alias value : _slider.value + property alias defaultValue : _slider.defaultValue + property alias step : _slider.step + property alias inActiveZero: _slider.inActiveZero + + property string zeroLabel : "" + + property string unit : "" + property bool active : false + property bool valid : true + + property alias enableAdjustButtons : _sliderArrows.enabled + + signal pressed () + signal released() + + height : Variables.createTreatmentSliderHeight + width : Variables.createTreatmentSliderWidth + color : Colors.transparent + + anchors.horizontalCenter: parent.horizontalCenter + + function clear() { + reset(defaultValue) + if ( toggleSwich ) { + toggleSwich.checked = false + toggleSwich.active = false + } + _root.active = false + } + + function reset(vValue) { + _slider.reset(vValue) + } + + function setColor() { + let color = Colors.textMain + if ( ! _root.valid ) { color = Colors.createTreatmentInvalidParam ; return color } + if ( ! _root.active ) { color = Colors.textDisableButton ; return color } + return color + } + + function setValue() { + // The slider is not adjustable, implying it won't have a value change + if ( !adjustable && zeroLabel !== "") { + return _root.zeroLabel + } + + let mValue = "__" + let unit = " " + _root.unit + + if ( _root.active ) { + if ( _slider.value === 0 && zeroLabel !== "" ) { + return _root.zeroLabel + } + mValue = _slider.value.toFixed(decimal) + } + return mValue + unit + } + + function setInteractive( vInteractive ) { + if (_root.flickable) { + _root.flickable.interactive = vInteractive + } + } + + function setActiveValid() { + _root.active = true + } + + Slider { id : _slider + objectName : _root.objectName + "Slider" + anchors { + left : parent.left + right : _sliderArrows.left + rightMargin : 60 + verticalCenter : _sliderArrows.verticalCenter + } + enabled : _root.adjustable + height : Variables.ultraFiltrationProgressBarHeight + bgColor : Colors.ufAdjustmentProgressBarBg + highlightColor : Colors.ufAdjustmentDeltaFill + diameter : Variables.progressbarHandler + touchMargin : Variables.createTreatmentSliderMargin + handler.z : 5 + handlerColor : Colors.createTreatmentInactive + handlerVisible : _root.adjustable + isActive : _root.active + stepSnap : true + ticks : true + onDragged : { setInteractive(false) ; ; } + onPressed : { setInteractive(false) ; _root.pressed () ; } + onReleased : { setInteractive(true ) ; _root.released() ; } + onHandleSelected : { setActiveValid(); } + onSliderSelected : { setActiveValid(); } + minText { + font { + pixelSize : Fonts.fontPixelButton + weight : Font.Normal + } + text : _root.minimum.toFixed(_root.decimal) + (_root.unit.length ? (" " + _root.unit) : "") + } + maxText { + font { + pixelSize : minText.font.pixelSize + weight : minText.font.weight + } + text : _root.maximum.toFixed(_root.decimal) + (_root.unit.length ? (" " + _root.unit) : "") + } + + Rectangle { id: _removedFill + anchors { + top : parent.top + bottom : parent.bottom + left : parent.left + right : _removedMarker.right + // adjust margin so fill completely covers the underlying slider + leftMargin : -1 + } + z : _removedMarker.z - 1 + color : Colors.ufProgressBarFill + radius : height / 2 + + Rectangle { id: _removedFillCover + anchors { + top : parent.top + bottom : parent.bottom + right : parent.right + } + width : Math.min(parent.radius, _removedMarker.x) + color : parent.color + } + } + + RangeMarker { id: _removedMarker + x : (_slider.width * (_slider.minStop / _slider.maximum)) - ((width+1)/2) + z : _slider.handler.z - 1 + width : Variables.ultrafiltrationRangeMarkerWidth + height : Variables.rangeMarkerHeight + hasHandle : true + valueOnTop : true + decimal : Variables.ultrafiltrationPrecision + value : _root.minStop + handle.width : Variables.ultrafiltrationRangeMarkerHandleWidth + text { + anchors.bottomMargin: marker.valueOnTop ? 15 : 0 + font { + pixelSize: Fonts.fontPixelUltrafiltrationRangeMarker + weight: Font.DemiBold + } + } + } + } + + SliderArrows{ id:_sliderArrows + anchors { + verticalCenter : _slider.verticalCenter + right : parent.right + } + + // NOTE: @inActiveZero + // the slider which use inActiveZero are the once, with OFF button. + // these sliders have 0 as defalut to indicate OFF. + // when activated the first value they get is still the 0 ( OFF ). + // in that case we decrement once to get the correct minimum value. + // as example heparin dispensing after gets ON, firsrt decrement shows OFF ( 0 ). + // NOTE: if 0=defaultValue is in range (minimum < defaultValue < maximum), we still have problem, and needs more investigation + onIncrementValue : { + if ( _slider.isActive) { + _slider.incrementValue(true) + } else { + setActiveValid() + if ( inActiveZero ) { // NOTE: @inActiveZero + _slider.decrementValue() + } + } + } + onDecrementValue : { + // do not allow slider to decrement if doing so will let it go below the minimum bound + if (_slider.minStop && (_slider.value - _slider.step) < _slider.minStop) { + return + } + if ( _slider.isActive) { + _slider.decrementValue(true) + } else { + setActiveValid() + if ( inActiveZero ) { // NOTE: @inActiveZero + _slider.decrementValue() + } + } + } + } +} Index: sources/gui/qml/globals/Colors.qml =================================================================== diff -u -ra6ad83a73eb80978261a408ee5a92fbc8f7faa4e -r4746b6bcbf4def7888f7b29d72431b28e6672f12 --- sources/gui/qml/globals/Colors.qml (.../Colors.qml) (revision a6ad83a73eb80978261a408ee5a92fbc8f7faa4e) +++ sources/gui/qml/globals/Colors.qml (.../Colors.qml) (revision 4746b6bcbf4def7888f7b29d72431b28e6672f12) @@ -148,6 +148,8 @@ readonly property color ufVolumeGoalText : "#f5be59" readonly property color ufNotificationBarBg : "#0f2841" readonly property color ufProgressBarFill : "#467bbe" + readonly property color ufAdjustmentDeltaFill : "#747974" + readonly property color ufAdjustmentProgressBarBg : "#2c517b" // ---------- < PRS > Related Section ---------- // Alarm priority colors Index: sources/gui/qml/globals/Variables.qml =================================================================== diff -u -rde68fcc0e2885ef78670ce8edf5e10f88b705d8d -r4746b6bcbf4def7888f7b29d72431b28e6672f12 --- sources/gui/qml/globals/Variables.qml (.../Variables.qml) (revision de68fcc0e2885ef78670ce8edf5e10f88b705d8d) +++ sources/gui/qml/globals/Variables.qml (.../Variables.qml) (revision 4746b6bcbf4def7888f7b29d72431b28e6672f12) @@ -147,6 +147,8 @@ readonly property int ultraFiltrationEditSliderHeight : sliderDefaultBodyHeight // to be consistent with other sliders readonly property int ultrafiltrationButtonWidth : 300 readonly property int ultrafiltrationButtonHeight : 60 + readonly property int ultrafiltrationRangeMarkerWidth : 4 + readonly property int ultrafiltrationRangeMarkerHandleWidth : 12 readonly property int silenceIconMargin : 10 readonly property int notificationBarIconMargin : 10 Index: sources/gui/qml/pages/treatment/adjustments/TreatmentAdjustmentUltrafiltrationEdit.qml =================================================================== diff -u -r86274f18e9356126c41d848bc78bfba318638aee -r4746b6bcbf4def7888f7b29d72431b28e6672f12 --- sources/gui/qml/pages/treatment/adjustments/TreatmentAdjustmentUltrafiltrationEdit.qml (.../TreatmentAdjustmentUltrafiltrationEdit.qml) (revision 86274f18e9356126c41d848bc78bfba318638aee) +++ sources/gui/qml/pages/treatment/adjustments/TreatmentAdjustmentUltrafiltrationEdit.qml (.../TreatmentAdjustmentUltrafiltrationEdit.qml) (revision 4746b6bcbf4def7888f7b29d72431b28e6672f12) @@ -30,114 +30,73 @@ contentItem.objectName: "TreatmentAdjustmentUltrafiltrationEdit" //SquishQt testability QtObject { id: _private property int decimal : Variables.ultrafiltrationPrecision - property real minAdjust : vTreatmentRanges.treatmentRanges_Ultrafiltration_Volume_Min - property real valAdjust : _volumeSlider.value - property real maxAdjust : vTreatmentRanges.treatmentRanges_Ultrafiltration_Volume_Max - - property real min : vTreatmentUltrafiltration.minimum - property real val : vTreatmentUltrafiltration.volumeRemoved - property real max : vTreatmentUltrafiltration.maximum + property real setVolume : vTreatmentUltrafiltration.setVolume + property real volumeRemoved : vTreatmentUltrafiltration.volumeRemoved } signal nextClicked(real vVolume) function reset() { - _volumeSlider.value = _private.max + _setVolumeSlider.reset(_private.setVolume) } closeVisible : false confirmVisible : false backVisible : true information { - visible : true && information.text && ! notification.visible - imageSource : ufInfoImageSource - text : ufInfoText + visible : true && information.text && ! notification.visible + imageSource : ufInfoImageSource + text : ufInfoText + radius : 0 + color : Colors.ufNotificationBarBg + textColor : Colors.ufVolumeGoalText + textfontSize : Fonts.fontPixelUltrafiltrationAdjustmentNotification + textfontWeight : Font.Normal } - titleText : qsTr("ULTRAFILTRATION VOLUME") + " " + Variables.unitTextUltrafiltrationVolume + titleText : qsTr("Ultrafiltration Volume ") + Variables.unitTextUltrafiltrationVolume - ProgressBarEx { id: _rangeProgressBar - width : Variables.ultrafiltrationProgressbarWidth - height : Variables.ultraFiltrationProgressBarHeight + TreatmentAdjustmentUltrafiltrationMetrics { id: _ufMetrics anchors { - top : parent.top - topMargin : 250 - right : parent.right - rightMargin : _volumeSliderArrows.width + Variables.sliderAdjustButtonSpacing*2 + top : parent.top + topMargin : Variables.defaultMargin * 2 + horizontalCenter: parent.horizontalCenter } - decimal : _private.decimal - minimum : _private.min // suppose to be always 0 // DEN-6022 // _private.maxAdjust => _private.min - maximum : _private.maxAdjust - value : _private.val - valueEx : _private.valAdjust - progressEx.maxText.visible: false + setVolume : _setVolumeSlider.value + volumeRemoved : _private.volumeRemoved } - Slider { id: _volumeSlider - // TODO : These two values shall get from a model - property int minGapValue: 0 // No gap for now. - property int maxGapValue: 0 // No gap for now. - - readonly property int minPrgWidth: _rangeProgressBar.maximum - _rangeProgressBar.minimum - readonly property int maxPrgWidth: _rangeProgressBar.maximum - _rangeProgressBar.minimum - readonly property int minGapWidth: minPrgWidth > 0 ? (minGapValue * _rangeProgressBar.width) / minPrgWidth : 0 - readonly property int maxGapWidth: maxPrgWidth > 0 ? (maxGapValue * _rangeProgressBar.width) / maxPrgWidth : 0 - + SliderUfAdjustment { id: _setVolumeSlider anchors { - top: _rangeProgressBar.bottom - topMargin: 50 + top : _ufMetrics.bottom + topMargin : 160 + left : parent.left + leftMargin : 80 + right : parent.right + rightMargin : anchors.leftMargin + horizontalCenter: undefined } - - x : _rangeProgressBar.x + minGapWidth + _rangeProgressBar.progressWidth - width : _rangeProgressBar.width - maxGapWidth - minGapWidth - _rangeProgressBar.progressWidth - height : Variables.ultraFiltrationEditSliderHeight - step : 0.100 - stepSnap: true - ticks : true - decimal : _private.decimal - minimum : _private.minAdjust + minGapValue - maximum : _private.maxAdjust - maxGapValue + minimum : 0 + minStop : _private.volumeRemoved + maximum : 20 + defaultValue : { defaultValue =_private.setVolume } // set without binding + unit : Variables.unitVolume } - SliderArrows{ id: _volumeSliderArrows - visible : true - anchors.verticalCenter : _volumeSlider.verticalCenter - anchors.right : parent.right - anchors.rightMargin : Variables.sliderAdjustButtonSpacing - - onIncrementValue : _volumeSlider.incrementValue(true) - onDecrementValue : _volumeSlider.decrementValue(true) - } - - Text { id: _textVolume - visible : true - color : Colors.textMain - text : _private.valAdjust.toFixed(_private.decimal) - font { - pixelSize : Fonts.fontPixelUltrafiltrationAdjustmentEditValue - } + TouchRect { id: _continueButton anchors { + top : _setVolumeSlider.bottom + topMargin : 110 horizontalCenter: parent.horizontalCenter - top : parent.top - topMargin : 150 } - } - - TouchRect { id: _nextButton - width : 530 - height : 95 - anchors { - top: parent.top - topMargin: 460 - horizontalCenter: parent.horizontalCenter - } - isDefault: true + width : Variables.ultrafiltrationButtonWidth + height : Variables.ultrafiltrationButtonHeight text { - text: qsTr("NEXT") - font.weight : Font .DemiBold - font.pixelSize: Fonts.fontPixelUltrafiltrationAdjustmentNextButton + text : qsTr("Continue") + font.weight : Font.DemiBold } + isDefault : true onClicked: nextClicked( _private.valAdjust.toFixed(_private.decimal) ) } } Index: sources/gui/qml/pages/treatment/adjustments/TreatmentAdjustmentUltrafiltrationStart.qml =================================================================== diff -u -rde68fcc0e2885ef78670ce8edf5e10f88b705d8d -r4746b6bcbf4def7888f7b29d72431b28e6672f12 --- sources/gui/qml/pages/treatment/adjustments/TreatmentAdjustmentUltrafiltrationStart.qml (.../TreatmentAdjustmentUltrafiltrationStart.qml) (revision de68fcc0e2885ef78670ce8edf5e10f88b705d8d) +++ sources/gui/qml/pages/treatment/adjustments/TreatmentAdjustmentUltrafiltrationStart.qml (.../TreatmentAdjustmentUltrafiltrationStart.qml) (revision 4746b6bcbf4def7888f7b29d72431b28e6672f12) @@ -71,7 +71,7 @@ top : _ufMetrics.bottom topMargin : 160 left : parent.left - leftMargin : 60 + leftMargin : 80 right : parent.right rightMargin : anchors.leftMargin } @@ -81,7 +81,8 @@ maximum : _private.setVolume value : _private.volumeRemoved valueEx : 0 - color: Colors.ufProgressBarFill + color : Colors.ufProgressBarFill + bgColor : Colors.ufAdjustmentDeltaFill minText { font { pixelSize : Fonts.fontPixelButton @@ -97,10 +98,10 @@ text : _private.setVolume.toFixed(Variables.ultrafiltrationPrecision) + " " + Variables.unitVolume } marker { - width : Variables.rangeMarkerWidthMidle - handle.width : marker.width * 4 + width : Variables.ultrafiltrationRangeMarkerWidth + handle.width : Variables.ultrafiltrationRangeMarkerHandleWidth text { - anchors.bottomMargin: marker.valueOnTop ? 10 : 0 + anchors.bottomMargin: marker.valueOnTop ? 13 : 0 font { pixelSize: Fonts.fontPixelUltrafiltrationRangeMarker weight: Font.DemiBold