import QtQuick import QtQuick.Controls import QtQuick.Controls.impl 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. ColumnLayout { spacing: 6 property var s: streamController.stats property alias showLabels: labelsToggle.checked property alias heatmapBlend: heatmapSlider.value property alias showThickness: thicknessToggle.checked signal exportRequested(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 radius: 9 color: Theme.fieldBackground border.color: Theme.cardBorder border.width: 1 property alias text: badgeLabel.text Label { id: badgeLabel anchors.centerIn: parent color: Theme.bodyColor font.pixelSize: Theme.font2xs font.weight: Font.Medium } } StreamControlPanel { Layout.fillWidth: true onExportRequested: function(filePath) { root.exportRequested(filePath); } } Rectangle { Layout.fillWidth: true implicitHeight: readoutCard.implicitHeight + 24 color: Theme.sidePanelBackground radius: Theme.sidePanelRadius border.color: Theme.sideBorder border.width: 1 ColumnLayout { id: readoutCard anchors { left: parent.left right: parent.right top: parent.top topMargin: 12 } spacing: 0 // 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 } // Min Temp Row RowLayout { Layout.fillWidth: true Layout.leftMargin: 14 Layout.rightMargin: 14 Layout.preferredHeight: 32 Label { text: "MIN TEMP" color: Theme.sideMutedText font.family: Theme.uiFontFamily font.pixelSize: Theme.fontSm font.bold: true } Item { Layout.fillWidth: true } RowLayout { 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 Layout.alignment: Qt.AlignBottom bottomPadding: 3 } } } Rectangle { Layout.fillWidth: true height: 1 color: Theme.cardBorder } // Max Temp Row RowLayout { Layout.fillWidth: true Layout.leftMargin: 14 Layout.rightMargin: 14 Layout.preferredHeight: 32 Label { text: "MAX TEMP" color: Theme.sideMutedText font.family: Theme.uiFontFamily font.pixelSize: Theme.fontSm font.bold: true } Item { Layout.fillWidth: true } RowLayout { 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 Layout.alignment: Qt.AlignBottom bottomPadding: 3 } } } Rectangle { Layout.fillWidth: true height: 1 color: Theme.cardBorder } // Differential Row RowLayout { Layout.fillWidth: true Layout.leftMargin: 14 Layout.rightMargin: 14 Layout.preferredHeight: 32 Label { text: "DIFF" color: Theme.sideMutedText font.family: Theme.uiFontFamily font.pixelSize: Theme.fontSm font.bold: true } Item { Layout.fillWidth: true } Label { text: s.diff !== undefined ? s.diff : "—" color: Theme.diffAccent font.family: Theme.codeFontFamily font.pixelSize: Theme.fontLg font.bold: true } } Rectangle { Layout.fillWidth: true height: 1 color: Theme.cardBorder } // Average Row RowLayout { Layout.fillWidth: true Layout.leftMargin: 14 Layout.rightMargin: 14 Layout.preferredHeight: 32 Label { text: "AVERAGE" color: Theme.sideMutedText font.family: Theme.uiFontFamily font.pixelSize: Theme.fontSm font.bold: true } Item { Layout.fillWidth: true } Label { 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 RowLayout { Layout.fillWidth: true Layout.leftMargin: 14 Layout.rightMargin: 14 Layout.preferredHeight: 32 Label { text: "SIGMA (Σ)" color: Theme.sideMutedText font.family: Theme.uiFontFamily font.pixelSize: Theme.fontSm font.bold: true } Item { Layout.fillWidth: true } Label { 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 RowLayout { Layout.fillWidth: true Layout.leftMargin: 14 Layout.rightMargin: 14 Layout.preferredHeight: 32 Label { text: "3Σ VALUE" color: Theme.sideMutedText font.family: Theme.uiFontFamily font.pixelSize: Theme.fontSm font.bold: true } Item { Layout.fillWidth: true } Label { text: s.threeSigma !== undefined ? s.threeSigma : "—" color: Theme.headingColor font.family: Theme.codeFontFamily font.pixelSize: Theme.fontLg font.bold: true } } } } Rectangle { Layout.fillWidth: true implicitHeight: displayCard.implicitHeight + 24 color: Theme.sidePanelBackground radius: Theme.sidePanelRadius border.color: Theme.sideBorder border.width: 1 ColumnLayout { id: displayCard anchors { left: parent.left right: parent.right top: parent.top 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 } PanelCheckBox { id: thicknessToggle text: "Show Thickness" checked: false font.pixelSize: Theme.fontSm } PanelCheckBox { id: labelsToggle text: "Labels" checked: true font.pixelSize: Theme.fontSm } PanelCheckBox { id: clusterAverageToggle text: "Average Clusters" checked: streamController.clusterAveragingEnabled font.pixelSize: Theme.fontSm onCheckedChanged: streamController.clusterAveragingEnabled = checked } Rectangle { Layout.fillWidth: true height: 1 color: Theme.cardBorder } RowLayout { Layout.fillWidth: true spacing: 6 Label { text: "Heatmap" color: Theme.bodyColor font.pixelSize: Theme.fontSm Layout.preferredWidth: 52 } Slider { id: heatmapSlider from: 0 to: 1 value: 0 Layout.fillWidth: true AppToolTip { 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) + "%" color: Theme.bodyColor font.pixelSize: Theme.fontSm font.weight: Font.Medium Layout.preferredWidth: 32 horizontalAlignment: Text.AlignRight } } } } Rectangle { Layout.fillWidth: true implicitHeight: thresholdCard.implicitHeight + 24 color: Theme.sidePanelBackground radius: Theme.sidePanelRadius border.color: Theme.sideBorder border.width: 1 ColumnLayout { id: thresholdCard anchors { left: parent.left right: parent.right top: parent.top 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 } Label { text: "Set Point (°C)" color: Theme.bodyColor font.pixelSize: Theme.fontSm } TextField { id: spField Layout.fillWidth: true text: "149.0" font.pixelSize: Theme.fontSm inputMethodHints: Qt.ImhFormattedNumbersOnly color: Theme.fieldText placeholderTextColor: Theme.fieldPlaceholder selectedTextColor: Theme.fieldBackground selectionColor: Theme.fieldText background: Rectangle { radius: Theme.radiusXs color: Theme.fieldBackground border.width: spField.activeFocus ? Theme.borderStrong : Theme.borderThin border.color: spField.activeFocus ? Theme.fieldBorderFocus : Theme.fieldBorder Behavior on color { ColorAnimation { duration: Theme.durationFast } } Behavior on border.color { ColorAnimation { duration: Theme.durationFast } } } onEditingFinished: pushThresholds() } Label { text: "Margin (±°C)" color: Theme.bodyColor font.pixelSize: Theme.fontSm } TextField { id: mgField Layout.fillWidth: true text: "1.0" font.pixelSize: Theme.fontSm inputMethodHints: Qt.ImhFormattedNumbersOnly color: Theme.fieldText placeholderTextColor: Theme.fieldPlaceholder selectedTextColor: Theme.fieldBackground selectionColor: Theme.fieldText background: Rectangle { radius: Theme.radiusXs color: Theme.fieldBackground border.width: mgField.activeFocus ? Theme.borderStrong : Theme.borderThin border.color: mgField.activeFocus ? Theme.fieldBorderFocus : Theme.fieldBorder Behavior on color { ColorAnimation { duration: Theme.durationFast } } Behavior on border.color { ColorAnimation { duration: Theme.durationFast } } } onEditingFinished: pushThresholds() } PanelCheckBox { id: autoCheck text: "Auto range (mean ± 1σ)" checked: true font.pixelSize: Theme.fontSm onCheckedChanged: pushThresholds() } } } Item { Layout.fillHeight: true } function pushThresholds() { var sp = parseFloat(spField.text) || 149.0; var mg = parseFloat(mgField.text) || 1.0; streamController.setThresholds(sp, mg, autoCheck.checked); } }