1
0
mirror of https://gitlab.com/kelteseth/ScreenPlay.git synced 2024-11-07 03:22:33 +01:00

Merge remote-tracking branch 'origin/174-add-godot-wallpaper-support' into 174-add-godot-wallpaper-support

This commit is contained in:
Elias Steurer 2023-11-29 11:33:18 +01:00
commit c5d2871440
74 changed files with 1020 additions and 566 deletions

View File

@ -35,7 +35,7 @@
- cd .. - cd ..
- git clone https://invent.kde.org/plasma/layer-shell-qt.git - git clone https://invent.kde.org/plasma/layer-shell-qt.git
- cd layer-shell-qt - cd layer-shell-qt
- cmake configure . -DCMAKE_PREFIX_PATH="./../../../aqt/6.6.0/gcc_64" - cmake configure . -DCMAKE_PREFIX_PATH="./../../../aqt/6.6.1/gcc_64"
- make - make
- make install - make install
- cd .. - cd ..

2
.vscode/launch.json vendored
View File

@ -17,7 +17,7 @@
"environment": [ "environment": [
{ {
"name": "Path", "name": "Path",
"value": "${env:Path};${workspaceFolder}\\..\\aqt\\6.6.0\\msvc2019_64\\bin\\;${workspaceFolder}\\..\\aqt\\6.6.0\\msvc2019_64\\modules\\;${workspaceFolder}\\..\\aqt\\6.6.0\\msvc2019_64\\qml\\;${workspaceFolder}\\..\\vcpkg\\installed\\x64-windows\\debug\\bin;" "value": "${env:Path};${workspaceFolder}\\..\\aqt\\6.6.1\\msvc2019_64\\bin\\;${workspaceFolder}\\..\\aqt\\6.6.1\\msvc2019_64\\modules\\;${workspaceFolder}\\..\\aqt\\6.6.1\\msvc2019_64\\qml\\;${workspaceFolder}\\..\\vcpkg\\installed\\x64-windows\\debug\\bin;"
} }
], ],
"visualizerFile": "${workspaceFolder}/.vscode/qt.natvis.xml" "visualizerFile": "${workspaceFolder}/.vscode/qt.natvis.xml"

View File

@ -1,7 +1,10 @@
#pragma once #pragma once
#define SCREENPLAY_VERSION "@SCREENPLAY_VERSION@"
#define SCREENPLAY_SOURCE_DIR "@SCREENPLAY_SOURCE_DIR@" #define SCREENPLAY_SOURCE_DIR "@SCREENPLAY_SOURCE_DIR@"
#define SCREENPLAY_GODOT_VERSION "@SCREENPLAY_GODOT_VERSION@" #define SCREENPLAY_GODOT_VERSION "@SCREENPLAY_GODOT_VERSION@"
#define SCREENPLAY_GODOT_VERSION_MAJOR @SCREENPLAY_GODOT_VERSION_MAJOR@
#define SCREENPLAY_GODOT_VERSION_MINOR @SCREENPLAY_GODOT_VERSION_MINOR@
#define SCREENPLAY_GODOT_RELEASE_TYPE "@SCREENPLAY_GODOT_RELEASE_TYPE@" #define SCREENPLAY_GODOT_RELEASE_TYPE "@SCREENPLAY_GODOT_RELEASE_TYPE@"
#define SCREENPLAY_BUILD_TYPE "@SCREENPLAY_BUILD_TYPE@" #define SCREENPLAY_BUILD_TYPE "@SCREENPLAY_BUILD_TYPE@"
#define SCREENPLAY_GIT_BRANCH_NAME "@SCREENPLAY_GIT_BRANCH_NAME@" #define SCREENPLAY_GIT_BRANCH_NAME "@SCREENPLAY_GIT_BRANCH_NAME@"

View File

@ -1,17 +1,24 @@
# ! generate_cmake_variable_header : Generates a header CmakeVariables.h that contains defines for the variables specified in CmakeVariables.h.in! # ! generate_cmake_variable_header : Generates a header CmakeVariables.h that contains defines for the variables specified in
# CmakeVariables.h.in!
# #
# The generated CmakeVariables.h header can then be used to access e.g. the PROJECT_NAME define in C++ code. # The generated CmakeVariables.h header can then be used to access e.g. the PROJECT_NAME define in C++ code.
# #
# Example # Example generate_cmake_variable_header(${PROJECT_NAME})
# generate_cmake_variable_header(${PROJECT_NAME})
# #
function(generate_cmake_variable_header TARGET) function(generate_cmake_variable_header TARGET)
# NOTE: Also add to CMakeVariables.h.in ! # Also add to CMakeVariables.h.in
set(SCREENPLAY_SOURCE_DIR ${CMAKE_SOURCE_DIR}) set(SCREENPLAY_SOURCE_DIR ${CMAKE_SOURCE_DIR})
# Like v4.2-beta3 or v5.0.1-stable
set(SCREENPLAY_GODOT_VERSION ${GODOT_VERSION}) set(SCREENPLAY_GODOT_VERSION ${GODOT_VERSION})
# Only single numbers
set(SCREENPLAY_GODOT_VERSION_MAJOR ${GODOT_VERSION_MAJOR})
set(SCREENPLAY_GODOT_VERSION_MINOR ${GODOT_VERSION_MINOR})
# stable, rc1 or beta5
set(SCREENPLAY_GODOT_RELEASE_TYPE ${GODOT_RELEASE_TYPE}) set(SCREENPLAY_GODOT_RELEASE_TYPE ${GODOT_RELEASE_TYPE})
set(SCREENPLAY_BUILD_TYPE "${CMAKE_BUILD_TYPE}") set(SCREENPLAY_BUILD_TYPE "${CMAKE_BUILD_TYPE}")
set(SCREENPLAY_BUILD_DATE "${BUILD_DATE}") set(SCREENPLAY_BUILD_DATE "${BUILD_DATE}")
set(SCREENPLAY_VERSION "${SCREENPLAY_VERSION}")
set(SCREENPLAY_GIT_BRANCH_NAME "${GIT_BRANCH_NAME}") set(SCREENPLAY_GIT_BRANCH_NAME "${GIT_BRANCH_NAME}")
set(SCREENPLAY_GIT_COMMIT_HASH "${GIT_COMMIT_HASH}") set(SCREENPLAY_GIT_COMMIT_HASH "${GIT_COMMIT_HASH}")
@ -27,7 +34,8 @@ function(generate_cmake_variable_header TARGET)
# Specify the configuration file from which the header file will be generated # Specify the configuration file from which the header file will be generated
configure_file(${CMAKE_SOURCE_DIR}/CMake/CMakeVariables.h.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}/CMakeVariables.h @ONLY) configure_file(${CMAKE_SOURCE_DIR}/CMake/CMakeVariables.h.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}/CMakeVariables.h @ONLY)
message(STATUS "GENERATE: ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}/CMakeVariables.h and add ${TARGET} to ${CMAKE_CURRENT_BINARY_DIR}") message(
STATUS "GENERATE: ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}/CMakeVariables.h and add ${TARGET} to ${CMAKE_CURRENT_BINARY_DIR}")
# Add the directory containing the generated header # Add the directory containing the generated header
target_include_directories(${TARGET} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) target_include_directories(${TARGET} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})

View File

@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.22.0)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake" ${CMAKE_MODULE_PATH}) set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake" ${CMAKE_MODULE_PATH})
include(GetProjectVersion) include(GetProjectVersion)
get_project_version(PROJECT_VERSION) get_project_version(SCREENPLAY_VERSION)
# This must be set before project() # This must be set before project()
if(APPLE) if(APPLE)
@ -13,7 +13,7 @@ endif()
project( project(
ScreenPlay ScreenPlay
VERSION ${PROJECT_VERSION} VERSION ${SCREENPLAY_VERSION}
DESCRIPTION "Modern, Cross Plattform, Live Wallpaper, Widgets and AppDrawer!" DESCRIPTION "Modern, Cross Plattform, Live Wallpaper, Widgets and AppDrawer!"
HOMEPAGE_URL "https://screen-play.app/" HOMEPAGE_URL "https://screen-play.app/"
LANGUAGES CXX) LANGUAGES CXX)
@ -43,9 +43,11 @@ set(CMAKE_OSX_DEPLOYMENT_TARGET "13.0")
# This subdirectoy is needed for OSX and Linux to fix linker errors because we would have ScreenPlayApp executable and folder for the qml # This subdirectoy is needed for OSX and Linux to fix linker errors because we would have ScreenPlayApp executable and folder for the qml
# files in the same directory. # files in the same directory.
set(SCREENPLAY_QML_MODULES_PATH "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/qml") set(SCREENPLAY_QML_MODULES_PATH "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/qml")
if(APPLE) if(APPLE)
set(SCREENPLAY_QML_MODULES_PATH "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ScreenPlay.app/Contents/MacOS/qml") set(SCREENPLAY_QML_MODULES_PATH "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ScreenPlay.app/Contents/MacOS/qml")
endif() endif()
# Adds the qml import path so QtCreator can find them # Adds the qml import path so QtCreator can find them
list(APPEND QML_DIRS "${SCREENPLAY_QML_MODULES_PATH}") list(APPEND QML_DIRS "${SCREENPLAY_QML_MODULES_PATH}")
set(QML_IMPORT_PATH set(QML_IMPORT_PATH
@ -57,15 +59,26 @@ set(VCPKG_INSTALLED_PATH "${VCPKG_PATH}/installed/${VCPKG_ARCH}")
set(VCPKG_BIN_PATH "${VCPKG_INSTALLED_PATH}/bin") set(VCPKG_BIN_PATH "${VCPKG_INSTALLED_PATH}/bin")
# Godot Editor # Godot Editor
set(GODOT_VERSION "v4.2") set(GODOT_VERSION_MAJOR "4")
set(GODOT_RELEASE_TYPE "beta4") set(GODOT_VERSION_MINOR "2")
set(GODOT_VERSION_PATCH "")
set(GODOT_RELEASE_TYPE "rc2")
# Use an if statement to check if GODOT_VERSION_PATCH is empty or not
if(GODOT_VERSION_PATCH STREQUAL "")
# If patch version is empty, don't include it and the preceding dot
set(GODOT_VERSION "v${GODOT_VERSION_MAJOR}.${GODOT_VERSION_MINOR}-${GODOT_RELEASE_TYPE}")
else()
# If patch version is not empty, include it and the preceding dot
set(GODOT_VERSION "v${GODOT_VERSION_MAJOR}.${GODOT_VERSION_MINOR}.${GODOT_VERSION_PATCH}-${GODOT_RELEASE_TYPE}")
endif()
if(WIN32) if(WIN32)
set(GODOT_EDITOR_NAME "Godot_${GODOT_VERSION}-${GODOT_RELEASE_TYPE}_win64.exe") set(GODOT_EDITOR_NAME "Godot_${GODOT_VERSION}_win64.exe")
elseif(APPLE) elseif(APPLE)
set(GODOT_EDITOR_NAME "Godot.app") set(GODOT_EDITOR_NAME "Godot.app")
elseif(UNIX) elseif(UNIX)
set(GODOT_EDITOR_NAME "Godot_${GODOT_VERSION}-${GODOT_RELEASE_TYPE}_linux.x86_64") set(GODOT_EDITOR_NAME "Godot_${GODOT_VERSION}_linux.x86_64")
else() else()
message(FATAL_ERROR "Unsupported OS") message(FATAL_ERROR "Unsupported OS")
endif() endif()
@ -166,7 +179,6 @@ if(${SCREENPLAY_INSTALLER})
endif() endif()
message(STATUS "[PROJECT] CMAKE_MODULE_PATH = ${CMAKE_MODULE_PATH}") message(STATUS "[PROJECT] CMAKE_MODULE_PATH = ${CMAKE_MODULE_PATH}")
message(STATUS "[PROJECT] PROJECT_VERSION = ${PROJECT_VERSION}")
message(STATUS "[PROJECT] CMAKE_VERSION = ${CMAKE_VERSION}") message(STATUS "[PROJECT] CMAKE_VERSION = ${CMAKE_VERSION}")
message(STATUS "[PROJECT] SCREENPLAY_QML_MODULES_PATH = ${SCREENPLAY_QML_MODULES_PATH}") message(STATUS "[PROJECT] SCREENPLAY_QML_MODULES_PATH = ${SCREENPLAY_QML_MODULES_PATH}")
message(STATUS "[PROJECT] CMAKE_TOOLCHAIN_FILE = ${CMAKE_TOOLCHAIN_FILE}") message(STATUS "[PROJECT] CMAKE_TOOLCHAIN_FILE = ${CMAKE_TOOLCHAIN_FILE}")
@ -176,6 +188,7 @@ message(STATUS "[PROJECT] VCPKG_TARGET_TRIPLET = ${VCPKG_TARGET_TRIPLET}
message(STATUS "[PROJECT] CMAKE_PREFIX_PATH = ${CMAKE_PREFIX_PATH}") message(STATUS "[PROJECT] CMAKE_PREFIX_PATH = ${CMAKE_PREFIX_PATH}")
message(STATUS "[PROJECT] GODOT_VERSION = ${GODOT_VERSION}") message(STATUS "[PROJECT] GODOT_VERSION = ${GODOT_VERSION}")
message(STATUS "[PROJECT] GODOT_EDITOR_NAME = ${GODOT_EDITOR_NAME}") message(STATUS "[PROJECT] GODOT_EDITOR_NAME = ${GODOT_EDITOR_NAME}")
message(STATUS "[PROJECT] SCREENPLAY_VERSION = ${SCREENPLAY_VERSION}")
message(STATUS "[OPTION] SCREENPLAY_DEPLOY = ${SCREENPLAY_DEPLOY}") message(STATUS "[OPTION] SCREENPLAY_DEPLOY = ${SCREENPLAY_DEPLOY}")
message(STATUS "[OPTION] SCREENPLAY_INSTALLER = ${SCREENPLAY_INSTALLER}") message(STATUS "[OPTION] SCREENPLAY_INSTALLER = ${SCREENPLAY_INSTALLER}")
message(STATUS "[OPTION] SCREENPLAY_STEAM = ${SCREENPLAY_STEAM}") message(STATUS "[OPTION] SCREENPLAY_STEAM = ${SCREENPLAY_STEAM}")

View File

@ -19,7 +19,7 @@
}, },
"environment": { "environment": {
"qt_path": "${sourceDir}/../aqt", "qt_path": "${sourceDir}/../aqt",
"qt_version": "6.6.0" "qt_version": "6.6.1"
}, },
"toolset": { "toolset": {
"value": "host=x64", "value": "host=x64",
@ -38,46 +38,46 @@
} }
}, },
{ {
"name": "windows-debug-qt-6.6.0", "name": "windows-debug-qt-6.6.1",
"inherits": "default-windows", "inherits": "default-windows",
"displayName": "MSVC SP Qt 6.6.0 Debug", "displayName": "MSVC SP Qt 6.6.1 Debug",
"binaryDir": "${sourceDir}/../build_ScreenPlay_Qt_6.6.0_MSVC_Debug", "binaryDir": "${sourceDir}/../build_ScreenPlay_Qt_6.6.1_MSVC_Debug",
"environment": { "environment": {
"qt_version": "6.6.0" "qt_version": "6.6.1"
}, },
"cacheVariables": { "cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug" "CMAKE_BUILD_TYPE": "Debug"
} }
}, },
{ {
"name": "windows-relwithdebinfo-qt-6.6.0", "name": "windows-relwithdebinfo-qt-6.6.1",
"inherits": "default-windows", "inherits": "default-windows",
"displayName": "MSVC SP Qt 6.6.0 RelWithDebInfo", "displayName": "MSVC SP Qt 6.6.1 RelWithDebInfo",
"binaryDir": "${sourceDir}/../build_ScreenPlay_Qt_6.6.0_MSVC_RelWithDebInfo", "binaryDir": "${sourceDir}/../build_ScreenPlay_Qt_6.6.1_MSVC_RelWithDebInfo",
"environment": { "environment": {
"qt_version": "6.6.0" "qt_version": "6.6.1"
}, },
"cacheVariables": { "cacheVariables": {
"CMAKE_BUILD_TYPE": "RelWithDebInfo" "CMAKE_BUILD_TYPE": "RelWithDebInfo"
} }
}, },
{ {
"name": "windows-release-qt-6.6.0", "name": "windows-release-qt-6.6.1",
"inherits": "default-windows", "inherits": "default-windows",
"displayName": "MSVC SP Qt 6.6.0 Release", "displayName": "MSVC SP Qt 6.6.1 Release",
"binaryDir": "${sourceDir}/../build_ScreenPlay_Qt_6.6.0_MSVC_Release", "binaryDir": "${sourceDir}/../build_ScreenPlay_Qt_6.6.1_MSVC_Release",
"environment": { "environment": {
"qt_version": "6.6.0" "qt_version": "6.6.1"
}, },
"cacheVariables": { "cacheVariables": {
"CMAKE_BUILD_TYPE": "Release" "CMAKE_BUILD_TYPE": "Release"
} }
}, },
{ {
"name": "windows-release-qt-6.6.0-release-deploy", "name": "windows-release-qt-6.6.1-release-deploy",
"inherits": "windows-release-qt-6.6.0", "inherits": "windows-release-qt-6.6.1",
"displayName": "MSVC SP Qt 6.6.0 Release Steam Deploy", "displayName": "MSVC SP Qt 6.6.1 Release Steam Deploy",
"binaryDir": "${sourceDir}/../build_ScreenPlay_Qt_6.6.0_MSVC_Release_Steam_Deploy", "binaryDir": "${sourceDir}/../build_ScreenPlay_Qt_6.6.1_MSVC_Release_Steam_Deploy",
"cacheVariables": { "cacheVariables": {
"CMAKE_BUILD_TYPE": "Release", "CMAKE_BUILD_TYPE": "Release",
"SCREENPLAY_DEPLOY": "ON", "SCREENPLAY_DEPLOY": "ON",
@ -89,7 +89,7 @@
"displayName": "ScreenPlay 64bit Debug Linux", "displayName": "ScreenPlay 64bit Debug Linux",
"description": "Linux only!", "description": "Linux only!",
"generator": "Ninja", "generator": "Ninja",
"binaryDir": "${sourceDir}/../build_ScreenPlay_Qt_6.6.0_GCC_Debug", "binaryDir": "${sourceDir}/../build_ScreenPlay_Qt_6.6.1_GCC_Debug",
"condition": { "condition": {
"type": "equals", "type": "equals",
"lhs": "${hostSystemName}", "lhs": "${hostSystemName}",
@ -113,7 +113,7 @@
"name": "linux-relwithdebinfo", "name": "linux-relwithdebinfo",
"displayName": "ScreenPlay 64bit RelWithDebInfo Linux", "displayName": "ScreenPlay 64bit RelWithDebInfo Linux",
"inherits": "linux-generic-debug", "inherits": "linux-generic-debug",
"binaryDir": "${sourceDir}/../build_ScreenPlay_Qt_6.6.0_GCC_RelWithDebInfo", "binaryDir": "${sourceDir}/../build_ScreenPlay_Qt_6.6.1_GCC_RelWithDebInfo",
"cacheVariables": { "cacheVariables": {
"CMAKE_BUILD_TYPE": "RelWithDebInfo" "CMAKE_BUILD_TYPE": "RelWithDebInfo"
} }
@ -123,7 +123,7 @@
"displayName": "ScreenPlay 64bit Debug Linux using aqt", "displayName": "ScreenPlay 64bit Debug Linux using aqt",
"description": "Linux only!", "description": "Linux only!",
"generator": "Ninja", "generator": "Ninja",
"binaryDir": "${sourceDir}/../build_ScreenPlay_Qt_6.6.0_GCC_Debug", "binaryDir": "${sourceDir}/../build_ScreenPlay_Qt_6.6.1_GCC_Debug",
"condition": { "condition": {
"type": "equals", "type": "equals",
"lhs": "${hostSystemName}", "lhs": "${hostSystemName}",
@ -140,7 +140,7 @@
"CMAKE_CXX_COMPILER": "g++", "CMAKE_CXX_COMPILER": "g++",
"CMAKE_C_COMPILER": "gcc", "CMAKE_C_COMPILER": "gcc",
"CMAKE_BUILD_TYPE": "Debug", "CMAKE_BUILD_TYPE": "Debug",
"CMAKE_PREFIX_PATH": "$env{qt_path}/6.6.0/gcc_64", "CMAKE_PREFIX_PATH": "$env{qt_path}/6.6.1/gcc_64",
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/../vcpkg/scripts/buildsystems/vcpkg.cmake", "CMAKE_TOOLCHAIN_FILE": "${sourceDir}/../vcpkg/scripts/buildsystems/vcpkg.cmake",
"VCPKG_TARGET_TRIPLET": "x64-linux" "VCPKG_TARGET_TRIPLET": "x64-linux"
} }
@ -149,7 +149,7 @@
"name": "linux-aqt-relwithdebinfo", "name": "linux-aqt-relwithdebinfo",
"displayName": "ScreenPlay 64bit RelWithDebInfo Linux using aqt", "displayName": "ScreenPlay 64bit RelWithDebInfo Linux using aqt",
"inherits": "linux-ubuntu-debug", "inherits": "linux-ubuntu-debug",
"binaryDir": "${sourceDir}/../build_ScreenPlay_Qt_6.6.0_GCC_RelWithDebInfo", "binaryDir": "${sourceDir}/../build_ScreenPlay_Qt_6.6.1_GCC_RelWithDebInfo",
"cacheVariables": { "cacheVariables": {
"CMAKE_BUILD_TYPE": "RelWithDebInfo" "CMAKE_BUILD_TYPE": "RelWithDebInfo"
} }
@ -159,7 +159,7 @@
"displayName": "ScreenPlay 64bit Debug osx", "displayName": "ScreenPlay 64bit Debug osx",
"description": "Osx only!", "description": "Osx only!",
"generator": "Ninja", "generator": "Ninja",
"binaryDir": "${sourceDir}/../build_ScreenPlay_Qt_6.6.0_Clang_Debug", "binaryDir": "${sourceDir}/../build_ScreenPlay_Qt_6.6.1_Clang_Debug",
"condition": { "condition": {
"type": "equals", "type": "equals",
"lhs": "${hostSystemName}", "lhs": "${hostSystemName}",
@ -174,7 +174,7 @@
"CMAKE_CXX_COMPILER": "clang++", "CMAKE_CXX_COMPILER": "clang++",
"CMAKE_C_COMPILER": "clang", "CMAKE_C_COMPILER": "clang",
"CMAKE_BUILD_TYPE": "Debug", "CMAKE_BUILD_TYPE": "Debug",
"CMAKE_PREFIX_PATH": "$env{qt_path}/6.6.0/macos", "CMAKE_PREFIX_PATH": "$env{qt_path}/6.6.1/macos",
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/../vcpkg/scripts/buildsystems/vcpkg.cmake" "CMAKE_TOOLCHAIN_FILE": "${sourceDir}/../vcpkg/scripts/buildsystems/vcpkg.cmake"
} }
}, },
@ -182,7 +182,7 @@
"name": "osx-relwithdebinfo", "name": "osx-relwithdebinfo",
"displayName": "ScreenPlay 64bit RelWithDebInfo osx", "displayName": "ScreenPlay 64bit RelWithDebInfo osx",
"inherits": "osx-debug", "inherits": "osx-debug",
"binaryDir": "${sourceDir}/../build_ScreenPlay_Qt_6.6.0_Clang_RelWithDebInfo", "binaryDir": "${sourceDir}/../build_ScreenPlay_Qt_6.6.1_Clang_RelWithDebInfo",
"cacheVariables": { "cacheVariables": {
"CMAKE_BUILD_TYPE": "RelWithDebInfo" "CMAKE_BUILD_TYPE": "RelWithDebInfo"
} }
@ -207,7 +207,7 @@
"name": "Test", "name": "Test",
"description": "", "description": "",
"displayName": "", "displayName": "",
"configurePreset": "windows-release-qt-6.6.0" "configurePreset": "windows-release-qt-6.6.1"
} }
] ]
} }

View File

@ -12,7 +12,7 @@ config_version=5
config/name="Fjord" config/name="Fjord"
run/main_scene="res://wallpaper.tscn" run/main_scene="res://wallpaper.tscn"
config/features=PackedStringArray("4.1", "Mobile") config/features=PackedStringArray("4.2", "Mobile")
config/icon="res://icon.svg" config/icon="res://icon.svg"
[rendering] [rendering]

View File

@ -60,6 +60,7 @@ set(QML
qml/Create/StartInfoLinkImage.qml qml/Create/StartInfoLinkImage.qml
qml/Create/Wizard.qml qml/Create/Wizard.qml
qml/Create/Wizards/GifWallpaper.qml qml/Create/Wizards/GifWallpaper.qml
qml/Create/Wizards/GodotWallpaper.qml
qml/Create/Wizards/HTMLWallpaper.qml qml/Create/Wizards/HTMLWallpaper.qml
qml/Create/Wizards/HTMLWidget.qml qml/Create/Wizards/HTMLWidget.qml
qml/Create/Wizards/Importh264/Importh264.qml qml/Create/Wizards/Importh264/Importh264.qml
@ -76,8 +77,6 @@ set(QML
qml/Create/Wizards/QMLWidget.qml qml/Create/Wizards/QMLWidget.qml
qml/Create/Wizards/WebsiteWallpaper.qml qml/Create/Wizards/WebsiteWallpaper.qml
qml/Create/Wizards/WizardPage.qml qml/Create/Wizards/WizardPage.qml
qml/Create/WizardsFiles/QMLWallpaperMain.qml
qml/Create/WizardsFiles/QMLWidgetMain.qml
qml/Installed/Installed.qml qml/Installed/Installed.qml
qml/Installed/InstalledNavigation.qml qml/Installed/InstalledNavigation.qml
qml/Installed/InstalledWelcomeScreen.qml qml/Installed/InstalledWelcomeScreen.qml
@ -129,6 +128,7 @@ set(RESOURCES
assets/icons/brand_reddit.svg assets/icons/brand_reddit.svg
assets/icons/brand_twitch.svg assets/icons/brand_twitch.svg
assets/icons/brand_twitter.svg assets/icons/brand_twitter.svg
assets/icons/icon_cancel_presentation.svg
assets/icons/exclamation-triangle-solid.svg assets/icons/exclamation-triangle-solid.svg
assets/icons/font-awsome/close.svg assets/icons/font-awsome/close.svg
assets/icons/font-awsome/frown-o.svg assets/icons/font-awsome/frown-o.svg
@ -146,6 +146,7 @@ set(RESOURCES
assets/icons/icon_document.svg assets/icons/icon_document.svg
assets/icons/icon_done.svg assets/icons/icon_done.svg
assets/icons/icon_download.svg assets/icons/icon_download.svg
assets/icons/icon_edit.svg
assets/icons/icon_emptyWidget.svg assets/icons/icon_emptyWidget.svg
assets/icons/icon_folder_open.svg assets/icons/icon_folder_open.svg
assets/icons/icon_forum.svg assets/icons/icon_forum.svg
@ -159,6 +160,7 @@ set(RESOURCES
assets/icons/icon_movie.svg assets/icons/icon_movie.svg
assets/icons/icon_new_releases.svg assets/icons/icon_new_releases.svg
assets/icons/icon_open_in_new.svg assets/icons/icon_open_in_new.svg
assets/icons/icon_open_in_new_black.svg
assets/icons/icon_pause.svg assets/icons/icon_pause.svg
assets/icons/icon_people.svg assets/icons/icon_people.svg
assets/icons/icon_play.svg assets/icons/icon_play.svg
@ -175,7 +177,7 @@ set(RESOURCES
assets/icons/icon_thumb_down.svg assets/icons/icon_thumb_down.svg
assets/icons/icon_thumb_up.svg assets/icons/icon_thumb_up.svg
assets/icons/icon_upload.svg assets/icons/icon_upload.svg
assets/icons/icon_video_settings_black_24dp.svg assets/icons/icon_video_settings.svg
assets/icons/icon_volume.svg assets/icons/icon_volume.svg
assets/icons/icon_volume_mute.svg assets/icons/icon_volume_mute.svg
assets/icons/icon_volume_up.svg assets/icons/icon_volume_up.svg
@ -201,9 +203,6 @@ set(RESOURCES
assets/licenses/Apache2.txt assets/licenses/Apache2.txt
assets/licenses/OFL.txt assets/licenses/OFL.txt
assets/macos/app.screenplay.plist assets/macos/app.screenplay.plist
assets/particle/backgroundGlow.png
assets/particle/dot.png
assets/shader/movingcolorramp.fsh
assets/startinfo/blender.png assets/startinfo/blender.png
assets/startinfo/flaticon.png assets/startinfo/flaticon.png
assets/startinfo/forums.png assets/startinfo/forums.png
@ -232,7 +231,6 @@ set(RESOURCES
assets/wizards/License_CC_Attribution-ShareAlike_4.0.txt assets/wizards/License_CC_Attribution-ShareAlike_4.0.txt
assets/wizards/License_CC_Attribution_4.0.txt assets/wizards/License_CC_Attribution_4.0.txt
assets/wizards/License_GPL_3.0.txt assets/wizards/License_GPL_3.0.txt
assets/wizards/QmlProject.qmlproject
assets/WorkshopPreview.html assets/WorkshopPreview.html
legal/DataProtection.txt legal/DataProtection.txt
legal/gpl-3.0.txt legal/gpl-3.0.txt
@ -242,6 +240,13 @@ set(RESOURCES
profiles.json profiles.json
qml/Create/WizardsFiles/HTMLWallpaperMain.html qml/Create/WizardsFiles/HTMLWallpaperMain.html
qml/Create/WizardsFiles/HTMLWidgetMain.html qml/Create/WizardsFiles/HTMLWidgetMain.html
qml/Create/WizardsFiles/QmlProject.qmlproject
qml/Create/WizardsFiles/QMLWallpaperMain.qml
qml/Create/WizardsFiles/QMLWidgetMain.qml
qml/Create/WizardsFiles/Godot_v5/export_presets.cfg
qml/Create/WizardsFiles/Godot_v5/project.godot
qml/Create/WizardsFiles/Godot_v5/spinner.gd
qml/Create/WizardsFiles/Godot_v5/wallpaper.tscn
qml/Create/WizardsFiles/QMLWallpaperMain.qml qml/Create/WizardsFiles/QMLWallpaperMain.qml
qml/Create/WizardsFiles/QMLWidgetMain.qml qml/Create/WizardsFiles/QMLWidgetMain.qml
qtquickcontrols2.conf) qtquickcontrols2.conf)

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="m376-320 104-104 104 104 56-56-104-104 104-104-56-56-104 104-104-104-56 56 104 104-104 104 56 56ZM160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h640q33 0 56.5 23.5T880-720v480q0 33-23.5 56.5T800-160H160Zm0-80h640v-480H160v480Zm0 0v-480 480Z"/></svg>

After

Width:  |  Height:  |  Size: 358 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M200-200h57l391-391-57-57-391 391v57Zm-80 80v-170l528-527q12-11 26.5-17t30.5-6q16 0 31 6t26 18l55 56q12 11 17.5 26t5.5 30q0 16-5.5 30.5T817-647L290-120H120Zm640-584-56-56 56 56Zm-141 85-28-29 57 57-29-28Z"/></svg>

After

Width:  |  Height:  |  Size: 310 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h280v80H200v560h560v-280h80v280q0 33-23.5 56.5T760-120H200Zm188-212-56-56 372-372H560v-80h280v280h-80v-144L388-332Z"/></svg>

After

Width:  |  Height:  |  Size: 281 B

View File

@ -1 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 512 512" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;"><path id="steam-square" d="M413.982,173.02c0,-35.325 -28.99,-64.336 -64.656,-64.336c-35.326,0 -64.336,28.99 -64.336,64.336c0,35.667 28.989,64.336 64.336,64.336c35.666,0 64.656,-28.669 64.656,-64.336Zm-203.312,195.995c0,36.669 -29.33,65.999 -65.999,65.999c-25.342,0 -47.335,-14.334 -58.321,-35.325c11.007,4.331 21.673,8.661 32.659,13.333c26.664,10.665 57.339,-2.326 68.325,-29.331c10.666,-26.665 -2.325,-57.34 -29.331,-67.984l-27.326,-11.007c4.33,-1.003 9.343,-1.664 13.994,-1.664c36.669,0 65.999,29.331 65.999,66l0,-0.021Zm301.309,-272.98l0,319.973c0,52.988 -43.005,95.992 -95.992,95.992l-319.974,0c-52.987,0 -95.992,-43.004 -95.992,-95.992l0,-51.004l57.34,22.996c8.66,40.338 44.668,70.671 87.331,70.671c46.652,0 84.985,-35.666 89.336,-80.996l114.999,-84.003c66.661,0 120.331,-53.991 120.331,-119.99c0,-66.662 -53.67,-120.332 -120.331,-120.332c-65.659,0 -119.329,53.329 -119.99,118.988l-75.002,107.319c-3.008,-0.342 -5.994,-0.342 -9.343,-0.342c-16.66,0 -32.339,4.331 -45.671,12.33l-99,-39.655l0,-155.998c0,-52.988 43.005,-95.992 95.992,-95.992l319.974,0c52.987,0 95.992,43.004 95.992,95.992l0,0.043Zm-82.319,77.668c0,44.327 -35.986,80.334 -80.654,80.334c-44.327,0 -80.335,-35.986 -80.335,-80.334c0,-44.668 35.986,-80.655 80.335,-80.655c44.668,0 80.654,35.987 80.654,80.655Z" style="fill:#bebebe;fill-rule:nonzero;"/></svg> <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 512 512" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
<path id="steam-square" d="M413.982,173.02C413.982,137.695 384.992,108.684 349.326,108.684C314,108.684 284.99,137.674 284.99,173.02C284.99,208.687 313.979,237.356 349.326,237.356C384.992,237.356 413.982,208.687 413.982,173.02ZM210.67,369.015C210.67,405.684 181.34,435.014 144.671,435.014C119.329,435.014 97.336,420.68 86.35,399.689C97.357,404.02 108.023,408.35 119.009,413.022C145.673,423.687 176.348,410.696 187.334,383.691C198,357.026 185.009,326.351 158.003,315.707L130.677,304.7C135.007,303.697 140.02,303.036 144.671,303.036C181.34,303.036 210.67,332.367 210.67,369.036L210.67,369.015ZM511.979,95.992L511.979,416.008C511.979,468.996 468.974,512 415.987,512L96.013,512C43.026,512 0.021,468.996 0.021,416.008L0.021,365.004L57.361,388C66.021,428.338 102.029,458.671 144.692,458.671C191.344,458.671 229.677,423.005 234.028,377.675L349.027,293.672C415.688,293.672 469.358,239.681 469.358,173.682C469.358,107.02 415.688,53.35 349.027,53.35C283.368,53.35 229.698,106.679 229.037,172.338L154.035,279.657C151.027,279.315 148.041,279.315 144.692,279.315C128.032,279.315 112.353,283.646 99.021,291.645L0.021,251.99L0.021,95.992C0.021,43.004 43.026,-0 96.013,-0L415.987,-0C468.974,-0 511.979,43.004 511.979,95.992ZM429.66,173.703C429.66,218.03 393.674,254.037 349.006,254.037C304.679,254.037 268.671,218.051 268.671,173.703C268.671,129.035 304.657,93.048 349.006,93.048C393.674,93.048 429.66,129.035 429.66,173.703Z" style="fill-rule:nonzero;"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -1,18 +0,0 @@
uniform float time;
uniform float shaderOpacity;
uniform vec2 resolution;
void main( void ) {
vec2 position = ( gl_FragCoord.xy / resolution.xy );
vec3 color1 = vec3(1.0, 0.6, 0.01);
vec3 color2 = vec3(0.97, 0.24, 0.24);
float mixValue = distance(position,vec2(0,1));
vec3 color = mix( color1, color2, mixValue);
gl_FragColor = vec4(color,mixValue) * shaderOpacity;
}

View File

@ -32,6 +32,7 @@ namespace ScreenPlay {
class Create : public QObject { class Create : public QObject {
Q_OBJECT Q_OBJECT
QML_ELEMENT QML_ELEMENT
QML_UNCREATABLE("")
Q_PROPERTY(QString workingDir READ workingDir WRITE setWorkingDir NOTIFY workingDirChanged) Q_PROPERTY(QString workingDir READ workingDir WRITE setWorkingDir NOTIFY workingDirChanged)
Q_PROPERTY(float progress READ progress WRITE setProgress NOTIFY progressChanged) Q_PROPERTY(float progress READ progress WRITE setProgress NOTIFY progressChanged)

View File

@ -16,6 +16,7 @@ namespace ScreenPlay {
class GlobalVariables : public QObject { class GlobalVariables : public QObject {
Q_OBJECT Q_OBJECT
QML_ELEMENT QML_ELEMENT
QML_UNCREATABLE("")
Q_PROPERTY(QVersionNumber version READ version CONSTANT) Q_PROPERTY(QVersionNumber version READ version CONSTANT)
Q_PROPERTY(QUrl localStoragePath READ localStoragePath WRITE setLocalStoragePath NOTIFY localStoragePathChanged FINAL) Q_PROPERTY(QUrl localStoragePath READ localStoragePath WRITE setLocalStoragePath NOTIFY localStoragePathChanged FINAL)

View File

@ -77,7 +77,7 @@ public slots:
void append(const QString& projectJsonFilePath); void append(const QString& projectJsonFilePath);
void reset(); void reset();
void init(); void init();
void deinstallItemAt(const QString& absoluteStoragePath); bool deinstallItemAt(const QString& absoluteStoragePath);
void setCount(int count) void setCount(int count)
{ {
@ -96,6 +96,7 @@ private:
QFileSystemWatcher m_fileSystemWatcher; QFileSystemWatcher m_fileSystemWatcher;
QVector<ProjectFile> m_screenPlayFiles; QVector<ProjectFile> m_screenPlayFiles;
int m_count { 0 }; int m_count { 0 };
QTimer m_reloadLimiter;
std::atomic_bool m_isLoading { false }; std::atomic_bool m_isLoading { false };
const std::shared_ptr<GlobalVariables>& m_globalVariables; const std::shared_ptr<GlobalVariables>& m_globalVariables;

View File

@ -41,6 +41,7 @@ struct Monitor {
class MonitorListModel : public QAbstractListModel { class MonitorListModel : public QAbstractListModel {
Q_OBJECT Q_OBJECT
QML_ELEMENT QML_ELEMENT
QML_UNCREATABLE("")
public: public:
explicit MonitorListModel(QObject* parent = nullptr); explicit MonitorListModel(QObject* parent = nullptr);

View File

@ -24,6 +24,7 @@ namespace ScreenPlay {
class ScreenPlayManager : public QObject { class ScreenPlayManager : public QObject {
Q_OBJECT Q_OBJECT
QML_ELEMENT QML_ELEMENT
QML_UNCREATABLE("")
Q_PROPERTY(int activeWallpaperCounter READ activeWallpaperCounter WRITE setActiveWallpaperCounter NOTIFY activeWallpaperCounterChanged) Q_PROPERTY(int activeWallpaperCounter READ activeWallpaperCounter WRITE setActiveWallpaperCounter NOTIFY activeWallpaperCounterChanged)
Q_PROPERTY(int activeWidgetsCounter READ activeWidgetsCounter WRITE setActiveWidgetsCounter NOTIFY activeWidgetsCounterChanged) Q_PROPERTY(int activeWidgetsCounter READ activeWidgetsCounter WRITE setActiveWidgetsCounter NOTIFY activeWidgetsCounterChanged)

View File

@ -3,10 +3,13 @@
#pragma once #pragma once
#include <QDebug> #include <QDebug>
#include <QDir>
#include <QFileInfoList>
#include <QJsonObject> #include <QJsonObject>
#include <QObject> #include <QObject>
#include <QProcess> #include <QProcess>
#include <QString>
#include <QStringList>
#include <memory> #include <memory>
#include "ScreenPlay/globalvariables.h" #include "ScreenPlay/globalvariables.h"
@ -19,27 +22,21 @@ namespace ScreenPlay {
class ScreenPlayWallpaper : public QObject { class ScreenPlayWallpaper : public QObject {
Q_OBJECT Q_OBJECT
QML_ELEMENT QML_ELEMENT
QML_UNCREATABLE("")
Q_PROPERTY(bool isConnected READ isConnected WRITE setIsConnected NOTIFY isConnectedChanged) Q_PROPERTY(bool isConnected READ isConnected WRITE setIsConnected NOTIFY isConnectedChanged)
Q_PROPERTY(QVector<int> screenNumber READ screenNumber WRITE setScreenNumber NOTIFY screenNumberChanged) Q_PROPERTY(QVector<int> screenNumber READ screenNumber WRITE setScreenNumber NOTIFY screenNumberChanged)
Q_PROPERTY(float volume READ volume WRITE setVolume NOTIFY volumeChanged) Q_PROPERTY(float volume READ volume WRITE setVolume NOTIFY volumeChanged)
Q_PROPERTY(float playbackRate READ playbackRate WRITE setPlaybackRate NOTIFY playbackRateChanged) Q_PROPERTY(float playbackRate READ playbackRate WRITE setPlaybackRate NOTIFY playbackRateChanged)
Q_PROPERTY(bool isLooping READ isLooping WRITE setIsLooping NOTIFY isLoopingChanged) Q_PROPERTY(bool isLooping READ isLooping WRITE setIsLooping NOTIFY isLoopingChanged)
Q_PROPERTY(QString file READ file WRITE setFile NOTIFY fileChanged) Q_PROPERTY(QString file READ file WRITE setFile NOTIFY fileChanged)
Q_PROPERTY(QString absolutePath READ absolutePath WRITE setAbsolutePath NOTIFY absolutePathChanged) Q_PROPERTY(QString absolutePath READ absolutePath WRITE setAbsolutePath NOTIFY absolutePathChanged)
Q_PROPERTY(QString previewImage READ previewImage WRITE setPreviewImage NOTIFY previewImageChanged) Q_PROPERTY(QString previewImage READ previewImage WRITE setPreviewImage NOTIFY previewImageChanged)
Q_PROPERTY(QString appID READ appID WRITE setAppID NOTIFY appIDChanged) Q_PROPERTY(QString appID READ appID WRITE setAppID NOTIFY appIDChanged)
Q_PROPERTY(FillMode::FillMode fillMode READ fillMode WRITE setFillMode NOTIFY fillModeChanged) Q_PROPERTY(FillMode::FillMode fillMode READ fillMode WRITE setFillMode NOTIFY fillModeChanged)
Q_PROPERTY(InstalledType::InstalledType type READ type WRITE setType NOTIFY typeChanged) Q_PROPERTY(InstalledType::InstalledType type READ type WRITE setType NOTIFY typeChanged)
public: public:
// Default constructor needed for qml engine
ScreenPlayWallpaper() { }
explicit ScreenPlayWallpaper( explicit ScreenPlayWallpaper(
const QVector<int>& screenNumber, const QVector<int>& screenNumber,
const std::shared_ptr<GlobalVariables>& globalVariables, const std::shared_ptr<GlobalVariables>& globalVariables,
@ -210,7 +207,7 @@ public slots:
} }
private: private:
bool exportGodotProject(const QString& absolutePath, int timeoutMilliseconds = 30000); bool exportGodotProject();
private: private:
const std::shared_ptr<GlobalVariables> m_globalVariables; const std::shared_ptr<GlobalVariables> m_globalVariables;
@ -218,6 +215,7 @@ private:
const std::shared_ptr<Settings> m_settings; const std::shared_ptr<Settings> m_settings;
ProjectSettingsListModel m_projectSettingsListModel; ProjectSettingsListModel m_projectSettingsListModel;
QJsonObject m_projectJson;
QVector<int> m_screenNumber; QVector<int> m_screenNumber;
QProcess m_process; QProcess m_process;
QString m_previewImage; QString m_previewImage;

View File

@ -23,6 +23,7 @@ namespace ScreenPlay {
class ScreenPlayWidget : public QObject { class ScreenPlayWidget : public QObject {
Q_OBJECT Q_OBJECT
QML_ELEMENT QML_ELEMENT
QML_UNCREATABLE("")
Q_PROPERTY(QString absolutePath READ absolutePath WRITE setAbsolutePath NOTIFY absolutePathChanged) Q_PROPERTY(QString absolutePath READ absolutePath WRITE setAbsolutePath NOTIFY absolutePathChanged)
Q_PROPERTY(QString previewImage READ previewImage WRITE setPreviewImage NOTIFY previewImageChanged) Q_PROPERTY(QString previewImage READ previewImage WRITE setPreviewImage NOTIFY previewImageChanged)

View File

@ -58,7 +58,8 @@ class Util : public QObject {
Q_PROPERTY(QString debugMessages READ debugMessages NOTIFY debugMessagesChanged) Q_PROPERTY(QString debugMessages READ debugMessages NOTIFY debugMessagesChanged)
public: public:
Util(); Util(
const std::shared_ptr<GlobalVariables>& globalVariables);
~Util(); ~Util();
QString debugMessages() const { return m_debugMessages; } QString debugMessages() const { return m_debugMessages; }
@ -82,6 +83,7 @@ public slots:
void openFolderInExplorer(const QString& url) const; void openFolderInExplorer(const QString& url) const;
QString toLocal(const QString& url) const; QString toLocal(const QString& url) const;
bool exportProject(QString contentPath, QString exportFileName); bool exportProject(QString contentPath, QString exportFileName);
bool openGodotEditor(QString contentPath) const;
bool importProject(QString archivePath, QString extractionPath); bool importProject(QString archivePath, QString extractionPath);
void requestAllLicenses(); void requestAllLicenses();
void requestDataProtection(); void requestDataProtection();
@ -124,6 +126,7 @@ private:
QFuture<void> m_requestAllLicensesFuture; QFuture<void> m_requestAllLicensesFuture;
std::unique_ptr<QArchive::DiskCompressor> m_compressor; std::unique_ptr<QArchive::DiskCompressor> m_compressor;
std::unique_ptr<QArchive::DiskExtractor> m_extractor; std::unique_ptr<QArchive::DiskExtractor> m_extractor;
const std::shared_ptr<GlobalVariables>& m_globalVariables;
}; };
} }

View File

@ -2,6 +2,7 @@
#pragma once #pragma once
#include <QColor>
#include <QDir> #include <QDir>
#include <QFile> #include <QFile>
#include <QFileInfo> #include <QFileInfo>
@ -34,9 +35,11 @@ namespace ScreenPlay {
class Wizards : public QObject { class Wizards : public QObject {
Q_OBJECT Q_OBJECT
QML_ELEMENT QML_ELEMENT
QML_UNCREATABLE("CPP ONLY")
public: public:
explicit Wizards(const std::shared_ptr<GlobalVariables>& globalVariables, QObject* parent = nullptr); explicit Wizards(
Wizards() { } const std::shared_ptr<GlobalVariables>& globalVariables,
QObject* parent = nullptr);
enum class WizardResult { enum class WizardResult {
Ok, Ok,
@ -82,6 +85,14 @@ public slots:
const QString& previewThumbnail, const QString& previewThumbnail,
const QVector<QString>& tags); const QVector<QString>& tags);
void createGodotWallpaper(
const QString& title,
const QString& licenseName,
const QString& licenseFile,
const QString& createdBy,
const QString& previewThumbnail,
const QVector<QString>& tags);
void createGifWallpaper( void createGifWallpaper(
const QString& title, const QString& title,
const QString& licenseName, const QString& licenseName,
@ -103,8 +114,16 @@ signals:
private: private:
const std::shared_ptr<GlobalVariables> m_globalVariables; const std::shared_ptr<GlobalVariables> m_globalVariables;
const std::optional<QString> createTemporaryFolder() const; const std::optional<QString> createTemporaryFolder() const;
void createPreviewImage(const QString& name, const QString& targetPath);
private: private:
QFuture<void> m_wizardFuture; QFuture<void> m_wizardFuture;
QVector<QColor> m_gradientColors = {
QColor("#B71C1C"),
QColor("#1B5E20"),
QColor("#0D47A1"),
QColor("#FFD600"),
QColor("#4A148C")
};
}; };
} }

View File

@ -48,6 +48,7 @@ ApplicationWindow {
stackView.replace("qrc:/qml/ScreenPlayApp/qml/" + name + "/" + name + ".qml", { stackView.replace("qrc:/qml/ScreenPlayApp/qml/" + name + "/" + name + ".qml", {
"modalSource": content "modalSource": content
}); });
nav.setNavigation(name);
sidebar.state = "inactive"; sidebar.state = "inactive";
} }
@ -56,7 +57,7 @@ ApplicationWindow {
visible: false visible: false
width: 1400 width: 1400
height: 810 height: 810
title: "ScreenPlay Alpha - V" + App.version() title: "ScreenPlay Alpha - v" + App.version()
minimumHeight: 450 minimumHeight: 450
minimumWidth: 1050 minimumWidth: 1050
@ -72,9 +73,10 @@ ApplicationWindow {
// https://bugreports.qt.io/browse/QTBUG-86047 // https://bugreports.qt.io/browse/QTBUG-86047
Material.accent: Material.color(Material.Orange) Material.accent: Material.color(Material.Orange)
onVisibilityChanged: { onVisibilityChanged: {
if (root.visibility === 2) if (root.visibility !== 2)
App.installedListModel.reset(); return;
} }
onClosing: close => { onClosing: close => {
close.accepted = false; close.accepted = false;
if (App.screenPlayManager.activeWallpaperCounter === 0 && App.screenPlayManager.activeWidgetsCounter === 0) { if (App.screenPlayManager.activeWallpaperCounter === 0 && App.screenPlayManager.activeWidgetsCounter === 0) {
@ -111,6 +113,7 @@ ApplicationWindow {
App.showDockIcon(true); App.showDockIcon(true);
root.show(); root.show();
} }
App.installedListModel.reset();
} }
Item { Item {

View File

@ -42,9 +42,7 @@ Rectangle {
function onWizardExited() { function onWizardExited() {
root.expanded = true; root.expanded = true;
stackView.clear(StackView.PushTransition); App.util.setNavigation("Installed");
stackView.push("qrc:/qml/ScreenPlayApp/qml/Create/StartInfo.qml");
listView.currentIndex = 0;
App.util.setNavigationActive(true); App.util.setNavigationActive(true);
} }
@ -87,6 +85,13 @@ Rectangle {
objectName: "" objectName: ""
} }
ListElement {
headline: qsTr("Godot Wallpaper")
source: "qrc:/qml/ScreenPlayApp/qml/Create/Wizards/GodotWallpaper.qml"
category: "Code Wallpaper"
objectName: ""
}
ListElement { ListElement {
headline: qsTr("QML Wallpaper") headline: qsTr("QML Wallpaper")
source: "qrc:/qml/ScreenPlayApp/qml/Create/Wizards/QMLWallpaper.qml" source: "qrc:/qml/ScreenPlayApp/qml/Create/Wizards/QMLWallpaper.qml"

View File

@ -0,0 +1,101 @@
import QtQuick
import Qt5Compat.GraphicalEffects
import QtQuick.Controls
import QtQuick.Controls.Material
import QtQuick.Layouts
import ScreenPlayApp
import ScreenPlay
import ScreenPlay.Create
import ScreenPlayUtil as Util
WizardPage {
id: root
sourceComponent: ColumnLayout {
id: rightWrapper
function create() {
App.wizards.createGodotWallpaper(tfTitle.text, cbLicense.name, cbLicense.licenseFile, tfCreatedBy.text, previewSelector.imageSource, tagSelector.getTags());
}
spacing: 10
anchors {
top: parent.top
right: parent.right
left: parent.left
}
Util.Headline {
text: qsTr("Create a Godot Wallpaper")
Layout.fillWidth: true
}
Util.HeadlineSection {
text: qsTr("General")
}
RowLayout {
spacing: 20
Util.TextField {
id: tfTitle
Layout.fillWidth: true
placeholderText: qsTr("Wallpaper name")
required: true
onTextChanged: root.ready = text.length >= 1
}
Util.TextField {
id: tfCreatedBy
Layout.fillWidth: true
placeholderText: qsTr("Created By")
}
}
Util.TextField {
id: tfDescription
Layout.fillWidth: true
placeholderText: qsTr("Description")
}
Item {
height: 30
}
Util.HeadlineSection {
text: qsTr("License & Tags")
}
RowLayout {
spacing: 20
Util.LicenseSelector {
id: cbLicense
}
Util.TagSelector {
id: tagSelector
Layout.fillWidth: true
}
}
Item {
height: 30
}
Util.HeadlineSection {
text: qsTr("Preview Image")
}
Util.ImageSelector {
id: previewSelector
Layout.fillWidth: true
}
}
}

View File

@ -10,16 +10,21 @@ import ScreenPlayUtil as Util
WizardPage { WizardPage {
id: root id: root
function isValidURL(string) {
var res = string.match(/(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/g);
return (res !== null);
}
sourceComponent: ColumnLayout { sourceComponent: ColumnLayout {
property bool ready: tfTitle.text.length >= 1 && tfUrl.text.length > 1 id: layout
function validate() {
root.ready = tfTitle.text.length >= 1 && root.isValidURL(tfUrl.text);
}
function create() { function create() {
App.wizards.createWebsiteWallpaper(tfTitle.text, previewSelector.imageSource, tfUrl.text, tagSelector.getTags()); App.wizards.createWebsiteWallpaper(tfTitle.text, previewSelector.imageSource, tfUrl.text, tagSelector.getTags());
} }
spacing: 10 spacing: 10
onReadyChanged: root.ready = ready
anchors { anchors {
top: parent.top top: parent.top
@ -41,11 +46,10 @@ WizardPage {
Util.TextField { Util.TextField {
id: tfTitle id: tfTitle
Layout.fillWidth: true Layout.fillWidth: true
placeholderText: qsTr("Wallpaper name") placeholderText: qsTr("Wallpaper name")
required: true required: true
onTextChanged: root.ready = text.length >= 1 onTextChanged: layout.validate()
} }
Util.TextField { Util.TextField {
@ -65,10 +69,10 @@ WizardPage {
Util.TextField { Util.TextField {
id: tfUrl id: tfUrl
Layout.fillWidth: true Layout.fillWidth: true
required: true required: true
text: "https://" text: "https://"
onTextChanged: layout.validate()
} }
Item { Item {

View File

@ -0,0 +1,15 @@
[preset.0]
name="Windows Desktop"
platform="Windows Desktop"
runnable=true
dedicated_server=false
custom_features=""
export_filter="all_resources"
include_filter=""
exclude_filter=""
export_path=""
encryption_include_filters=""
encryption_exclude_filters=""
encrypt_pck=false
encrypt_directory=false

View File

@ -0,0 +1,15 @@
; Engine configuration file.
; It's best edited using the editor UI and not directly,
; since the parameters that go here are not all obvious.
;
; Format:
; [section] ; section goes between []
; param=value ; assign values to parameters
config_version=5
[application]
config/name="Test"
run/main_scene="res://wallpaper.tscn"
config/features=PackedStringArray("4.2", "Forward Plus")

View File

@ -0,0 +1,6 @@
extends CSGBox3D
var rotation_speed = 3.0
func _process(delta):
rotate_y(rotation_speed * delta)

View File

@ -0,0 +1,19 @@
[gd_scene load_steps=2 format=3 uid="uid://d105uliklnkd5"]
[ext_resource type="Script" path="res://spinner.gd" id="1_ggnsn"]
[node name="Node3D" type="Node3D"]
[node name="Camera3D" type="Camera3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 5)
[node name="CSGBox3D" type="CSGBox3D" parent="."]
transform = Transform3D(0.707107, -0.5, -0.5, 0, 0.707107, -0.707107, 0.707107, 0.5, 0.5, 0, 0, 0)
script = ExtResource("1_ggnsn")
[node name="OmniLight3D" type="OmniLight3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.41283, 1.52646)
[node name="Label3D" type="Label3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.874896, 0.37249)
text = "Godot Wallpaper"

View File

@ -41,7 +41,6 @@ Item {
StackView.onActivated: { StackView.onActivated: {
navWrapper.state = "in"; navWrapper.state = "in";
App.installedListFilter.sortBySearchType(SearchType.All);
checkIsContentInstalled(); checkIsContentInstalled();
} }
@ -86,8 +85,6 @@ Item {
property bool isScrolling: gridView.verticalVelocity !== 0 property bool isScrolling: gridView.verticalVelocity !== 0
boundsBehavior: Flickable.DragOverBounds boundsBehavior: Flickable.DragOverBounds
maximumFlickVelocity: 3000
flickDeceleration: 7500
anchors.fill: parent anchors.fill: parent
cellWidth: 340 cellWidth: 340
cellHeight: 200 cellHeight: 200
@ -240,11 +237,19 @@ Item {
contextMenu.publishedFileID = delegate.publishedFileID; contextMenu.publishedFileID = delegate.publishedFileID;
contextMenu.absoluteStoragePath = delegate.absoluteStoragePath; contextMenu.absoluteStoragePath = delegate.absoluteStoragePath;
contextMenu.fileName = delegate.customTitle; contextMenu.fileName = delegate.customTitle;
contextMenu.type = delegate.type;
print(delegate.publishedFileID);
if (contextMenu.godotItem)
contextMenu.godotItem.destroy();
const pos = delegate.mapToItem(root, position.x, position.y); const pos = delegate.mapToItem(root, position.x, position.y);
// Disable duplicate opening. The can happen if we // Disable duplicate opening. The can happen if we
// call popup when we are in the closing animtion. // call popup when we are in the closing animtion.
if (contextMenu.visible || contextMenu.opened) if (contextMenu.visible || contextMenu.opened)
return; return;
if (delegate.type === InstalledType.GodotWallpaper) {
contextMenu.godotItem = editGodotWallpaperComp.createObject();
contextMenu.insertItem(0, contextMenu.godotItem);
}
contextMenu.popup(pos.x, pos.y); contextMenu.popup(pos.x, pos.y);
} }
} }
@ -253,14 +258,30 @@ Item {
snapMode: ScrollBar.SnapOnRelease snapMode: ScrollBar.SnapOnRelease
} }
} }
Component {
id: editGodotWallpaperComp
MenuItem {
text: qsTr("Edit Wallpaper")
objectName: "editWallpaper"
enabled: contextMenu.type === InstalledType.GodotWallpaper
icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_edit.svg"
onClicked: {
App.util.openGodotEditor(contextMenu.absoluteStoragePath);
}
}
}
Menu { Menu {
id: contextMenu id: contextMenu
objectName: "installedItemContextMenu" objectName: "installedItemContextMenu"
// Must be var to support 64-bit size!
property var publishedFileID: 0 property var publishedFileID: 0
property var type: 0
property url absoluteStoragePath property url absoluteStoragePath
property string fileName property string fileName
// We need to dynamically add this menu item
// if it is a Godot Wallpaper, see onOpenContextMenu
property var godotItem
MenuItem { MenuItem {
text: qsTr("Open containing folder") text: qsTr("Open containing folder")
@ -312,7 +333,9 @@ Item {
anchors.centerIn: Overlay.overlay anchors.centerIn: Overlay.overlay
onAccepted: { onAccepted: {
root.sidebar.clear(); root.sidebar.clear();
App.installedListModel.deinstallItemAt(contextMenu.absoluteStoragePath); if (!App.installedListModel.deinstallItemAt(contextMenu.absoluteStoragePath)) {
console.error("Unable to uninstall item", contextMenu.absoluteStoragePath);
}
} }
} }
@ -392,7 +415,8 @@ Item {
importProjectErrorDialog.open(); importProjectErrorDialog.open();
return; return;
} }
var file = ""; // Convert url to string var file = "";
// Convert url to string
file = "" + drop.urls[0]; file = "" + drop.urls[0];
if (!file.endsWith('.screenplay')) { if (!file.endsWith('.screenplay')) {
importProjectErrorDialog.title = qsTr("File type not supported. We only support '.screenplay' files."); importProjectErrorDialog.title = qsTr("File type not supported. We only support '.screenplay' files.");

View File

@ -14,6 +14,7 @@ Item {
property string screenId property string screenId
property url absoluteStoragePath property url absoluteStoragePath
property int type: InstalledType.Unknown property int type: InstalledType.Unknown
// Must be var to make it work wit 64bit ints
property var publishedFileID: 0 property var publishedFileID: 0
property int itemIndex property int itemIndex
property bool isScrolling: false property bool isScrolling: false

View File

@ -13,7 +13,7 @@ Rectangle {
id: root id: root
property string currentNavigationName: "Installed" property string currentNavigationName: "Installed"
property var navArray: [navCreate, navWorkshop, navInstalled, navSettings, navCommunity] property var navArray: [navCreate, navWorkshop, navInstalled, navCommunity, navSettings]
property bool navActive: true property bool navActive: true
property Item modalSource property Item modalSource
property int iconWidth: 16 property int iconWidth: 16
@ -28,13 +28,12 @@ Rectangle {
else else
root.state = "disabled"; root.state = "disabled";
} }
function setNavigation(name) { function setNavigation(name) {
var i = 0; for (var i = 0; i < navArray.length; i++) {
for (; i < navArray.length; i++) { if (navArray[i].objectName === name) {
if (navArray[i].name === name) {
navArray[i].state = "active"; navArray[i].state = "active";
root.currentNavigationName = name; root.currentNavigationName = name;
tabBar.currentIndex = navArray[i].index;
} else { } else {
navArray[i].state = "inactive"; navArray[i].state = "inactive";
} }
@ -70,7 +69,7 @@ Rectangle {
} }
TabBar { TabBar {
id: row id: tabBar
height: 50 height: 50
currentIndex: 2 currentIndex: 2
@ -84,55 +83,60 @@ Rectangle {
CustomTabButton { CustomTabButton {
id: navCreate id: navCreate
index: 0
icon.height: 22 icon.height: 22
icon.width: 22 icon.width: 22
text: qsTr("Create") text: qsTr("Create")
objectName: "Create"
icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_plus.svg" icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_plus.svg"
onClicked: { onClicked: {
root.onPageChanged("Create"); root.onPageChanged("Create");
} }
objectName: "createTab"
} }
CustomTabButton { CustomTabButton {
id: navWorkshop id: navWorkshop
index: 1
enabled: App.settings.steamVersion enabled: App.settings.steamVersion
text: qsTr("Workshop") text: qsTr("Workshop")
objectName: "Workshop"
icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_steam.svg" icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_steam.svg"
onClicked: { onClicked: {
root.onPageChanged("Workshop"); root.onPageChanged("Workshop");
} }
objectName: "workshopTab"
} }
CustomTabButton { CustomTabButton {
id: navInstalled id: navInstalled
index: 2
text: qsTr("Installed") + " " + App.installedListModel.count text: qsTr("Installed") + " " + App.installedListModel.count
objectName: "Installed"
icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_installed.svg" icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_installed.svg"
onClicked: { onClicked: {
root.onPageChanged("Installed"); root.onPageChanged("Installed");
} }
objectName: "installedTab"
} }
CustomTabButton { CustomTabButton {
id: navCommunity id: navCommunity
index: 3
text: qsTr("Community") text: qsTr("Community")
objectName: "Community"
icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_community.svg" icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_community.svg"
onClicked: { onClicked: {
root.onPageChanged("Community"); root.onPageChanged("Community");
} }
objectName: "communityTab"
} }
CustomTabButton { CustomTabButton {
id: navSettings id: navSettings
index: 4
text: qsTr("Settings") text: qsTr("Settings")
objectName: "Settings"
icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_settings.svg" icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_settings.svg"
onClicked: { onClicked: {
root.onPageChanged("Settings"); root.onPageChanged("Settings");
} }
objectName: "settingsTab"
} }
} }
@ -142,6 +146,7 @@ Rectangle {
font.pointSize: 12 font.pointSize: 12
height: parent.height height: parent.height
width: implicitWidth width: implicitWidth
property int index: 0
background: Item { background: Item {
} }
font.capitalization: Font.MixedCase font.capitalization: Font.MixedCase
@ -260,7 +265,7 @@ Rectangle {
ToolButton { ToolButton {
id: miConfig id: miConfig
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_video_settings_black_24dp.svg" icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_video_settings.svg"
icon.width: root.iconWidth icon.width: root.iconWidth
icon.height: root.iconHeight icon.height: root.iconHeight
onClicked: App.util.setToggleWallpaperConfiguration() onClicked: App.util.setToggleWallpaperConfiguration()
@ -278,7 +283,7 @@ Rectangle {
name: "disabled" name: "disabled"
PropertyChanges { PropertyChanges {
target: row target: tabBar
opacity: 0.3 opacity: 0.3
} }
} }
@ -289,7 +294,7 @@ Rectangle {
to: "*" to: "*"
PropertyAnimation { PropertyAnimation {
target: row target: tabBar
duration: 300 duration: 300
} }
} }

View File

@ -78,7 +78,7 @@ Item {
id: radioButton id: radioButton
checked: settingsBool.isChecked checked: settingsBool.isChecked
onCheckedChanged: { onClicked: {
if (radioButton.checkState === Qt.Checked) if (radioButton.checkState === Qt.Checked)
checkboxChanged(true); checkboxChanged(true);
else else

View File

@ -403,7 +403,7 @@ Item {
Image { Image {
id: imgLogoHead id: imgLogoHead
source: "https://assets.gitlab-static.net/uploads/-/system/user/avatar/64172/avatar.png" source: "https://gitlab.com/uploads/-/system/user/avatar/64172/avatar.png"
width: 120 width: 120
height: 120 height: 120
visible: false visible: false

View File

@ -27,29 +27,99 @@ SystemTrayIcon {
} }
} }
menu: Menu { function open() {
MenuItem {
text: qsTr("Open ScreenPlay")
onTriggered: {
App.showDockIcon(true); App.showDockIcon(true);
window.show(); window.show();
} }
menu: Menu {
MenuItem {
id: miOpenScreenPlay
text: qsTr("Open ScreenPlay")
icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_open_in_new_black.svg"
onTriggered: {
root.open();
}
}
MenuItem {
id: miChangeWallpaperSettings
text: qsTr("Change Wallpaper settings")
icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_video_settings.svg"
onTriggered: {
root.open();
App.util.setNavigation("Installed");
App.util.setToggleWallpaperConfiguration();
}
}
MenuItem {
separator: true
} }
MenuItem {
text: qsTr("Browse Workshop")
icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_steam.svg"
onTriggered: {
root.open();
App.util.setNavigation("Workshop");
}
}
MenuItem {
id: miCreate
text: qsTr("Create new Wallpaper or Widgets")
icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_plus.svg"
onTriggered: {
root.open();
App.util.setNavigation("Create");
}
}
MenuItem {
id: miSettings
icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_settings.svg"
text: qsTr("Settings")
onTriggered: {
root.open();
App.util.setNavigation("Settings");
}
}
MenuItem {
separator: true
}
MenuItem {
text: qsTr("Forums and Help")
icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_supervisor_account.svg"
onTriggered: {
Qt.openUrlExternally("https://forum.screen-play.app/");
}
}
MenuItem {
text: qsTr("Frequently Asked Questions (FAQ)")
icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_help_center.svg"
onTriggered: {
Qt.openUrlExternally("https://kelteseth.gitlab.io/ScreenPlayDocs/Frequently%20Asked%20Questions/");
}
}
MenuItem {
separator: true
}
MenuItem { MenuItem {
id: miMuteAll id: miMuteAll
property bool isMuted: true property bool isMuted: true
text: qsTr("Mute all") text: qsTr("Mute all")
icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_volume_mute.svg"
onTriggered: { onTriggered: {
if (miMuteAll.isMuted) { if (miMuteAll.isMuted) {
isMuted = false; isMuted = false;
miMuteAll.text = qsTr("Mute all"); miMuteAll.text = qsTr("Mute all");
miMuteAll.icon.source = "qrc:/qml/ScreenPlayApp/assets/icons/icon_volume_mute.svg"
App.screenPlayManager.setAllWallpaperValue("muted", "true"); App.screenPlayManager.setAllWallpaperValue("muted", "true");
} else { } else {
isMuted = true; isMuted = true;
miMuteAll.text = qsTr("Unmute all"); miMuteAll.text = qsTr("Unmute all");
miMuteAll.icon.source = "qrc:/qml/ScreenPlayApp/assets/icons/icon_volume_up.svg"
App.screenPlayManager.setAllWallpaperValue("muted", "false"); App.screenPlayManager.setAllWallpaperValue("muted", "false");
} }
} }
@ -61,14 +131,17 @@ SystemTrayIcon {
property bool isPlaying: false property bool isPlaying: false
text: qsTr("Pause all") text: qsTr("Pause all")
icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_pause.svg"
onTriggered: { onTriggered: {
if (miStopAll.isPlaying) { if (miStopAll.isPlaying) {
isPlaying = false; isPlaying = false;
miStopAll.text = qsTr("Pause all"); miStopAll.text = qsTr("Pause all");
miStopAll.icon.source = "qrc:/qml/ScreenPlayApp/assets/icons/icon_pause.svg"
App.screenPlayManager.setAllWallpaperValue("isPlaying", "true"); App.screenPlayManager.setAllWallpaperValue("isPlaying", "true");
} else { } else {
isPlaying = true; isPlaying = true;
miStopAll.text = qsTr("Play all"); miStopAll.text = qsTr("Play all");
miStopAll.icon.source = "qrc:/qml/ScreenPlayApp/assets/icons/icon_play.svg"
App.screenPlayManager.setAllWallpaperValue("isPlaying", "false"); App.screenPlayManager.setAllWallpaperValue("isPlaying", "false");
} }
} }
@ -76,6 +149,7 @@ SystemTrayIcon {
MenuItem { MenuItem {
text: qsTr("Quit ScreenPlay") text: qsTr("Quit ScreenPlay")
icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_cancel_presentation.svg"
onTriggered: App.exit() onTriggered: App.exit()
} }
} }

View File

@ -5,6 +5,7 @@
#include "ScreenPlayUtil/macutils.h" #include "ScreenPlayUtil/macutils.h"
#endif #endif
#include "ScreenPlay/CMakeVariables.h"
#include "app.h" #include "app.h"
#include "steam/steam_qt_enums_generated.h" #include "steam/steam_qt_enums_generated.h"
#include <QGuiApplication> #include <QGuiApplication>
@ -71,8 +72,22 @@ App::App()
QGuiApplication::setOrganizationName("ScreenPlay"); QGuiApplication::setOrganizationName("ScreenPlay");
QGuiApplication::setOrganizationDomain("screen-play.app"); QGuiApplication::setOrganizationDomain("screen-play.app");
QGuiApplication::setApplicationName("ScreenPlay"); QGuiApplication::setApplicationName("ScreenPlay");
QGuiApplication::setApplicationVersion(QVersionNumber(0, 15, 0).toString()); QGuiApplication::setApplicationVersion(QString(SCREENPLAY_VERSION));
QGuiApplication::setQuitOnLastWindowClosed(false); QGuiApplication::setQuitOnLastWindowClosed(false);
// ScreenPlayManager first to check if another ScreenPlay Instace is running
m_screenPlayManager = std::make_unique<ScreenPlayManager>();
m_isAnotherScreenPlayInstanceRunning = m_screenPlayManager->isAnotherScreenPlayInstanceRunning();
}
/*!
\brief Used for initialization after the constructor. The sole purpose is to check if
another ScreenPlay instance is running and then quit early. This is also because we cannot
call QGuiApplication::quit(); in the SDKConnector before the app.exec(); ( the Qt main event
loop ) has started.
*/
void App::init()
{
qInfo() << "Init ScreenPlay";
QString fontsPath = QGuiApplication::instance()->applicationDirPath() + "/assets/fonts/"; QString fontsPath = QGuiApplication::instance()->applicationDirPath() + "/assets/fonts/";
#if defined(Q_OS_MACOS) #if defined(Q_OS_MACOS)
@ -121,26 +136,11 @@ App::App()
"SearchType", "SearchType",
"Error: only enums"); "Error: only enums");
// ScreenPlayManager first to check if another ScreenPlay Instace is running
m_screenPlayManager = std::make_unique<ScreenPlayManager>();
m_isAnotherScreenPlayInstanceRunning = m_screenPlayManager->isAnotherScreenPlayInstanceRunning();
}
/*!
\brief Used for initialization after the constructor. The sole purpose is to check if
another ScreenPlay instance is running and then quit early. This is also because we cannot
call QGuiApplication::quit(); in the SDKConnector before the app.exec(); ( the Qt main event
loop ) has started.
*/
void App::init()
{
using std::make_shared, std::make_unique; using std::make_shared, std::make_unique;
// Util should be created as first so we redirect qDebugs etc. into the log
m_util = make_unique<Util>();
m_globalVariables = make_shared<GlobalVariables>(); m_globalVariables = make_shared<GlobalVariables>();
m_monitorListModel = make_shared<MonitorListModel>(); m_monitorListModel = make_shared<MonitorListModel>();
m_util = make_unique<Util>(m_globalVariables);
m_profileListModel = make_shared<ProfileListModel>(m_globalVariables); m_profileListModel = make_shared<ProfileListModel>(m_globalVariables);
m_settings = make_shared<Settings>(m_globalVariables); m_settings = make_shared<Settings>(m_globalVariables);
m_installedListModel = make_shared<InstalledListModel>(m_globalVariables, m_settings); m_installedListModel = make_shared<InstalledListModel>(m_globalVariables, m_settings);

View File

@ -35,18 +35,23 @@ InstalledListModel::InstalledListModel(
*/ */
void InstalledListModel::init() void InstalledListModel::init()
{ {
if (!m_fileSystemWatcher.addPath(m_globalVariables->localStoragePath().toLocalFile())) { QString projectsPath = m_globalVariables->localStoragePath().toLocalFile();
qWarning() << "Could not setup file system watcher for changed files with path: " << m_globalVariables->localStoragePath().toLocalFile(); QDirIterator projectFilesIter(projectsPath, { "*.qml", "*.html", "*.css", "*.js", "*.png", "project.json" }, QDir::Files | QDir::NoSymLinks, QDirIterator::Subdirectories);
while (projectFilesIter.hasNext()) {
m_fileSystemWatcher.addPath(projectFilesIter.next());
} }
m_reloadLimiter.setInterval(500);
auto reloadLambda = [this]() { m_reloadLimiter.setSingleShot(true);
QTimer::singleShot(500, this, [this]() { QObject::connect(&m_reloadLimiter, &QTimer::timeout, this, [this]() {
reset(); reset();
}); });
auto restartTimer = [this]() {
m_reloadLimiter.start();
}; };
QObject::connect(&m_fileSystemWatcher, &QFileSystemWatcher::directoryChanged, this, reloadLambda); QObject::connect(&m_fileSystemWatcher, &QFileSystemWatcher::directoryChanged, this, restartTimer);
QObject::connect(&m_fileSystemWatcher, &QFileSystemWatcher::fileChanged, this, reloadLambda); QObject::connect(&m_fileSystemWatcher, &QFileSystemWatcher::fileChanged, this, restartTimer);
} }
/*! /*!
@ -54,12 +59,12 @@ void InstalledListModel::init()
installed list. We wait for the qml engine to free all resources before installed list. We wait for the qml engine to free all resources before
we proceed. This like the preview.gif will be in use when clicking on an item we proceed. This like the preview.gif will be in use when clicking on an item
*/ */
void InstalledListModel::deinstallItemAt(const QString& absoluteStoragePath) bool InstalledListModel::deinstallItemAt(const QString& absoluteStoragePath)
{ {
QTimer::singleShot(1000, this, [this, absoluteStoragePath]() { const QString path = ScreenPlayUtil::toLocal(absoluteStoragePath);
int index = -1; int index = -1;
for (int i = 0; i < m_screenPlayFiles.size(); ++i) { for (int i = 0; i < m_screenPlayFiles.size(); ++i) {
if (m_screenPlayFiles.at(i).projectJsonFilePath.absoluteFilePath() == absoluteStoragePath) { if (m_screenPlayFiles.at(i).projectJsonFilePath.path() == path) {
index = i; index = i;
break; break;
} }
@ -67,15 +72,14 @@ void InstalledListModel::deinstallItemAt(const QString& absoluteStoragePath)
if (index < 0 || index >= m_screenPlayFiles.count()) { if (index < 0 || index >= m_screenPlayFiles.count()) {
qWarning() << "Remove folder error, invalid index " << index; qWarning() << "Remove folder error, invalid index " << index;
return; return false;
} }
beginRemoveRows(QModelIndex(), index, index); beginRemoveRows(QModelIndex(), index, index);
m_screenPlayFiles.removeAt(index); m_screenPlayFiles.removeAt(index);
endRemoveRows(); endRemoveRows();
const QString path = ScreenPlayUtil::toLocal(absoluteStoragePath); QTimer::singleShot(1000, this, [this, path]() {
QDir dir(path); QDir dir(path);
bool success = true; bool success = true;
if (!dir.exists()) { if (!dir.exists()) {
@ -110,6 +114,7 @@ void InstalledListModel::deinstallItemAt(const QString& absoluteStoragePath)
m_fileSystemWatcher.blockSignals(false); m_fileSystemWatcher.blockSignals(false);
}); });
}); });
return true;
} }
/*! /*!
@ -288,6 +293,10 @@ QVariantMap InstalledListModel::get(const QString& folderName) const
*/ */
void InstalledListModel::reset() void InstalledListModel::reset()
{ {
if (m_isLoading) {
qInfo() << "loadInstalledContent is already running. Skip.";
return;
}
beginResetModel(); beginResetModel();
m_screenPlayFiles.clear(); m_screenPlayFiles.clear();
m_screenPlayFiles.squeeze(); m_screenPlayFiles.squeeze();

View File

@ -114,16 +114,15 @@ void MonitorListModel::loadMonitors()
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
QModelIndex index; QModelIndex index;
WinMonitorStats monitors; auto monitors = WindowsIntegration().getAllMonitors();
// This offset lets us center the monitor selection view in the center // This offset lets us center the monitor selection view in the center
int offsetX = 0; int offsetX = 0;
int offsetY = 0; int offsetY = 0;
const int moinitorCount = monitors.iMonitors.size();
for (int i = 0; i < moinitorCount; i++) { for (auto& monitor : monitors) {
const int x = monitors.rcMonitors[i].left; const int x = monitor.position.left;
const int y = monitors.rcMonitors[i].top; const int y = monitor.position.top;
if (x < 0) { if (x < 0) {
offsetX += (x * -1); offsetX += (x * -1);
} }
@ -132,11 +131,11 @@ void MonitorListModel::loadMonitors()
} }
} }
for (int i = 0; i < moinitorCount; i++) { for (int i = 0; auto& monitor : monitors) {
const int width = std::abs(monitors.rcMonitors[i].right - monitors.rcMonitors[i].left); const int width = std::abs(monitor.position.right - monitor.position.left);
const int height = std::abs(monitors.rcMonitors[i].top - monitors.rcMonitors[i].bottom); const int height = std::abs(monitor.position.top - monitor.position.bottom);
const int x = monitors.rcMonitors[i].left; const int x = monitor.position.left;
const int y = monitors.rcMonitors[i].top; const int y = monitor.position.top;
QRect geometry( QRect geometry(
x + offsetX, x + offsetX,
y + offsetY, y + offsetY,
@ -145,6 +144,7 @@ void MonitorListModel::loadMonitors()
beginInsertRows(index, m_monitorList.size(), m_monitorList.size()); beginInsertRows(index, m_monitorList.size(), m_monitorList.size());
m_monitorList.append(Monitor { i, geometry }); m_monitorList.append(Monitor { i, geometry });
endInsertRows(); endInsertRows();
i++;
} }
#else #else
QModelIndex index; QModelIndex index;

View File

@ -22,7 +22,9 @@ namespace ScreenPlay {
/*! /*!
Constructor Constructor
*/ */
ProfileListModel::ProfileListModel(const std::shared_ptr<GlobalVariables>& globalVariables, QObject* parent) ProfileListModel::ProfileListModel(
const std::shared_ptr<GlobalVariables>& globalVariables,
QObject* parent)
: QAbstractListModel(parent) : QAbstractListModel(parent)
, m_globalVariables { globalVariables } , m_globalVariables { globalVariables }
{ {

View File

@ -303,7 +303,7 @@ bool ScreenPlayManager::removeWallpaperAt(int index)
*/ */
bool ScreenPlayManager::requestProjectSettingsAtMonitorIndex(const int index) bool ScreenPlayManager::requestProjectSettingsAtMonitorIndex(const int index)
{ {
for (const std::shared_ptr<ScreenPlayWallpaper>& uPtrWallpaper : qAsConst(m_screenPlayWallpapers)) { for (const std::shared_ptr<ScreenPlayWallpaper>& uPtrWallpaper : std::as_const(m_screenPlayWallpapers)) {
if (uPtrWallpaper->screenNumber()[0] == index) { if (uPtrWallpaper->screenNumber()[0] == index) {
emit projectSettingsListModelResult( emit projectSettingsListModelResult(
@ -514,12 +514,12 @@ bool ScreenPlayManager::saveProfiles()
m_saveLimiter.stop(); m_saveLimiter.stop();
QJsonArray wallpaper {}; QJsonArray wallpaper {};
for (const auto& activeWallpaper : qAsConst(m_screenPlayWallpapers)) { for (const auto& activeWallpaper : std::as_const(m_screenPlayWallpapers)) {
wallpaper.append(activeWallpaper->getActiveSettingsJson()); wallpaper.append(activeWallpaper->getActiveSettingsJson());
} }
QJsonArray widgets {}; QJsonArray widgets {};
for (const auto& activeWidget : qAsConst(m_screenPlayWidgets)) { for (const auto& activeWidget : std::as_const(m_screenPlayWidgets)) {
widgets.append(activeWidget->getActiveSettingsJson()); widgets.append(activeWidget->getActiveSettingsJson());
} }

View File

@ -16,7 +16,8 @@ namespace ScreenPlay {
/*! /*!
\brief Constructor for ScreenPlayWallpaper. \brief Constructor for ScreenPlayWallpaper.
*/ */
ScreenPlayWallpaper::ScreenPlayWallpaper(const QVector<int>& screenNumber, ScreenPlayWallpaper::ScreenPlayWallpaper(
const QVector<int>& screenNumber,
const std::shared_ptr<GlobalVariables>& globalVariables, const std::shared_ptr<GlobalVariables>& globalVariables,
const QString& appID, const QString& appID,
const QString& absolutePath, const QString& absolutePath,
@ -42,7 +43,10 @@ ScreenPlayWallpaper::ScreenPlayWallpaper(const QVector<int>& screenNumber,
, m_playbackRate { playbackRate } , m_playbackRate { playbackRate }
, m_settings { settings } , m_settings { settings }
{ {
std::optional<QJsonObject> projectOpt = ScreenPlayUtil::openJsonFileToObject(absolutePath + "/project.json");
if (projectOpt.has_value()) {
m_projectJson = projectOpt.value();
}
QJsonObject projectSettingsListModelProperties; QJsonObject projectSettingsListModelProperties;
if (type == InstalledType::InstalledType::VideoWallpaper) { if (type == InstalledType::InstalledType::VideoWallpaper) {
projectSettingsListModelProperties.insert("volume", m_volume); projectSettingsListModelProperties.insert("volume", m_volume);
@ -66,7 +70,7 @@ ScreenPlayWallpaper::ScreenPlayWallpaper(const QVector<int>& screenNumber,
QString tmpScreenNumber; QString tmpScreenNumber;
if (m_screenNumber.length() > 1) { if (m_screenNumber.length() > 1) {
for (const int number : qAsConst(m_screenNumber)) { for (const int number : std::as_const(m_screenNumber)) {
// IMPORTANT: NO TRAILING COMMA! // IMPORTANT: NO TRAILING COMMA!
if (number == m_screenNumber.back()) { if (number == m_screenNumber.back()) {
tmpScreenNumber += QString::number(number); tmpScreenNumber += QString::number(number);
@ -92,13 +96,22 @@ ScreenPlayWallpaper::ScreenPlayWallpaper(const QVector<int>& screenNumber,
if (m_type != InstalledType::InstalledType::GodotWallpaper) { if (m_type != InstalledType::InstalledType::GodotWallpaper) {
m_appArgumentsList.append(" --disable-features=HardwareMediaKeyHandling"); m_appArgumentsList.append(" --disable-features=HardwareMediaKeyHandling");
} }
if (m_type == InstalledType::InstalledType::GodotWallpaper) {
if (m_projectJson.contains("version")) {
const quint64 version = m_projectJson.value("version").toInt();
const QString packageFileName = QString("project-v%1.zip").arg(version);
m_appArgumentsList.append(packageFileName);
}
}
} }
bool ScreenPlayWallpaper::start() bool ScreenPlayWallpaper::start()
{ {
if (m_type == InstalledType::InstalledType::GodotWallpaper) { if (m_type == InstalledType::InstalledType::GodotWallpaper) {
exportGodotProject(m_absolutePath); if (!exportGodotProject())
return false;
} }
m_process.setArguments(m_appArgumentsList); m_process.setArguments(m_appArgumentsList);
if (m_type == InstalledType::InstalledType::GodotWallpaper) { if (m_type == InstalledType::InstalledType::GodotWallpaper) {
m_process.setProgram(m_globalVariables->godotWallpaperExecutablePath().toString()); m_process.setProgram(m_globalVariables->godotWallpaperExecutablePath().toString());
@ -126,7 +139,7 @@ bool ScreenPlayWallpaper::start()
QJsonObject ScreenPlayWallpaper::getActiveSettingsJson() QJsonObject ScreenPlayWallpaper::getActiveSettingsJson()
{ {
QJsonArray screenNumber; QJsonArray screenNumber;
for (const int i : qAsConst(m_screenNumber)) { for (const int i : std::as_const(m_screenNumber)) {
screenNumber.append(i); screenNumber.append(i);
} }
@ -293,22 +306,40 @@ bool ScreenPlayWallpaper::replace(
return success; return success;
} }
bool ScreenPlayWallpaper::exportGodotProject(const QString& absolutePath, int timeoutMilliseconds) /*!
\brief .
*/
bool ScreenPlayWallpaper::exportGodotProject()
{ {
if (!m_projectJson.contains("version"))
return false;
const quint64 version = m_projectJson.value("version").toInt();
const QString packageFileName = QString("project-v%1.zip").arg(version);
QFileInfo godotPackageFile(m_absolutePath + "/" + packageFileName);
// Skip reexport
if (godotPackageFile.exists())
return true;
qInfo() << "No suitable version found for Godot package" << packageFileName << " at" << godotPackageFile.absoluteFilePath() << " exporting a new pck as zip.";
// Prepare the Godot export command // Prepare the Godot export command
const QList<QString> godotCmd = { "--export-pack", "--headless", "Windows Desktop", "project.zip" }; const QList<QString>
godotCmd
= { "--export-pack", "--headless", "Windows Desktop", packageFileName };
// Create QProcess instance to run the command // Create QProcess instance to run the command
QProcess process; QProcess process;
// Set the working directory to the given absolute path // Set the working directory to the given absolute path
process.setWorkingDirectory(absolutePath); process.setWorkingDirectory(m_absolutePath);
process.setProgram(m_globalVariables->godotEditorExecutablePath().toString()); process.setProgram(m_globalVariables->godotEditorExecutablePath().toString());
// Start the Godot export process // Start the Godot export process
process.setArguments(godotCmd); process.setArguments(godotCmd);
process.start(); process.start();
// Wait for the process to finish or timeout // Wait for the process to finish or timeout
const int timeoutMilliseconds = 30000;
if (!process.waitForFinished(timeoutMilliseconds)) { if (!process.waitForFinished(timeoutMilliseconds)) {
qCritical() << "Godot export process timed out or failed to start."; qCritical() << "Godot export process timed out or failed to start.";
return false; return false;
@ -331,9 +362,9 @@ bool ScreenPlayWallpaper::exportGodotProject(const QString& absolutePath, int ti
} }
// Check if the project.zip file was created // Check if the project.zip file was created
QString zipPath = QDir(absolutePath).filePath("project.zip"); QString zipPath = QDir(m_absolutePath).filePath(packageFileName);
if (!QFile::exists(zipPath)) { if (!QFile::exists(zipPath)) {
qCritical() << "Expected export file (project.zip) was not created."; qCritical() << "Expected export file (" << packageFileName << ") was not created.";
return false; return false;
} }
@ -342,7 +373,7 @@ bool ScreenPlayWallpaper::exportGodotProject(const QString& absolutePath, int ti
// but for simplicity, we're just checking its size here) // but for simplicity, we're just checking its size here)
QFileInfo zipInfo(zipPath); QFileInfo zipInfo(zipPath);
if (zipInfo.size() <= 0) { if (zipInfo.size() <= 0) {
qCritical() << "The exported project.zip file seems to be invalid."; qCritical() << "The exported " << packageFileName << " file seems to be invalid.";
return false; return false;
} }

View File

@ -161,7 +161,7 @@ void Settings::setupWidgetAndWindowPaths()
m_globalVariables->setWidgetExecutablePath(QUrl(workingDir.path() + "/ScreenPlayWidget" + ScreenPlayUtil::executableBinEnding())); m_globalVariables->setWidgetExecutablePath(QUrl(workingDir.path() + "/ScreenPlayWidget" + ScreenPlayUtil::executableBinEnding()));
m_globalVariables->setWallpaperExecutablePath(QUrl(workingDir.path() + "/ScreenPlayWallpaper" + ScreenPlayUtil::executableBinEnding())); m_globalVariables->setWallpaperExecutablePath(QUrl(workingDir.path() + "/ScreenPlayWallpaper" + ScreenPlayUtil::executableBinEnding()));
m_globalVariables->setGodotWallpaperExecutablePath(QUrl(workingDir.path() + "/ScreenPlayWallpaperGodot" + ScreenPlayUtil::executableBinEnding())); m_globalVariables->setGodotWallpaperExecutablePath(QUrl(workingDir.path() + "/ScreenPlayWallpaperGodot" + ScreenPlayUtil::executableBinEnding()));
const auto godotEditorName = "Godot_" + godotVersion + "-" + godotReleaseType + "_win64.exe"; const auto godotEditorName = "Godot_" + godotVersion + "_win64.exe";
m_globalVariables->setGodotEditorExecutablePath(QUrl(workingDir.path() + "/" + godotEditorName)); m_globalVariables->setGodotEditorExecutablePath(QUrl(workingDir.path() + "/" + godotEditorName));
} else if (osType == "macos") { } else if (osType == "macos") {
// ScreenPlayTest is not bundled in an .app so the working directory // ScreenPlayTest is not bundled in an .app so the working directory

View File

@ -23,8 +23,10 @@ namespace ScreenPlay {
/*! /*!
\brief Constructor. \brief Constructor.
*/ */
Util::Util() Util::Util(
const std::shared_ptr<GlobalVariables>& globalVariables)
: QObject(nullptr) : QObject(nullptr)
, m_globalVariables { globalVariables }
{ {
m_extractor = std::make_unique<QArchive::DiskExtractor>(); m_extractor = std::make_unique<QArchive::DiskExtractor>();
m_compressor = std::make_unique<QArchive::DiskCompressor>(); m_compressor = std::make_unique<QArchive::DiskCompressor>();
@ -144,6 +146,15 @@ bool Util::exportProject(QString contentPath, QString exportFileName)
return true; return true;
} }
bool Util::openGodotEditor(QString contentPath) const
{
const QList<QString> godotCmd = { "--editor", "--path", toLocal(contentPath) };
QProcess process;
process.setProgram(m_globalVariables->godotEditorExecutablePath().toString());
process.setArguments(godotCmd);
return process.startDetached();
}
/*! /*!
\brief Imports a given project from a .screenplay zip file. The argument extractionPath \brief Imports a given project from a .screenplay zip file. The argument extractionPath
must be copied otherwise it will get reset in qml before extracting. must be copied otherwise it will get reset in qml before extracting.

View File

@ -1,6 +1,11 @@
// SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only // SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only
#include "ScreenPlay/wizards.h" #include "ScreenPlay/wizards.h"
#include "ScreenPlay/CMakeVariables.h"
#include "ScreenPlayUtil/util.h" #include "ScreenPlayUtil/util.h"
#include <QFont>
#include <QLinearGradient>
#include <QPainter>
#include <QTextOption>
namespace ScreenPlay { namespace ScreenPlay {
/*! /*!
@ -67,15 +72,13 @@ void Wizards::createQMLWidget(const QString& title,
} }
if (!previewThumbnail.isEmpty()) { if (!previewThumbnail.isEmpty()) {
QUrl previewThumbnailUrl { previewThumbnail }; if (!Util::copyPreviewThumbnail(obj, previewThumbnail, workingPath)) {
QFileInfo previewImageFile(previewThumbnailUrl.toLocalFile()); emit widgetCreationFinished(WizardResult::CopyPreviewThumbnailError);
obj.insert("previewThumbnail", previewImageFile.fileName());
obj.insert("preview", previewImageFile.fileName());
if (!QFile::copy(previewThumbnailUrl.toLocalFile(), workingPath + "/" + previewImageFile.fileName())) {
qWarning() << "Could not copy" << previewThumbnailUrl.toLocalFile() << " to " << workingPath + "/" + previewImageFile.fileName();
emit widgetCreationFinished(WizardResult::CopyError);
return; return;
} }
} else {
obj.insert("preview", "preview.png");
createPreviewImage(title, workingPath);
} }
if (!Util::writeSettings(obj, workingPath + "/project.json")) { if (!Util::writeSettings(obj, workingPath + "/project.json")) {
@ -136,13 +139,13 @@ void Wizards::createHTMLWidget(const QString& title,
QFileInfo previewImageFile(previewThumbnailUrl.toLocalFile()); QFileInfo previewImageFile(previewThumbnailUrl.toLocalFile());
if (!previewThumbnail.isEmpty()) { if (!previewThumbnail.isEmpty()) {
obj.insert("previewThumbnail", previewImageFile.fileName()); if (!Util::copyPreviewThumbnail(obj, previewThumbnail, workingPath)) {
obj.insert("preview", previewImageFile.fileName()); emit widgetCreationFinished(WizardResult::CopyPreviewThumbnailError);
if (!QFile::copy(previewThumbnailUrl.toLocalFile(), workingPath + "/" + previewImageFile.fileName())) {
qWarning() << "Could not copy" << previewThumbnailUrl.toLocalFile() << " to " << workingPath + "/" + previewImageFile.fileName();
emit widgetCreationFinished(WizardResult::CopyError);
return; return;
} }
} else {
obj.insert("preview", "preview.png");
createPreviewImage(title, workingPath);
} }
if (!Util::writeSettings(obj, workingPath + "/project.json")) { if (!Util::writeSettings(obj, workingPath + "/project.json")) {
@ -201,15 +204,13 @@ void Wizards::createHTMLWallpaper(
} }
if (!previewThumbnail.isEmpty()) { if (!previewThumbnail.isEmpty()) {
QUrl previewThumbnailUrl { previewThumbnail }; if (!Util::copyPreviewThumbnail(obj, previewThumbnail, workingPath)) {
QFileInfo previewImageFile(previewThumbnailUrl.toLocalFile());
obj.insert("previewThumbnail", previewImageFile.fileName());
obj.insert("preview", previewImageFile.fileName());
if (!QFile::copy(previewThumbnailUrl.toLocalFile(), workingPath + "/" + previewImageFile.fileName())) {
qWarning() << "Could not copy" << previewThumbnailUrl.toLocalFile() << " to " << workingPath + "/" + previewImageFile.fileName();
emit widgetCreationFinished(WizardResult::CopyPreviewThumbnailError); emit widgetCreationFinished(WizardResult::CopyPreviewThumbnailError);
return; return;
} }
} else {
obj.insert("preview", "preview.png");
createPreviewImage(title, workingPath);
} }
if (!Util::writeSettings(obj, workingPath + "/project.json")) { if (!Util::writeSettings(obj, workingPath + "/project.json")) {
@ -260,6 +261,9 @@ void Wizards::createQMLWallpaper(
emit widgetCreationFinished(WizardResult::CopyPreviewThumbnailError); emit widgetCreationFinished(WizardResult::CopyPreviewThumbnailError);
return; return;
} }
} else {
obj.insert("preview", "preview.png");
createPreviewImage(title, workingPath);
} }
if (!Util::writeFileFromQrc(":/qml/ScreenPlayApp/assets/wizards/" + licenseFile, workingPath + "/" + licenseFile)) { if (!Util::writeFileFromQrc(":/qml/ScreenPlayApp/assets/wizards/" + licenseFile, workingPath + "/" + licenseFile)) {
@ -269,7 +273,7 @@ void Wizards::createQMLWallpaper(
} }
const QString qmlproject = workingPath + "/" + title + ".qmlproject"; const QString qmlproject = workingPath + "/" + title + ".qmlproject";
if (!Util::writeFileFromQrc(":/qml/ScreenPlayApp/assets/wizards/" + QString("QmlProject.qmlproject"), qmlproject)) { if (!Util::writeFileFromQrc(":/qml/ScreenPlayApp/qml/Create/WizardsFiles/" + QString("QmlProject.qmlproject"), qmlproject)) {
qWarning() << "Could not write " << qmlproject; qWarning() << "Could not write " << qmlproject;
emit widgetCreationFinished(WizardResult::WriteLicenseFileError); emit widgetCreationFinished(WizardResult::WriteLicenseFileError);
return; return;
@ -289,6 +293,95 @@ void Wizards::createQMLWallpaper(
}); });
} }
/*!
\brief .
*/
void Wizards::createGodotWallpaper(
const QString& title,
const QString& licenseName,
const QString& licenseFile,
const QString& createdBy,
const QString& previewThumbnail,
const QVector<QString>& tags)
{
if (m_wizardFuture.isRunning()) {
qWarning() << "Another wizard is already running! Abort.";
return;
}
m_wizardFuture = QtConcurrent::run([=]() {
std::optional<QString> folderName = createTemporaryFolder();
if (!folderName.has_value()) {
emit widgetCreationFinished(WizardResult::CreateProjectFolderError);
return;
}
const QString workingPath = ScreenPlayUtil::toLocal(m_globalVariables->localStoragePath().toString() + "/" + folderName.value());
QJsonObject obj;
obj.insert("license", licenseName);
obj.insert("title", title);
obj.insert("createdBy", createdBy);
// Every version change will trigger an reexport
obj.insert("version", 1);
// Something like v4.2-beta3 or v5.0.1-stable
QString godotVersionMajor = QString::number(SCREENPLAY_GODOT_VERSION_MAJOR);
QString godotVersionMinor = QString::number(SCREENPLAY_GODOT_VERSION_MINOR);
obj.insert("godotVersionMajor", godotVersionMajor);
obj.insert("godotVersionMinor", godotVersionMinor);
obj.insert("tags", ScreenPlayUtil::fillArray(tags));
obj.insert("type", QVariant::fromValue(InstalledType::InstalledType::GodotWallpaper).toString());
obj.insert("file", "wallpaper.tscn");
if (!previewThumbnail.isEmpty()) {
if (!Util::copyPreviewThumbnail(obj, previewThumbnail, workingPath)) {
emit widgetCreationFinished(WizardResult::CopyPreviewThumbnailError);
return;
}
} else {
obj.insert("preview", "preview.png");
createPreviewImage(title, workingPath);
}
if (!Util::writeFileFromQrc(":/qml/ScreenPlayApp/assets/wizards/" + licenseFile, workingPath + "/" + licenseFile)) {
qWarning() << "Could not write " << licenseFile;
emit widgetCreationFinished(WizardResult::WriteLicenseFileError);
return;
}
if (!Util::writeSettings(obj, workingPath + "/project.json")) {
emit widgetCreationFinished(WizardResult::WriteProjectFileError);
return;
}
if (!Util::writeFileFromQrc(":/qml/ScreenPlayApp/qml/Create/WizardsFiles/Godot_v5/project.godot", workingPath + "/project.godot")) {
qWarning() << "Could not write project.godot";
return;
}
if (!Util::writeFileFromQrc(":/qml/ScreenPlayApp/qml/Create/WizardsFiles/Godot_v5/spinner.gd", workingPath + "/spinner.gd")) {
qWarning() << "Could not write spinner.gd";
return;
}
if (!Util::writeFileFromQrc(":/qml/ScreenPlayApp/qml/Create/WizardsFiles/Godot_v5/wallpaper.tscn", workingPath + "/wallpaper.tscn")) {
qWarning() << "Could not write wallpaper.tscn";
return;
}
// This presets file is needed for the export. Because we do only export
// package files, it does not matter that we hardcode "Windows Desktop" as
// export preset.
if (!Util::writeFileFromQrc(":/qml/ScreenPlayApp/qml/Create/WizardsFiles/Godot_v5/export_presets.cfg", workingPath + "/export_presets.cfg")) {
qWarning() << "Could not write export_presets.cfg";
return;
}
emit widgetCreationFinished(WizardResult::Ok, workingPath);
});
}
void Wizards::createGifWallpaper( void Wizards::createGifWallpaper(
const QString& title, const QString& title,
const QString& licenseName, const QString& licenseName,
@ -378,6 +471,9 @@ void Wizards::createWebsiteWallpaper(
emit widgetCreationFinished(WizardResult::CopyPreviewThumbnailError); emit widgetCreationFinished(WizardResult::CopyPreviewThumbnailError);
return; return;
} }
} else {
obj.insert("preview", "preview.png");
createPreviewImage(title, workingPath);
} }
if (!Util::writeSettings(obj, workingPath + "/project.json")) { if (!Util::writeSettings(obj, workingPath + "/project.json")) {
@ -408,6 +504,48 @@ const std::optional<QString> Wizards::createTemporaryFolder() const
return folderName; return folderName;
} }
/*!
\brief Creates a default preview.png.
*/
void Wizards::createPreviewImage(const QString& name, const QString& targetPath)
{
// Step 1: Create QImage and QPainter
QImage image(749, 442, QImage::Format_ARGB32);
QPainter painter(&image);
// Step 2: Select Random Colors (example colors, replace with Material colors)
// These are just placeholder colors, replace with actual Material colors
int randomIndex1 = QRandomGenerator::global()->bounded(5);
int randomIndex2 = QRandomGenerator::global()->bounded(5);
// Step 3: Create and Set Gradient
QLinearGradient gradient(QPointF(0, image.height()), QPointF(image.width(), 0));
gradient.setColorAt(0, m_gradientColors[randomIndex1].darker()); // Dark color
gradient.setColorAt(1, m_gradientColors[randomIndex2].lighter()); // Bright color
painter.fillRect(image.rect(), gradient);
// Step 4: Draw Text
// Set the font size depending on the size of the image
painter.setPen(Qt::white);
int fontSize = qMin(image.width(), image.height()) / 10; // Adjust proportion as needed
QFont font = painter.font();
font.setFamily("Noto Sans Light");
font.setPointSize(fontSize);
painter.setFont(font);
// Define a margin and adjust the rect accordingly
int margin = 30;
QRect rect(margin, margin, image.width() - 2 * margin, image.height() - 2 * margin);
// Draw text within the adjusted rect
QTextOption option(Qt::AlignCenter);
painter.drawText(rect, name, option);
// Step 5: Save Image
image.save(targetPath + "/preview.png");
}
} }
#include "moc_wizards.cpp" #include "moc_wizards.cpp"

View File

@ -102,7 +102,7 @@ void ScreenPlayTest::import_convert_video()
auto* createWallpaperInit = m_window->findChild<QQuickItem*>("createWallpaperInit"); auto* createWallpaperInit = m_window->findChild<QQuickItem*>("createWallpaperInit");
QVERIFY(createWallpaperInit); QVERIFY(createWallpaperInit);
const QString originalVideoPath = QString(SCREENPLAY_SOURCE_DIR) + "/ScreenPlay/assets/tests/video_import.mp4"; const QString originalVideoPath = QString(SCREENPLAY_SOURCE_DIR) + "/Content/wallpaper_video_nebula_h264/mantissa.xyz_loop_072.mp4";
qInfo() << originalVideoPath; qInfo() << originalVideoPath;
QVERIFY(QMetaObject::invokeMethod(createWallpaperInit, QVERIFY(QMetaObject::invokeMethod(createWallpaperInit,

View File

@ -107,3 +107,7 @@ if(WIN32)
# Used for query windows monitor data # Used for query windows monitor data
target_link_libraries(${PROJECT_NAME} PUBLIC shcore.lib) target_link_libraries(${PROJECT_NAME} PUBLIC shcore.lib)
endif() endif()
# ##### USE CMAKE VARIABLES IN CODE #####
include(GenerateCMakeVariableHeader)
generate_cmake_variable_header(${PROJECT_NAME})

View File

@ -8,6 +8,8 @@
#include <QUrl> #include <QUrl>
#include <fmt/color.h> #include <fmt/color.h>
#include "ScreenPlayUtil/CMakeVariables.h"
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
#ifndef NOMINMAX #ifndef NOMINMAX
#define NOMINMAX #define NOMINMAX
@ -29,11 +31,14 @@ LoggingHandler::LoggingHandler(const QString& logFileName)
#ifdef Q_OS_WINDOWS #ifdef Q_OS_WINDOWS
// Enable UTF-8 support // Enable UTF-8 support
SetConsoleOutputCP(CP_UTF8); SetConsoleOutputCP(CP_UTF8);
// This is a QtCreator workaround and crashes std::fmt
// when running standalone.
if (!SCREENPLAY_DEPLOY_VERSION) {
// QtCreator has issues with fmt prints // QtCreator has issues with fmt prints
// https://bugreports.qt.io/browse/QTCREATORBUG-3994 // https://bugreports.qt.io/browse/QTCREATORBUG-3994
setbuf(stdout, NULL); setvbuf(stdout, NULL, _IONBF, 0);
qInfo() << "Setting setvbuf(stdout, NULL, _IONBF, 0); This unbuffered output causes crashes in release with threaded fmt!";
}
#endif #endif
qSetMessagePattern("[%{time dd.MM.yyyy h:mm:ss.zzz} %{if-debug}Debug%{endif}%{if-info}Info%{endif}%{if-warning}Warning%{endif}%{if-critical}Critical%{endif}%{if-fatal}Fatal%{endif}] %{file}:%{line} - %{message}"); qSetMessagePattern("[%{time dd.MM.yyyy h:mm:ss.zzz} %{if-debug}Debug%{endif}%{if-info}Info%{endif}%{if-warning}Warning%{endif}%{if-critical}Critical%{endif}%{if-fatal}Fatal%{endif}] %{file}:%{line} - %{message}");
@ -227,7 +232,6 @@ void LoggingHandler::writeToConsole(QtMsgType type, const QMessageLogContext& co
const auto filename = extractFileName(context); const auto filename = extractFileName(context);
const auto function = extractFunction(context); const auto function = extractFunction(context);
const auto line = context.line; const auto line = context.line;
fmt::print( fmt::print(
"[{}] {} {}:{} - {}\n", "[{}] {} {}:{} - {}\n",
fmt::styled(now.toStdString(), fmt::emphasis::bold), fmt::styled(now.toStdString(), fmt::emphasis::bold),

View File

@ -36,9 +36,11 @@ bool ProjectFile::init()
} }
type = typeParsed.value(); type = typeParsed.value();
// Required: // File is required. Website Wallpaper doe not have a file, but a url
if (!obj.contains("file")) if (!obj.contains("file") && type != ScreenPlay::InstalledType::InstalledType::WebsiteWallpaper)
return false; return false;
if (type != ScreenPlay::InstalledType::InstalledType::WebsiteWallpaper) {
file = obj.value("file").toString(); file = obj.value("file").toString();
if (type == ScreenPlay::InstalledType::InstalledType::GodotWallpaper) { if (type == ScreenPlay::InstalledType::InstalledType::GodotWallpaper) {
@ -54,6 +56,7 @@ bool ProjectFile::init()
return false; return false;
} }
} }
}
// Optional: // Optional:
if (!obj.contains("description")) if (!obj.contains("description"))
@ -105,13 +108,13 @@ bool ProjectFile::init()
qWarning("Invalid videoCodec was specified inside the json object!"); qWarning("Invalid videoCodec was specified inside the json object!");
} }
} else if (type == ScreenPlay::InstalledType::InstalledType::VideoWallpaper) { } else if (type == ScreenPlay::InstalledType::InstalledType::VideoWallpaper) {
qWarning("No videoCodec was specified inside the json object!"); // qWarning("No videoCodec was specified inside the json object!");
if (file.endsWith(".mp4")) { if (file.endsWith(".mp4")) {
videoCodec = ScreenPlay::VideoCodec::VideoCodec::H264; videoCodec = ScreenPlay::VideoCodec::VideoCodec::H264;
qWarning("Eyeball to h264 because of .mp4"); // qWarning("Eyeball to h264 because of .mp4");
} else if (file.endsWith(".webm")) { } else if (file.endsWith(".webm")) {
videoCodec = ScreenPlay::VideoCodec::VideoCodec::VP8; videoCodec = ScreenPlay::VideoCodec::VideoCodec::VP8;
qWarning("Eyeball to VP8 because of .webm"); // qWarning("Eyeball to VP8 because of .webm");
} }
} }

View File

@ -46,7 +46,7 @@ set(QML
qml/Wallpaper.qml qml/Wallpaper.qml
qml/WebsiteWallpaper.qml) qml/WebsiteWallpaper.qml)
set(RESOURCES dot.png qtquickcontrols2.conf index.html) set(RESOURCES qtquickcontrols2.conf index.html)
set(LIB_SOURCES) set(LIB_SOURCES)
set(LIB_HEADER) set(LIB_HEADER)

View File

@ -32,8 +32,15 @@ project(ScreenPlayGodotWallpaper LANGUAGES CXX)
# Create our library # Create our library
add_library(${PROJECT_NAME} SHARED) add_library(${PROJECT_NAME} SHARED)
# Runs after compilation Enable executing python scripts
find_package(Python COMPONENTS Interpreter)
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_17) add_custom_command(
TARGET ${PROJECT_NAME}
POST_BUILD
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/Tools"
COMMAND "${Python_EXECUTABLE}" "build_godot.py" "--build_path" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}"
COMMENT "Running post-build step")
# LIB_ARCH is the architecture being built. It is set to the build system's architecture. For macOS, we build a universal library (both # LIB_ARCH is the architecture being built. It is set to the build system's architecture. For macOS, we build a universal library (both
# arm64 and x86_64). # arm64 and x86_64).

@ -1 +1 @@
Subproject commit c1196a1ab0a1ca166d0e5e2f08f9fe4156118c5e Subproject commit 32409472b785fd6f9062300664fa55b46bfd07e7

View File

@ -33,6 +33,9 @@ void ScreenPlayGodotWallpaper::_bind_methods()
ClassDB::bind_method(godot::D_METHOD("get_activeScreensList"), &ScreenPlayGodotWallpaper::get_activeScreensList); ClassDB::bind_method(godot::D_METHOD("get_activeScreensList"), &ScreenPlayGodotWallpaper::get_activeScreensList);
ClassDB::bind_method(godot::D_METHOD("set_activeScreensList", "screens"), &ScreenPlayGodotWallpaper::set_activeScreensList); ClassDB::bind_method(godot::D_METHOD("set_activeScreensList", "screens"), &ScreenPlayGodotWallpaper::set_activeScreensList);
ClassDB::bind_method(godot::D_METHOD("get_projectPackageFile"), &ScreenPlayGodotWallpaper::get_projectPackageFile);
ClassDB::bind_method(godot::D_METHOD("set_projectPackageFile", "projectPackageFile"), &ScreenPlayGodotWallpaper::set_projectPackageFile);
ClassDB::bind_method(godot::D_METHOD("get_projectPath"), &ScreenPlayGodotWallpaper::get_projectPath); ClassDB::bind_method(godot::D_METHOD("get_projectPath"), &ScreenPlayGodotWallpaper::get_projectPath);
ClassDB::bind_method(godot::D_METHOD("set_projectPath", "path"), &ScreenPlayGodotWallpaper::set_projectPath); ClassDB::bind_method(godot::D_METHOD("set_projectPath", "path"), &ScreenPlayGodotWallpaper::set_projectPath);
@ -54,6 +57,16 @@ void ScreenPlayGodotWallpaper::hideFromTaskbar(HWND hwnd)
SetWindowLong(hwnd, GWL_EXSTYLE, lExStyle); SetWindowLong(hwnd, GWL_EXSTYLE, lExStyle);
} }
godot::String ScreenPlayGodotWallpaper::get_projectPackageFile() const
{
return m_projectPackageFile;
}
void ScreenPlayGodotWallpaper::set_projectPackageFile(const godot::String& projectPackageFile)
{
m_projectPackageFile = projectPackageFile;
}
bool ScreenPlayGodotWallpaper::configureWindowGeometry() bool ScreenPlayGodotWallpaper::configureWindowGeometry()
{ {
if (!m_windowsIntegration.searchWorkerWindowToParentTo()) { if (!m_windowsIntegration.searchWorkerWindowToParentTo()) {
@ -74,18 +87,26 @@ bool ScreenPlayGodotWallpaper::configureWindowGeometry()
bool ScreenPlayGodotWallpaper::init(int activeScreen) bool ScreenPlayGodotWallpaper::init(int activeScreen)
{ {
auto* displayServer = DisplayServer::get_singleton(); auto* displayServer = DisplayServer::get_singleton();
{
int64_t handle_int = displayServer->window_get_native_handle(godot::DisplayServer::HandleType::WINDOW_HANDLE, activeScreen); int64_t handle_int = displayServer->window_get_native_handle(godot::DisplayServer::HandleType::WINDOW_HANDLE);
HWND hwnd = reinterpret_cast<HWND>(static_cast<intptr_t>(handle_int)); HWND hwnd = reinterpret_cast<HWND>(handle_int);
m_windowsIntegration.setWindowHandle(hwnd); m_windowsIntegration.setWindowHandle(hwnd);
ShowWindow(m_windowsIntegration.windowHandle(), SW_HIDE);
if (!IsWindow(hwnd)) {
UtilityFunctions::print("ScreenPlayGodotWallpaper::init Could not get a valid window handle !", activeScreen, handle_int);
UtilityFunctions::print("init hwnd: ", (int64_t)hwnd, activeScreen, handle_int);
std::vector<Monitor> monitors = m_windowsIntegration.getAllMonitors();
for (const auto& monitor : monitors) {
UtilityFunctions::print(monitor.toString().c_str());
}
return false;
} }
hideFromTaskbar(m_windowsIntegration.windowHandle());
if (!configureWindowGeometry()) { if (!configureWindowGeometry()) {
return false; return false;
} }
ShowWindow(m_windowsIntegration.windowHandle(), SW_HIDE); hideFromTaskbar(m_windowsIntegration.windowHandle());
auto updateWindowSize = [&displayServer](const int width, const int height) { auto updateWindowSize = [&displayServer](const int width, const int height) {
displayServer->window_set_size(godot::Vector2((real_t)width, (real_t)height)); displayServer->window_set_size(godot::Vector2((real_t)width, (real_t)height));
}; };
@ -101,38 +122,38 @@ bool ScreenPlayGodotWallpaper::init(int activeScreen)
SetWindowText(m_windowsIntegration.windowHandle(), windowTitle.c_str()); SetWindowText(m_windowsIntegration.windowHandle(), windowTitle.c_str());
ShowWindow(m_windowsIntegration.windowHandle(), SW_SHOW); ShowWindow(m_windowsIntegration.windowHandle(), SW_SHOW);
m_windowsIntegration.setupWindowMouseHook(); // m_windowsIntegration.setupWindowMouseHook();
// Set up the mouse event handler // Set up the mouse event handler
m_windowsIntegration.setMouseEventHandler([this](DWORD mouseButton, UINT type, POINT p) { // m_windowsIntegration.setMouseEventHandler([this](DWORD mouseButton, UINT type, POINT p) {
Ref<InputEventMouseButton> mouse_event; // Ref<InputEventMouseButton> mouse_event;
Ref<InputEventMouseMotion> motion_event; // Ref<InputEventMouseMotion> motion_event;
switch (type) { // switch (type) {
case WM_LBUTTONDOWN: // case WM_LBUTTONDOWN:
case WM_LBUTTONUP: // case WM_LBUTTONUP:
case WM_RBUTTONDOWN: // case WM_RBUTTONDOWN:
case WM_RBUTTONUP: // case WM_RBUTTONUP:
mouse_event.instantiate(); // mouse_event.instantiate();
mouse_event->set_position(Vector2(p.x, p.y)); // mouse_event->set_position(Vector2(p.x, p.y));
mouse_event->set_global_position(Vector2(p.x, p.y)); // Assuming global == local for this context // mouse_event->set_global_position(Vector2(p.x, p.y)); // Assuming global == local for this context
mouse_event->set_button_index( // mouse_event->set_button_index(
type == WM_LBUTTONDOWN || type == WM_LBUTTONUP ? MOUSE_BUTTON_LEFT : MOUSE_BUTTON_RIGHT); // type == WM_LBUTTONDOWN || type == WM_LBUTTONUP ? MOUSE_BUTTON_LEFT : MOUSE_BUTTON_RIGHT);
mouse_event->set_pressed(type == WM_LBUTTONDOWN || type == WM_RBUTTONDOWN); // mouse_event->set_pressed(type == WM_LBUTTONDOWN || type == WM_RBUTTONDOWN);
break; // break;
case WM_MOUSEMOVE: // case WM_MOUSEMOVE:
motion_event.instantiate(); // motion_event.instantiate();
motion_event->set_position(Vector2(p.x, p.y)); // motion_event->set_position(Vector2(p.x, p.y));
motion_event->set_global_position(Vector2(p.x, p.y)); // motion_event->set_global_position(Vector2(p.x, p.y));
break; // break;
// Add more cases as needed // // Add more cases as needed
} // }
if (mouse_event.is_valid()) { // if (mouse_event.is_valid()) {
get_tree()->get_root()->get_viewport()->push_input(mouse_event); // get_tree()->get_root()->get_viewport()->push_input(mouse_event);
} // }
if (motion_event.is_valid()) { // if (motion_event.is_valid()) {
get_tree()->get_root()->get_viewport()->push_input(motion_event); // get_tree()->get_root()->get_viewport()->push_input(motion_event);
} // }
}); // }); 2
return true; return true;
} }
@ -222,18 +243,6 @@ void ScreenPlayGodotWallpaper::messageReceived(const std::string& key, const std
std::cerr << "Out of range: " << oor.what() << std::endl; std::cerr << "Out of range: " << oor.what() << std::endl;
} }
} }
void ScreenPlayGodotWallpaper::set_checkWallpaperVisible(bool visible)
{
m_checkWallpaperVisible = visible;
}
bool ScreenPlayGodotWallpaper::get_screenPlayConnected() const
{
return m_screenPlayConnected;
}
bool ScreenPlayGodotWallpaper::get_pipeConnected() const
{
return m_pipeConnected;
}
bool ScreenPlayGodotWallpaper::exit() bool ScreenPlayGodotWallpaper::exit()
{ {
// Somehow this gets called at editor startup // Somehow this gets called at editor startup
@ -247,6 +256,18 @@ bool ScreenPlayGodotWallpaper::exit()
ShowWindow(m_windowsIntegration.windowHandleWorker(), SW_HIDE); ShowWindow(m_windowsIntegration.windowHandleWorker(), SW_HIDE);
return true; return true;
} }
void ScreenPlayGodotWallpaper::set_checkWallpaperVisible(bool visible)
{
m_checkWallpaperVisible = visible;
}
bool ScreenPlayGodotWallpaper::get_screenPlayConnected() const
{
return m_screenPlayConnected;
}
bool ScreenPlayGodotWallpaper::get_pipeConnected() const
{
return m_pipeConnected;
}
bool ScreenPlayGodotWallpaper::get_checkWallpaperVisible() const bool ScreenPlayGodotWallpaper::get_checkWallpaperVisible() const
{ {
return m_checkWallpaperVisible; return m_checkWallpaperVisible;

View File

@ -57,6 +57,9 @@ public:
bool send_ping(); bool send_ping();
bool exit(); bool exit();
godot::String get_projectPackageFile() const;
void set_projectPackageFile(const godot::String& projectPackageFile);
protected: protected:
static void _bind_methods(); static void _bind_methods();
@ -70,6 +73,7 @@ private:
godot::String m_appID = ""; godot::String m_appID = "";
godot::String m_projectPath = ""; godot::String m_projectPath = "";
godot::String m_projectPackageFile = "";
WindowsIntegration m_windowsIntegration; WindowsIntegration m_windowsIntegration;
double m_timesinceLastRead = 0.0; double m_timesinceLastRead = 0.0;
bool m_pipeConnected = false; bool m_pipeConnected = false;

View File

@ -44,7 +44,7 @@ func _ready():
get_tree().quit() get_tree().quit()
return return
#screen_play_wallpaper.set_projectPath("C:\\Code\\cpp\\ScreenPlay\\ScreenPlay\\Content\\wallpaper_godot_fjord") #screen_play_wallpaper.set_projectPath("C:\\Code\\cpp\\ScreenPlay\\ScreenPlay\\Content\\wallpaper_godot_fjord")
path = screen_play_wallpaper.get_projectPath() + "/project.zip" path = screen_play_wallpaper.get_projectPath() + "/" + screen_play_wallpaper.get_projectPackageFile()
else: else:
get_tree().quit() get_tree().quit()
return return
@ -55,7 +55,7 @@ func _ready():
# yet setup via screenplay_manager.init() # yet setup via screenplay_manager.init()
get_tree().quit() get_tree().quit()
return return
Engine.set_max_fps(24) Engine.set_max_fps(144)
var ok = screen_play_wallpaper.init(screen_play_wallpaper.get_activeScreensList()[0]) var ok = screen_play_wallpaper.init(screen_play_wallpaper.get_activeScreensList()[0])
if not ok: if not ok:
@ -99,7 +99,7 @@ func parse_args():
if args[0] == "res://main.tscn": if args[0] == "res://main.tscn":
offset = 1 offset = 1
if args.size() < 7: # Adjust this number based on the expected number of arguments if args.size() < 8: # Adjust this number based on the expected number of arguments
print("Not enough arguments provided!") print("Not enough arguments provided!")
return false return false
@ -122,6 +122,7 @@ func parse_args():
var type = args[5] # This might need further parsing depending on its expected format var type = args[5] # This might need further parsing depending on its expected format
screen_play_wallpaper.set_checkWallpaperVisible(args[6 + offset].to_lower() == "true") screen_play_wallpaper.set_checkWallpaperVisible(args[6 + offset].to_lower() == "true")
screen_play_wallpaper.set_activeScreensList(activeScreensList) screen_play_wallpaper.set_activeScreensList(activeScreensList)
screen_play_wallpaper.set_projectPackageFile(args[7 + offset])
# Print or use the parsed values as needed # Print or use the parsed values as needed
print("Parsing done:", activeScreensList, screen_play_wallpaper.get_projectPath(), screen_play_wallpaper.get_appID(), screen_play_wallpaper.get_volume(), type, screen_play_wallpaper.get_checkWallpaperVisible()) print("Parsing done:", activeScreensList, screen_play_wallpaper.get_projectPath(), screen_play_wallpaper.get_appID(), screen_play_wallpaper.get_volume(), type, screen_play_wallpaper.get_checkWallpaperVisible())

View File

@ -23,14 +23,14 @@ config/icon="res://icon.svg"
window/size/viewport_width=1 window/size/viewport_width=1
window/size/viewport_height=1 window/size/viewport_height=1
window/size/mode=1 window/size/resizable=false
window/size/initial_position_type=0
window/size/initial_position=Vector2i(9999999, 9999999)
window/size/borderless=true window/size/borderless=true
window/size/transparent=true
window/energy_saving/keep_screen_on=false
[editor] [editor]
run/main_run_args="\"0\" \"C:/Code/Cpp/ScreenPlay/ScreenPlay/Content/wallpaper_godot_fjord\" \"appID=test\" \"1\" \"Cover\" \"GodotWallpaper\" \"1\"" run/main_run_args="\"1\" \"C:/Code/Cpp/ScreenPlay/ScreenPlay/Content/wallpaper_godot_fjord\" \"appID=test\" \"1\" \"Cover\" \"GodotWallpaper\" \"1\" \"project-v1.zip\""
[filesystem] [filesystem]

View File

@ -104,14 +104,6 @@ Rectangle {
} }
} }
ImageParticle {
height: 16
width: 16
source: "dot.png"
system: particleSystem
opacity: root.imgOpacity
}
Text { Text {
id: txtMousePos id: txtMousePos
@ -216,7 +208,6 @@ Rectangle {
spacing: 20 spacing: 20
TextField { TextField {
placeholderText: "Edit me" placeholderText: "Edit me"
} }
Button { Button {
text: "Exit" text: "Exit"
@ -226,10 +217,8 @@ Rectangle {
}); });
} }
} }
} }
MultimediaView { MultimediaView {
width: 1000 width: 1000
height: 400 height: 400

View File

@ -1,111 +0,0 @@
#include "windowshook.h"
BOOL CALLBACK WinMonitorStats::MonitorEnum(HMONITOR hMon, HDC hdc, LPRECT lprcMonitor, LPARAM pData)
{
WinMonitorStats* pThis = reinterpret_cast<WinMonitorStats*>(pData);
auto scaleFactor = DEVICE_SCALE_FACTOR::DEVICE_SCALE_FACTOR_INVALID;
GetScaleFactorForMonitor(hMon, &scaleFactor);
UINT x = 0;
UINT y = 0;
GetDpiForMonitor(hMon, MONITOR_DPI_TYPE::MDT_RAW_DPI, &x, &y);
pThis->sizes.push_back({ x, y });
pThis->scaleFactor.push_back(scaleFactor);
pThis->hMonitors.push_back(hMon);
pThis->hdcMonitors.push_back(hdc);
pThis->rcMonitors.push_back(*lprcMonitor);
pThis->iMonitors.push_back(static_cast<int>(pThis->hdcMonitors.size()));
// qInfo() << std::abs(lprcMonitor->right - lprcMonitor->left) << std::abs(lprcMonitor->top - lprcMonitor->bottom);
return TRUE;
}
/*!
\brief Searches for the worker window for our window to parent to.
*/
BOOL WINAPI SearchForWorkerWindow(HWND hwnd, LPARAM lparam)
{
// 0xXXXXXXX "" WorkerW
// ...
// 0xXXXXXXX "" SHELLDLL_DefView
// 0xXXXXXXXX "FolderView" SysListView32
// 0xXXXXXXXX "" WorkerW <---- We want this one
// 0xXXXXXXXX "Program Manager" Progman
if (FindWindowExW(hwnd, nullptr, L"SHELLDLL_DefView", nullptr))
*reinterpret_cast<HWND*>(lparam) = FindWindowExW(nullptr, hwnd, L"WorkerW", nullptr);
return TRUE;
}
bool WindowsHook::searchWorkerWindowToParentTo()
{
HWND progman_hwnd = FindWindowW(L"Progman", L"Program Manager");
const DWORD WM_SPAWN_WORKER = 0x052C;
SendMessageTimeoutW(progman_hwnd, WM_SPAWN_WORKER, 0xD, 0x1, SMTO_NORMAL,
10000, nullptr);
return EnumWindows(SearchForWorkerWindow, reinterpret_cast<LPARAM>(&windowHandleWorker));
}
/*!
\brief Returns scaling factor as reported by Windows.
*/
float WindowsHook::getScaling(const int monitorIndex) const
{
// Get all monitors
int monitorCount = GetSystemMetrics(SM_CMONITORS);
if (monitorIndex < 0 || monitorIndex >= monitorCount) {
// Invalid monitor index
return 1.0f;
}
DISPLAY_DEVICE displayDevice;
ZeroMemory(&displayDevice, sizeof(displayDevice));
displayDevice.cb = sizeof(displayDevice);
// Enumerate through monitors until we find the one we're looking for
for (int i = 0; EnumDisplayDevices(NULL, i, &displayDevice, 0); i++) {
if (i == monitorIndex) {
DEVMODE devMode;
ZeroMemory(&devMode, sizeof(devMode));
devMode.dmSize = sizeof(devMode);
// Get settings for selected monitor
if (!EnumDisplaySettings(displayDevice.DeviceName, ENUM_CURRENT_SETTINGS, &devMode)) {
// Unable to get monitor settings
return 1.0f;
}
// Get DPI for selected monitor
HMONITOR hMonitor = MonitorFromPoint({ devMode.dmPosition.x, devMode.dmPosition.y }, MONITOR_DEFAULTTONEAREST);
UINT dpiX = 0, dpiY = 0;
if (SUCCEEDED(GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY))) {
return (float)dpiX / 96.0f; // Standard DPI is 96
}
}
}
// If we reach here, it means we couldn't find the monitor with the given index or couldn't get the DPI.
return 1.0f;
}
/*!
\brief Returns true of at least one monitor has active scaling enabled.
*/
bool WindowsHook::hasWindowScaling() const
{
auto enumMonitorCallback = [](HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) -> BOOL {
int scaling = GetDeviceCaps(hdcMonitor, LOGPIXELSX) / 96;
if (scaling != 1) {
*(bool*)dwData = true;
return false; // Stop enumeration
}
return true; // Continue enumeration
};
bool hasScaling = false;
EnumDisplayMonitors(NULL, NULL, enumMonitorCallback, (LPARAM)&hasScaling);
return hasScaling;
}

View File

@ -1,41 +0,0 @@
#pragma once
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <Windows.h>
#include <algorithm>
#include <iostream>
#include <shellscalingapi.h>
#include <vector>
struct WinMonitorStats {
WinMonitorStats()
{
EnumDisplayMonitors(NULL, NULL, MonitorEnum, (LPARAM)this);
}
static BOOL CALLBACK MonitorEnum(HMONITOR hMon, HDC hdc, LPRECT lprcMonitor, LPARAM pData);
std::vector<int> iMonitors;
std::vector<HMONITOR> hMonitors;
std::vector<HDC> hdcMonitors;
std::vector<RECT> rcMonitors;
std::vector<DEVICE_SCALE_FACTOR> scaleFactor;
std::vector<std::pair<UINT, UINT>> sizes;
int index = 0;
};
struct Point {
int x = 0;
int y = 0;
};
struct WindowsHook {
bool searchWorkerWindowToParentTo();
float getScaling(const int monitorIndex) const;
bool hasWindowScaling() const;
HWND windowHandle {};
HWND windowHandleWorker {};
Point zeroPoint;
};

View File

@ -68,7 +68,7 @@ BOOL SearchForWorkerWindow(HWND hwnd, LPARAM lparam)
return TRUE; return TRUE;
} }
std::vector<Monitor> WindowsIntegration::GetAllMonitors() std::vector<Monitor> WindowsIntegration::getAllMonitors()
{ {
std::vector<Monitor> monitors; std::vector<Monitor> monitors;
@ -150,7 +150,7 @@ WindowsIntegration::MonitorResult WindowsIntegration::setupWallpaperForOneScreen
return { std::nullopt, MonitorResultStatus::WorkerWindowHandleInvalidError }; return { std::nullopt, MonitorResultStatus::WorkerWindowHandleInvalidError };
} }
std::vector<Monitor> monitors = GetAllMonitors(); std::vector<Monitor> monitors = getAllMonitors();
for (const auto& monitor : monitors) { for (const auto& monitor : monitors) {
monitor.print(); monitor.print();
if (monitor.index != activeScreen) if (monitor.index != activeScreen)
@ -212,7 +212,7 @@ WindowsIntegration::MonitorResult WindowsIntegration::setupWallpaperForOneScreen
*/ */
WindowsIntegration::SpanResult WindowsIntegration::setupWallpaperForMultipleScreens(const std::vector<int>& activeScreens) WindowsIntegration::SpanResult WindowsIntegration::setupWallpaperForMultipleScreens(const std::vector<int>& activeScreens)
{ {
std::vector<Monitor> monitors = GetAllMonitors(); std::vector<Monitor> monitors = getAllMonitors();
int leftmost = INT_MAX; int leftmost = INT_MAX;
int topmost = INT_MAX; int topmost = INT_MAX;
@ -272,7 +272,7 @@ WindowsIntegration::SpanResult WindowsIntegration::setupWallpaperForMultipleScre
*/ */
WindowsIntegration::SpanResult WindowsIntegration::setupWallpaperForAllScreens() WindowsIntegration::SpanResult WindowsIntegration::setupWallpaperForAllScreens()
{ {
std::vector<Monitor> monitors = GetAllMonitors(); std::vector<Monitor> monitors = getAllMonitors();
int leftmost = INT_MAX; int leftmost = INT_MAX;
int topmost = INT_MAX; int topmost = INT_MAX;

View File

@ -7,6 +7,7 @@
// Do not change windows.h order ! // Do not change windows.h order !
#include <algorithm> #include <algorithm>
#include <format>
#include <functional> #include <functional>
#include <iostream> #include <iostream>
#include <optional> #include <optional>
@ -22,16 +23,21 @@ struct Monitor {
RECT position; // Monitor's position and size RECT position; // Monitor's position and size
SIZE size; // Monitor's width and height SIZE size; // Monitor's width and height
float scaleFactor; // Scale factor (DPI scaling as a factor, e.g., 1.5 for 150% scaling) float scaleFactor; // Scale factor (DPI scaling as a factor, e.g., 1.5 for 150% scaling)
std::string toString() const
{
return std::format(
"Monitor Info:\n"
"Monitor ID: {}\n"
"Index: {}\n"
"Position: ({}, {}, {}, {})\n"
"Size: ({}x{})\n"
"Scale Factor: {}\n",
(int64_t)monitorID, index, position.left, position.top,
position.right, position.bottom, size.cx, size.cy, scaleFactor);
}
void print() const void print() const
{ {
std::cout << "Monitor Info:" << std::endl; std::cout << toString() << std::endl;
std::cout << "Monitor ID: " << monitorID << std::endl;
std::cout << "Index: " << index << std::endl;
std::cout << "Position: (" << position.left << ", " << position.top << ", "
<< position.right << ", " << position.bottom << ")" << std::endl;
std::cout << "Size: (" << size.cx << "x" << size.cy << ")" << std::endl;
std::cout << "Scale Factor: " << scaleFactor << std::endl;
} }
}; };
@ -41,39 +47,6 @@ BOOL CALLBACK GetMonitorByHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcM
BOOL CALLBACK FindTheDesiredWnd(HWND hWnd, LPARAM lParam); BOOL CALLBACK FindTheDesiredWnd(HWND hWnd, LPARAM lParam);
BOOL WINAPI SearchForWorkerWindow(HWND hwnd, LPARAM lparam); BOOL WINAPI SearchForWorkerWindow(HWND hwnd, LPARAM lparam);
struct WinMonitorStats {
WinMonitorStats()
{
EnumDisplayMonitors(NULL, NULL, MonitorEnum, (LPARAM)this);
}
static BOOL CALLBACK MonitorEnum(HMONITOR hMon, HDC hdc, LPRECT lprcMonitor, LPARAM pData)
{
WinMonitorStats* pThis = reinterpret_cast<WinMonitorStats*>(pData);
auto scaleFactor = DEVICE_SCALE_FACTOR::DEVICE_SCALE_FACTOR_INVALID;
GetScaleFactorForMonitor(hMon, &scaleFactor);
UINT x = 0;
UINT y = 0;
GetDpiForMonitor(hMon, MONITOR_DPI_TYPE::MDT_RAW_DPI, &x, &y);
pThis->sizes.push_back({ x, y });
pThis->scaleFactor.push_back(scaleFactor);
pThis->hMonitors.push_back(hMon);
pThis->hdcMonitors.push_back(hdc);
pThis->rcMonitors.push_back(*lprcMonitor);
pThis->iMonitors.push_back(pThis->hdcMonitors.size());
return TRUE;
}
std::vector<size_t> iMonitors;
std::vector<HMONITOR> hMonitors;
std::vector<HDC> hdcMonitors;
std::vector<RECT> rcMonitors;
std::vector<DEVICE_SCALE_FACTOR> scaleFactor;
std::vector<std::pair<UINT, UINT>> sizes;
};
struct Point { struct Point {
int x = 0; int x = 0;
int y = 0; int y = 0;
@ -112,7 +85,7 @@ public:
bool searchWorkerWindowToParentTo(); bool searchWorkerWindowToParentTo();
float getScaling(const int monitorIndex) const; float getScaling(const int monitorIndex) const;
std::vector<Monitor> GetAllMonitors(); std::vector<Monitor> getAllMonitors();
int GetMonitorIndex(HMONITOR hMonitor); int GetMonitorIndex(HMONITOR hMonitor);
bool checkForFullScreenWindow(HWND windowHandle); bool checkForFullScreenWindow(HWND windowHandle);
WindowsIntegration::MonitorResult setupWallpaperForOneScreen(const int activeScreen, std::function<void(int, int)> updateWindowSize); WindowsIntegration::MonitorResult setupWallpaperForOneScreen(const int activeScreen, std::function<void(int, int)> updateWindowSize);

View File

@ -11,7 +11,7 @@ FetchContent_Populate(
FetchContent_Populate( FetchContent_Populate(
qml-plausible qml-plausible
GIT_REPOSITORY https://gitlab.com/kelteseth/qml-plausible.git GIT_REPOSITORY https://gitlab.com/kelteseth/qml-plausible.git
GIT_TAG 5069ba3bf25663ea06be8b94c398d6c61058d4d5 GIT_TAG 322d8e17cab77b496f0d7fafb19f6dcda4193ed7
# Workaround because: 1. QtCreator cannot handle QML_ELEMENT stuff when it is in bin folder # Workaround because: 1. QtCreator cannot handle QML_ELEMENT stuff when it is in bin folder
# https://bugreports.qt.io/browse/QTCREATORBUG-27083 # https://bugreports.qt.io/browse/QTCREATORBUG-27083
SOURCE_DIR ${THIRD_PARTY_PATH}/qml-plausible) SOURCE_DIR ${THIRD_PARTY_PATH}/qml-plausible)

View File

@ -46,17 +46,19 @@ def execute(
# temporary files in the build directory. # temporary files in the build directory.
clean_build_dir(build_config.build_folder) clean_build_dir(build_config.build_folder)
# Build Godot Wallpaper
# Note: This must happen before building ScreenPlay!
if platform.system() == "Windows" and build_config.build_godot == "ON":
build_godot.build_godot(str(build_config.bin_dir), build_config.build_type)
# Runs cmake configure and cmake build # Runs cmake configure and cmake build
step_time = time.time() step_time = time.time()
build_result = build(build_config, build_result) build_result = build(build_config, build_result)
build_duration = time.time() - step_time build_duration = time.time() - step_time
print(f"⏱️ build_duration: {build_duration}s") print(f"⏱️ build_duration: {build_duration}s")
# Build Godot Wallpaper
# Note: This must happen after building ScreenPlay!
if platform.system() == "Windows":
build_godot.build_godot(str(build_config.bin_dir), build_config.build_type)
# Copies all needed libraries and assets into the bin folder # Copies all needed libraries and assets into the bin folder
step_time = time.time() step_time = time.time()
package(build_config) package(build_config)
@ -181,7 +183,6 @@ def build(build_config: BuildConfig, build_result: BuildResult) -> BuildResult:
-DSCREENPLAY_STEAM={build_config.build_steam} \ -DSCREENPLAY_STEAM={build_config.build_steam} \
-DSCREENPLAY_TESTS={build_config.build_tests} \ -DSCREENPLAY_TESTS={build_config.build_tests} \
-DSCREENPLAY_DEPLOY={build_config.build_deploy} \ -DSCREENPLAY_DEPLOY={build_config.build_deploy} \
-DSCREENPLAY_GODOT={build_config.build_godot} \
-DSCREENPLAY_INSTALLER={build_config.create_installer} \ -DSCREENPLAY_INSTALLER={build_config.create_installer} \
-DSCREENPLAY_IFW_ROOT:STRING={build_config.ifw_root_path} \ -DSCREENPLAY_IFW_ROOT:STRING={build_config.ifw_root_path} \
-G "Ninja" \ -G "Ninja" \
@ -287,14 +288,6 @@ def package(build_config: BuildConfig):
print("Copy: ", file, build_config.bin_dir) print("Copy: ", file, build_config.bin_dir)
shutil.copy2(file, build_config.bin_dir) shutil.copy2(file, build_config.bin_dir)
# Use Qt OpenSSLv3
openSLL_path = Path(
f"{defines.QT_PATH}/Tools/OpenSSLv3/Win_x64/bin").resolve()
for file in openSLL_path.iterdir():
if file.suffix == ".dll" and file.is_file():
print("Copy: ", file, build_config.bin_dir)
shutil.copy2(file, build_config.bin_dir)
if not platform.system() == "Darwin": if not platform.system() == "Darwin":
file_endings = [".ninja_deps", ".ninja", ".ninja_log", ".lib", ".a", ".exp", file_endings = [".ninja_deps", ".ninja", ".ninja_log", ".lib", ".a", ".exp",
".manifest", ".cmake", ".cbp", "CMakeCache.txt"] ".manifest", ".cmake", ".cbp", "CMakeCache.txt"]
@ -365,7 +358,6 @@ if __name__ == "__main__":
help="Create a deploy version of ScreenPlay for sharing with the world. A not deploy version is for local development only!") help="Create a deploy version of ScreenPlay for sharing with the world. A not deploy version is for local development only!")
parser.add_argument('--architecture', action="store", dest="build_architecture", default="", parser.add_argument('--architecture', action="store", dest="build_architecture", default="",
help="Sets the build architecture. Used to build x86 and ARM osx versions. Currently only works with x86_64 and arm64") help="Sets the build architecture. Used to build x86 and ARM osx versions. Currently only works with x86_64 and arm64")
parser.add_argument('--build-godot', action="store", dest="build_godot", default="", help="Builds the Godot Wallpaper")
args = parser.parse_args() args = parser.parse_args()
qt_version = defines.QT_VERSION qt_version = defines.QT_VERSION
@ -409,10 +401,6 @@ if __name__ == "__main__":
if args.build_deploy: if args.build_deploy:
build_deploy = "ON" build_deploy = "ON"
build_godot = "OFF"
if args.build_godot:
build_godot = "ON"
create_installer = "OFF" create_installer = "OFF"
if args.create_installer: if args.create_installer:
create_installer = "ON" create_installer = "ON"
@ -429,7 +417,6 @@ if __name__ == "__main__":
build_config.build_steam = build_steam build_config.build_steam = build_steam
build_config.build_tests = build_tests build_config.build_tests = build_tests
build_config.build_deploy = build_deploy build_config.build_deploy = build_deploy
build_config.build_godot = build_godot
build_config.create_installer = create_installer build_config.create_installer = create_installer
build_config.build_type = build_type build_config.build_type = build_type
build_config.screenplay_version = screenplay_version build_config.screenplay_version = screenplay_version

View File

@ -67,7 +67,6 @@ if __name__ == "__main__":
build_config.build_tests = "OFF" build_config.build_tests = "OFF"
build_config.build_deploy = "ON" build_config.build_deploy = "ON"
build_config.create_installer = "OFF" build_config.create_installer = "OFF"
build_config.build_godot = "OFF"
build_config.build_type = "release" build_config.build_type = "release"
build_config.screenplay_version = screenplay_version build_config.screenplay_version = screenplay_version

View File

@ -12,7 +12,7 @@ import argparse
def main(): def main():
# Parse build folder as arugment # Parse build folder as arugment
parser = argparse.ArgumentParser(description='Build K3000Map to the bin build folder: D:/Backup/Code/Qt/build_ScreenPlay_Qt_6.6.0_MSVC_Debug/bin') parser = argparse.ArgumentParser(description='Build K3000Map to the bin build folder: D:/Backup/Code/Qt/build_ScreenPlay_Qt_6.6.1_MSVC_Debug/bin')
parser.add_argument('--build_path', dest="build_path", type=str, help='Build folder') parser.add_argument('--build_path', dest="build_path", type=str, help='Build folder')
parser.add_argument('--skip_if_exists', dest="skip_if_exists", default=False, action="store_true", help='Skips the build if the index.html file exists. This is used for faster CMake configure') parser.add_argument('--skip_if_exists', dest="skip_if_exists", default=False, action="store_true", help='Skips the build if the index.html file exists. This is used for faster CMake configure')
@ -20,7 +20,7 @@ def main():
if not args.build_path: if not args.build_path:
print("ERROR: Please specify the build folder") print("ERROR: Please specify the build folder")
print("py build_godot.py --build_path D:/Backup/Code/Qt/build_ScreenPlay_Qt_6.6.0_MSVC_Debug/bin/") print("py build_godot.py --build_path D:/Backup/Code/Qt/build_ScreenPlay_Qt_6.6.1_MSVC_Debug/bin/")
exit() exit()
# if build path exists and contains a index.html file, skip the build # if build path exists and contains a index.html file, skip the build

View File

@ -21,14 +21,15 @@ elif sys.platform == "linux":
REPO_PATH = Path(__file__, "../../").resolve() REPO_PATH = Path(__file__, "../../").resolve()
THIRDPATH_PATH = Path(REPO_PATH, "ThirdParty").resolve() THIRDPATH_PATH = Path(REPO_PATH, "ThirdParty").resolve()
QT_PATH = path = Path(REPO_PATH, "../aqt").resolve() QT_PATH = path = Path(REPO_PATH, "../aqt").resolve()
QT_VERSION = "6.6.0" QT_VERSION = "6.6.1"
QT_BIN_PATH = QT_PATH.joinpath(f"{QT_VERSION}/{QT_PLATFORM}/bin") QT_BIN_PATH = QT_PATH.joinpath(f"{QT_VERSION}/{QT_PLATFORM}/bin")
QT_TOOLS_PATH = QT_PATH.joinpath("Tools/") QT_TOOLS_PATH = QT_PATH.joinpath("Tools/")
QT_IFW_VERSION = "4.6" QT_IFW_VERSION = "4.6"
# 02.06.2023 https://gitlab.com/kelteseth/screenplay-vcpkg : # 25.11.2023 https://gitlab.com/kelteseth/screenplay-vcpkg :
VCPKG_VERSION = "f06975f46d8c7a1dad916e1e997584f77ae0c34a" VCPKG_VERSION = "cabba0d0379b78e34d0a0d37edb4c459c5a03337"
VCPKG_BASE_PACKAGES = [ VCPKG_BASE_PACKAGES = [
"curl", "curl",
"openssl",
"cpp-httplib", "cpp-httplib",
"libarchive", "libarchive",
"fmt", "fmt",
@ -37,20 +38,25 @@ VCPKG_BASE_PACKAGES = [
PYTHON_EXECUTABLE = "python" if sys.platform == "win32" else "python3" PYTHON_EXECUTABLE = "python" if sys.platform == "win32" else "python3"
FFMPEG_VERSION = "6.0" FFMPEG_VERSION = "6.0"
GODOT_VERSION = "4.2" GODOT_VERSION = "4.2"
GODOT_RELEASE_TYPE = "beta5" GODOT_RELEASE_TYPE = "rc2"
GODOT_DOWNLOAD_SERVER = "https://downloads.tuxfamily.org/godotengine" GODOT_DOWNLOAD_SERVER = "https://github.com/godotengine/godot-builds/releases/download"
if sys.platform == "win32": if sys.platform == "win32":
SCREENPLAYWALLPAPER_GODOT_EXECUTABLE = "ScreenPlayWallpaperGodot.exe" SCREENPLAYWALLPAPER_GODOT_EXECUTABLE = "ScreenPlayWallpaperGodot.exe"
GODOT_EDITOR_EXECUTABLE = f"Godot_v{GODOT_VERSION}-{GODOT_RELEASE_TYPE}_win64.exe" GODOT_EDITOR_EXECUTABLE = f"Godot_v{GODOT_VERSION}-{GODOT_RELEASE_TYPE}_win64.exe"
GODOT_EDITOR_DOWNLOAD_NAME = GODOT_EDITOR_EXECUTABLE + ".zip"
GODOT_TEMPLATES_PATH = os.path.join(os.getenv( GODOT_TEMPLATES_PATH = os.path.join(os.getenv(
'APPDATA'), f"Godot/templates/{GODOT_VERSION}.{GODOT_RELEASE_TYPE}") 'APPDATA'), f"Godot/templates/{GODOT_VERSION}.{GODOT_RELEASE_TYPE}")
elif sys.platform == "darwin": elif sys.platform == "darwin":
SCREENPLAYWALLPAPER_GODOT_EXECUTABLE = "ScreenPlayWallpaperGodot.app" SCREENPLAYWALLPAPER_GODOT_EXECUTABLE = "ScreenPlayWallpaperGodot.app"
GODOT_EDITOR_EXECUTABLE = f"Godot_v{GODOT_VERSION}-{GODOT_RELEASE_TYPE}_osx.universal" # Godot_v4.2-beta6_macos.universal.zip
GODOT_EDITOR_EXECUTABLE = "Godot.app"
GODOT_EDITOR_DOWNLOAD_NAME = f"Godot_v{GODOT_VERSION}-{GODOT_RELEASE_TYPE}_macos.universal.zip"
GODOT_TEMPLATES_PATH = "TODO" GODOT_TEMPLATES_PATH = "TODO"
elif sys.platform == "linux": elif sys.platform == "linux":
SCREENPLAYWALLPAPER_GODOT_EXECUTABLE = "ScreenPlayWallpaperGodot" SCREENPLAYWALLPAPER_GODOT_EXECUTABLE = "ScreenPlayWallpaperGodot"
GODOT_EDITOR_EXECUTABLE = f"Godot_v{GODOT_VERSION}-{GODOT_RELEASE_TYPE}_x11.64" # Godot_v4.2-beta6_linux.x86_64
GODOT_EDITOR_EXECUTABLE = f"Godot_v{GODOT_VERSION}-{GODOT_RELEASE_TYPE}_linux.x86_64"
GODOT_EDITOR_DOWNLOAD_NAME = GODOT_EDITOR_EXECUTABLE + ".zip"
# /home/eli/.local/share/godot/templates/ # /home/eli/.local/share/godot/templates/
GODOT_TEMPLATES_PATH = os.path.join( GODOT_TEMPLATES_PATH = os.path.join(
Path.home(), f".local/share/godot/templates/{GODOT_VERSION}.{GODOT_RELEASE_TYPE}") Path.home(), f".local/share/godot/templates/{GODOT_VERSION}.{GODOT_RELEASE_TYPE}")

View File

@ -0,0 +1,95 @@
#!/usr/bin/python3
# SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only
from distutils.dir_util import mkpath
import os
import subprocess
from pathlib import Path
import util
from util import run, run_and_capture_output
from sys import stdout
stdout.reconfigure(encoding='utf-8')
def listfiles(path):
files = []
ignored = ('.DS_Store',) # Ignored files
print(f"WALK: {path}")
for dirName, _, fileList in os.walk(path):
for fname in fileList:
if fname in ignored:
continue # Skip ignored files
file_path = os.path.join(dirName, fname)
if os.path.isfile(file_path) and (fname.endswith('.a')):
files.append(file_path)
if os.path.islink(file_path):
print(f"Warning: file {file_path} is a symlink!")
print("Symlink target: ", os.readlink(file_path))
return files
def is_mach_o_binary(file_path):
"""
Check if a file is a Mach-O binary using the file command.
"""
try:
result = subprocess.run(["file", file_path], capture_output=True, text=True)
return 'Mach-O' in result.stdout
except Exception as e:
print(f"Error checking file type of {file_path}: {e}")
return False
# Merges x64 and arm64 vcpkg build into universal
def run_lipo():
workspace_path = util.workspace_path()
vcpkg_installed_path = str(Path(workspace_path).joinpath("vcpkg/installed/").absolute())
arm64_dir = f"{vcpkg_installed_path}/arm64-osx"
x64_dir = f"{vcpkg_installed_path}/x64-osx"
universal_dir = f"{vcpkg_installed_path}/64-osx-universal"
# Ensure the universal directory is created and empty
run(f"rm -rf {universal_dir}", workspace_path)
# Copy the x64 build as a base for the universal build
run(f"cp -a {arm64_dir} {universal_dir}", workspace_path)
files = listfiles(str(universal_dir))
for file in files:
# Extract the relative path for file
rel_path = os.path.relpath(file, universal_dir)
# Construct the corresponding arm64 and x64 file paths
arm64_file = os.path.join(arm64_dir, rel_path)
x64_file = os.path.join(x64_dir, rel_path)
universal_file = file # file is already in universal_dir
#and is_mach_o_binary(arm64_file)
if os.path.exists(x64_file) :
run(f"lipo -create {arm64_file} {x64_file} -output {universal_file}")
print(f"Processing binary file: {universal_file}")
run(f"lipo -info {universal_file}")
else:
print(f"Skipping non-binary file: {universal_file}")
def check_fat_binary():
# Ensure the script starts from the correct directory
workspace_path = Path(util.workspace_path())
dir = 'vcpkg/installed/64-osx-universal'
universal_dir = str(workspace_path.joinpath(dir))
print(f"check_fat_binary {universal_dir}")
files = listfiles(universal_dir)
for file in files:
out = run_and_capture_output(f"lipo -info {file}")
if out.startswith('Non-fat'):
out = out.replace("\n","")
print(f"{out}")
else:
print(f"{file}")
def execute():
run_lipo()
check_fat_binary()
if __name__ == "__main__":
execute()

View File

@ -7,6 +7,7 @@ import download_ffmpeg
import defines import defines
import argparse import argparse
import util import util
import macos_make_universal
import datetime import datetime
import setup_godot import setup_godot
from sys import stdout from sys import stdout
@ -54,17 +55,15 @@ def download(aqt_path: Path, qt_platform: Path):
qt_packages = "qtwaylandcompositor " qt_packages = "qtwaylandcompositor "
os = "linux" os = "linux"
# Windows: python -m aqt list-qt windows desktop --modules 6.6.0 win64_msvc2019_64
# Linux: python3 -m aqt list-qt linux desktop --modules 6.6.0 gcc_64
qt_packages += "qt3d qtquick3d qtconnectivity qt5compat qtimageformats qtmultimedia qtshadertools qtwebchannel qtwebengine qtwebsockets qtwebview qtpositioning" qt_packages += "qt3d qtquick3d qtconnectivity qt5compat qtimageformats qtmultimedia qtshadertools qtwebchannel qtwebengine qtwebsockets qtwebview qtpositioning"
# Windows: python -m aqt list-qt windows desktop --modules 6.6.1 win64_msvc2019_64
# Linux: python3 -m aqt list-qt linux desktop --modules 6.6.1 gcc_64
print(f"Downloading: {qt_packages} to {aqt_path}") print(f"Downloading: {qt_packages} to {aqt_path}")
execute(f"{defines.PYTHON_EXECUTABLE} -m aqt install-qt -O {aqt_path} {os} desktop {defines.QT_VERSION} {qt_platform} -m {qt_packages}") execute(f"{defines.PYTHON_EXECUTABLE} -m aqt install-qt -O {aqt_path} {os} desktop {defines.QT_VERSION} {qt_platform} -m {qt_packages}")
# Tools can only be installed one at the time: # Tools can only be installed one at the time:
# see: python -m aqt list-tool windows desktop # see: python -m aqt list-tool windows desktop
tools = ["tools_ifw", "tools_qtcreator", "tools_ninja", "tools_cmake"] tools = ["tools_ifw"]
if system() == "Windows":
tools += ["tools_opensslv3_x64"]
for tool in tools: for tool in tools:
execute( execute(
f"{defines.PYTHON_EXECUTABLE} -m aqt install-tool -O {aqt_path} {os} desktop {tool}") f"{defines.PYTHON_EXECUTABLE} -m aqt install-tool -O {aqt_path} {os} desktop {tool}")
@ -107,9 +106,7 @@ def main():
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description='Build and Package ScreenPlay') description='Build and Package ScreenPlay')
parser.add_argument('--skip-aqt', action="store_true", dest="skip_aqt", parser.add_argument('--skip-aqt', action="store_true", dest="skip_aqt",
help="Downloads QtCreator and needed binaries \Windows: C:\aqt\nLinux & macOS:~/aqt/.") help="Downloads QtCreator and needed binaries Windows: C:\\aqt\\nLinux & macOS:~/aqt/.")
parser.add_argument('--setup-godot', action="store_true", dest="setup_godot",
help="Downloads Godot Editor.")
args = parser.parse_args() args = parser.parse_args()
root_path = Path(util.cd_repo_root_path()) root_path = Path(util.cd_repo_root_path())
@ -117,7 +114,7 @@ def main():
vcpkg_path = project_source_parent_path.joinpath("vcpkg").resolve() vcpkg_path = project_source_parent_path.joinpath("vcpkg").resolve()
vcpkg_packages_list = defines.VCPKG_BASE_PACKAGES vcpkg_packages_list = defines.VCPKG_BASE_PACKAGES
if system() == "Windows" and args.setup_godot: if system() != "Darwin":
if not setup_godot.execute(): if not setup_godot.execute():
raise RuntimeError("Unable to download godot") raise RuntimeError("Unable to download godot")
@ -140,7 +137,7 @@ def main():
platform_command.add("chmod +x bootstrap-vcpkg.sh", vcpkg_path) platform_command.add("chmod +x bootstrap-vcpkg.sh", vcpkg_path)
platform_command.add("./bootstrap-vcpkg.sh", vcpkg_path, False) platform_command.add("./bootstrap-vcpkg.sh", vcpkg_path, False)
platform_command.add("chmod +x vcpkg", vcpkg_path) platform_command.add("chmod +x vcpkg", vcpkg_path)
vcpkg_triplet = ["64-osx-universal"] vcpkg_triplet = ["x64-osx","arm64-osx"]
elif system() == "Linux": elif system() == "Linux":
vcpkg_command = "./vcpkg" vcpkg_command = "./vcpkg"
# vcpkg_packages_list.append("infoware[opengl]") # vcpkg_packages_list.append("infoware[opengl]")
@ -153,7 +150,7 @@ def main():
raise NotImplementedError("Unknown system: {}".format(system())) raise NotImplementedError("Unknown system: {}".format(system()))
print(f"Clone into {vcpkg_path}") print(f"Clone into {vcpkg_path}")
execute("git clone https://gitlab.com/kelteseth/screenplay-vcpkg vcpkg", execute("git clone https://github.com/microsoft/vcpkg vcpkg",
project_source_parent_path, True) project_source_parent_path, True)
execute("git fetch", vcpkg_path) execute("git fetch", vcpkg_path)
execute(f"git checkout {defines.VCPKG_VERSION}", vcpkg_path) execute(f"git checkout {defines.VCPKG_VERSION}", vcpkg_path)
@ -168,8 +165,14 @@ def main():
execute( execute(
f"{vcpkg_command} install {vcpkg_packages} --triplet {triplet} --recurse", vcpkg_path, False) f"{vcpkg_command} install {vcpkg_packages} --triplet {triplet} --recurse", vcpkg_path, False)
# Combine x64 and arm
if system() == "Darwin":
macos_make_universal.execute()
if not args.skip_aqt: if not args.skip_aqt:
setup_qt() setup_qt()
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@ -8,19 +8,22 @@ from pathlib import Path
import defines import defines
import util import util
def download_godot(version: str, exe_zip_filename: str, export_templates: str, download_destination_path: str) -> bool: def download_godot(exe_zip_filename: str, export_templates: str, download_destination_path: str) -> bool:
# https://downloads.tuxfamily.org/godotengine/4.2/beta4/Godot_v4.2-beta4_win64.exe.zip # https://github.com/godotengine/godot-builds/releases/download/4.2-beta6/Godot_v4.2-beta6_win64.exe.zip
# https://downloads.tuxfamily.org/godotengine/4.2/Godot_v4.2-beta4_win64.exe.zip subfolder = f"{defines.GODOT_VERSION}-{defines.GODOT_RELEASE_TYPE}"
download_export_templates = f"{defines.GODOT_DOWNLOAD_SERVER}/{version}/{defines.GODOT_RELEASE_TYPE}/{export_templates}" base_url = f"{defines.GODOT_DOWNLOAD_SERVER}/{subfolder}"
download_export_templates = f"{base_url}/{export_templates}"
exe_destination_filepath = os.path.join( exe_destination_filepath = os.path.join(
download_destination_path, exe_zip_filename) download_destination_path, exe_zip_filename)
export_templates_destination_path = os.path.join( export_templates_destination_path = os.path.join(
download_destination_path, export_templates) download_destination_path, export_templates)
# Godot adds ".stable" to the folder names for full releases: "AppData/Roaming/Godot/templates/3.4.stable": # Godot adds ".stable" to the folder names for full releases: "AppData/Roaming/Godot/templates/4.2.stable":
print(f"Downloading Godot from {defines.GODOT_DOWNLOAD_SERVER}/") download_editor = f"{base_url}/{exe_zip_filename}"
download_link = f"{defines.GODOT_DOWNLOAD_SERVER}/{version}/{defines.GODOT_RELEASE_TYPE}/{exe_zip_filename}" print(f"⬇️ Downloading Godot editor {download_editor}")
util.download(download_link, exe_destination_filepath, False) util.download(download_editor, exe_destination_filepath, False)
print(f"⬇️ Downloading Godot export templates {download_export_templates}")
util.download(download_export_templates, util.download(download_export_templates,
export_templates_destination_path, False) export_templates_destination_path, False)
@ -28,20 +31,20 @@ def download_godot(version: str, exe_zip_filename: str, export_templates: str, d
def unzip_godot(exe_zip_filepath: str, export_templates_filepath: str, destination_path: str) -> bool: def unzip_godot(exe_zip_filepath: str, export_templates_filepath: str, destination_path: str) -> bool:
print("Unzip Godot") print("🪛 Unzip Godot")
util.unzip(exe_zip_filepath, destination_path) util.unzip(exe_zip_filepath, destination_path)
# The export templates contain a templates subfolder in which the content is. This is bad because it clashes # The export templates contain a templates subfolder in which the content is. This is bad because it clashes
# with the folder structure where the version comes after: AppData\Roaming\Godot\templates\3.3.4.stable # with the folder structure where the version comes after: /home/eli/.local/share/godot/export_templates/
# Rename: AppData\Roaming\Godot\templates\templates # Rename: AppData\Roaming\Godot\export_templates\templates
# to : AppData\Roaming\Godot\templates\3.4.stable # to : AppData\Roaming\Godot\export_templates\3.4.stable
godot_templates_dir = "" godot_templates_dir = ""
if sys.platform == "win32": if sys.platform == "win32":
godot_templates_dir = os.path.join( godot_templates_dir = os.path.join(
os.getenv('APPDATA'), "Godot/templates/") os.getenv('APPDATA'), "Godot/export_templates")
elif sys.platform == "linux": elif sys.platform == "linux":
godot_templates_dir = os.path.join( godot_templates_dir = os.path.join(
str(Path.home()), ".local/share/godot/templates/") str(Path.home()), ".local/share/godot/export_templates")
os.makedirs(godot_templates_dir, exist_ok=True) os.makedirs(godot_templates_dir, exist_ok=True)
export_templates_destination_version = f"{godot_templates_dir}/{defines.GODOT_VERSION}.{defines.GODOT_RELEASE_TYPE}" export_templates_destination_version = f"{godot_templates_dir}/{defines.GODOT_VERSION}.{defines.GODOT_RELEASE_TYPE}"
@ -54,14 +57,14 @@ def unzip_godot(exe_zip_filepath: str, export_templates_filepath: str, destinati
os.rename(os.path.join(godot_templates_dir, "templates"), os.rename(os.path.join(godot_templates_dir, "templates"),
export_templates_destination_version) export_templates_destination_version)
print(f"Remove {exe_zip_filepath}") print(f"🚮 Remove {exe_zip_filepath}")
try: try:
os.remove(exe_zip_filepath) os.remove(exe_zip_filepath)
except OSError as error: except OSError as error:
print(f"Error deleting file: {error}") print(f"Error deleting file: {error}")
return False return False
print(f"Remove {export_templates_filepath}") print(f"🚮 Remove {export_templates_filepath}")
try: try:
os.remove(export_templates_filepath) os.remove(export_templates_filepath)
except OSError as error: except OSError as error:
@ -72,22 +75,22 @@ def unzip_godot(exe_zip_filepath: str, export_templates_filepath: str, destinati
def setup_godot() -> bool: def setup_godot() -> bool:
print(f"Set up GODOT version {defines.GODOT_VERSION} {defines.GODOT_RELEASE_TYPE}") print(f"🚀 Set up GODOT version {defines.GODOT_VERSION} {defines.GODOT_RELEASE_TYPE}")
destination_path = os.path.join(defines.THIRDPATH_PATH, "Godot") destination_path = os.path.join(defines.THIRDPATH_PATH, "Godot")
export_templates = f"Godot_v{defines.GODOT_VERSION}-{defines.GODOT_RELEASE_TYPE}_export_templates.tpz" export_templates = f"Godot_v{defines.GODOT_VERSION}-{defines.GODOT_RELEASE_TYPE}_export_templates.tpz"
export_templates_filepath = os.path.join( export_templates_filepath = os.path.join(
destination_path, export_templates) destination_path, export_templates)
exe_zip_filename = defines.GODOT_EDITOR_EXECUTABLE + '.zip' exe_zip_filepath = os.path.join(destination_path, defines.GODOT_EDITOR_DOWNLOAD_NAME)
exe_zip_filepath = os.path.join(destination_path, exe_zip_filename) download_godot( defines.GODOT_EDITOR_DOWNLOAD_NAME,
download_godot(defines.GODOT_VERSION, exe_zip_filename,
export_templates, destination_path) export_templates, destination_path)
if not unzip_godot(exe_zip_filepath, export_templates_filepath, destination_path): if not unzip_godot(exe_zip_filepath, export_templates_filepath, destination_path):
return False return False
# Linux needs to change file permission to be able to run godot # Linux needs to change file permission to be able to run godot
if sys.platform == "linux": if sys.platform == "linux":
execute(f"chmod +x {defines.GODOT_EDITOR_EXECUTABLE}", command = f"chmod +x {defines.GODOT_EDITOR_EXECUTABLE}"
destination_path, False) print(f"Make editor executable: {command} at {destination_path}")
util.run(command,destination_path)
return True return True