From 50955c740e6e29fa08ced25b124f2fe259597139 Mon Sep 17 00:00:00 2001 From: "Jack.Le" Date: Thu, 23 Apr 2026 11:39:46 -0700 Subject: [PATCH] Initial commit of ISC QtQuick application scaffold, including main application logic in , QML components for UI in directory, project metadata in , and runtime dependencies in . Added README for setup instructions and project structure overview. --- ISC/HomePage.qml | 151 ++++++++++++++++++++++++++++++++++++++++++++ ISC/Main.qml | 20 ++++++ ISC/Tabs/qmldir | 8 +++ ISC/Theme.qml | 75 ++++++++++++++++++++++ ISC/qmldir | 9 +++ README.md | 73 +++++++++++++++++++++ backend/__init__.py | 1 + main.py | 17 +++++ pyproject.toml | 7 ++ requirements.txt | 2 + 10 files changed, 363 insertions(+) create mode 100644 ISC/HomePage.qml create mode 100644 ISC/Main.qml create mode 100644 ISC/Tabs/qmldir create mode 100644 ISC/Theme.qml create mode 100644 ISC/qmldir create mode 100644 README.md create mode 100644 backend/__init__.py create mode 100644 main.py create mode 100644 pyproject.toml create mode 100644 requirements.txt diff --git a/ISC/HomePage.qml b/ISC/HomePage.qml new file mode 100644 index 0000000..7731f5d --- /dev/null +++ b/ISC/HomePage.qml @@ -0,0 +1,151 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import ISC + +Rectangle { + id: root + anchors.fill: parent + color: Theme.pageBackground + clip: true + + // Primary navigation shown in the left rail. + property var sideActions: ["DETECT WAFER", "READ MEMORY", "OPEN CSV IN EXCEL", "ERASE MEMORY", "IMPORT DATA", "STORED DATA"] + + // Footer tabs drive the active workspace section. + property var bottomTabs: ["Status", "Graph", "Data", "Wafer Map", "Compare", "Split", "Settings", "About"] + + property int selectedTabIndex: 0 + + RowLayout { + anchors.fill: parent + spacing: 0 + + // Left control rail. + Rectangle { + id: sideRail + Layout.preferredWidth: Theme.sideRailWidth + Layout.fillHeight: true + color: Theme.sideRailBackground + border.color: Theme.workspaceBorder + border.width: 1 + + readonly property int actionCount: root.sideActions.length + readonly property real computedButtonHeight: Math.min(Theme.sideButtonHeight, (height - (Theme.panelPadding * 2) - (Theme.sideRailSpacing * Math.max(0, actionCount - 1))) / Math.max(1, actionCount)) + + ColumnLayout { + anchors.fill: parent + anchors.margins: Theme.panelPadding + spacing: Theme.sideRailSpacing + + Repeater { + model: root.sideActions + + Button { + id: control + text: modelData + Layout.fillWidth: true + Layout.preferredHeight: Math.max(Theme.sideButtonMinHeight, sideRail.computedButtonHeight) + + background: Rectangle { + color: control.down ? Theme.buttonPressed : Theme.cardBackground + border.color: Theme.cardBorder + border.width: 1 + radius: 4 + } + + contentItem: Text { + text: control.text + color: Theme.headingColor + font.bold: true + font.pixelSize: 18 + wrapMode: Text.WordWrap + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + } + } + } + } + + // Main workspace and footer navigation. + Rectangle { + Layout.fillWidth: true + Layout.fillHeight: true + color: Theme.workspaceBackground + border.color: Theme.workspaceBorder + border.width: 1 + + ColumnLayout { + anchors.fill: parent + anchors.margins: Theme.mainAreaPadding + spacing: Theme.rightPaneGap + + Rectangle { + Layout.fillWidth: true + Layout.fillHeight: true + Layout.minimumHeight: 220 + color: Theme.responseBackground + border.color: Theme.responseBorder + border.width: 1 + radius: 8 + + Label { + anchors.centerIn: parent + text: "Main content area" + color: Theme.bodyColor + font.pixelSize: 20 + } + } + + // Keep the tab strip evenly distributed across the footer. + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: Theme.tabBarHeight + (Theme.tabBarPadding * 2) + color: Theme.tabBarBackground + border.color: Theme.workspaceBorder + border.width: 1 + + RowLayout { + anchors.fill: parent + anchors.margins: Theme.tabBarPadding + spacing: Theme.tabSpacing + + Repeater { + model: root.bottomTabs + + Button { + id: botTabBtn + property bool isActive: index === root.selectedTabIndex + + text: modelData + Layout.fillWidth: true + Layout.preferredHeight: Theme.tabBarHeight + Layout.minimumWidth: Theme.tabButtonMinWidth + onClicked: root.selectedTabIndex = index + hoverEnabled: true + + background: Rectangle { + color: botTabBtn.isActive ? Theme.tabActiveBackground : (botTabBtn.hovered ? Theme.tabHoverBackground : Theme.tabBackground) + border.color: Theme.tabBorder + border.width: 1 + radius: Theme.tabRadius + } + + contentItem: Text { + text: botTabBtn.text + color: botTabBtn.isActive ? Theme.tabActiveText : Theme.tabText + font.pixelSize: Theme.tabFontSize + font.bold: botTabBtn.isActive + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + } + } + } + } + } + } + } + } +} diff --git a/ISC/Main.qml b/ISC/Main.qml new file mode 100644 index 0000000..2137804 --- /dev/null +++ b/ISC/Main.qml @@ -0,0 +1,20 @@ +import QtQuick.Window +import ISC + +// ===== App Window Shell ===== +Window { + // ===== Window Dimensions ===== + width: 1400 + height: 820 + minimumWidth: 1100 + minimumHeight: 700 + visible: true + title: qsTr("ISenseCloud") + + // Keep the window file very small. + // Styling and layout now live in HomePage.qml. + // ===== Root Page Mount ===== + HomePage { + anchors.fill: parent + } +} diff --git a/ISC/Tabs/qmldir b/ISC/Tabs/qmldir new file mode 100644 index 0000000..b3dfc04 --- /dev/null +++ b/ISC/Tabs/qmldir @@ -0,0 +1,8 @@ +# ===== ISC Tabs Module ===== +module ISC.Tabs + +# ===== Tab Components ===== +SettingsTab 1.0 SettingsTab.qml + +# ===== Local Python Helpers ===== +local_settings 1.0 local_settings.py diff --git a/ISC/Theme.qml b/ISC/Theme.qml new file mode 100644 index 0000000..8ef58fe --- /dev/null +++ b/ISC/Theme.qml @@ -0,0 +1,75 @@ +pragma Singleton + +import QtQuick + +// ===== Shared Theme Tokens ===== +QtObject { + // ===== Theme Mode ===== + // Toggle this to preview the same shell in light mode. + property bool isDarkMode: true + + // ===== Surface Colors ===== + // Core application surfaces. + readonly property color pageBackground: isDarkMode ? "#11161c" : "#eef4f7" + readonly property color cardBackground: isDarkMode ? "#1b232d" : "#ffffff" + readonly property color workspaceBackground: isDarkMode ? "#121923" : "#ffffff" + readonly property color sideRailBackground: isDarkMode ? "#18202a" : "#f5f7fa" + readonly property color responseBackground: isDarkMode ? "#18212a" : "#f9fbfc" + + // Shared border and text colors. + readonly property color cardBorder: isDarkMode ? "#334155" : "#cbd5e1" + readonly property color workspaceBorder: isDarkMode ? "#334155" : "#d7dde5" + readonly property color responseBorder: isDarkMode ? "#334155" : "#d5e0e8" + + readonly property color headingColor: isDarkMode ? "#e5eef7" : "#12324a" + readonly property color bodyColor: isDarkMode ? "#afbdca" : "#415a6b" + readonly property color buttonPressed: isDarkMode ? "#214d60" : "#17576c" + readonly property color statusSuccessColor: isDarkMode ? "#7cd67e" : "#1f7a33" + readonly property color statusErrorColor: isDarkMode ? "#ff8a80" : "#c62828" + readonly property color statusWarningColor: isDarkMode ? "#f3c677" : "#9a6700" + + // ===== Side Rail Sizing ===== + readonly property int sideRailWidth: 190 + readonly property int sideRailSpacing: 14 + readonly property int sideButtonHeight: 146 + readonly property int sideButtonMinHeight: 88 + readonly property int panelPadding: 12 + + // ===== Main Panel Spacing ===== + // Main content spacing. + readonly property int mainAreaPadding: 10 + readonly property int rightPaneGap: 6 + readonly property int tabBarHeight: 34 + readonly property int settingsPanelMaxWidth: 760 + readonly property int settingsOuterMargin: 40 + readonly property int settingsSectionSpacing: 20 + readonly property int settingsRowSpacing: 16 + readonly property int settingsGridSpacing: 12 + readonly property int settingsButtonHeight: 40 + readonly property int settingsActionWidth: 200 + readonly property int settingsFieldMinWidth: 160 + + // ===== Footer Tab Theme ===== + // Bottom tab styling. + readonly property color tabBarBackground: isDarkMode ? "#161d26" : "#f2f2f2" + readonly property color tabBackground: isDarkMode ? "#202833" : "#ececec" + readonly property color tabActiveBackground: isDarkMode ? "#2a3440" : "#ffffff" + readonly property color tabHoverBackground: isDarkMode ? "#263140" : "#f7f7f7" + readonly property color tabBorder: isDarkMode ? "#3a4758" : "#cfcfcf" + readonly property color tabText: isDarkMode ? "#c6d0da" : "#222222" + readonly property color tabActiveText: isDarkMode ? "#ffffff" : "#111111" + + readonly property int tabButtonMinWidth: 80 + readonly property int tabHorizontalPadding: 14 + readonly property int tabBarPadding: 6 + readonly property int tabSpacing: 2 + readonly property int tabRadius: 2 + readonly property int tabFontSize: 12 + + // ===== Form Control Theme ===== + readonly property color inputBackground: isDarkMode ? "#202833" : "#ffffff" + readonly property color inputBorder: isDarkMode ? "#4a596d" : "#cfcfcf" + readonly property color buttonBackground: isDarkMode ? "#202833" : "#ffffff" + readonly property color buttonText: isDarkMode ? "#e5eef7" : "#111111" + readonly property color checkboxText: isDarkMode ? "#d6dfeb" : "#111111" +} diff --git a/ISC/qmldir b/ISC/qmldir new file mode 100644 index 0000000..73297e3 --- /dev/null +++ b/ISC/qmldir @@ -0,0 +1,9 @@ +# ===== ISC QML Module ===== +module ISC + +# ===== Root Components ===== +Main 1.0 Main.qml +HomePage 1.0 HomePage.qml + +# ===== Singleton Theme ===== +singleton Theme 1.0 Theme.qml diff --git a/README.md b/README.md new file mode 100644 index 0000000..b0fb2c2 --- /dev/null +++ b/README.md @@ -0,0 +1,73 @@ +# ISC QtQuick App + +Small PySide6 + Qt Quick application scaffold for the `ISenseCloud` desktop UI shell. + +## Requirements + +- Python 3.10+ (tested with Python 3.14 in this workspace) +- macOS, Linux, or Windows with GUI support + +## Setup + +From the project root: + +```bash +python3 -m venv .venv +source .venv/bin/activate +python -m pip install --upgrade pip +pip install -r requirements.txt +``` + +## Run + +```bash +source .venv/bin/activate +python main.py +``` + +This launches the Qt window and loads the `ISC` QML module from `ISC/Main.qml`. + +## Project Structure + +- `main.py`: PySide6 bootstrap; creates the Qt app and loads QML module `ISC/Main`. +- `ISC/Main.qml`: top-level window definition. +- `ISC/HomePage.qml`: main UI layout (left action rail, workspace panel, footer tabs). +- `ISC/Theme.qml`: shared theme constants and dark/light mode tokens. +- `ISC/qmldir`: QML module registration. + +## Window Configuration + +Window dimensions and constraints are defined in `ISC/Main.qml`: + +- **Default size**: 1400 × 820 pixels +- **Minimum size**: 1100 × 700 pixels +- **Title bar**: "ISenseCloud" + +To adjust the window, edit the `Window` block in `ISC/Main.qml`: + +```qml +Window { + width: 1400 + height: 820 + minimumWidth: 1100 + minimumHeight: 700 + visible: true + title: qsTr("ISenseCloud") +} +``` + +## Customization + +- Toggle dark/light mode in `ISC/Theme.qml` via `isDarkMode`. +- Update sidebar and footer labels in `ISC/HomePage.qml` through `sideActions` and `bottomTabs`. + +## Troubleshooting + +- If the app does not start, verify the venv is active and dependencies are installed: + + ```bash + source .venv/bin/activate + pip install -r requirements.txt + ``` + +- If no window appears, ensure you are running in a desktop session with GUI access. diff --git a/backend/__init__.py b/backend/__init__.py new file mode 100644 index 0000000..a22d05a --- /dev/null +++ b/backend/__init__.py @@ -0,0 +1 @@ +# ===== Backend Package Marker ===== diff --git a/main.py b/main.py new file mode 100644 index 0000000..b9401f7 --- /dev/null +++ b/main.py @@ -0,0 +1,17 @@ +import sys +from pathlib import Path + +from PySide6.QtGui import QGuiApplication +from PySide6.QtQml import QQmlApplicationEngine + +if __name__ == "__main__": + # Minimal Qt bootstrap: load the ISC QML module and exit if it fails. + app = QGuiApplication(sys.argv) + engine = QQmlApplicationEngine() + engine.addImportPath(Path(__file__).parent) + engine.loadFromModule("ISC", "Main") + + if not engine.rootObjects(): + sys.exit(-1) + + sys.exit(app.exec()) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..65d13df --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,7 @@ +# ===== Project Metadata ===== +[project] +name = "PySide QtQuick Project" + +# ===== PySide Build Inputs ===== +[tool.pyside6-project] +files = ["ISC/HomePage.qml", "ISC/Main.qml", "ISC/Theme.qml", "ISC/Tabs/SettingsTab.qml", "ISC/Tabs/qmldir", "ISC/qmldir", "main.py", "backend/local_settings.py", "backend/local_settings_model.py"] diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..acc0c78 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +# ===== Runtime Dependencies ===== +PySide6