From 8bcf948b76c9564cb38d3611228ccaf73890a548 Mon Sep 17 00:00:00 2001 From: Thomas Vanbesien Date: Mon, 23 Mar 2026 16:48:32 +0100 Subject: Rename demo/ → jetting-interface/, mock-server/ → mock-jetting-controller/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Executables: QtXpl2Demo → JettingInterfaceDemo, Xpl2MockServer → MockJettingController. Dev log prefixes: "Demo" → "JI", "MockServer" → "MockJC". Window title → "Jetting Interface". --- jetting-interface/CMakeLists.txt | 25 ++ jetting-interface/CommandsPage.qml | 213 +++++++++++++ jetting-interface/DebugConsole.qml | 34 ++ jetting-interface/Main.qml | 173 +++++++++++ jetting-interface/StatusPage.qml | 620 +++++++++++++++++++++++++++++++++++++ jetting-interface/main.cpp | 42 +++ 6 files changed, 1107 insertions(+) create mode 100644 jetting-interface/CMakeLists.txt create mode 100644 jetting-interface/CommandsPage.qml create mode 100644 jetting-interface/DebugConsole.qml create mode 100644 jetting-interface/Main.qml create mode 100644 jetting-interface/StatusPage.qml create mode 100644 jetting-interface/main.cpp (limited to 'jetting-interface') diff --git a/jetting-interface/CMakeLists.txt b/jetting-interface/CMakeLists.txt new file mode 100644 index 0000000..4d46ba6 --- /dev/null +++ b/jetting-interface/CMakeLists.txt @@ -0,0 +1,25 @@ +qt_add_executable(JettingInterfaceDemo main.cpp) + +qt_add_qml_module( + JettingInterfaceDemo + URI + JettingInterfaceDemo + VERSION + 1.0 + QML_FILES + Main.qml + CommandsPage.qml + StatusPage.qml + DebugConsole.qml + # IMPORT_PATH sets QT_QML_IMPORT_PATH on the target, which qmlls reads to + # resolve imports like "import Xpl2" in .qmlls.ini. + IMPORT_PATH + "${PROJECT_BINARY_DIR}/qml") + +set_target_properties( + JettingInterfaceDemo PROPERTIES RUNTIME_OUTPUT_DIRECTORY + "${PROJECT_BINARY_DIR}/bin") + +target_link_libraries(JettingInterfaceDemo PRIVATE Qt6::Quick QtXpl2plugin) +target_include_directories(JettingInterfaceDemo + PRIVATE "${PROJECT_SOURCE_DIR}/src") diff --git a/jetting-interface/CommandsPage.qml b/jetting-interface/CommandsPage.qml new file mode 100644 index 0000000..5a084e6 --- /dev/null +++ b/jetting-interface/CommandsPage.qml @@ -0,0 +1,213 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Xpl2 + +ColumnLayout { + id: commandsPage + + required property int demoPhCount + required property ListModel phModel + + spacing: 12 + + // --- JC Version --- + GroupBox { + Layout.fillWidth: true + enabled: Xpl2Client.connected + title: "Jetting Controller" + + RowLayout { + anchors.fill: parent + + Button { + text: "Get JC Version" + + onClicked: Xpl2Client.getJcVersion() + } + + Label { + text: Xpl2Client.controllerId > 0 + ? "Controller: %1 | FW: %2 | HW: %3 | PHs: %4".arg( + Xpl2Client.controllerId).arg( + Xpl2Client.firmwareVersion).arg( + Xpl2Client.hardwareVersion).arg( + Xpl2Client.printheadCount) : "No version data" + } + } + } + + // --- Control --- + GroupBox { + Layout.fillWidth: true + enabled: Xpl2Client.connected + title: "Control" + + GridLayout { + anchors.fill: parent + columns: 4 + + Button { + text: "Jetting All On" + + onClicked: Xpl2Client.jettingAllOn() + } + + Button { + text: "Jetting Off" + + onClicked: Xpl2Client.jettingOff() + } + + Button { + text: "JC LED On" + + onClicked: Xpl2Client.jcIdLedOn() + } + + Button { + text: "JC LED Off" + + onClicked: Xpl2Client.jcIdLedOff() + } + + Button { + text: "JC Calibration" + + onClicked: Xpl2Client.jcCalibration() + } + + Button { + text: "Reset Fault Codes" + + onClicked: Xpl2Client.jcResetFaultCodes() + } + } + } + + // --- Configuration --- + GroupBox { + Layout.fillWidth: true + enabled: Xpl2Client.connected + title: "Configuration" + + GridLayout { + anchors.fill: parent + columns: 4 + + Button { + text: "Save All Settings" + + onClicked: Xpl2Client.jcSaveAllPrintheadSettings() + } + + Button { + text: "Reboot All PHs" + + onClicked: Xpl2Client.jcRebootAllPrintheads() + } + + Button { + text: "Restart JC" + + onClicked: Xpl2Client.jcRestart() + } + + Button { + text: "Shutdown JC" + + onClicked: Xpl2Client.jcShutdown() + } + } + } + + // --- Imaging --- + GroupBox { + Layout.fillWidth: true + enabled: Xpl2Client.connected + title: "Imaging" + + GridLayout { + anchors.fill: parent + columns: 4 + + Button { + text: "Start Imaging" + + onClicked: Xpl2Client.imagingStart(1.0) + } + + Button { + text: "Stop Imaging" + + onClicked: Xpl2Client.imagingStop() + } + + Button { + text: "Image Count" + + onClicked: Xpl2Client.imageCount() + } + } + } + + // --- Printheads --- + GroupBox { + Layout.fillHeight: true + Layout.fillWidth: true + enabled: Xpl2Client.connected + title: "Printheads (%1)".arg(commandsPage.demoPhCount) + + ColumnLayout { + anchors.fill: parent + + Button { + text: "Get All PH Versions" + + onClicked: { + for (let i = 0; i < commandsPage.phModel.count; ++i) + Xpl2Client.getPhVersion(commandsPage.phModel.get(i).phId); + } + } + + ScrollView { + Layout.fillHeight: true + Layout.fillWidth: true + + ListView { + model: commandsPage.phModel + spacing: 4 + + delegate: RowLayout { + id: phDelegate + + required property int phId + required property string versionInfo + + width: ListView.view.width + + Label { + Layout.preferredWidth: 50 + font.bold: true + text: "PH %1".arg(phDelegate.phId) + } + + Button { + text: "Version" + + onClicked: Xpl2Client.getPhVersion(phDelegate.phId) + } + + Label { + Layout.fillWidth: true + elide: Text.ElideRight + text: phDelegate.versionInfo || "—" + } + } + } + } + } + } +} diff --git a/jetting-interface/DebugConsole.qml b/jetting-interface/DebugConsole.qml new file mode 100644 index 0000000..9a5a9ff --- /dev/null +++ b/jetting-interface/DebugConsole.qml @@ -0,0 +1,34 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import QtQuick.Controls + +Rectangle { + id: debugRoot + + function appendLog(msg: string): void { + let ts = new Date().toLocaleTimeString(Qt.locale(), "HH:mm:ss.zzz"); + debugLog.text += "[" + ts + "] " + msg + "\n"; + debugLog.cursorPosition = debugLog.text.length; + } + + border.color: "#444" + color: "#1e1e1e" + radius: 4 + + ScrollView { + anchors.fill: parent + anchors.margins: 4 + + TextArea { + id: debugLog + + background: null + color: "#cccccc" + font.family: "monospace" + font.pointSize: 9 + readOnly: true + wrapMode: TextEdit.Wrap + } + } +} diff --git a/jetting-interface/Main.qml b/jetting-interface/Main.qml new file mode 100644 index 0000000..1c7b553 --- /dev/null +++ b/jetting-interface/Main.qml @@ -0,0 +1,173 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Xpl2 + +ApplicationWindow { + id: root + + // Set from C++ via setInitialProperties (--printheads CLI arg, default 10). + required property int demoPhCount + + height: 1200 + title: "Jetting Interface" + visible: true + width: 900 + + Component.onCompleted: { + for (let i = 1; i <= root.demoPhCount; ++i) + phModel.append({ + "phId": i, + "versionInfo": "" + }); + } + + ListModel { + id: phModel + + } + + Connections { + function onConnectedChanged() { + debugConsole.appendLog(Xpl2Client.connected + ? "Controller connected" : + "Controller disconnected"); + } + + function onErrorOccurred(error: string) { + debugConsole.appendLog("ERROR: " + error); + } + + function onJcStatusReceived(status) { + statusPage.lastJcStatus = status; + } + + function onListeningChanged() { + debugConsole.appendLog(Xpl2Client.listening + ? "Listening on ports 9110/9111/9112" : + "Stopped listening"); + } + + function onPhStatusReceived(status) { + statusPage.lastPhStatus = status; + } + + function onPhVersionReceived(controllerId: int, printheadId: int, + mcuFirmwareVersion: string, + mcuHardwareVersion: string, + mcuFirmwareVariant: string, + fpgaFirmwareVersion: string, + fpgaHardwareVersion: string, + bootloaderVersion: string) { + for (let i = 0; i < phModel.count; ++i) { + if (phModel.get(i).phId === printheadId) { + phModel.setProperty(i, "versionInfo", + "MCU %1/%2 (%3) | FPGA %4/%5 | Boot %6".arg( + mcuFirmwareVersion).arg( + mcuHardwareVersion).arg( + mcuFirmwareVariant).arg( + fpgaFirmwareVersion).arg( + fpgaHardwareVersion).arg( + bootloaderVersion)); + break; + } + } + } + + function onShuttingDown() { + debugConsole.appendLog("SERVER SHUTTING DOWN"); + } + + function onStatusMessage(message: string) { + debugConsole.appendLog(message); + } + + target: Xpl2Client + } + + ColumnLayout { + anchors.fill: parent + spacing: 0 + + // --- Connection (always visible) --- + GroupBox { + Layout.bottomMargin: 0 + Layout.fillWidth: true + Layout.margins: 16 + title: "Connection" + + RowLayout { + anchors.fill: parent + + Label { + text: Xpl2Client.connected ? "Controller connected" : + "Waiting for controller…" + } + + Item { + Layout.fillWidth: true + } + + Button { + text: Xpl2Client.listening ? "Stop" : "Listen" + + onClicked: { + if (Xpl2Client.listening) + Xpl2Client.stopListening(); + else + Xpl2Client.startListening(); + } + } + } + } + + // --- Tab bar --- + TabBar { + id: tabBar + + Layout.fillWidth: true + Layout.leftMargin: 16 + Layout.rightMargin: 16 + + TabButton { + text: "Commands" + } + + TabButton { + text: "Status" + } + } + + // --- Swipe view --- + SwipeView { + id: swipeView + + Layout.fillHeight: true + Layout.fillWidth: true + Layout.margins: 16 + currentIndex: tabBar.currentIndex + + onCurrentIndexChanged: tabBar.currentIndex = currentIndex + + CommandsPage { + demoPhCount: root.demoPhCount + phModel: phModel + } + + StatusPage { + id: statusPage + + } + } + + // --- Debug Console --- + DebugConsole { + id: debugConsole + + Layout.fillWidth: true + Layout.preferredHeight: 160 + } + } +} diff --git a/jetting-interface/StatusPage.qml b/jetting-interface/StatusPage.qml new file mode 100644 index 0000000..6a85bcc --- /dev/null +++ b/jetting-interface/StatusPage.qml @@ -0,0 +1,620 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Xpl2 + +ColumnLayout { + id: statusPage + + property var lastJcStatus: null + property var lastPhStatus: null + + spacing: 12 + + // --- Status Messaging Controls --- + GroupBox { + Layout.fillWidth: true + enabled: Xpl2Client.connected + title: "Status Messaging" + + GridLayout { + anchors.fill: parent + columns: 2 + + Label { + text: "Level:" + } + + ComboBox { + id: statusLevelCombo + + Layout.fillWidth: true + model: ["1 — Basic", "2 — Extended"] + } + + Label { + text: "Interval (ms):" + } + + SpinBox { + id: statusIntervalSpin + + Layout.fillWidth: true + from: 100 + stepSize: 100 + to: 10000 + value: 1000 + } + + Button { + text: "Start JC Status" + + onClicked: Xpl2Client.jcStatusMessagingStart( + statusLevelCombo.currentIndex + 1, + statusIntervalSpin.value) + } + + Button { + text: "Stop JC Status" + + onClicked: Xpl2Client.jcStatusMessagingStop() + } + + Button { + text: "Start PH Status" + + onClicked: Xpl2Client.phStatusMessagingStart( + statusLevelCombo.currentIndex + 1, + statusIntervalSpin.value) + } + + Button { + text: "Stop PH Status" + + onClicked: Xpl2Client.phStatusMessagingStop() + } + } + } + + // --- JC Status Display --- + GroupBox { + Layout.fillWidth: true + title: "JC Status" + + RowLayout { + anchors.fill: parent + + GridLayout { + Layout.fillWidth: true + columns: 4 + + Label { + font.bold: true + text: "CPU:" + } + + Label { + text: statusPage.lastJcStatus + ? statusPage.lastJcStatus.cpuPercentageBusy.toFixed( + 1) + "%" : "—" + } + + Label { + font.bold: true + text: "Temp:" + } + + Label { + text: statusPage.lastJcStatus + ? statusPage.lastJcStatus.temperature.toFixed(1) + + "°C" : "—" + } + + Label { + font.bold: true + text: "Rail 5V:" + } + + Label { + text: statusPage.lastJcStatus + ? statusPage.lastJcStatus.rail5V.toFixed(2) + "V" : + "—" + } + + Label { + font.bold: true + text: "CAN 8V:" + } + + Label { + text: statusPage.lastJcStatus + ? statusPage.lastJcStatus.railCanBus8V.toFixed(2) + + "V" : "—" + } + + Label { + font.bold: true + text: "Humidity:" + } + + Label { + text: statusPage.lastJcStatus + ? statusPage.lastJcStatus.humidity.toFixed(1) + "%" : + "—" + } + + Label { + font.bold: true + text: "Bus I:" + } + + Label { + text: statusPage.lastJcStatus + ? statusPage.lastJcStatus.busCurrent.toFixed(3) + "A" : + "—" + } + + Label { + font.bold: true + text: "Uptime:" + } + + Label { + text: statusPage.lastJcStatus + ? statusPage.lastJcStatus.onTimeSeconds + "s" : "—" + } + } + + // --- Extended (Level 2) --- + GridLayout { + Layout.fillWidth: true + columns: 4 + visible: statusPage.lastJcStatus !== null + && statusPage.lastJcStatus.statusLevel >= 2 + + Label { + font.bold: true + text: "IP:" + } + + Label { + text: statusPage.lastJcStatus + ? statusPage.lastJcStatus.ipAddress : "—" + } + + Label { + font.bold: true + text: "eFuse V:" + } + + Label { + text: statusPage.lastJcStatus + ? statusPage.lastJcStatus.eFuseVoltage.toFixed(2) + + "V" : "—" + } + + Label { + font.bold: true + text: "eFuse Bus:" + } + + Label { + text: statusPage.lastJcStatus ? ( + statusPage.lastJcStatus.eFuseBusEnabled + ? "On" : "Off") : "—" + } + + Label { + font.bold: true + text: "Bus Power:" + } + + Label { + text: statusPage.lastJcStatus ? ( + statusPage.lastJcStatus.busPowerEnabled + ? "On" : "Off") : "—" + } + + Label { + font.bold: true + text: "Bus OK:" + } + + Label { + text: statusPage.lastJcStatus ? ( + statusPage.lastJcStatus.busPowerOk + ? "Yes" : "No") : "—" + } + + Label { + font.bold: true + text: "Switch:" + } + + Label { + text: statusPage.lastJcStatus ? String( + statusPage.lastJcStatus.switchValue) : + "—" + } + + Label { + font.bold: true + text: "FW:" + } + + Label { + text: statusPage.lastJcStatus + ? statusPage.lastJcStatus.firmwareVersion : "—" + } + + Label { + font.bold: true + text: "HW:" + } + + Label { + text: statusPage.lastJcStatus + ? statusPage.lastJcStatus.hardwareVersion : "—" + } + + Label { + font.bold: true + text: "Indicators:" + } + + Label { + Layout.columnSpan: 3 + text: statusPage.lastJcStatus + ? [statusPage.lastJcStatus.indicator0, + statusPage.lastJcStatus.indicator1, + statusPage.lastJcStatus.indicator2, + statusPage.lastJcStatus.indicator3, + statusPage.lastJcStatus.indicator4, + statusPage.lastJcStatus.indicator5].map(function ( + v) { + return v ? "1" : "0"; + }).join(" ") : "—" + } + } + } + } + + // --- PH Status Display --- + GroupBox { + Layout.fillHeight: true + Layout.fillWidth: true + title: "PH Status" + + RowLayout { + anchors.fill: parent + + GridLayout { + Layout.fillWidth: true + columns: 4 + + Label { + font.bold: true + text: "PH:" + } + + Label { + text: statusPage.lastPhStatus ? String( + statusPage.lastPhStatus.printheadId) : + "—" + } + + Label { + font.bold: true + text: "Temp:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.temperature.toFixed(1) + + "°C" : "—" + } + + Label { + font.bold: true + text: "MCU Temp:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.mcuTemperature.toFixed(1) + + "°C" : "—" + } + + Label { + font.bold: true + text: "Humidity:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.humidity.toFixed(1) + "%" : + "—" + } + + Label { + font.bold: true + text: "PDS V:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.pdsVoltage.toFixed(2) + "V" : + "—" + } + + Label { + font.bold: true + text: "MDS V:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.mdsVoltage.toFixed(2) + "V" : + "—" + } + + Label { + font.bold: true + text: "Sys V:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.systemVoltage.toFixed(2) + + "V" : "—" + } + + Label { + font.bold: true + text: "VDD:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.vdd.toFixed(2) + "V" : "—" + } + + Label { + font.bold: true + text: "eFuse I:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.eFuseCurrent.toFixed(3) + + "A" : "—" + } + + Label { + font.bold: true + text: "Nozzle I:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.nozzleCurrent.toFixed(3) + + "A" : "—" + } + + Label { + font.bold: true + text: "Duty Cycle:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.dutyCycle.toFixed(1) + "%" : + "—" + } + + Label { + font.bold: true + text: "Drive:" + } + + Label { + text: statusPage.lastPhStatus ? String( + statusPage.lastPhStatus.drive) : + "—" + } + + Label { + font.bold: true + text: "Uptime:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.onTimeSeconds + "s" : "—" + } + } + + // --- Extended (Level 2) --- + GridLayout { + Layout.fillWidth: true + columns: 4 + visible: statusPage.lastPhStatus !== null + && statusPage.lastPhStatus.statusLevel >= 2 + + Label { + font.bold: true + text: "MCU FW:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.mcuFirmwareVersion : "—" + } + + Label { + font.bold: true + text: "MCU HW:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.mcuHardwareVersion : "—" + } + + Label { + font.bold: true + text: "MCU Variant:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.mcuFirmwareVariant : "—" + } + + Label { + font.bold: true + text: "FPGA FW:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.fpgaFirmwareVersion : "—" + } + + Label { + font.bold: true + text: "FPGA HW:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.fpgaHardwareVersion : "—" + } + + Label { + font.bold: true + text: "Boot:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.bootloaderVersion : "—" + } + + Label { + font.bold: true + text: "Max Temp:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.maxAllowedTemperature.toFixed( + 1) + "°C" : "—" + } + + Label { + font.bold: true + text: "eFuse Max:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.eFuseCurrentMax.toFixed(2) + + "A" : "—" + } + + Label { + font.bold: true + text: "PDS V Max:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.pdsVoltageMax.toFixed(2) + + "V" : "—" + } + + Label { + font.bold: true + text: "PDS V Min:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.pdsVoltageMin.toFixed(2) + + "V" : "—" + } + + Label { + font.bold: true + text: "MDS V Max:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.mdsVoltageMax.toFixed(2) + + "V" : "—" + } + + Label { + font.bold: true + text: "MDS V Min:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.mdsVoltageMin.toFixed(2) + + "V" : "—" + } + + Label { + font.bold: true + text: "Meas. HW:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.measuredHardwareVersion : + "—" + } + + Label { + font.bold: true + text: "Accel ID:" + } + + Label { + text: statusPage.lastPhStatus ? String( + statusPage.lastPhStatus.accelerometerId) : + "—" + } + + Label { + font.bold: true + text: "Gyro:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.gyroX + ", " + + statusPage.lastPhStatus.gyroY + ", " + + statusPage.lastPhStatus.gyroZ : "—" + } + + Label { + font.bold: true + text: "Accel:" + } + + Label { + text: statusPage.lastPhStatus + ? statusPage.lastPhStatus.accelerationX + ", " + + statusPage.lastPhStatus.accelerationY + ", " + + statusPage.lastPhStatus.accelerationZ : "—" + } + } + } + } +} diff --git a/jetting-interface/main.cpp b/jetting-interface/main.cpp new file mode 100644 index 0000000..b88bd37 --- /dev/null +++ b/jetting-interface/main.cpp @@ -0,0 +1,42 @@ +/** + * @file main.cpp + * @brief Entry point for the Jetting Interface demo application. + */ +#include "Xpl2Client.h" + +#include +#include +#include + +#include +Q_IMPORT_QML_PLUGIN (Xpl2Plugin) + +int +main (int argc, char *argv[]) +{ + qSetMessagePattern ("JI [%{time HH:mm:ss.zzz}] %{message}"); + + QGuiApplication app (argc, argv); + + QCommandLineParser parser; + parser.addOption ({ "wire-debug", "Log raw wire TX/RX to dev log" }); + parser.addOption ({ "printheads", + "Number of simulated printheads (default 10)", "N", + "10" }); + parser.addHelpOption (); + parser.process (app); + + if (parser.isSet ("wire-debug")) + Xpl2Client::enableWireDebug (); + + int phCount = qBound (1, parser.value ("printheads").toInt (), 99); + + QQmlApplicationEngine engine; + engine.setInitialProperties ({ { "demoPhCount", phCount } }); + QObject::connect ( + &engine, &QQmlApplicationEngine::objectCreationFailed, &app, + [] () { QCoreApplication::exit (1); }, Qt::QueuedConnection); + + engine.loadFromModule ("JettingInterfaceDemo", "Main"); + return app.exec (); +} -- cgit v1.2.3