diff --git a/src/pygui/ISC/Tabs/WaferMapTab.qml b/src/pygui/ISC/Tabs/WaferMapTab.qml index 206c4d7..0edc5de 100644 --- a/src/pygui/ISC/Tabs/WaferMapTab.qml +++ b/src/pygui/ISC/Tabs/WaferMapTab.qml @@ -26,8 +26,8 @@ Item { ColumnLayout { anchors.fill: parent - anchors.margins: Theme.panelPadding - spacing: Theme.rightPaneGap + anchors.margins: 16 + spacing: 16 // ── Toolbar ─────────────────────────────────────────────────────── RowLayout { @@ -176,7 +176,7 @@ Item { RowLayout { Layout.fillWidth: true Layout.fillHeight: true - spacing: Theme.rightPaneGap + spacing: 16 // Source panel — bordered card Rectangle { @@ -207,6 +207,18 @@ Item { showLabels: readoutPanel.showLabels } + // Horizontal separation line with vertical padding + Item { + Layout.fillWidth: true + implicitHeight: 32 + Rectangle { + anchors.centerIn: parent + width: parent.width + height: 1 + color: Theme.cardBorder + } + } + TransportBar { Layout.fillWidth: true } } diff --git a/src/pygui/ISC/Tabs/components/ReadoutPanel.qml b/src/pygui/ISC/Tabs/components/ReadoutPanel.qml index a8187ba..e302d9d 100644 --- a/src/pygui/ISC/Tabs/components/ReadoutPanel.qml +++ b/src/pygui/ISC/Tabs/components/ReadoutPanel.qml @@ -16,118 +16,120 @@ ColumnLayout { font.pixelSize: 10 font.letterSpacing: 1.8 font.weight: Font.Medium - bottomPadding: 4 + topPadding: 6 + bottomPadding: 8 } - GridLayout { - columns: 2 - rowSpacing: 4 - columnSpacing: 4 + Rectangle { Layout.fillWidth: true + implicitHeight: statsLayout.implicitHeight + 20 + color: Theme.subtleSectionBackground + radius: Theme.radiusSm + border.color: Theme.cardBorder + border.width: 1 - // MIN TEMP - Rectangle { - Layout.fillWidth: true; height: 52 - color: Theme.subtleSectionBackground; radius: Theme.radiusSm - border.color: Theme.cardBorder; border.width: 1 - ColumnLayout { - anchors { fill: parent; margins: 7 } - spacing: 1 - Label { text: "MIN TEMP"; color: Theme.bodyColor; font.pixelSize: 9; font.letterSpacing: 1 } - Label { - text: s.min !== undefined ? s.min + " #" + s.minIndex : "—" - color: Theme.sensorLow - font.pixelSize: 15; font.weight: Font.Bold + ColumnLayout { + id: statsLayout + anchors { fill: parent; margins: 10 } + spacing: 8 + + // Min Temp Row + RowLayout { + Layout.fillWidth: true + Label { text: "Min Temp"; color: Theme.bodyColor; font.pixelSize: 11 } + Item { Layout.fillWidth: true } + RowLayout { + spacing: 4 + Label { + text: s.min !== undefined ? s.min : "—" + color: Theme.sensorLow + font.pixelSize: 13; font.weight: Font.Bold + } + Label { + text: s.minIndex !== undefined ? "#" + s.minIndex : "" + color: Theme.bodyColor + font.pixelSize: 10 + } } } - } - // MAX TEMP - Rectangle { - Layout.fillWidth: true; height: 52 - color: Theme.subtleSectionBackground; radius: Theme.radiusSm - border.color: Theme.cardBorder; border.width: 1 - ColumnLayout { - anchors { fill: parent; margins: 7 } - spacing: 1 - Label { text: "MAX TEMP"; color: Theme.bodyColor; font.pixelSize: 9; font.letterSpacing: 1 } - Label { - text: s.max !== undefined ? s.max + " #" + s.maxIndex : "—" - color: Theme.sensorHigh - font.pixelSize: 15; font.weight: Font.Bold + // Max Temp Row + RowLayout { + Layout.fillWidth: true + Label { text: "Max Temp"; color: Theme.bodyColor; font.pixelSize: 11 } + Item { Layout.fillWidth: true } + RowLayout { + spacing: 4 + Label { + text: s.max !== undefined ? s.max : "—" + color: Theme.sensorHigh + font.pixelSize: 13; font.weight: Font.Bold + } + Label { + text: s.maxIndex !== undefined ? "#" + s.maxIndex : "" + color: Theme.bodyColor + font.pixelSize: 10 + } } } - } - // DIFFERENTIAL - Rectangle { - Layout.fillWidth: true; height: 52 - color: Theme.subtleSectionBackground; radius: Theme.radiusSm - border.color: Theme.cardBorder; border.width: 1 - ColumnLayout { - anchors { fill: parent; margins: 7 } - spacing: 1 - Label { text: "DIFFERENTIAL"; color: Theme.bodyColor; font.pixelSize: 9; font.letterSpacing: 1 } + Rectangle { Layout.fillWidth: true; height: 1; color: Theme.cardBorder } + + // Differential Row + RowLayout { + Layout.fillWidth: true + Label { text: "Differential"; color: Theme.bodyColor; font.pixelSize: 11 } + Item { Layout.fillWidth: true } Label { text: s.diff !== undefined ? s.diff : "—" color: Theme.headingColor - font.pixelSize: 15; font.weight: Font.Bold + font.pixelSize: 13; font.weight: Font.Bold } } - } - // AVERAGE - Rectangle { - Layout.fillWidth: true; height: 52 - color: Theme.subtleSectionBackground; radius: Theme.radiusSm - border.color: Theme.cardBorder; border.width: 1 - ColumnLayout { - anchors { fill: parent; margins: 7 } - spacing: 1 - Label { text: "AVERAGE"; color: Theme.bodyColor; font.pixelSize: 9; font.letterSpacing: 1 } + // Average Row + RowLayout { + Layout.fillWidth: true + Label { text: "Average"; color: Theme.bodyColor; font.pixelSize: 11 } + Item { Layout.fillWidth: true } Label { text: s.avg !== undefined ? s.avg : "—" color: Theme.headingColor - font.pixelSize: 15; font.weight: Font.Bold + font.pixelSize: 13; font.weight: Font.Bold } } - } - } - // SIGMA — full-width - Rectangle { - Layout.fillWidth: true; height: 44 - color: Theme.subtleSectionBackground; radius: Theme.radiusSm - border.color: Theme.cardBorder; border.width: 1 - RowLayout { - anchors { fill: parent; leftMargin: 7; rightMargin: 7; topMargin: 4; bottomMargin: 4 } - ColumnLayout { - spacing: 1 - Label { text: "SIGMA (σ)"; color: Theme.bodyColor; font.pixelSize: 9; font.letterSpacing: 1 } - Label { text: "3σ"; color: Theme.bodyColor; font.pixelSize: 9; font.letterSpacing: 1 } - } - Item { Layout.fillWidth: true } - ColumnLayout { - spacing: 1 + Rectangle { Layout.fillWidth: true; height: 1; color: Theme.cardBorder } + + // Sigma Row + RowLayout { + Layout.fillWidth: true + Label { text: "Sigma (σ)"; color: Theme.bodyColor; font.pixelSize: 11 } + Item { Layout.fillWidth: true } Label { text: s.sigma !== undefined ? s.sigma : "—" color: Theme.headingColor - font.pixelSize: 15; font.weight: Font.Bold - Layout.alignment: Qt.AlignRight + font.pixelSize: 13; font.weight: Font.Bold } + } + + // 3-Sigma Row + RowLayout { + Layout.fillWidth: true + Label { text: "3σ Value"; color: Theme.bodyColor; font.pixelSize: 11 } + Item { Layout.fillWidth: true } Label { text: s.threeSigma !== undefined ? s.threeSigma : "—" color: Theme.bodyColor font.pixelSize: 12; font.weight: Font.Medium - Layout.alignment: Qt.AlignRight } } } } - Item { height: 8 } + Item { height: 12 } Rectangle { Layout.fillWidth: true; height: 1; color: Theme.cardBorder } - Item { height: 8 } + Item { height: 12 } // ── DISPLAY ─────────────────────────────────────────────────────────── Label { @@ -136,7 +138,8 @@ ColumnLayout { font.pixelSize: 10 font.letterSpacing: 1.8 font.weight: Font.Medium - bottomPadding: 4 + topPadding: 6 + bottomPadding: 8 } CheckBox { @@ -164,9 +167,9 @@ ColumnLayout { } } - Item { height: 8 } + Item { height: 12 } Rectangle { Layout.fillWidth: true; height: 1; color: Theme.cardBorder } - Item { height: 8 } + Item { height: 12 } // ── THRESHOLDS ──────────────────────────────────────────────────────── Label { @@ -175,10 +178,16 @@ ColumnLayout { font.pixelSize: 10 font.letterSpacing: 1.8 font.weight: Font.Medium - bottomPadding: 4 + topPadding: 6 + bottomPadding: 8 } - Label { text: "Set Point (°C)"; color: Theme.bodyColor; font.pixelSize: 11 } + Label { + text: "Set Point (°C)" + color: Theme.bodyColor + font.pixelSize: 11 + bottomPadding: 3 + } TextField { id: spField Layout.fillWidth: true @@ -198,9 +207,14 @@ ColumnLayout { onEditingFinished: pushThresholds() } - Item { height: 4 } + Item { height: 10 } - Label { text: "Margin (±°C)"; color: Theme.bodyColor; font.pixelSize: 11 } + Label { + text: "Margin (±°C)" + color: Theme.bodyColor + font.pixelSize: 11 + bottomPadding: 3 + } TextField { id: mgField Layout.fillWidth: true @@ -220,7 +234,7 @@ ColumnLayout { onEditingFinished: pushThresholds() } - Item { height: 4 } + Item { height: 10 } CheckBox { id: autoCheck diff --git a/src/pygui/ISC/Tabs/components/SourcePanel.qml b/src/pygui/ISC/Tabs/components/SourcePanel.qml index 8b6bd20..f92451e 100644 --- a/src/pygui/ISC/Tabs/components/SourcePanel.qml +++ b/src/pygui/ISC/Tabs/components/SourcePanel.qml @@ -6,13 +6,45 @@ import ISC ColumnLayout { spacing: 6 - // ── Section label ───────────────────────────────────────────────────── - Label { - text: "SOURCE" - color: Theme.bodyColor - font.pixelSize: 10 - font.letterSpacing: 1.8 - font.weight: Font.Medium + // ── Section label & Refresh ─────────────────────────────────────────── + RowLayout { + Layout.fillWidth: true + spacing: 4 + + Label { + text: "SOURCE" + color: Theme.bodyColor + font.pixelSize: 10 + font.letterSpacing: 1.8 + font.weight: Font.Medium + topPadding: 6 + bottomPadding: 8 + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter + } + + Button { + id: refreshBtn + text: "⟳" + implicitWidth: 26 + implicitHeight: 26 + hoverEnabled: true + font.pixelSize: 14 + background: Rectangle { + color: refreshBtn.pressed ? Theme.buttonPressed + : refreshBtn.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: file_browser.refreshFiles() + } } // ── Directory button ────────────────────────────────────────────────── @@ -82,7 +114,7 @@ ColumnLayout { delegate: ItemDelegate { id: fileItem width: ListView.view.width - padding: 0 + padding: 8 highlighted: false focusPolicy: Qt.NoFocus @@ -131,11 +163,13 @@ ColumnLayout { contentItem: RowLayout { spacing: 8 - anchors.margins: 8 // Wafer-type avatar (circle) Rectangle { - width: 28; height: 28 + implicitWidth: 28; implicitHeight: 28 + Layout.preferredWidth: 28 + Layout.preferredHeight: 28 + Layout.alignment: Qt.AlignVCenter radius: 14 color: { var t = modelData.waferType @@ -158,9 +192,9 @@ ColumnLayout { spacing: 1 Layout.fillWidth: true - // Primary: serial number + // Primary: wafer type + serial number Label { - text: modelData.serialNumber || modelData.baseName + text: modelData.serialNumber ? (modelData.waferType + modelData.serialNumber) : modelData.baseName color: Theme.headingColor font.pixelSize: 13 font.weight: Font.Bold diff --git a/src/pygui/ISC/Tabs/components/TransportBar.qml b/src/pygui/ISC/Tabs/components/TransportBar.qml index a544353..590bb08 100644 --- a/src/pygui/ISC/Tabs/components/TransportBar.qml +++ b/src/pygui/ISC/Tabs/components/TransportBar.qml @@ -26,6 +26,26 @@ RowLayout { } } + // Frame counter badge on the left + Rectangle { + id: frameCounter + implicitWidth: frameCounterText.implicitWidth + 16 + implicitHeight: 32 + color: Theme.fieldBackground + border.color: Theme.cardBorder + border.width: Theme.borderThin + radius: Theme.radiusSm + + Text { + id: frameCounterText + anchors.centerIn: parent + text: "Frame " + (streamController.frameIndex + 1) + " / " + streamController.frameTotal + color: Theme.headingColor + font.pixelSize: 11 + font.weight: Font.Medium + } + } + // Left fill — centers the button cluster Item { Layout.fillWidth: true } @@ -80,12 +100,4 @@ RowLayout { streamController.setSpeed(speeds[idx]) } } - - Item { width: 8 } - - Label { - text: "frame " + (streamController.frameIndex + 1) + " / " + streamController.frameTotal - color: Theme.bodyColor - font.pixelSize: 11 - } } diff --git a/src/pygui/backend/data/file_browser.py b/src/pygui/backend/data/file_browser.py index db70f30..45c20ad 100644 --- a/src/pygui/backend/data/file_browser.py +++ b/src/pygui/backend/data/file_browser.py @@ -123,6 +123,13 @@ class FileBrowser(QObject): wafer_type = metadata.get_wafer_type().upper() or (csv_path.stem[0].upper() if csv_path.stem else "") date_str = metadata.string_date_format() serial = metadata.wafer[1:] if len(metadata.wafer) > 1 else "" + if not serial: + stem = csv_path.stem + serial = stem[1:] if len(stem) > 1 else "" + if "-" in serial: + serial = serial.split("-")[0] + if "_" in serial: + serial = serial.split("_")[0] time_str = date_str[11:] if len(date_str) > 10 else "" self._files.append( { @@ -142,13 +149,18 @@ class FileBrowser(QObject): ) except Exception: stem = csv_path.stem + serial_fallback = stem[1:] if len(stem) > 1 else "" + if "-" in serial_fallback: + serial_fallback = serial_fallback.split("-")[0] + if "_" in serial_fallback: + serial_fallback = serial_fallback.split("_")[0] self._files.append( { "selected": selected_state.get(str(csv_path), False), "baseName": stem, "wafer": stem, "waferType": stem[0].upper() if stem else "", - "serialNumber": stem[1:] if len(stem) > 1 else "", + "serialNumber": serial_fallback, "date": "", "timeStr": "", "chamber": "", diff --git a/src/pygui/backend/visualization/wafer_map_item.py b/src/pygui/backend/visualization/wafer_map_item.py index b372992..022cd09 100644 --- a/src/pygui/backend/visualization/wafer_map_item.py +++ b/src/pygui/backend/visualization/wafer_map_item.py @@ -229,8 +229,8 @@ class WaferMapItem(QQuickPaintedItem): return groups def _scale(self, ds: int, r_mm: float) -> float: - """Pixels per mm. The wafer radius maps to ds//2 - 4 px.""" - return (ds / 2 - 4) / r_mm + """Pixels per mm. The wafer radius maps to ds//2 - 24 px.""" + return (ds / 2 - 24) / r_mm def _to_px(self, x_mm: float, y_mm: float, cx: int, cy: int, scale: float) -> tuple[int, int]: """Center-origin mm → pixel (top-left origin). Y is flipped."""