Compare commits

...

2 Commits

8 changed files with 274 additions and 121 deletions
+11 -7
View File
@@ -107,25 +107,29 @@ Item {
x: toggle.leftPadding x: toggle.leftPadding
y: parent.height / 2 - height / 2 y: parent.height / 2 - height / 2
radius: Theme.radiusXs radius: Theme.radiusXs
color: toggle.checked ? Theme.primaryAccent : Theme.fieldBackground color: toggle.checked ? Theme.primaryAccent : "transparent"
border.width: Theme.borderThin border.width: Theme.borderThin
border.color: toggle.checked ? Theme.primaryAccent : Theme.fieldBorder border.color: toggle.checked ? Theme.primaryAccent : Theme.fieldBorder
Rectangle { Text {
anchors.centerIn: parent anchors.centerIn: parent
width: 9 text: "✓"
height: 9 font.pixelSize: 14
radius: Theme.radiusXs font.bold: true
color: Theme.panelBackground
visible: toggle.checked visible: toggle.checked
color: Theme.fieldBackground // Small nudge to center the checkmark perfectly
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
} }
} }
contentItem: Text { contentItem: Text {
text: toggle.text text: toggle.text
color: Theme.checkboxText color: Theme.headingColor
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
leftPadding: toggle.indicator.width + toggle.spacing leftPadding: toggle.indicator.width + toggle.spacing
font.pixelSize: 13
} }
} }
+15 -3
View File
@@ -26,8 +26,8 @@ Item {
ColumnLayout { ColumnLayout {
anchors.fill: parent anchors.fill: parent
anchors.margins: Theme.panelPadding anchors.margins: 16
spacing: Theme.rightPaneGap spacing: 16
// ── Toolbar ─────────────────────────────────────────────────────── // ── Toolbar ───────────────────────────────────────────────────────
RowLayout { RowLayout {
@@ -176,7 +176,7 @@ Item {
RowLayout { RowLayout {
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
spacing: Theme.rightPaneGap spacing: 16
// Source panel — bordered card // Source panel — bordered card
Rectangle { Rectangle {
@@ -207,6 +207,18 @@ Item {
showLabels: readoutPanel.showLabels 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 } TransportBar { Layout.fillWidth: true }
} }
+133 -86
View File
@@ -9,6 +9,39 @@ ColumnLayout {
property alias showLabels: labelsToggle.checked property alias showLabels: labelsToggle.checked
property alias heatmapBlend: heatmapSlider.value property alias heatmapBlend: heatmapSlider.value
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
Text {
anchors.centerIn: parent
text: "✓"
font.pixelSize: 13
font.bold: true
color: Theme.panelBackground
visible: toggle.checked
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
}
}
contentItem: Text {
text: toggle.text
color: Theme.headingColor
verticalAlignment: Text.AlignVCenter
leftPadding: toggle.indicator.width + toggle.spacing
font.pixelSize: toggle.font.pixelSize || 11
}
}
// ── READOUT ─────────────────────────────────────────────────────────── // ── READOUT ───────────────────────────────────────────────────────────
Label { Label {
text: "READOUT" text: "READOUT"
@@ -16,118 +49,120 @@ ColumnLayout {
font.pixelSize: 10 font.pixelSize: 10
font.letterSpacing: 1.8 font.letterSpacing: 1.8
font.weight: Font.Medium font.weight: Font.Medium
bottomPadding: 4 topPadding: 6
bottomPadding: 8
} }
GridLayout { Rectangle {
columns: 2
rowSpacing: 4
columnSpacing: 4
Layout.fillWidth: true Layout.fillWidth: true
implicitHeight: statsLayout.implicitHeight + 20
color: Theme.subtleSectionBackground
radius: Theme.radiusSm
border.color: Theme.cardBorder
border.width: 1
// MIN TEMP ColumnLayout {
Rectangle { id: statsLayout
Layout.fillWidth: true; height: 52 anchors { fill: parent; margins: 10 }
color: Theme.subtleSectionBackground; radius: Theme.radiusSm spacing: 8
border.color: Theme.cardBorder; border.width: 1
ColumnLayout { // Min Temp Row
anchors { fill: parent; margins: 7 } RowLayout {
spacing: 1 Layout.fillWidth: true
Label { text: "MIN TEMP"; color: Theme.bodyColor; font.pixelSize: 9; font.letterSpacing: 1 } Label { text: "Min Temp"; color: Theme.bodyColor; font.pixelSize: 11 }
Label { Item { Layout.fillWidth: true }
text: s.min !== undefined ? s.min + " #" + s.minIndex : "—" RowLayout {
color: Theme.sensorLow spacing: 4
font.pixelSize: 15; font.weight: Font.Bold 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 // Max Temp Row
Rectangle { RowLayout {
Layout.fillWidth: true; height: 52 Layout.fillWidth: true
color: Theme.subtleSectionBackground; radius: Theme.radiusSm Label { text: "Max Temp"; color: Theme.bodyColor; font.pixelSize: 11 }
border.color: Theme.cardBorder; border.width: 1 Item { Layout.fillWidth: true }
ColumnLayout { RowLayout {
anchors { fill: parent; margins: 7 } spacing: 4
spacing: 1 Label {
Label { text: "MAX TEMP"; color: Theme.bodyColor; font.pixelSize: 9; font.letterSpacing: 1 } text: s.max !== undefined ? s.max : "—"
Label { color: Theme.sensorHigh
text: s.max !== undefined ? s.max + " #" + s.maxIndex : "—" font.pixelSize: 13; font.weight: Font.Bold
color: Theme.sensorHigh }
font.pixelSize: 15; font.weight: Font.Bold Label {
text: s.maxIndex !== undefined ? "#" + s.maxIndex : ""
color: Theme.bodyColor
font.pixelSize: 10
}
} }
} }
}
// DIFFERENTIAL Rectangle { Layout.fillWidth: true; height: 1; color: Theme.cardBorder }
Rectangle {
Layout.fillWidth: true; height: 52 // Differential Row
color: Theme.subtleSectionBackground; radius: Theme.radiusSm RowLayout {
border.color: Theme.cardBorder; border.width: 1 Layout.fillWidth: true
ColumnLayout { Label { text: "Differential"; color: Theme.bodyColor; font.pixelSize: 11 }
anchors { fill: parent; margins: 7 } Item { Layout.fillWidth: true }
spacing: 1
Label { text: "DIFFERENTIAL"; color: Theme.bodyColor; font.pixelSize: 9; font.letterSpacing: 1 }
Label { Label {
text: s.diff !== undefined ? s.diff : "—" text: s.diff !== undefined ? s.diff : "—"
color: Theme.headingColor color: Theme.headingColor
font.pixelSize: 15; font.weight: Font.Bold font.pixelSize: 13; font.weight: Font.Bold
} }
} }
}
// AVERAGE // Average Row
Rectangle { RowLayout {
Layout.fillWidth: true; height: 52 Layout.fillWidth: true
color: Theme.subtleSectionBackground; radius: Theme.radiusSm Label { text: "Average"; color: Theme.bodyColor; font.pixelSize: 11 }
border.color: Theme.cardBorder; border.width: 1 Item { Layout.fillWidth: true }
ColumnLayout {
anchors { fill: parent; margins: 7 }
spacing: 1
Label { text: "AVERAGE"; color: Theme.bodyColor; font.pixelSize: 9; font.letterSpacing: 1 }
Label { Label {
text: s.avg !== undefined ? s.avg : "—" text: s.avg !== undefined ? s.avg : "—"
color: Theme.headingColor 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: 1; color: Theme.cardBorder }
Rectangle {
Layout.fillWidth: true; height: 44 // Sigma Row
color: Theme.subtleSectionBackground; radius: Theme.radiusSm RowLayout {
border.color: Theme.cardBorder; border.width: 1 Layout.fillWidth: true
RowLayout { Label { text: "Sigma (σ)"; color: Theme.bodyColor; font.pixelSize: 11 }
anchors { fill: parent; leftMargin: 7; rightMargin: 7; topMargin: 4; bottomMargin: 4 } Item { Layout.fillWidth: true }
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
Label { Label {
text: s.sigma !== undefined ? s.sigma : "—" text: s.sigma !== undefined ? s.sigma : "—"
color: Theme.headingColor color: Theme.headingColor
font.pixelSize: 15; font.weight: Font.Bold font.pixelSize: 13; font.weight: Font.Bold
Layout.alignment: Qt.AlignRight
} }
}
// 3-Sigma Row
RowLayout {
Layout.fillWidth: true
Label { text: "3σ Value"; color: Theme.bodyColor; font.pixelSize: 11 }
Item { Layout.fillWidth: true }
Label { Label {
text: s.threeSigma !== undefined ? s.threeSigma : "—" text: s.threeSigma !== undefined ? s.threeSigma : "—"
color: Theme.bodyColor color: Theme.bodyColor
font.pixelSize: 12; font.weight: Font.Medium 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 } Rectangle { Layout.fillWidth: true; height: 1; color: Theme.cardBorder }
Item { height: 8 } Item { height: 12 }
// ── DISPLAY ─────────────────────────────────────────────────────────── // ── DISPLAY ───────────────────────────────────────────────────────────
Label { Label {
@@ -136,10 +171,11 @@ ColumnLayout {
font.pixelSize: 10 font.pixelSize: 10
font.letterSpacing: 1.8 font.letterSpacing: 1.8
font.weight: Font.Medium font.weight: Font.Medium
bottomPadding: 4 topPadding: 6
bottomPadding: 8
} }
CheckBox { PanelCheckBox {
id: labelsToggle id: labelsToggle
text: "Labels" text: "Labels"
checked: true checked: true
@@ -164,9 +200,9 @@ ColumnLayout {
} }
} }
Item { height: 8 } Item { height: 12 }
Rectangle { Layout.fillWidth: true; height: 1; color: Theme.cardBorder } Rectangle { Layout.fillWidth: true; height: 1; color: Theme.cardBorder }
Item { height: 8 } Item { height: 12 }
// ── THRESHOLDS ──────────────────────────────────────────────────────── // ── THRESHOLDS ────────────────────────────────────────────────────────
Label { Label {
@@ -175,10 +211,16 @@ ColumnLayout {
font.pixelSize: 10 font.pixelSize: 10
font.letterSpacing: 1.8 font.letterSpacing: 1.8
font.weight: Font.Medium 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 { TextField {
id: spField id: spField
Layout.fillWidth: true Layout.fillWidth: true
@@ -198,9 +240,14 @@ ColumnLayout {
onEditingFinished: pushThresholds() 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 { TextField {
id: mgField id: mgField
Layout.fillWidth: true Layout.fillWidth: true
@@ -220,9 +267,9 @@ ColumnLayout {
onEditingFinished: pushThresholds() onEditingFinished: pushThresholds()
} }
Item { height: 4 } Item { height: 10 }
CheckBox { PanelCheckBox {
id: autoCheck id: autoCheck
text: "Auto range (mean ± 1σ)" text: "Auto range (mean ± 1σ)"
checked: true checked: true
+78 -12
View File
@@ -2,17 +2,76 @@ import QtQuick
import QtQuick.Controls import QtQuick.Controls
import QtQuick.Layouts import QtQuick.Layouts
import ISC import ISC
import ".."
ColumnLayout { ColumnLayout {
spacing: 6 spacing: 6
// ── Section label ───────────────────────────────────────────────────── // ── Section label & Refresh ───────────────────────────────────────────
Label { RowLayout {
text: "SOURCE" Layout.fillWidth: true
color: Theme.bodyColor spacing: 4
font.pixelSize: 10
font.letterSpacing: 1.8 Label {
font.weight: Font.Medium 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: editBtn
text: "✎"
implicitWidth: 26
implicitHeight: 26
hoverEnabled: true
font.pixelSize: 14
background: Rectangle {
color: editBtn.pressed ? Theme.buttonPressed
: editBtn.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()
csvEditorDialog.open()
}
}
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 ────────────────────────────────────────────────── // ── Directory button ──────────────────────────────────────────────────
@@ -82,7 +141,7 @@ ColumnLayout {
delegate: ItemDelegate { delegate: ItemDelegate {
id: fileItem id: fileItem
width: ListView.view.width width: ListView.view.width
padding: 0 padding: 8
highlighted: false highlighted: false
focusPolicy: Qt.NoFocus focusPolicy: Qt.NoFocus
@@ -131,11 +190,13 @@ ColumnLayout {
contentItem: RowLayout { contentItem: RowLayout {
spacing: 8 spacing: 8
anchors.margins: 8
// Wafer-type avatar (circle) // Wafer-type avatar (circle)
Rectangle { Rectangle {
width: 28; height: 28 implicitWidth: 28; implicitHeight: 28
Layout.preferredWidth: 28
Layout.preferredHeight: 28
Layout.alignment: Qt.AlignVCenter
radius: 14 radius: 14
color: { color: {
var t = modelData.waferType var t = modelData.waferType
@@ -158,9 +219,9 @@ ColumnLayout {
spacing: 1 spacing: 1
Layout.fillWidth: true Layout.fillWidth: true
// Primary: serial number // Primary: wafer type + serial number
Label { Label {
text: modelData.serialNumber || modelData.baseName text: modelData.serialNumber ? (modelData.waferType + modelData.serialNumber) : modelData.baseName
color: Theme.headingColor color: Theme.headingColor
font.pixelSize: 13 font.pixelSize: 13
font.weight: Font.Bold font.weight: Font.Bold
@@ -226,4 +287,9 @@ ColumnLayout {
color: Theme.bodyColor color: Theme.bodyColor
font.pixelSize: 10 font.pixelSize: 10
} }
SelectFileDialog {
id: csvEditorDialog
tableModel: file_browser.files
}
} }
+20 -8
View File
@@ -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 // Left fill — centers the button cluster
Item { Layout.fillWidth: true } Item { Layout.fillWidth: true }
@@ -80,12 +100,4 @@ RowLayout {
streamController.setSpeed(speeds[idx]) streamController.setSpeed(speeds[idx])
} }
} }
Item { width: 8 }
Label {
text: "frame " + (streamController.frameIndex + 1) + " / " + streamController.frameTotal
color: Theme.bodyColor
font.pixelSize: 11
}
} }
+2 -2
View File
@@ -81,7 +81,7 @@ QtObject {
// ── 8. Tabs (footer tab bar) ───────────────────────────────────────────── // ── 8. Tabs (footer tab bar) ─────────────────────────────────────────────
readonly property color tabBarBackground: tone200 readonly property color tabBarBackground: tone200
readonly property color tabBackground: "transparent" readonly property color tabBackground: "transparent"
readonly property color tabActiveBackground: "transparent" readonly property color tabActiveBackground: isDarkMode ? "#333333" : "#FFFFFF"
readonly property color tabHoverBackground: tone300 readonly property color tabHoverBackground: tone300
readonly property color tabBorder: "transparent" readonly property color tabBorder: "transparent"
readonly property color tabText: toneMute readonly property color tabText: toneMute
@@ -132,7 +132,7 @@ QtObject {
readonly property int tabBarHeight: 34 readonly property int tabBarHeight: 34
readonly property int tabBarPadding: 6 readonly property int tabBarPadding: 6
readonly property int tabSpacing: 2 readonly property int tabSpacing: 2
readonly property int tabRadius: 2 readonly property int tabRadius: 8
readonly property int tabFontSize: 12 readonly property int tabFontSize: 12
readonly property int tabButtonMinWidth: 80 readonly property int tabButtonMinWidth: 80
// Settings page layout // Settings page layout
+13 -1
View File
@@ -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 "") wafer_type = metadata.get_wafer_type().upper() or (csv_path.stem[0].upper() if csv_path.stem else "")
date_str = metadata.string_date_format() date_str = metadata.string_date_format()
serial = metadata.wafer[1:] if len(metadata.wafer) > 1 else "" 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 "" time_str = date_str[11:] if len(date_str) > 10 else ""
self._files.append( self._files.append(
{ {
@@ -142,13 +149,18 @@ class FileBrowser(QObject):
) )
except Exception: except Exception:
stem = csv_path.stem 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( self._files.append(
{ {
"selected": selected_state.get(str(csv_path), False), "selected": selected_state.get(str(csv_path), False),
"baseName": stem, "baseName": stem,
"wafer": stem, "wafer": stem,
"waferType": stem[0].upper() if stem else "", "waferType": stem[0].upper() if stem else "",
"serialNumber": stem[1:] if len(stem) > 1 else "", "serialNumber": serial_fallback,
"date": "", "date": "",
"timeStr": "", "timeStr": "",
"chamber": "", "chamber": "",
@@ -229,8 +229,8 @@ class WaferMapItem(QQuickPaintedItem):
return groups return groups
def _scale(self, ds: int, r_mm: float) -> float: def _scale(self, ds: int, r_mm: float) -> float:
"""Pixels per mm. The wafer radius maps to ds//2 - 4 px.""" """Pixels per mm. The wafer radius maps to ds//2 - 24 px."""
return (ds / 2 - 4) / r_mm 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]: 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.""" """Center-origin mm → pixel (top-left origin). Y is flipped."""