feat: Add Wafer Map tab and associated components
- Introduced a new Wafer Map tab in the HomePage.qml, which loads WaferMapTab.qml when selected. - Created WaferMapTab.qml to display wafer map with live data and controls. - Added ReadoutPanel.qml for displaying sensor statistics and thresholds. - Implemented SourcePanel.qml for file selection and filtering. - Developed TransportBar.qml for playback controls. - Added WaferMapView.qml to visualize wafer data with interactive features. - Created ReplaceSensorDialog.qml for sensor value overrides. - Updated Theme.qml for new color schemes and UI adjustments. - Modified qmldir files to include new components in the ISC.Tabs and ISC.Tabs.components modules.
This commit is contained in:
@@ -0,0 +1,206 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import ISC
|
||||
|
||||
Dialog {
|
||||
id: root
|
||||
title: "Sensor Override"
|
||||
modal: true
|
||||
standardButtons: Dialog.NoButton
|
||||
width: 300
|
||||
|
||||
// called by WaferMapView's TapHandler
|
||||
property int sensorIndex: -1
|
||||
property string sensorLabel: ""
|
||||
property real currentValue: 0.0
|
||||
property bool hasOverride: streamController.overriddenSensors.indexOf(sensorIndex) >= 0
|
||||
|
||||
function openFor(index) {
|
||||
sensorIndex = index
|
||||
var dot = streamController.sensorDots[index]
|
||||
if (!dot) return
|
||||
sensorLabel = dot.label !== undefined ? String(dot.label) : String(index + 1)
|
||||
currentValue = dot.value
|
||||
valueField.text = ""
|
||||
offsetField.text = ""
|
||||
open()
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
color: Theme.cardBackground
|
||||
radius: 8
|
||||
border.color: Theme.cardBorder
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: Theme.rightPaneGap
|
||||
|
||||
// ── header ───────────────────────────────────────────────
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Label {
|
||||
text: "Sensor #" + (root.sensorIndex + 1) +
|
||||
(root.sensorLabel ? " (" + root.sensorLabel + ")" : "")
|
||||
color: Theme.headingColor
|
||||
font.bold: true
|
||||
font.pixelSize: 13
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Rectangle {
|
||||
visible: root.hasOverride
|
||||
width: overrideTag.implicitWidth + 12
|
||||
height: overrideTag.implicitHeight + 6
|
||||
radius: 4
|
||||
color: Theme.statusWarningColor
|
||||
opacity: 0.85
|
||||
Label {
|
||||
id: overrideTag
|
||||
anchors.centerIn: parent
|
||||
text: "OVERRIDE"
|
||||
color: "white"
|
||||
font.pixelSize: 10
|
||||
font.bold: true
|
||||
font.letterSpacing: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: "Live: " + root.currentValue.toFixed(2)
|
||||
color: Theme.bodyColor
|
||||
font.pixelSize: 12
|
||||
}
|
||||
|
||||
Rectangle { Layout.fillWidth: true; height: 1; color: Theme.cardBorder }
|
||||
|
||||
// ── replace field ─────────────────────────────────────────
|
||||
Label { text: "Replace with value"; color: Theme.bodyColor; font.pixelSize: 11 }
|
||||
TextField {
|
||||
id: valueField
|
||||
Layout.fillWidth: true
|
||||
placeholderText: "100"
|
||||
inputMethodHints: Qt.ImhFormattedNumbersOnly
|
||||
color: Theme.fieldText
|
||||
placeholderTextColor: Theme.fieldPlaceholder
|
||||
selectedTextColor: Theme.fieldBackground
|
||||
selectionColor: Theme.fieldText
|
||||
background: Rectangle {
|
||||
radius: Theme.radiusXs
|
||||
color: Theme.fieldBackground
|
||||
border.width: valueField.activeFocus ? Theme.borderStrong : Theme.borderThin
|
||||
border.color: valueField.activeFocus ? Theme.fieldBorderFocus : Theme.fieldBorder
|
||||
}
|
||||
}
|
||||
|
||||
// ── offset field ──────────────────────────────────────────
|
||||
Label { text: "Or add offset (± delta)"; color: Theme.bodyColor; font.pixelSize: 11 }
|
||||
TextField {
|
||||
id: offsetField
|
||||
Layout.fillWidth: true
|
||||
placeholderText: "e.g. +0.5 or -0.5 (blank = skip)"
|
||||
inputMethodHints: Qt.ImhFormattedNumbersOnly
|
||||
color: Theme.fieldText
|
||||
placeholderTextColor: Theme.fieldPlaceholder
|
||||
selectedTextColor: Theme.fieldBackground
|
||||
selectionColor: Theme.fieldText
|
||||
background: Rectangle {
|
||||
radius: Theme.radiusXs
|
||||
color: Theme.fieldBackground
|
||||
border.width: offsetField.activeFocus ? Theme.borderStrong : Theme.borderThin
|
||||
border.color: offsetField.activeFocus ? Theme.fieldBorderFocus : Theme.fieldBorder
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle { Layout.fillWidth: true; height: 1; color: Theme.cardBorder }
|
||||
|
||||
// ── buttons ───────────────────────────────────────────────
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: 8
|
||||
|
||||
Button {
|
||||
id: applyBtn
|
||||
text: "Apply"
|
||||
Layout.fillWidth: true
|
||||
hoverEnabled: true
|
||||
enabled: valueField.text !== "" || offsetField.text !== ""
|
||||
opacity: enabled ? 1.0 : 0.4
|
||||
background: Rectangle {
|
||||
radius: Theme.radiusSm
|
||||
color: applyBtn.down ? Theme.buttonNeutralPressed : applyBtn.hovered ? Theme.buttonNeutralHover : Theme.buttonNeutralBackground
|
||||
border.width: Theme.borderThin
|
||||
border.color: Theme.fieldBorder
|
||||
}
|
||||
contentItem: Text {
|
||||
text: applyBtn.text
|
||||
color: Theme.buttonNeutralText
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
font.bold: true
|
||||
font.pixelSize: 13
|
||||
}
|
||||
onClicked: {
|
||||
if (valueField.text !== "") {
|
||||
var v = parseFloat(valueField.text)
|
||||
if (!isNaN(v))
|
||||
streamController.replaceSensor(root.sensorIndex, v)
|
||||
}
|
||||
if (offsetField.text !== "") {
|
||||
var d = parseFloat(offsetField.text)
|
||||
if (!isNaN(d))
|
||||
streamController.offsetSensor(root.sensorIndex, d)
|
||||
}
|
||||
root.close()
|
||||
}
|
||||
}
|
||||
Button {
|
||||
id: clearBtn
|
||||
text: "Clear"
|
||||
Layout.fillWidth: true
|
||||
hoverEnabled: true
|
||||
enabled: root.hasOverride
|
||||
opacity: enabled ? 1.0 : 0.4
|
||||
background: Rectangle {
|
||||
radius: Theme.radiusSm
|
||||
color: clearBtn.down ? Theme.buttonNeutralPressed : clearBtn.hovered ? Theme.buttonNeutralHover : Theme.buttonNeutralBackground
|
||||
border.width: Theme.borderThin
|
||||
border.color: Theme.fieldBorder
|
||||
}
|
||||
contentItem: Text {
|
||||
text: clearBtn.text
|
||||
color: Theme.buttonNeutralText
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
font.bold: true
|
||||
font.pixelSize: 13
|
||||
}
|
||||
onClicked: {
|
||||
streamController.clearSensorEdit(root.sensorIndex)
|
||||
root.close()
|
||||
}
|
||||
}
|
||||
Button {
|
||||
id: cancelBtn
|
||||
text: "Cancel"
|
||||
hoverEnabled: true
|
||||
background: Rectangle {
|
||||
radius: Theme.radiusSm
|
||||
color: cancelBtn.down ? Theme.buttonNeutralPressed : cancelBtn.hovered ? Theme.buttonNeutralHover : Theme.buttonNeutralBackground
|
||||
border.width: Theme.borderThin
|
||||
border.color: Theme.fieldBorder
|
||||
}
|
||||
contentItem: Text {
|
||||
text: cancelBtn.text
|
||||
color: Theme.buttonNeutralText
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
font.bold: true
|
||||
font.pixelSize: 13
|
||||
}
|
||||
onClicked: root.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user