Files
pyGUI/ISC/Tabs/SettingsTab.qml
T
Jack.Le 9f8c6e1a4c Enhance UI and add file selection functionality
- Updated  to include new files for the project.
- Modified  to improve layout and navigation, including new properties for tab and action management.
- Introduced  for file selection with metadata editing capabilities.
- Created  for managing application settings and integrating the file selection dialog.
2026-04-27 13:56:36 -07:00

437 lines
15 KiB
QML

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.Dialogs
import ISC
Item {
id: root
anchors.fill: parent
// ===== CSV metadata dialog (must not live inside RowLayout: implicit size breaks the tab) =====
SelectFileDialog {
id: selectFileDialog
tableModel: file_browser.files
onFileChosen: function (path) {
root.handleCsvSelected(path);
}
}
function handleEditCsvMetadata() {
file_browser.refreshFiles();
selectFileDialog.open();
}
function handleCsvSelected(filePath) {
console.log("Doing work with:", filePath);
// @todo: implement CSV metadata handling after file selection.
}
// ===== Settings Data Helpers =====
readonly property var masterFamilies: ["A", "B", "C", "D", "E", "F", "P", "X", "Z"]
function masterPath(family) {
const table = settingsModel.masters;
return table && table[family] ? table[family] : "";
}
function statusColor() {
if (!settingsModel.isValid) {
return Theme.statusWarningColor;
}
return settingsModel.saveStatus.indexOf("error:") === 0 ? Theme.statusErrorColor : Theme.statusSuccessColor;
}
// ===== Reusable Settings Components =====
component SettingsGroupBox: GroupBox {
id: settingsGroup
background: Rectangle {
y: settingsGroup.topPadding - settingsGroup.bottomPadding
width: settingsGroup.width
height: settingsGroup.height - settingsGroup.topPadding + settingsGroup.bottomPadding
radius: Theme.radiusMd
color: Theme.panelBackground
border.color: Theme.innerFrameBorder
border.width: Theme.borderThin
}
label: Label {
text: settingsGroup.title
color: Theme.panelTitleText
font.pixelSize: 16
font.bold: true
}
}
component SettingsTextInput: TextField {
id: textInput
color: Theme.fieldText
placeholderTextColor: Theme.fieldPlaceholder
selectedTextColor: Theme.fieldBackground
selectionColor: Theme.fieldText
background: Rectangle {
radius: Theme.radiusXs
color: Theme.fieldBackground
border.width: textInput.activeFocus ? Theme.borderStrong : Theme.borderThin
border.color: textInput.activeFocus ? Theme.fieldBorderFocus : Theme.fieldBorder
}
}
component SettingsActionButton: Button {
id: actionButton
hoverEnabled: true
background: Rectangle {
radius: Theme.radiusSm
color: actionButton.down ? Theme.buttonNeutralPressed : (actionButton.hovered ? Theme.buttonNeutralHover : Theme.buttonNeutralBackground)
border.width: Theme.borderThin
border.color: Theme.fieldBorder
}
contentItem: Text {
text: actionButton.text
color: Theme.buttonNeutralText
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
font.bold: true
}
}
component SettingsToggle: CheckBox {
id: toggle
indicator: Rectangle {
implicitWidth: 20
implicitHeight: 20
x: toggle.leftPadding
y: parent.height / 2 - height / 2
radius: Theme.radiusXs
color: toggle.checked ? Theme.primaryAccent : Theme.fieldBackground
border.width: Theme.borderThin
border.color: toggle.checked ? Theme.primaryAccent : Theme.fieldBorder
Rectangle {
anchors.centerIn: parent
width: 9
height: 9
radius: Theme.radiusXs
visible: toggle.checked
color: Theme.fieldBackground
}
}
contentItem: Text {
text: toggle.text
color: Theme.checkboxText
verticalAlignment: Text.AlignVCenter
leftPadding: toggle.indicator.width + toggle.spacing
}
}
// ===== File Picker Dialog =====
FileDialog {
id: masterPicker
title: "Choose Master CSV"
nameFilters: ["CSV files (*.csv)"]
property string targetFamily: ""
onAccepted: settingsModel.setMaster(targetFamily, selectedFile.toLocalFile())
}
// ===== Settings Page Layout =====
Item {
anchors.fill: parent
ScrollView {
id: settingsScroll
anchors.fill: parent
anchors.margins: Theme.settingsOuterMargin
contentWidth: availableWidth
contentHeight: container.implicitHeight
ScrollBar.vertical: ScrollBar {
parent: settingsScroll
anchors.top: settingsScroll.top
anchors.right: settingsScroll.right
anchors.bottom: settingsScroll.bottom
policy: ScrollBar.AsNeeded
contentItem: Rectangle {
implicitWidth: 8
implicitHeight: 8
radius: Theme.radiusSm
color: Theme.trackBackground
}
background: Rectangle {
implicitWidth: 8
color: "transparent"
}
}
ColumnLayout {
id: container
width: Math.min(settingsScroll.availableWidth, Theme.settingsPanelMaxWidth)
x: (settingsScroll.availableWidth - width) / 2
spacing: Theme.settingsSectionSpacing
// ===== Page Title =====
Label {
text: "Settings"
font.pixelSize: 30
font.bold: true
color: Theme.headingColor
}
// ===== Chamber Settings =====
SettingsGroupBox {
title: "Chamber"
Layout.fillWidth: true
RowLayout {
anchors.fill: parent
spacing: Theme.settingsRowSpacing
Label {
text: "Chamber ID"
color: Theme.headingColor
Layout.alignment: Qt.AlignVCenter
}
SettingsTextInput {
id: chamberField
Layout.fillWidth: true
Layout.minimumWidth: Theme.settingsFieldMinWidth
placeholderText: "Enter chamber ID"
text: settingsModel.chamberId
onEditingFinished: settingsModel.setChamberId(text)
Connections {
target: settingsModel
function onChamberIdChanged() {
if (!chamberField.activeFocus) {
chamberField.text = settingsModel.chamberId;
}
}
}
}
SettingsActionButton {
text: "Set"
Layout.preferredWidth: 90
Layout.preferredHeight: Theme.settingsButtonHeight
onClicked: settingsModel.setChamberId(chamberField.text)
}
}
}
// ===== Master CSV Mapping =====
SettingsGroupBox {
title: "Master Files"
Layout.fillWidth: true
ColumnLayout {
anchors.fill: parent
spacing: Theme.settingsGridSpacing
Repeater {
model: root.masterFamilies
RowLayout {
property string family: modelData
Layout.fillWidth: true
spacing: Theme.settingsRowSpacing
Label {
text: family
font.bold: true
color: Theme.headingColor
Layout.preferredWidth: 24
}
SettingsTextInput {
Layout.fillWidth: true
readOnly: true
text: root.masterPath(family)
placeholderText: "No master selected"
color: Theme.bodyColor
}
SettingsActionButton {
text: "Browse"
Layout.preferredHeight: Theme.settingsButtonHeight
onClicked: {
masterPicker.targetFamily = family;
masterPicker.open();
}
}
SettingsActionButton {
text: "Clear"
Layout.preferredHeight: Theme.settingsButtonHeight
onClicked: settingsModel.clearMaster(family)
}
}
}
}
}
// ===== Wafer Behavior =====
SettingsGroupBox {
title: "Wafer Behavior"
Layout.fillWidth: true
ColumnLayout {
anchors.fill: parent
spacing: Theme.settingsGridSpacing
SettingsToggle {
text: "Reverse Z Wafer"
checked: settingsModel.reverseZWafer
onToggled: settingsModel.setReverseZWafer(checked)
}
}
}
// ===== Appearance =====
SettingsGroupBox {
title: "Appearance"
Layout.fillWidth: true
RowLayout {
anchors.fill: parent
spacing: Theme.settingsRowSpacing
// Custom pill toggle
Rectangle {
id: toggleTrack
implicitWidth: 52
implicitHeight: 28
radius: height / 2
color: Theme.trackBackground
Layout.alignment: Qt.AlignVCenter
Layout.preferredWidth: implicitWidth
Layout.preferredHeight: implicitHeight
Behavior on color {
ColorAnimation {
duration: 250
easing.type: Easing.InOutQuad
}
}
// Thumb
Rectangle {
id: toggleThumb
width: 22
height: 22
radius: height / 2
color: "white"
anchors.verticalCenter: parent.verticalCenter
x: Theme.isDarkMode ? parent.width - width - 3 : 3
Behavior on x {
NumberAnimation {
duration: 250
easing.type: Easing.InOutQuad
}
}
// Drop shadow effect
layer.enabled: true
layer.effect: null // swap for DropShadow if Qt.labs.effects is available
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: Theme.isDarkMode = !Theme.isDarkMode
}
}
// Label
Label {
text: Theme.isDarkMode ? "Dark" : "Light"
color: Theme.bodyColor
font.pixelSize: 13
Layout.alignment: Qt.AlignVCenter
Behavior on color {
ColorAnimation {
duration: 200
}
}
}
Item {
Layout.fillWidth: true
}
}
}
// ===== Adjustment Entry Point =====
RowLayout {
id: adjustmentRow
Layout.fillWidth: true
spacing: Theme.settingsRowSpacing
SettingsActionButton {
text: "Edit CSV Metadata"
Layout.preferredWidth: Theme.settingsActionWidth
Layout.preferredHeight: Theme.settingsButtonHeight
onClicked: root.handleEditCsvMetadata()
}
Item {
Layout.fillWidth: true
}
}
}
}
// ===== Scroll hint overlay (fades out when scrolled) =====
Rectangle {
id: scrollHint
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
height: 48
gradient: Gradient {
GradientStop {
position: 0.0
color: Theme.isDarkMode ? 'rgba(30,30,35,1)' : 'rgba(255,255,255,1)'
}
GradientStop {
position: 1.0
color: Qt.transparent
}
}
Label {
anchors.centerIn: parent
text: "↓ Scroll for more"
font.pixelSize: 13
font.bold: true
color: Theme.bodyColor
opacity: (settingsScroll.ScrollBar.vertical.position <= 0 && settingsScroll.contentHeight > settingsScroll.height) ? (scrollHintTimer.running ? 1 : 0) : 0
Behavior on opacity {
NumberAnimation { duration: 400 }
}
}
}
}
// ===== Auto-hide scroll hint after first interaction =====
Timer {
id: scrollHintTimer
running: true
repeat: false
onTriggered: scrollHint.visible = false
}
}