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:
@@ -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)"
|
||||
|
||||
Reference in New Issue
Block a user