import QtQuick import QtQuick.Layouts import QtQuick.Controls import QtQuick.Dialogs import ISC // ===== Status Tab ===== // Shows connection status, wafer info, and activity log. // Initially visible — displays connection status and activity log from start. ColumnLayout { id: root anchors.fill: parent anchors.margins: Theme.panelPadding spacing: Theme.rightPaneGap property alias waferFamilyCode: waferInfoFamily.text property alias waferSerialNumber: waferSerial.text property alias waferSensorCount: waferSensors.text property alias waferRuntime: waferRuntime.text property alias waferCycles: waferCycles.text property bool waferDetected: false // Data summary after parse property int dataRows: 0 property int dataCols: 0 property string csvPath: "" property bool dataParsed: false function cleanFolderUrl(url) { return decodeURIComponent(String(url).replace(/^file:\/\//, "")) } function currentFamilyCode() { var info = deviceController.lastWaferInfo return info && info.length > 0 ? (info[0] || "") : "" } function parseAndSavePendingRead() { deviceController.parseAndSaveData(root.currentFamilyCode(), deviceController.selectedPort || "") } FolderDialog { id: saveDirDialog title: "Choose a folder to save." onAccepted: { deviceController.setSaveDataDir(root.cleanFolderUrl(selectedFolder)) root.parseAndSavePendingRead() } } ColumnLayout { Layout.fillWidth: true Layout.fillHeight: true spacing: Theme.rightPaneGap // --- Connection Status --- Rectangle { Layout.fillWidth: true Layout.preferredHeight: 92 color: Theme.cardBackground border.color: { if (deviceController.connectionStatus === "Connected") return Theme.statusSuccessColor if (deviceController.connectionStatus === "Disconnected") return Theme.statusErrorColor return Theme.cardBorder } radius: Theme.radiusSm ColumnLayout { anchors.fill: parent anchors.margins: Theme.panelPadding spacing: 4 Text { text: deviceController.connectionStatus color: { if (deviceController.connectionStatus === "Connected") return Theme.statusSuccessColor if (deviceController.connectionStatus === "Disconnected") return Theme.statusErrorColor return Theme.bodyColor } font.bold: true font.pixelSize: 16 Layout.fillWidth: true } Text { text: "Port: " + (deviceController.selectedPort || "None selected") color: Theme.bodyColor font.pixelSize: 14 Layout.fillWidth: true } RowLayout { Layout.fillWidth: true spacing: 8 Layout.alignment: Qt.AlignVCenter Text { text: "Save dir: " + (deviceController.saveDataDir || "None selected") color: Theme.bodyColor font.pixelSize: 12 opacity: 0.7 elide: Text.ElideMiddle Layout.fillWidth: true Layout.alignment: Qt.AlignVCenter } Button { id: browseBtn text: "BROWSE..." font.pixelSize: 9 font.weight: Font.Medium implicitHeight: 20 implicitWidth: 65 hoverEnabled: true background: Rectangle { color: parent.hovered ? Theme.buttonNeutralHover : Theme.buttonNeutralBackground border.color: Theme.cardBorder border.width: 1 radius: Theme.radiusSm } contentItem: Text { text: parent.text color: Theme.bodyColor font: parent.font horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } onClicked: saveDirDialog.open() } } } } // --- Wafer Info --- GroupBox { title: "Wafer Information" visible: root.waferDetected Layout.fillWidth: true ColumnLayout { anchors.fill: parent anchors.margins: Theme.panelPadding spacing: 8 RowLayout { Layout.fillWidth: true spacing: Theme.rightPaneGap ColumnLayout { Layout.fillWidth: true spacing: 4 Text { text: "Family Code"; color: Theme.subheadingColor; font.pixelSize: 12 } Text { id: waferInfoFamily; text: "—"; color: Theme.bodyColor; font.pixelSize: 16; font.bold: true } } ColumnLayout { Layout.fillWidth: true spacing: 4 Text { text: "Serial Number"; color: Theme.subheadingColor; font.pixelSize: 12 } Text { id: waferSerial; text: "—"; color: Theme.bodyColor; font.pixelSize: 16; font.bold: true } } ColumnLayout { Layout.fillWidth: true spacing: 4 Text { text: "Sensor Count"; color: Theme.subheadingColor; font.pixelSize: 12 } Text { id: waferSensors; text: "—"; color: Theme.bodyColor; font.pixelSize: 16; font.bold: true } } } RowLayout { Layout.fillWidth: true spacing: Theme.rightPaneGap ColumnLayout { Layout.fillWidth: true spacing: 4 Text { text: "Runtime"; color: Theme.subheadingColor; font.pixelSize: 12 } Text { id: waferRuntime; text: "—"; color: Theme.bodyColor; font.pixelSize: 16; font.bold: true } } ColumnLayout { Layout.fillWidth: true spacing: 4 Text { text: "Cycles"; color: Theme.subheadingColor; font.pixelSize: 12 } Text { id: waferCycles; text: "—"; color: Theme.bodyColor; font.pixelSize: 16; font.bold: true } } } } } // --- Data Summary (shown after parse) --- GroupBox { title: "Data Summary" visible: root.dataParsed Layout.fillWidth: true RowLayout { anchors.fill: parent anchors.margins: Theme.panelPadding spacing: Theme.rightPaneGap ColumnLayout { Layout.fillWidth: true spacing: 4 Text { text: "Rows"; color: Theme.subheadingColor; font.pixelSize: 12 } Text { text: String(root.dataRows); color: Theme.bodyColor; font.pixelSize: 16; font.bold: true } } ColumnLayout { Layout.fillWidth: true spacing: 4 Text { text: "Sensors"; color: Theme.subheadingColor; font.pixelSize: 12 } Text { text: String(root.dataCols); color: Theme.bodyColor; font.pixelSize: 16; font.bold: true } } ColumnLayout { Layout.fillWidth: true spacing: 4 Text { text: "CSV"; color: Theme.subheadingColor; font.pixelSize: 12 } Text { text: root.csvPath; color: Theme.bodyColor; font.pixelSize: 12; elide: Text.ElideMiddle } } } } // --- Activity Log --- Rectangle { Layout.fillWidth: true Layout.fillHeight: true color: Theme.cardBackground border.color: Theme.cardBorder radius: Theme.radiusMd clip: true ColumnLayout { anchors.fill: parent spacing: 0 // Header Rectangle { Layout.fillWidth: true Layout.preferredHeight: 40 color: Theme.subtleSectionBackground RowLayout { anchors.fill: parent anchors.leftMargin: Theme.panelPadding anchors.rightMargin: Theme.panelPadding Label { text: "ACTIVITY LOG" color: Theme.bodyColor font.pixelSize: 10 font.letterSpacing: 1.8 font.weight: Font.Medium Layout.fillWidth: true Layout.alignment: Qt.AlignVCenter } Button { text: "REFRESH SESSION" font.pixelSize: 10 implicitHeight: 24 hoverEnabled: true background: Rectangle { color: parent.hovered ? Theme.buttonNeutralHover : "transparent" radius: Theme.radiusSm } contentItem: Text { text: parent.text color: Theme.bodyColor font: parent.font horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } onClicked: deviceController.clearSession() } Button { text: "CLEAR LOG" font.pixelSize: 10 implicitHeight: 24 hoverEnabled: true background: Rectangle { color: parent.hovered ? Theme.buttonNeutralHover : "transparent" radius: Theme.radiusSm } contentItem: Text { text: parent.text color: Theme.bodyColor font: parent.font horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } onClicked: deviceController.clearActivityLog() } } Rectangle { anchors.bottom: parent.bottom anchors.left: parent.left anchors.right: parent.right height: 1 color: Theme.cardBorder } } ScrollView { Layout.fillWidth: true Layout.fillHeight: true Layout.margins: Theme.panelPadding clip: true TextArea { id: activityLog width: parent.width text: qsTr("Welcome — use the side rail to detect a wafer, or import data to review.") readOnly: true font.family: "monospace" font.pixelSize: 12 wrapMode: TextArea.WordWrap color: Theme.bodyColor background: null } } } Connections { target: deviceController function onActivityLogUpdated(newLog) { activityLog.text = newLog } } } } // --- Signal Handlers --- Connections { target: deviceController function onLogMessage(message) { if (message == "CHOOSE_SAVE_DIR"){ saveDirDialog.open() } } // Any operation start (detect/read/erase/debug) latches the panel on. function onPortsUpdated() { // Status tab always visible now } function onDetectResult(result) { if (result && result.familyCode) { root.waferDetected = true waferInfoFamily.text = result.familyCode waferSerial.text = result.serialNumber waferSensors.text = String(result.sensorCount) waferRuntime.text = result.runtime + "s" waferCycles.text = String(result.cycleCount) } // On failure, keep the last displayed wafer info and do not change waferDetected. } function onStatusRestored() { // Show restored wafer info if available var info = deviceController.lastWaferInfo if (info && info.length > 0) { root.waferDetected = true waferInfoFamily.text = info[0] || "—" waferSerial.text = info[1] || "—" waferSensors.text = String(info[2] || 0) waferRuntime.text = (info[3] || 0) + "s" waferCycles.text = String(info[4] || 0) } // Show data summary if data was previously parsed if (deviceController.dataRowCount > 0) { root.dataParsed = true root.dataRows = deviceController.dataRowCount root.dataCols = deviceController.dataColCount root.csvPath = "" // CSV path not persisted as full path, just show it was parsed } } } Connections { target: deviceController function onReadResult(result) { root.dataParsed = false root.dataRows = 0 root.dataCols = 0 root.csvPath = "" if (result && result.success === true) saveDirDialog.open() } } Connections { target: deviceController function onParsedDataReady(result) { if (result && result.success) { root.dataParsed = true root.dataRows = result.rows root.dataCols = result.cols root.csvPath = result.csv_path || "" } else { root.dataParsed = false } } } }