feat(debug): add debug read with CSV export

- Parse F1 debug data via family-independent temp formula
  (bits 4-14 scaled by 2**(i-8), sign at bit 0)
- Save sensor+debug temps side-by-side to debug_info.csv
- Wire READ DEBUG button in StatusActionsPanel
- Rename ReplayChart → RunChart; move into GraphTab
- Extract PanelBox/SectionTitle/PanelSlider in ReadoutPanel
  to cut ~300 lines of duplicated styling
- Add rightRailWidth token to Theme for consistent rail sizing
- Wrap ReadoutPanel in ScrollView so Thresholds card stays
  reachable when E-C delta rows appear
This commit is contained in:
jack
2026-07-11 18:39:29 -07:00
parent fed4d9b590
commit 9e3bec9031
13 changed files with 349 additions and 451 deletions
+60 -400
View File
@@ -1,13 +1,14 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Controls.impl
import QtQuick.Dialogs
import QtQuick.Layouts
import ISC
// ===== Readout Panel =====
// Right-rail panel with three bordered sections: READOUT, DISPLAY, THRESHOLDS.
// Cards match the left-rail SOURCE / CONNECTION FLOW style.
// Right-rail panel with three bento-tile sections: READOUT, DISPLAY,
// THRESHOLDS. Uses the same PanelBox / SectionTitle / ReadoutStat /
// PanelCheckBox / PanelSlider components as the Data tab's
// ComparisonSidePanel, so both right rails share one visual language.
ColumnLayout {
id: root
spacing: 6
@@ -21,49 +22,6 @@ ColumnLayout {
signal exportRequested(string filePath, string extra)
signal thicknessFileChosen(string filePath)
component PanelCheckBox: CheckBox {
id: toggle
indicator: Rectangle {
implicitWidth: 18
implicitHeight: 18
x: toggle.leftPadding
y: parent.height / 2 - height / 2
radius: Theme.radiusXs
color: toggle.checked ? Theme.primaryAccent : "transparent"
border.width: Theme.borderThin
border.color: toggle.checked ? Theme.primaryAccent : Theme.fieldBorder
Behavior on color {
ColorAnimation { duration: Theme.durationFast }
}
Behavior on border.color {
ColorAnimation { duration: Theme.durationFast }
}
IconImage {
anchors.centerIn: parent
source: "../icons/check.svg"
width: 12; height: 12
sourceSize.width: 12
sourceSize.height: 12
color: Theme.panelBackground
opacity: toggle.checked ? 1.0 : 0.0
Behavior on opacity {
NumberAnimation { duration: Theme.durationFast }
}
}
}
contentItem: Text {
text: toggle.text
color: Theme.headingColor
font.family: Theme.uiFontFamily
verticalAlignment: Text.AlignVCenter
leftPadding: toggle.indicator.width + toggle.spacing
font.pixelSize: toggle.font.pixelSize || Theme.fontXs
}
}
component BadgePill: Rectangle {
implicitWidth: badgeLabel.implicitWidth + 10
implicitHeight: 10
@@ -89,349 +47,79 @@ ColumnLayout {
}
}
Rectangle {
// ── READOUT ─────────────────────────────────────────────────────
PanelBox {
Layout.fillWidth: true
implicitHeight: readoutCard.implicitHeight + 24
color: Theme.sidePanelBackground
radius: Theme.sidePanelRadius
border.color: Theme.sideBorder
border.width: 1
Layout.preferredHeight: readoutCol.implicitHeight + 24
ColumnLayout {
id: readoutCard
anchors {
left: parent.left
right: parent.right
top: parent.top
topMargin: 12
}
spacing: 0
id: readoutCol
anchors.fill: parent
anchors.margins: 12
spacing: 8
// Header Inside the Box
Label {
text: "READOUT"
color: Theme.sideMutedText
font.family: Theme.uiFontFamily
font.pixelSize: Theme.fontSm
font.letterSpacing: 1.5
font.bold: true
Layout.leftMargin: 14
Layout.rightMargin: 14
Layout.topMargin: 2
Layout.bottomMargin: 10
}
SectionTitle { text: "READOUT" }
// Min Temp Row
Item {
Layout.fillWidth: true
implicitHeight: 32
Label {
anchors.left: parent.left
anchors.leftMargin: 14
anchors.verticalCenter: parent.verticalCenter
text: "MIN TEMP"
color: Theme.sideMutedText
font.family: Theme.uiFontFamily
font.pixelSize: Theme.fontSm
font.bold: true
}
Row {
anchors.right: parent.right
anchors.rightMargin: 14
anchors.verticalCenter: parent.verticalCenter
spacing: 4
Label {
text: s.min !== undefined ? s.min : "—"
color: Theme.sensorLow
font.family: Theme.codeFontFamily
font.pixelSize: Theme.fontLg
font.bold: true
}
Label {
visible: (s.minIndex !== undefined) && s.minIndex >= 0
text: "#" + (s.minIndex !== undefined ? s.minIndex : "")
color: Theme.sideMutedText
font.family: Theme.uiFontFamily
font.pixelSize: Theme.font2xs
anchors.bottom: parent.bottom
anchors.bottomMargin: 2
}
}
ReadoutStat {
label: "Min Temp"
value: s.min !== undefined
? s.min + ((s.minIndex !== undefined && s.minIndex >= 0) ? " #" + s.minIndex : "")
: "—"
valueColor: Theme.sensorLow
}
Rectangle {
Layout.fillWidth: true
height: 1
color: Theme.cardBorder
ReadoutStat {
label: "Max Temp"
value: s.max !== undefined
? s.max + ((s.maxIndex !== undefined && s.maxIndex >= 0) ? " #" + s.maxIndex : "")
: "—"
valueColor: Theme.sensorHigh
}
// Max Temp Row
Item {
Layout.fillWidth: true
implicitHeight: 32
Label {
anchors.left: parent.left
anchors.leftMargin: 14
anchors.verticalCenter: parent.verticalCenter
text: "MAX TEMP"
color: Theme.sideMutedText
font.family: Theme.uiFontFamily
font.pixelSize: Theme.fontSm
font.bold: true
}
Row {
anchors.right: parent.right
anchors.rightMargin: 14
anchors.verticalCenter: parent.verticalCenter
spacing: 4
Label {
text: s.max !== undefined ? s.max : "—"
color: Theme.sensorHigh
font.family: Theme.codeFontFamily
font.pixelSize: Theme.fontLg
font.bold: true
}
Label {
visible: (s.maxIndex !== undefined) && s.maxIndex >= 0
text: "#" + (s.maxIndex !== undefined ? s.maxIndex : "")
color: Theme.sideMutedText
font.family: Theme.uiFontFamily
font.pixelSize: Theme.font2xs
anchors.bottom: parent.bottom
anchors.bottomMargin: 2
}
}
ReadoutStat {
label: "Diff"
value: s.diff !== undefined ? s.diff : "—"
valueColor: Theme.diffAccent
}
Rectangle {
Layout.fillWidth: true
height: 1
color: Theme.cardBorder
ReadoutStat {
label: "Average"
value: s.avg !== undefined ? s.avg : "—"
}
// Differential Row
Item {
Layout.fillWidth: true
implicitHeight: 32
Label {
anchors.left: parent.left
anchors.leftMargin: 14
anchors.verticalCenter: parent.verticalCenter
text: "DIFF"
color: Theme.sideMutedText
font.family: Theme.uiFontFamily
font.pixelSize: Theme.fontSm
font.bold: true
}
Label {
anchors.right: parent.right
anchors.rightMargin: 14
anchors.verticalCenter: parent.verticalCenter
text: s.diff !== undefined ? s.diff : "—"
color: Theme.diffAccent
font.family: Theme.codeFontFamily
font.pixelSize: Theme.fontLg
font.bold: true
}
ReadoutStat {
label: "Sigma (Σ)"
value: s.sigma !== undefined ? s.sigma : "—"
}
Rectangle {
Layout.fillWidth: true
height: 1
color: Theme.cardBorder
ReadoutStat {
label: "3Σ Value"
value: s.threeSigma !== undefined ? s.threeSigma : "—"
}
// Average Row
Item {
Layout.fillWidth: true
implicitHeight: 32
Label {
anchors.left: parent.left
anchors.leftMargin: 14
anchors.verticalCenter: parent.verticalCenter
text: "AVERAGE"
color: Theme.sideMutedText
font.family: Theme.uiFontFamily
font.pixelSize: Theme.fontSm
font.bold: true
}
Label {
anchors.right: parent.right
anchors.rightMargin: 14
anchors.verticalCenter: parent.verticalCenter
text: s.avg !== undefined ? s.avg : "—"
color: Theme.headingColor
font.family: Theme.codeFontFamily
font.pixelSize: Theme.fontLg
font.bold: true
}
}
Rectangle {
Layout.fillWidth: true
height: 1
color: Theme.cardBorder
}
// Sigma Row
Item {
Layout.fillWidth: true
implicitHeight: 32
Label {
anchors.left: parent.left
anchors.leftMargin: 14
anchors.verticalCenter: parent.verticalCenter
text: "SIGMA (\u03A3)"
color: Theme.sideMutedText
font.family: Theme.uiFontFamily
font.pixelSize: Theme.fontSm
font.bold: true
}
Label {
anchors.right: parent.right
anchors.rightMargin: 14
anchors.verticalCenter: parent.verticalCenter
text: s.sigma !== undefined ? s.sigma : "—"
color: Theme.headingColor
font.family: Theme.codeFontFamily
font.pixelSize: Theme.fontLg
font.bold: true
}
}
Rectangle {
Layout.fillWidth: true
height: 1
color: Theme.cardBorder
}
// 3-Sigma Row
Item {
Layout.fillWidth: true
implicitHeight: 32
Label {
anchors.left: parent.left
anchors.leftMargin: 14
anchors.verticalCenter: parent.verticalCenter
text: "3\u03A3 VALUE"
color: Theme.sideMutedText
font.family: Theme.uiFontFamily
font.pixelSize: Theme.fontSm
font.bold: true
}
Label {
anchors.right: parent.right
anchors.rightMargin: 14
anchors.verticalCenter: parent.verticalCenter
text: s.threeSigma !== undefined ? s.threeSigma : "—"
color: Theme.headingColor
font.family: Theme.codeFontFamily
font.pixelSize: Theme.fontLg
font.bold: true
}
}
Rectangle {
ReadoutStat {
visible: s.ecMinDelta !== undefined
Layout.fillWidth: true
height: 1
color: Theme.cardBorder
label: "E-C Δ Min"
value: s.ecMinDelta !== undefined
? s.ecMinDelta.toFixed(2) + " (#" + s.ecMinEdgeIndex + "→#" + s.ecMinCenterIndex + ")"
: "—"
}
// Edge-Center \u0394 min Row (per-family pair tables — see ADR-0002)
Item {
visible: s.ecMinDelta !== undefined
Layout.fillWidth: true
implicitHeight: 32
Label {
anchors.left: parent.left
anchors.leftMargin: 14
anchors.verticalCenter: parent.verticalCenter
text: "E-C \u0394 MIN"
color: Theme.sideMutedText
font.family: Theme.uiFontFamily
font.pixelSize: Theme.fontSm
font.bold: true
}
Label {
anchors.right: parent.right
anchors.rightMargin: 14
anchors.verticalCenter: parent.verticalCenter
text: s.ecMinDelta !== undefined
? s.ecMinDelta.toFixed(2) + " (#" + s.ecMinEdgeIndex + "\u2192#" + s.ecMinCenterIndex + ")"
: "—"
color: Theme.headingColor
font.family: Theme.codeFontFamily
font.pixelSize: Theme.fontSm
font.bold: true
}
}
Rectangle {
ReadoutStat {
visible: s.ecMaxDelta !== undefined
Layout.fillWidth: true
height: 1
color: Theme.cardBorder
}
// Edge-Center \u0394 max Row
Item {
visible: s.ecMaxDelta !== undefined
Layout.fillWidth: true
implicitHeight: 32
Label {
anchors.left: parent.left
anchors.leftMargin: 14
anchors.verticalCenter: parent.verticalCenter
text: "E-C \u0394 MAX"
color: Theme.sideMutedText
font.family: Theme.uiFontFamily
font.pixelSize: Theme.fontSm
font.bold: true
}
Label {
anchors.right: parent.right
anchors.rightMargin: 14
anchors.verticalCenter: parent.verticalCenter
text: s.ecMaxDelta !== undefined
? s.ecMaxDelta.toFixed(2) + " (#" + s.ecMaxEdgeIndex + "\u2192#" + s.ecMaxCenterIndex + ")"
: "—"
color: Theme.headingColor
font.family: Theme.codeFontFamily
font.pixelSize: Theme.fontSm
font.bold: true
}
label: "E-C Δ Max"
value: s.ecMaxDelta !== undefined
? s.ecMaxDelta.toFixed(2) + " (#" + s.ecMaxEdgeIndex + "→#" + s.ecMaxCenterIndex + ")"
: "—"
}
}
}
Rectangle {
// ── DISPLAY ─────────────────────────────────────────────────────
PanelBox {
Layout.fillWidth: true
implicitHeight: displayCard.implicitHeight + 24
color: Theme.sidePanelBackground
radius: Theme.sidePanelRadius
border.color: Theme.sideBorder
border.width: 1
Layout.preferredHeight: displayCard.implicitHeight + 24
ColumnLayout {
id: displayCard
anchors {
left: parent.left
right: parent.right
top: parent.top
margins: 12
}
anchors.fill: parent
anchors.margins: 12
spacing: 8
Label {
text: "DISPLAY"
color: Theme.sideMutedText
font.family: Theme.uiFontFamily
font.pixelSize: Theme.fontSm
font.letterSpacing: 1.5
font.bold: true
Layout.bottomMargin: 4
}
SectionTitle { text: "DISPLAY" }
PanelCheckBox {
id: thicknessToggle
@@ -491,7 +179,7 @@ ColumnLayout {
font.pixelSize: Theme.fontSm
Layout.preferredWidth: 52
}
Slider {
PanelSlider {
id: heatmapSlider
from: 0
to: 1
@@ -502,19 +190,6 @@ ColumnLayout {
visible: heatmapSlider.hovered
text: Math.round(heatmapSlider.value * 100) + "%"
}
handle: Rectangle {
x: heatmapSlider.leftPadding + heatmapSlider.visualPosition * (heatmapSlider.availableWidth - width)
y: heatmapSlider.topPadding + heatmapSlider.availableHeight / 2 - height / 2
implicitWidth: 18
implicitHeight: 18
radius: 9
color: Theme.primaryAccent
scale: heatmapSlider.pressed ? 1.15 : 1.0
Behavior on scale {
NumberAnimation { duration: Theme.durationFast; easing.type: Theme.easeStandard }
}
}
}
Label {
text: Math.round(heatmapSlider.value * 100) + "%"
@@ -528,33 +203,18 @@ ColumnLayout {
}
}
Rectangle {
// ── THRESHOLDS ──────────────────────────────────────────────────
PanelBox {
Layout.fillWidth: true
implicitHeight: thresholdCard.implicitHeight + 24
color: Theme.sidePanelBackground
radius: Theme.sidePanelRadius
border.color: Theme.sideBorder
border.width: 1
Layout.preferredHeight: thresholdCard.implicitHeight + 24
ColumnLayout {
id: thresholdCard
anchors {
left: parent.left
right: parent.right
top: parent.top
margins: 12
}
anchors.fill: parent
anchors.margins: 12
spacing: 6
Label {
text: "THRESHOLDS"
color: Theme.sideMutedText
font.family: Theme.uiFontFamily
font.pixelSize: Theme.fontSm
font.letterSpacing: 1.5
font.bold: true
Layout.bottomMargin: 4
}
SectionTitle { text: "THRESHOLDS" }
Label {
text: "Set Point (°C)"