feat(map): add edge-center delta stats, thickness overlay, and layout fix
- Add edge-center sensor pair tables and delta calculations per wafer family. - Parse and interpolate wafer thickness CSV data for offscreen visualization. - Refactor ReadoutPanel layout using Item + anchors to fix right-margin clipping. - Compact E-C Delta text format to fit standard sidebar width. - Add pytest suite covering delta calculations, layout pairs, and thickness CSV.
This commit is contained in:
@@ -206,9 +206,17 @@ Item {
|
||||
id: readoutPanel
|
||||
anchors.fill: parent
|
||||
anchors.margins: 0
|
||||
hasThicknessData: waferView.hasThickness
|
||||
onExportRequested: function(filePath, extra) {
|
||||
waferView.exportImage(filePath, extra);
|
||||
}
|
||||
onThicknessFileChosen: function(filePath) {
|
||||
var err = waferView.loadThickness(filePath);
|
||||
if (err !== "") {
|
||||
root.loadErrorMessage = err;
|
||||
readoutPanel.showThickness = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Controls.impl
|
||||
import QtQuick.Dialogs
|
||||
import QtQuick.Layouts
|
||||
import ISC
|
||||
|
||||
@@ -15,8 +16,10 @@ ColumnLayout {
|
||||
property alias showExtremes: extremesToggle.checked
|
||||
property alias heatmapBlend: heatmapSlider.value
|
||||
property alias showThickness: thicknessToggle.checked
|
||||
property bool hasThicknessData: false
|
||||
|
||||
signal exportRequested(string filePath, string extra)
|
||||
signal thicknessFileChosen(string filePath)
|
||||
|
||||
component PanelCheckBox: CheckBox {
|
||||
id: toggle
|
||||
@@ -119,20 +122,23 @@ ColumnLayout {
|
||||
}
|
||||
|
||||
// Min Temp Row
|
||||
RowLayout {
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 14
|
||||
Layout.rightMargin: 14
|
||||
Layout.preferredHeight: 32
|
||||
implicitHeight: 32
|
||||
Label {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 14
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: "MIN TEMP"
|
||||
color: Theme.sideMutedText
|
||||
font.family: Theme.uiFontFamily
|
||||
font.pixelSize: Theme.fontSm
|
||||
font.bold: true
|
||||
}
|
||||
Item { Layout.fillWidth: true }
|
||||
RowLayout {
|
||||
Row {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 14
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 4
|
||||
Label {
|
||||
text: s.min !== undefined ? s.min : "—"
|
||||
@@ -147,8 +153,8 @@ ColumnLayout {
|
||||
color: Theme.sideMutedText
|
||||
font.family: Theme.uiFontFamily
|
||||
font.pixelSize: Theme.font2xs
|
||||
Layout.alignment: Qt.AlignBottom
|
||||
bottomPadding: 3
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 2
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -160,20 +166,23 @@ ColumnLayout {
|
||||
}
|
||||
|
||||
// Max Temp Row
|
||||
RowLayout {
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 14
|
||||
Layout.rightMargin: 14
|
||||
Layout.preferredHeight: 32
|
||||
implicitHeight: 32
|
||||
Label {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 14
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: "MAX TEMP"
|
||||
color: Theme.sideMutedText
|
||||
font.family: Theme.uiFontFamily
|
||||
font.pixelSize: Theme.fontSm
|
||||
font.bold: true
|
||||
}
|
||||
Item { Layout.fillWidth: true }
|
||||
RowLayout {
|
||||
Row {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 14
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 4
|
||||
Label {
|
||||
text: s.max !== undefined ? s.max : "—"
|
||||
@@ -188,8 +197,8 @@ ColumnLayout {
|
||||
color: Theme.sideMutedText
|
||||
font.family: Theme.uiFontFamily
|
||||
font.pixelSize: Theme.font2xs
|
||||
Layout.alignment: Qt.AlignBottom
|
||||
bottomPadding: 3
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 2
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -201,20 +210,23 @@ ColumnLayout {
|
||||
}
|
||||
|
||||
// Differential Row
|
||||
RowLayout {
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 14
|
||||
Layout.rightMargin: 14
|
||||
Layout.preferredHeight: 32
|
||||
implicitHeight: 32
|
||||
Label {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 14
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: "DIFF"
|
||||
color: Theme.sideMutedText
|
||||
font.family: Theme.uiFontFamily
|
||||
font.pixelSize: Theme.fontSm
|
||||
font.bold: true
|
||||
}
|
||||
Item { Layout.fillWidth: true }
|
||||
Label {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 14
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: s.diff !== undefined ? s.diff : "—"
|
||||
color: Theme.diffAccent
|
||||
font.family: Theme.codeFontFamily
|
||||
@@ -230,20 +242,23 @@ ColumnLayout {
|
||||
}
|
||||
|
||||
// Average Row
|
||||
RowLayout {
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 14
|
||||
Layout.rightMargin: 14
|
||||
Layout.preferredHeight: 32
|
||||
implicitHeight: 32
|
||||
Label {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 14
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: "AVERAGE"
|
||||
color: Theme.sideMutedText
|
||||
font.family: Theme.uiFontFamily
|
||||
font.pixelSize: Theme.fontSm
|
||||
font.bold: true
|
||||
}
|
||||
Item { Layout.fillWidth: true }
|
||||
Label {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 14
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: s.avg !== undefined ? s.avg : "—"
|
||||
color: Theme.headingColor
|
||||
font.family: Theme.codeFontFamily
|
||||
@@ -259,20 +274,23 @@ ColumnLayout {
|
||||
}
|
||||
|
||||
// Sigma Row
|
||||
RowLayout {
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 14
|
||||
Layout.rightMargin: 14
|
||||
Layout.preferredHeight: 32
|
||||
implicitHeight: 32
|
||||
Label {
|
||||
text: "SIGMA (Σ)"
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 14
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: "SIGMA (\u03A3)"
|
||||
color: Theme.sideMutedText
|
||||
font.family: Theme.uiFontFamily
|
||||
font.pixelSize: Theme.fontSm
|
||||
font.bold: true
|
||||
}
|
||||
Item { Layout.fillWidth: true }
|
||||
Label {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 14
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: s.sigma !== undefined ? s.sigma : "—"
|
||||
color: Theme.headingColor
|
||||
font.family: Theme.codeFontFamily
|
||||
@@ -288,20 +306,23 @@ ColumnLayout {
|
||||
}
|
||||
|
||||
// 3-Sigma Row
|
||||
RowLayout {
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 14
|
||||
Layout.rightMargin: 14
|
||||
Layout.preferredHeight: 32
|
||||
implicitHeight: 32
|
||||
Label {
|
||||
text: "3Σ VALUE"
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 14
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: "3\u03A3 VALUE"
|
||||
color: Theme.sideMutedText
|
||||
font.family: Theme.uiFontFamily
|
||||
font.pixelSize: Theme.fontSm
|
||||
font.bold: true
|
||||
}
|
||||
Item { Layout.fillWidth: true }
|
||||
Label {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 14
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: s.threeSigma !== undefined ? s.threeSigma : "—"
|
||||
color: Theme.headingColor
|
||||
font.family: Theme.codeFontFamily
|
||||
@@ -309,6 +330,78 @@ ColumnLayout {
|
||||
font.bold: true
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
visible: s.ecMinDelta !== undefined
|
||||
Layout.fillWidth: true
|
||||
height: 1
|
||||
color: Theme.cardBorder
|
||||
}
|
||||
|
||||
// Edge-Center \u0394 min Row (per-family pair tables — see ADR-0002)
|
||||
Item {
|
||||
visible: s.ecMinDelta !== undefined
|
||||
Layout.fillWidth: true
|
||||
implicitHeight: 32
|
||||
Label {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 14
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: "E-C \u0394 MIN"
|
||||
color: Theme.sideMutedText
|
||||
font.family: Theme.uiFontFamily
|
||||
font.pixelSize: Theme.fontSm
|
||||
font.bold: true
|
||||
}
|
||||
Label {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 14
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: s.ecMinDelta !== undefined
|
||||
? s.ecMinDelta.toFixed(2) + " (#" + s.ecMinEdgeIndex + "\u2192#" + s.ecMinCenterIndex + ")"
|
||||
: "—"
|
||||
color: Theme.headingColor
|
||||
font.family: Theme.codeFontFamily
|
||||
font.pixelSize: Theme.fontSm
|
||||
font.bold: true
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
visible: s.ecMaxDelta !== undefined
|
||||
Layout.fillWidth: true
|
||||
height: 1
|
||||
color: Theme.cardBorder
|
||||
}
|
||||
|
||||
// Edge-Center \u0394 max Row
|
||||
Item {
|
||||
visible: s.ecMaxDelta !== undefined
|
||||
Layout.fillWidth: true
|
||||
implicitHeight: 32
|
||||
Label {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 14
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: "E-C \u0394 MAX"
|
||||
color: Theme.sideMutedText
|
||||
font.family: Theme.uiFontFamily
|
||||
font.pixelSize: Theme.fontSm
|
||||
font.bold: true
|
||||
}
|
||||
Label {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 14
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: s.ecMaxDelta !== undefined
|
||||
? s.ecMaxDelta.toFixed(2) + " (#" + s.ecMaxEdgeIndex + "\u2192#" + s.ecMaxCenterIndex + ")"
|
||||
: "—"
|
||||
color: Theme.headingColor
|
||||
font.family: Theme.codeFontFamily
|
||||
font.pixelSize: Theme.fontSm
|
||||
font.bold: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -345,6 +438,20 @@ ColumnLayout {
|
||||
text: "Show Thickness"
|
||||
checked: false
|
||||
font.pixelSize: Theme.fontSm
|
||||
// First check with no data prompts for the customer CSV;
|
||||
// unchecking only hides the overlay, data stays loaded.
|
||||
onToggled: {
|
||||
if (checked && !root.hasThicknessData)
|
||||
thicknessDialog.open();
|
||||
}
|
||||
}
|
||||
|
||||
FileDialog {
|
||||
id: thicknessDialog
|
||||
title: "Select Thickness Data File"
|
||||
nameFilters: ["CSV files (*.csv)"]
|
||||
onAccepted: root.thicknessFileChosen(String(selectedFile).replace(/^file:\/\//, ""))
|
||||
onRejected: thicknessToggle.checked = false
|
||||
}
|
||||
|
||||
PanelCheckBox {
|
||||
|
||||
@@ -9,6 +9,7 @@ Item {
|
||||
property bool showLabels: true
|
||||
property alias showExtremes: map.showExtremes
|
||||
property alias showThickness: map.showThickness
|
||||
property alias hasThickness: map.hasThickness
|
||||
|
||||
WaferMapItem {
|
||||
id: map
|
||||
@@ -66,4 +67,8 @@ Item {
|
||||
function exportImage(filePath, extra) {
|
||||
return map.export_image(filePath, extra || "");
|
||||
}
|
||||
|
||||
function loadThickness(filePath) {
|
||||
return map.loadThickness(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user