diff --git a/ScreenPlayWidget/Widget.qml b/ScreenPlayWidget/Widget.qml index aecb0edb..c3cfef46 100644 --- a/ScreenPlayWidget/Widget.qml +++ b/ScreenPlayWidget/Widget.qml @@ -22,20 +22,17 @@ Item { var newObject = Qt.createQmlObject(obj2.toString(), root, "err") newObject.destroy(10000) } - } + // Replace wallpaper with QML Scene + function onReloadQML(oldType) { - Action { - shortcut: "F5" - onTriggered: { loader.sourceComponent = undefined loader.source = "" Widget.clearComponentCache() - if (Widget.type === "qmlWidget") { - loader.source = Qt.resolvedUrl(Widget.sourcePath) - } else if (Widget.type === "htmlWidget") { - loader.sourceComponent = webViewComponent - } + + loader.source = Qt.resolvedUrl(Widget.projectSourceFileAbsolute) } + + } OpacityAnimator { diff --git a/ScreenPlayWidget/main.cpp b/ScreenPlayWidget/main.cpp index fba1bda1..42170886 100644 --- a/ScreenPlayWidget/main.cpp +++ b/ScreenPlayWidget/main.cpp @@ -16,8 +16,8 @@ int main(int argc, char* argv[]) // If we start with only one argument (path, appID, type), // it means we want to test a single widget if (argumentList.length() == 1) { - //WidgetWindow spwmw("test", "appid", "qmlWidget", { 0, 0 }); - WidgetWindow spwmw("C:/Program Files (x86)/Steam/steamapps/workshop/content/672870/2136442401", "appid", "qmlWidget", { 0, 0 }); + //WidgetWindow spwmw("test", "appid", "qmlWidget", { 0, 0 }, true); + WidgetWindow spwmw("C:/Program Files (x86)/Steam/steamapps/workshop/content/672870/2136442401", "appid", "qmlWidget", { 0, 0 }, true); return app.exec(); } diff --git a/ScreenPlayWidget/src/widgetwindow.cpp b/ScreenPlayWidget/src/widgetwindow.cpp index 4fadcbc3..39557856 100644 --- a/ScreenPlayWidget/src/widgetwindow.cpp +++ b/ScreenPlayWidget/src/widgetwindow.cpp @@ -21,11 +21,13 @@ WidgetWindow::WidgetWindow( const QString& projectPath, const QString& appID, const QString& type, - const QPoint& position) + const QPoint& position, + const bool debugMode) : QObject(nullptr) , m_appID { appID } , m_position { position } , m_sdk { std::make_unique(appID, type) } + , m_debugMode { debugMode } { qRegisterMetaType(); @@ -56,14 +58,15 @@ WidgetWindow::WidgetWindow( setProjectSourceFileAbsolute({ "qrc:/test.qml" }); setType(ScreenPlay::InstalledType::InstalledType::QMLWidget); } else { - auto projectOpt = ScreenPlayUtil::openJsonFileToObject(projectPath + "/project.json"); + setProjectPath(projectPath); + auto projectOpt = ScreenPlayUtil::openJsonFileToObject(m_projectPath + "/project.json"); if (!projectOpt.has_value()) { qWarning() << "Unable to parse project file!"; } m_project = projectOpt.value(); setProjectSourceFile(m_project.value("file").toString()); - setProjectSourceFileAbsolute(QUrl::fromLocalFile(projectPath + "/" + projectSourceFile())); + setProjectSourceFileAbsolute(QUrl::fromLocalFile(m_projectPath + "/" + projectSourceFile())); if (auto typeOpt = ScreenPlayUtil::getInstalledTypeFromString(m_project.value("type").toString())) { setType(typeOpt.value()); @@ -79,26 +82,30 @@ WidgetWindow::WidgetWindow( m_window.show(); // Do not trigger position changed save reuqest on startup - sdk()->start(); - QTimer::singleShot(1000, this, [=, this]() { - // We limit ourself to only update the position every 500ms! - auto sendPositionUpdate = [this]() { - m_positionMessageLimiter.stop(); - if (!m_sdk->isConnected()) - return; + if (!m_debugMode) { + sdk()->start(); + QTimer::singleShot(1000, this, [=, this]() { + // We limit ourself to only update the position every 500ms! + auto sendPositionUpdate = [this]() { + m_positionMessageLimiter.stop(); + if (!m_sdk->isConnected()) + return; - QJsonObject obj; - obj.insert("messageType", "positionUpdate"); - obj.insert("positionX", m_window.x()); - obj.insert("positionY", m_window.y()); - m_sdk->sendMessage(obj); - }; - m_positionMessageLimiter.setInterval(500); + QJsonObject obj; + obj.insert("messageType", "positionUpdate"); + obj.insert("positionX", m_window.x()); + obj.insert("positionY", m_window.y()); + m_sdk->sendMessage(obj); + }; + m_positionMessageLimiter.setInterval(500); - QObject::connect(&m_positionMessageLimiter, &QTimer::timeout, this, sendPositionUpdate); - QObject::connect(&m_window, &QWindow::xChanged, this, [this]() { m_positionMessageLimiter.start(); }); - QObject::connect(&m_window, &QWindow::yChanged, this, [this]() { m_positionMessageLimiter.start(); }); - }); + QObject::connect(&m_positionMessageLimiter, &QTimer::timeout, this, sendPositionUpdate); + QObject::connect(&m_window, &QWindow::xChanged, this, [this]() { m_positionMessageLimiter.start(); }); + QObject::connect(&m_window, &QWindow::yChanged, this, [this]() { m_positionMessageLimiter.start(); }); + }); + } + + setupLiveReloading(); } void WidgetWindow::setSize(QSize size) @@ -133,11 +140,6 @@ void WidgetWindow::setWidgetSize(const int with, const int height) m_window.setHeight(height); } -void WidgetWindow::clearComponentCache() -{ - m_window.engine()->clearComponentCache(); -} - #ifdef Q_OS_WIN void WidgetWindow::setWindowBlur(unsigned int style) { @@ -174,3 +176,34 @@ void WidgetWindow::setWindowBlur(unsigned int style) } } #endif + +/*! + \brief Call the qml engine clearComponentCache. This function is used for + refreshing wallpaper when the content has changed. For example this + is needed for live editing when the content is chached. +*/ +void WidgetWindow::clearComponentCache() +{ + m_window.engine()->clearComponentCache(); +} + +/*! + \brief This public slot is for QML usage. We limit the change event updates + to every 50ms, because the filesystem can be very trigger happy + with multiple change events per second. + */ +void WidgetWindow::setupLiveReloading() +{ + auto reloadQMLLambda = [this]() { + m_liveReloadLimiter.stop(); + emit reloadQML(type()); + }; + auto timeoutLambda = [this]() { + m_liveReloadLimiter.start(50); + }; + + QObject::connect(&m_fileSystemWatcher, &QFileSystemWatcher::directoryChanged, this, timeoutLambda); + QObject::connect(&m_fileSystemWatcher, &QFileSystemWatcher::fileChanged, this, timeoutLambda); + QObject::connect(&m_liveReloadLimiter, &QTimer::timeout, this, reloadQMLLambda); + m_fileSystemWatcher.addPaths({ projectPath() }); +} diff --git a/ScreenPlayWidget/src/widgetwindow.h b/ScreenPlayWidget/src/widgetwindow.h index e41e82f0..74ddcbf3 100644 --- a/ScreenPlayWidget/src/widgetwindow.h +++ b/ScreenPlayWidget/src/widgetwindow.h @@ -52,6 +52,7 @@ #include #ifdef Q_OS_WIN +#include #include #endif @@ -67,7 +68,8 @@ public: const QString& projectPath, const QString& appid, const QString& type, - const QPoint& position); + const QPoint& position, + const bool debugMode = false); Q_PROPERTY(QString appID READ appID WRITE setAppID NOTIFY appIDChanged) Q_PROPERTY(QString projectPath READ projectPath WRITE setProjectPath NOTIFY projectPathChanged) @@ -76,6 +78,7 @@ public: Q_PROPERTY(QPoint position READ position WRITE setPosition NOTIFY positionChanged) Q_PROPERTY(ScreenPlay::InstalledType::InstalledType type READ type WRITE setType NOTIFY typeChanged) Q_PROPERTY(ScreenPlaySDK* sdk READ sdk WRITE setSdk NOTIFY sdkChanged) + Q_PROPERTY(bool debugMode READ debugMode WRITE setDebugMode NOTIFY debugModeChanged) QString appID() const { return m_appID; } QPoint position() const { return m_position; } @@ -84,10 +87,11 @@ public: const QString& projectSourceFile() const { return m_projectSourceFile; } const QUrl& projectSourceFileAbsolute() const { return m_projectSourceFileAbsolute; } ScreenPlaySDK* sdk() const { return m_sdk.get(); } + bool debugMode() const { return m_debugMode; } signals: void qmlExit(); - + void reloadQML(const ScreenPlay::InstalledType::InstalledType oldType); void appIDChanged(QString appID); void qmlSceneValueReceived(QString key, QString value); void positionChanged(QPoint position); @@ -95,8 +99,8 @@ signals: void typeChanged(ScreenPlay::InstalledType::InstalledType); void projectSourceFileChanged(const QString& projectSourceFile); void projectSourceFileAbsoluteChanged(const QUrl& projectSourceFileAbsolute); - - void sdkChanged(ScreenPlaySDK*); + void sdkChanged(ScreenPlaySDK* sdk); + void debugModeChanged(bool debugMode); public slots: void setSize(QSize size); @@ -171,9 +175,21 @@ public slots: emit sdkChanged(sdk); } + void setDebugMode(bool debugMode) + { + if (m_debugMode == debugMode) + return; + m_debugMode = debugMode; + emit debugModeChanged(m_debugMode); + } + +private: + void setupLiveReloading(); + private: QString m_appID; QString m_projectPath; + QString m_projectSourceFile; QJsonObject m_project; QPoint m_clickPos = { 0, 0 }; QPoint m_lastPos = { 0, 0 }; @@ -182,10 +198,11 @@ private: std::unique_ptr m_sdk; QTimer m_positionMessageLimiter; ScreenPlay::InstalledType::InstalledType m_type; - + QFileSystemWatcher m_fileSystemWatcher; + QTimer m_liveReloadLimiter; + QUrl m_projectSourceFileAbsolute; #ifdef Q_OS_WIN HWND m_hwnd; #endif - QString m_projectSourceFile; - QUrl m_projectSourceFileAbsolute; + bool m_debugMode = false; };