Index: leahi.qrc
===================================================================
diff -u -rac81e21684bfb1c72b8ef86bfeda04e174e5066e -rd66feb12d37023f6f67672ff4acdb5abebdbff15
--- leahi.qrc (.../leahi.qrc) (revision ac81e21684bfb1c72b8ef86bfeda04e174e5066e)
+++ leahi.qrc (.../leahi.qrc) (revision d66feb12d37023f6f67672ff4acdb5abebdbff15)
@@ -210,6 +210,7 @@
sources/gui/qml/compounds/LabelUnitValueAdjuster.qml
sources/gui/qml/compounds/SettingsSlider.qml
sources/gui/qml/compounds/AutoStepController.qml
+ sources/gui/qml/compounds/InteractiveImage.qml
qtquickcontrols2.conf
Index: sources/gui/qml/compounds/AutoStepController.qml
===================================================================
diff -u -ra8a42037ec8a5b2a5057c8dbb0f6cc079672b7fe -rd66feb12d37023f6f67672ff4acdb5abebdbff15
--- sources/gui/qml/compounds/AutoStepController.qml (.../AutoStepController.qml) (revision a8a42037ec8a5b2a5057c8dbb0f6cc079672b7fe)
+++ sources/gui/qml/compounds/AutoStepController.qml (.../AutoStepController.qml) (revision d66feb12d37023f6f67672ff4acdb5abebdbff15)
@@ -14,9 +14,11 @@
signal triggered()
function refresh() {
- _stepTimer.running = false
- _stepTimer.running = true // restart timer
- _progressAnim.restart()
+ if ( isPlaying ) {
+ _stepTimer.stop()
+ _stepTimer.start() // restart timer
+ _progressAnim.restart()
+ }
}
Timer { id: _stepTimer
@@ -34,7 +36,7 @@
anchors.verticalCenter : _root.verticalCenter
iconImageSource : _root.isPlaying ? "qrc:/images/iPause" : "qrc:/images/iPlay"
isDefault : true
- borderColor: Colors.transparent
+ borderColor : Colors.transparent
onClicked : _root.isPlaying = ! _root.isPlaying
ProgressCircle { id: _progress
Index: sources/gui/qml/compounds/InstructionView.qml
===================================================================
diff -u -ra8a42037ec8a5b2a5057c8dbb0f6cc079672b7fe -rd66feb12d37023f6f67672ff4acdb5abebdbff15
--- sources/gui/qml/compounds/InstructionView.qml (.../InstructionView.qml) (revision a8a42037ec8a5b2a5057c8dbb0f6cc079672b7fe)
+++ sources/gui/qml/compounds/InstructionView.qml (.../InstructionView.qml) (revision d66feb12d37023f6f67672ff4acdb5abebdbff15)
@@ -20,6 +20,7 @@
// Qml imports
import "qrc:/globals"
import "qrc:/components"
+import "qrc:/compounds"
Rectangle { id: _root
property string title : ""
@@ -128,9 +129,15 @@
}
}
- Image { id: _image
- anchors.right : parent.right
- source : _root.stepImages.length && _root.stepImages[_root.currentIndex] ? _root.stepImages[_root.currentIndex] : ""
+ InteractiveImage { id: _image
+ anchors {
+ bottom : parent.bottom
+ right : parent.right
+ }
+ width : parent.width / 2
+ height : _root.height
+
+ source : _root.stepImages.length && _root.stepImages[_root.currentIndex] ? _root.stepImages[_root.currentIndex] : ""
}
}
}
Index: sources/gui/qml/compounds/InteractiveImage.qml
===================================================================
diff -u
--- sources/gui/qml/compounds/InteractiveImage.qml (revision 0)
+++ sources/gui/qml/compounds/InteractiveImage.qml (revision d66feb12d37023f6f67672ff4acdb5abebdbff15)
@@ -0,0 +1,118 @@
+import QtQuick 2.0
+
+Item { id: _root
+ property alias source:_image.source
+
+ property real minScale : 1
+ property real maxScale : 4
+ property real startScale: 1
+ property bool pinching : false
+
+ onSourceChanged: reset()
+
+ function snapBack() {
+ _flickable.contentX = Math.max( 0, Math.min(_flickable.contentWidth - _flickable.width, _flickable.contentX) )
+ _flickable.contentY = Math.max( 0, Math.min(_flickable.contentHeight - _flickable.height, _flickable.contentY) )
+ }
+
+ function rubberClamp() {
+ let minX = 0
+ let maxX = Math.max(0, _flickable.contentWidth - _flickable.width)
+ let minY = 0
+ let maxY = Math.max(0, _flickable.contentHeight - _flickable.height)
+ let resistance = 0.35
+
+ _flickable.contentX = (_flickable.contentX < minX) ? minX + (_flickable.contentX - minX) * resistance
+ : (_flickable.contentX > maxX) ? maxX + (_flickable.contentX - maxX) * resistance
+ : _flickable.contentX
+
+ _flickable.contentY = (_flickable.contentY < minY) ? minY + (_flickable.contentY - minY) * resistance
+ : (_flickable.contentY > maxY) ? maxY + (_flickable.contentY - maxY) * resistance
+ : _flickable.contentY
+ }
+
+ function reset() {
+ _scaleTransform.xScale = 1
+ _scaleTransform.yScale = 1
+ _flickable.contentX = 0
+ _flickable.contentY = 0
+ }
+
+ Flickable { id: _flickable
+ anchors.fill : parent
+ contentWidth : _image.width * _scaleTransform.xScale
+ contentHeight : _image.height * _scaleTransform.yScale
+ clip : true
+ interactive : ! pinching
+
+ PinchArea { id: _pinchArea
+ anchors.fill : parent
+ pinch.target: _image
+
+ Image { id: _image
+ fillMode : Image.PreserveAspectFit
+
+ transform: Scale { id: _scaleTransform
+ origin.x: 0
+ origin.y: 0
+ xScale : 1
+ yScale : 1
+
+ // smooth zoom feel
+ Behavior on xScale { NumberAnimation { duration: 80; easing.type: Easing.OutQuad } }
+ Behavior on yScale { NumberAnimation { duration: 80; easing.type: Easing.OutQuad } }
+ }
+
+ // ✅ bottom-right when not zoomed
+ x: (_flickable.contentWidth <= _flickable.width) ? (_flickable.width - width * _scaleTransform.xScale) : -_flickable.contentX
+ y: (_flickable.contentHeight <= _flickable.height) ? (_flickable.height - height * _scaleTransform.yScale) : -_flickable.contentY
+
+ // smooth snap
+ Behavior on x { NumberAnimation { duration: 80; easing.type: Easing.OutCubic } }
+ Behavior on y { NumberAnimation { duration: 80; easing.type: Easing.OutCubic } }
+ }
+
+ onPinchStarted: (pinch) => {
+ pinching = true
+ startScale = _scaleTransform.xScale
+ }
+
+ onPinchUpdated: (pinch) => {
+ if (Math.abs(pinch.scale - 1) < 0.01) return
+
+ // smooth scale
+ let newScale = startScale * pinch.scale
+ newScale = Math.max(minScale, Math.min(maxScale, newScale))
+
+ // 🔑 ratio between scales
+ let scaleRatio = newScale / _flickable.xScale
+
+ // 🔑 adjust content so zoom follows fingers
+ let cx = pinch.center.x
+ let cy = pinch.center.y
+
+ _flickable.contentX = (_flickable.contentX + cx) * scaleRatio - cx
+ _flickable.contentY = (_flickable.contentY + cy) * scaleRatio - cy
+
+ // apply scale AFTER adjusting content
+ _scaleTransform.xScale = newScale
+ _scaleTransform.yScale = newScale
+
+ // 🔑 now apply drag (correct direction)
+ let dx = pinch.center.x - pinch.previousCenter.x
+ let dy = pinch.center.y - pinch.previousCenter.y
+
+ _flickable.contentX -= dx * 0.8
+ _flickable.contentY -= dy * 0.8
+
+ rubberClamp()
+ }
+
+ onPinchFinished: {
+ reset()
+ snapBack()
+ Qt.callLater(() => pinching = false)
+ }
+ }
+ }
+}
Index: sources/gui/qml/dialogs/NotificationDialog.qml
===================================================================
diff -u -ra8a42037ec8a5b2a5057c8dbb0f6cc079672b7fe -rd66feb12d37023f6f67672ff4acdb5abebdbff15
--- sources/gui/qml/dialogs/NotificationDialog.qml (.../NotificationDialog.qml) (revision a8a42037ec8a5b2a5057c8dbb0f6cc079672b7fe)
+++ sources/gui/qml/dialogs/NotificationDialog.qml (.../NotificationDialog.qml) (revision d66feb12d37023f6f67672ff4acdb5abebdbff15)
@@ -152,7 +152,7 @@
onCurrentIndexChanged: {
var item = model.get(_listView.currentIndex)
- _root.figureImageSource = item.image
+ _root.figureImageSource = item.image ?? ""
_autoStepController.refresh()
}
@@ -213,9 +213,16 @@
}
}
- Image { id: _figureImage
- anchors.right : parent.right
- anchors.verticalCenter: parent.verticalCenter
+ InteractiveImage { id: _figureImage
+ anchors {
+ right : parent.right
+ bottom : parent.bottom
+ bottomMargin : Variables.defaultMargin * 3
+
+ }
+ width : parent.width / 2
+ height : _listView.height
+
}
}
Index: sources/gui/qml/pages/treatment/TreatmentSectionHeader.qml
===================================================================
diff -u -rac81e21684bfb1c72b8ef86bfeda04e174e5066e -rd66feb12d37023f6f67672ff4acdb5abebdbff15
--- sources/gui/qml/pages/treatment/TreatmentSectionHeader.qml (.../TreatmentSectionHeader.qml) (revision ac81e21684bfb1c72b8ef86bfeda04e174e5066e)
+++ sources/gui/qml/pages/treatment/TreatmentSectionHeader.qml (.../TreatmentSectionHeader.qml) (revision d66feb12d37023f6f67672ff4acdb5abebdbff15)
@@ -77,8 +77,6 @@
IconButton { id : _pauseResume
visible : showPauseResume
- iconSize : 25
- extraSpace : 30
iconImageSource : _root.isPaused ? "qrc:/images/iPlay" : "qrc:/images/iPause"
isDefault : true
onClicked : _root.pauseResumeClicked()
Index: sources/gui/qml/pages/treatment/TreatmentStack.qml
===================================================================
diff -u -r0bc5c7e5752e76707f92b9ef1ecfe54b0c5ead29 -rd66feb12d37023f6f67672ff4acdb5abebdbff15
--- sources/gui/qml/pages/treatment/TreatmentStack.qml (.../TreatmentStack.qml) (revision 0bc5c7e5752e76707f92b9ef1ecfe54b0c5ead29)
+++ sources/gui/qml/pages/treatment/TreatmentStack.qml (.../TreatmentStack.qml) (revision d66feb12d37023f6f67672ff4acdb5abebdbff15)
@@ -177,6 +177,7 @@
)
}
}
+
Connections { target: _treatmentAdjustmentPressuresLimits
function onConfirmClicked ( vValue ) {
vTreatmentAdjustmentPressuresLimits.doAdjustment(
@@ -187,6 +188,7 @@
)
}
}
+
Connections { target: _treatmentAdjustmentBolusVolume
function onConfirmClicked ( vValue ) {
vTreatmentAdjustmentBolusVolume.doAdjustment(_treatmentAdjustmentBolusVolume.fluidBolusVolume)