Files
pyGUI/src/pygui/ISC/Tabs/components/RunChart.qml
T

174 lines
6.3 KiB
QML

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import ISC
import ISC.Wafer
// ===== Run Chart =====
// Zoomable whole-run multi-sensor chart (C# parity: PopupChartForm.cs).
// Lives in the Graph tab. Mouse wheel zooms around the cursor, drag pans;
// the strip below shows the aggregate min/max/avg over the *visible* range
// (not the whole run), matching PopupChartForm's recalc_stats. Cursor/
// playhead tracking is out of scope — see specs/plans/2026-07-10-popup-chart.md
// and docs/adr/0004-graphquickitem-viewport-for-replay-chart.md.
Item {
id: root
property alias sensorNames: chart.sensorNames
property alias seriesData: chart.seriesData
property alias title: chart.title
// Same palette that colors the chart lines (GraphQuickItem.seriesColors,
// theme-agnostic — see docs/adr/0004 for why); falls back to the default
// text color when the sensor isn't found (e.g. a stale binding mid-swap).
function sensorColor(name) {
var idx = chart.sensorNames.indexOf(name)
return (idx >= 0 && idx < chart.seriesColors.length) ? chart.seriesColors[idx] : Theme.headingColor
}
ColumnLayout {
anchors.fill: parent
spacing: 8
Item {
Layout.fillWidth: true
Layout.fillHeight: true
GraphQuickItem {
id: chart
anchors.fill: parent
showMinMaxMarkers: true
xLabel: "Measurement Interval"
yLabel: "Temperature (°C)"
backgroundColor: Theme.cardBackground
gridColor: Theme.toneBorder
axisColor: Theme.toneMute
textColor: Theme.headingColor
}
MouseArea {
id: interaction
anchors.fill: parent
acceptedButtons: Qt.LeftButton
property real lastX: 0
onWheel: function(wheel) {
var frac = Math.max(0, Math.min(1, wheel.x / width));
var factor = wheel.angleDelta.y > 0 ? 0.8 : 1.25;
chart.zoomAtFraction(frac, factor);
wheel.accepted = true;
}
onPressed: function(mouse) {
lastX = mouse.x;
}
onPositionChanged: function(mouse) {
if (pressed && width > 0) {
chart.panByFraction(-(mouse.x - lastX) / width);
lastX = mouse.x;
}
}
}
Button {
id: resetZoomBtn
anchors.top: parent.top
anchors.right: parent.right
// Vertically centers on the chart title, which GraphQuickItem
// paints in a y=4..28 band (see graph_quick_item.py paint()).
anchors.topMargin: 2
anchors.rightMargin: 10
implicitHeight: 32
hoverEnabled: true
text: "Reset Zoom"
font.family: Theme.uiFontFamily
font.pixelSize: Theme.fontSm
font.weight: Font.Medium
background: Rectangle {
radius: Theme.radiusSm
color: resetZoomBtn.pressed ? Theme.transportButtonHover : Theme.transportButtonBg
border.color: Theme.sideBorder
border.width: 1
opacity: 0.9
}
contentItem: Text {
text: resetZoomBtn.text
color: Theme.headingColor
font: resetZoomBtn.font
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
onClicked: chart.resetZoom()
}
}
// ── Min/Max/Avg readout strip ───────────────────────────────────
RowLayout {
Layout.fillWidth: true
Layout.leftMargin: 8
spacing: 16
Label {
text: "Min:"
color: Theme.sensorLow
font.family: Theme.uiFontFamily
font.pixelSize: Theme.fontSm
font.weight: Font.Medium
}
Row {
Label {
text: chart.viewMin.toFixed(2)
color: Theme.headingColor
font.family: Theme.codeFontFamily
font.pixelSize: Theme.fontSm
}
Label {
visible: !!chart.viewMinSensor
text: chart.viewMinSensor ? " (" + chart.viewMinSensor + ")" : ""
color: root.sensorColor(chart.viewMinSensor)
font.family: Theme.codeFontFamily
font.pixelSize: Theme.fontSm
font.weight: Font.Medium
}
}
Label {
text: "Max:"
color: Theme.sensorHigh
font.family: Theme.uiFontFamily
font.pixelSize: Theme.fontSm
font.weight: Font.Medium
}
Row {
Label {
text: chart.viewMax.toFixed(2)
color: Theme.headingColor
font.family: Theme.codeFontFamily
font.pixelSize: Theme.fontSm
}
Label {
visible: !!chart.viewMaxSensor
text: chart.viewMaxSensor ? " (" + chart.viewMaxSensor + ")" : ""
color: root.sensorColor(chart.viewMaxSensor)
font.family: Theme.codeFontFamily
font.pixelSize: Theme.fontSm
font.weight: Font.Medium
}
}
Label {
text: "Avg:"
color: Theme.sideMutedText
font.family: Theme.uiFontFamily
font.pixelSize: Theme.fontSm
font.weight: Font.Medium
}
Label {
text: chart.viewAvg.toFixed(2)
color: Theme.headingColor
font.family: Theme.codeFontFamily
font.pixelSize: Theme.fontSm
}
}
}
}