feat(ui): decouple QML page modules and update tab layouts

Extract ReadoutPanel, WaferMapView, and TransportBar into reusable components and bind tabs to the new session controllers.
This commit is contained in:
jack
2026-06-25 13:48:20 -07:00
parent f4621f1faf
commit cfadbdf1c3
6 changed files with 205 additions and 79 deletions
+54 -20
View File
@@ -14,16 +14,26 @@ Rectangle {
border.width: Theme.borderStrong
// ===== Navigation Model =====
// Primary navigation shown in the left rail.
property var sideActions: ["DETECT WAFER", "READ MEMORY", "OPEN CSV IN EXCEL", "ERASE MEMORY", "IMPORT DATA", "STORED DATA"]
// ---------------------------------------------------------------------------
// TODO P1.1: Delete these 3 property blocks — superseded by mockup rail
//
// THINKING:
// The new rail uses a pill-tab-bar for navigation (Status/Data/Map) instead
// of sideActions[] + bottomTabs[]. The Repeaters below that consume these
// arrays are also deleted with the old layout (P1.1).
// selectedSideActionIndex is dead — the new rail has no concept of a
// globally-selected side action. selectedTabIndex stays, redefined below.
//
// Cross-ref: P1.2 (pill tabs), P1.3 (context panels), P1.4 (workspace)
// ---------------------------------------------------------------------------
property var sideActions: ["DETECT WAFER", "READ MEMORY", "ERASE MEMORY"]
// ===== Footer Tab Model =====
// Footer tabs drive the active workspace section.
property var bottomTabs: ["Status", "Graph", "Data", "Wafer Map", "Compare", "Split", "Settings", "About"]
property var bottomTabs: ["Status", "Data", "Wafer Map", "Settings"]
// ===== View State =====
property int selectedTabIndex: 0
property int selectedSideActionIndex: -1 // nothing active on startup
property int selectedSideActionIndex: -1
property bool memoryRead: false
property bool waferDetected: false
@@ -80,6 +90,22 @@ Rectangle {
}
}
// ---------------------------------------------------------------------------
// TODO P1.1: Delete importFileDialog + storedDataDialog (and the
// `selectedTabIndex = 3` lines inside them)
//
// THINKING:
// These dialogs were only opened from the old side-rail buttons
// "IMPORT DATA" (index 4) and "STORED DATA" (index 5). With the
// mockup rail, the Map tab's file list (P1.3) replaces both — it
// drives `streamController.loadFile()` directly from a file_browser
// Repeater. Keeping these dead dialogs would bloat the QML and
// confuse future contributors.
//
// `selectedTabIndex = 3` is also stale (Map tab is index 2 now).
// The replacement flow: file_row.onClicked → loadFile() →
// selectedTabIndex = 2.
// ---------------------------------------------------------------------------
FileDialog {
id: importFileDialog
title: "Import CSV / ZWafer file"
@@ -109,6 +135,27 @@ Rectangle {
}
// ===== Main Two-Column Layout ======
// ---------------------------------------------------------------------------
// TODO P1.1: Delete the ENTIRE RowLayout below (lines ~112-341) — old
// side-rail + workspace + footer-tab-strip.
//
// THINKING:
// This ~230-line RowLayout is being replaced by:
// P1.2 — Pill tab bar (BOX 1, top of rail)
// P1.3 — Context-sensitive panel (BOX 2, mid rail)
// P1.5 — Hardware status footer (BOX 3, below BOX 2)
// P1.6 — Settings/About utility buttons (BOX 4, rail bottom)
// P1.4 — Workspace StackLayout (fills right side)
//
// None of the old structure (Repeater for sideActions[], Repeater for
// bottomTabs[], footer tab strip) survives. Keeping it would cause
// double-rendering or visual conflicts.
//
// Keep: saveDirDialog (FolderDialog), cleanFolderUrl(), _doDetect(),
// and all Connections blocks (lines 31-61).
//
// Cross-ref: P1.2, P1.3, P1.4, P1.5, P1.6
// ---------------------------------------------------------------------------
RowLayout {
anchors.fill: parent
spacing: 0
@@ -141,10 +188,8 @@ Rectangle {
switch (index) {
case 0: return true // DETECT WAFER
case 1: return root.waferDetected // READ MEMORY
case 2: return root.memoryRead // OPEN CSV IN EXCEL
case 3: return root.waferDetected // ERASE MEMORY
case 4: return root.memoryRead // IMPORT DATA
default: return true // STORED DATA
case 2: return root.waferDetected // ERASE MEMORY
default: return true
}
}
property bool isActive: index === root.selectedSideActionIndex
@@ -167,22 +212,11 @@ Rectangle {
deviceController.readMemoryAsync()
}
else if (index === 2) {
deviceController.openCsvFile()
}
else if (index === 3) {
// ERASE MEMORY
streamController.setMode("review")
streamController.stopStream()
deviceController.eraseMemory(deviceController.selectedPort || "")
}
else if (index === 4) {
// IMPORT DATA
importFileDialog.open()
}
else if (index === 5) {
// STORED DATA
storedDataDialog.open()
}
}
background: Rectangle {