Add SettingsTab, StatusTab, DataTab and wire up DeviceController

- SettingsTab: chamber ID, master CSV mapping (families A-Z), wafer
  behavior toggle, light/dark mode toggle, Edit CSV Metadata dialog
- StatusTab: connection status card, wafer info, activity log (blank
  until Detect Wafer fires from the side rail)
- DataTab: empty state, ready for parsed data
- HomePage: side rail buttons dispatch device actions and jump to
  Status tab; selectedSideActionIndex defaults to -1 on startup
- DeviceController registered as QML context property in main.py
- LocalSettings: added status persistence fields
- Theme: added subheadingColor and disabledText
- Added serialcomm/ package and backend data/graph modules
- gitignore: restore clean version
This commit is contained in:
Jack.Le
2026-05-28 15:37:12 -07:00
parent 6d33da2eab
commit e306db6816
25 changed files with 2457 additions and 106 deletions
+153
View File
@@ -0,0 +1,153 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import ISC
// ===== Data Tab =====
// Displays parsed temperature data in a scrollable table.
// Column 0 = Row index, remaining columns = Sensor1, Sensor2, ...
Item {
id: root
anchors.fill: parent
readonly property int rowCount: deviceController.dataRowCount
// Re-layout columns whenever the model is reset
Connections {
target: deviceController
function onParsedDataReady(result) {
if (result && result.success) {
dataTable.forceLayout()
}
}
}
// ===== Empty State =====
Column {
anchors.centerIn: parent
spacing: 16
visible: root.rowCount === 0
Label {
text: "No Data"
font.pixelSize: 24
font.bold: true
color: Theme.headingColor
anchors.horizontalCenter: parent.horizontalCenter
}
Label {
text: "Read and parse wafer data to see temperature readings here."
font.pixelSize: 14
color: Theme.bodyColor
anchors.horizontalCenter: parent.horizontalCenter
wrapMode: Text.WordWrap
}
}
// ===== Data Table =====
ColumnLayout {
anchors.fill: parent
anchors.margins: Theme.panelPadding
spacing: Theme.rightPaneGap
visible: root.rowCount > 0
// --- Header row ---
RowLayout {
Layout.fillWidth: true
spacing: Theme.rightPaneGap
Label {
text: "Temperature Data"
font.pixelSize: 18
font.bold: true
color: Theme.headingColor
}
Item { Layout.fillWidth: true }
Label {
text: deviceController.dataRowCount + " rows × " +
deviceController.dataColCount + " sensors"
font.pixelSize: 13
color: Theme.bodyColor
}
}
// --- Table container ---
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
color: Theme.panelBackground
border.color: Theme.cardBorder
border.width: Theme.borderThin
radius: Theme.radiusSm
clip: true
ColumnLayout {
anchors.fill: parent
anchors.margins: 1
spacing: 0
// Column header strip
HorizontalHeaderView {
id: headerView
Layout.fillWidth: true
syncView: dataTable
clip: true
delegate: Rectangle {
implicitHeight: 28
color: Theme.cardBackground
border.color: Theme.cardBorder
border.width: 1
Text {
anchors.centerIn: parent
// 'display' is the Qt.DisplayRole value from headerData()
text: display !== undefined ? display : ""
color: Theme.headingColor
font.pixelSize: 11
font.bold: true
elide: Text.ElideRight
}
}
}
// Data rows
TableView {
id: dataTable
Layout.fillWidth: true
Layout.fillHeight: true
model: deviceController.dataModel
clip: true
reuseItems: true
columnWidthProvider: function(col) {
if (col === 0) return 52 // row index column
const sensorCols = Math.max(1, dataTable.columns - 1)
const available = dataTable.width - 52
return Math.max(52, Math.min(90, available / sensorCols))
}
rowHeightProvider: function() { return 24 }
delegate: Rectangle {
color: row % 2 === 0 ? Theme.panelBackground : Theme.cardBackground
Text {
anchors.centerIn: parent
text: display !== undefined ? display : ""
color: Theme.bodyColor
font.pixelSize: 11
elide: Text.ElideRight
}
}
ScrollBar.horizontal: ScrollBar { policy: ScrollBar.AsNeeded }
ScrollBar.vertical: ScrollBar { policy: ScrollBar.AsNeeded }
}
}
}
}
}