mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-01-04 10:40:09 -06:00
Merge branch 'master' into thesis/2022/software-integration
This commit is contained in:
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -6,7 +6,7 @@
|
||||
*.asset linguist-language=Lua
|
||||
# We have some SPICE frame kernels that get misclassified as code
|
||||
*.tf -linguist-detectable
|
||||
# We don't want to index the GDAL csv and xml files
|
||||
# We do not want to index the GDAL csv and xml files
|
||||
modules/globebrowsing/gdal_data/* linguist-vendored
|
||||
# No need to index any external files
|
||||
*/ext/* linguist-vendored
|
||||
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -1,8 +1,5 @@
|
||||
# Build and editor thing
|
||||
/build/
|
||||
/build-ninja/
|
||||
/build-xcode/
|
||||
/build-make/
|
||||
/build*/
|
||||
*~
|
||||
*.dir
|
||||
*.idea/
|
||||
@@ -28,6 +25,7 @@ Thumbs.db
|
||||
/cache/
|
||||
/cache-*/
|
||||
/cache_gdal/
|
||||
/mrf_cache/
|
||||
/documentation/
|
||||
/logs/
|
||||
/screenshots/
|
||||
@@ -42,3 +40,5 @@ COMMIT.md
|
||||
*_codegen.cpp
|
||||
# SkyBrowser Module downloaded data
|
||||
/modules/skybrowser/wwtimagedata
|
||||
doc
|
||||
config/schema/sgct.schema.json
|
||||
|
||||
8
.gitmodules
vendored
8
.gitmodules
vendored
@@ -9,7 +9,7 @@
|
||||
url = https://github.com/OpenSpace/Spice.git
|
||||
[submodule "modules/touch/ext/libTUIO11"]
|
||||
path = modules/touch/ext/libTUIO11
|
||||
url = https://github.com/mkalten/TUIO11_CPP
|
||||
url = https://github.com/OpenSpace/TUIO11_CPP.git
|
||||
[submodule "apps/OpenSpace-MinVR/ext/minvr"]
|
||||
path = apps/OpenSpace-MinVR/ext/minvr
|
||||
url = https://github.com/OpenSpace/minvr
|
||||
@@ -32,3 +32,9 @@
|
||||
[submodule "support/coding/codegen"]
|
||||
path = support/coding/codegen
|
||||
url = https://github.com/OpenSpace/codegen
|
||||
[submodule "modules/globebrowsing/ext/geos"]
|
||||
path = modules/globebrowsing/ext/geos
|
||||
url = https://github.com/OpenSpace/geos.git
|
||||
[submodule "documentation"]
|
||||
path = documentation
|
||||
url = https://github.com/OpenSpace/OpenSpace-Documentation-Dist.git
|
||||
|
||||
73
CITATION.cff
Normal file
73
CITATION.cff
Normal file
@@ -0,0 +1,73 @@
|
||||
cff-version: 1.2.0
|
||||
message: "If you use this software, please cite it as below."
|
||||
authors:
|
||||
- family-names: "Bock"
|
||||
given-names: "Alexander"
|
||||
orcid: "https://orcid.org/0000-0002-2849-6146"
|
||||
- family-names: "Axelsson"
|
||||
given-names: "Emil"
|
||||
- family-names: "Costa"
|
||||
given-names: "Jonathas"
|
||||
orcid: "https://orcid.org/0000-0002-5008-5685"
|
||||
- family-names: "Payne"
|
||||
given-names: "Gene"
|
||||
orcid: "https://orcid.org/0000-0001-8022-4781"
|
||||
- family-names: "Acinapura"
|
||||
given-names: "Micah"
|
||||
- family-names: "Trakinski"
|
||||
given-names: "Vivian"
|
||||
- family-names: "Emmart"
|
||||
given-names: "Carter"
|
||||
- family-names: "Silva"
|
||||
given-names: "Claudio"
|
||||
orcid: "https://orcid.org/0000-0003-2452-2295"
|
||||
- family-names: "Hansen"
|
||||
given-names: "Charles"
|
||||
orcid: "https://orcid.org/0000-0002-8480-2152"
|
||||
- family-names: "Ynnerman"
|
||||
given-names: "Anders"
|
||||
orcid: "https://orcid.org/0000-0002-9466-9826"
|
||||
title: "OpenSpace"
|
||||
version: 0.18.2
|
||||
doi: 10.1109/TVCG.2019.2934259
|
||||
date-released: 2022-12-24
|
||||
url: "https://github.com/OpenSpace/OpenSpace"
|
||||
preferred-citation:
|
||||
scope: "If you use this software, please cite it as below"
|
||||
type: article
|
||||
authors:
|
||||
- family-names: "Bock"
|
||||
given-names: "Alexander"
|
||||
orcid: "https://orcid.org/0000-0002-2849-6146"
|
||||
- family-names: "Axelsson"
|
||||
given-names: "Emil"
|
||||
- family-names: "Costa"
|
||||
given-names: "Jonathas"
|
||||
orcid: "https://orcid.org/0000-0002-5008-5685"
|
||||
- family-names: "Payne"
|
||||
given-names: "Gene"
|
||||
orcid: "https://orcid.org/0000-0001-8022-4781"
|
||||
- family-names: "Acinapura"
|
||||
given-names: "Micah"
|
||||
- family-names: "Trakinski"
|
||||
given-names: "Vivian"
|
||||
- family-names: "Emmart"
|
||||
given-names: "Carter"
|
||||
- family-names: "Silva"
|
||||
given-names: "Claudio"
|
||||
orcid: "https://orcid.org/0000-0003-2452-2295"
|
||||
- family-names: "Hansen"
|
||||
given-names: "Charles"
|
||||
orcid: "https://orcid.org/0000-0002-8480-2152"
|
||||
- family-names: "Ynnerman"
|
||||
given-names: "Anders"
|
||||
orcid: "https://orcid.org/0000-0002-9466-9826"
|
||||
doi: 10.1109/TVCG.2019.2934259
|
||||
journal: "IEEE Transactions on Visualization and Computer Graphics"
|
||||
month: 1
|
||||
start: 633
|
||||
end: 642
|
||||
title: "OpenSpace: A System for Astrographics"
|
||||
issue: 1
|
||||
volume: 26
|
||||
year: 2020
|
||||
111
CMakeLists.txt
111
CMakeLists.txt
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# OpenSpace #
|
||||
# #
|
||||
# Copyright (c) 2014-2022 #
|
||||
# Copyright (c) 2014-2023 #
|
||||
# #
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of this #
|
||||
# software and associated documentation files (the "Software"), to deal in the Software #
|
||||
@@ -22,28 +22,22 @@
|
||||
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #
|
||||
##########################################################################################
|
||||
|
||||
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
|
||||
cmake_minimum_required(VERSION 3.25 FATAL_ERROR)
|
||||
cmake_policy(VERSION 3.25)
|
||||
|
||||
project(OpenSpace)
|
||||
|
||||
set(OPENSPACE_VERSION_MAJOR 0)
|
||||
set(OPENSPACE_VERSION_MINOR 18)
|
||||
set(OPENSPACE_VERSION_MINOR 19)
|
||||
set(OPENSPACE_VERSION_PATCH 0)
|
||||
set(OPENSPACE_VERSION_STRING "Beta-11")
|
||||
set(OPENSPACE_VERSION_STRING "<dev>")
|
||||
|
||||
set(OPENSPACE_BASE_DIR "${PROJECT_SOURCE_DIR}")
|
||||
set(OPENSPACE_CMAKE_EXT_DIR "${OPENSPACE_BASE_DIR}/support/cmake")
|
||||
set(GHOUL_BASE_DIR "${OPENSPACE_BASE_DIR}/ext/ghoul")
|
||||
|
||||
include(${OPENSPACE_CMAKE_EXT_DIR}/module_common.cmake)
|
||||
include(${OPENSPACE_CMAKE_EXT_DIR}/global_variables.cmake)
|
||||
include(${GHOUL_BASE_DIR}/support/cmake/copy_shared_libraries.cmake)
|
||||
include(${GHOUL_BASE_DIR}/support/cmake/handle_external_library.cmake)
|
||||
include(${GHOUL_BASE_DIR}/support/cmake/message_macros.cmake)
|
||||
include(${PROJECT_SOURCE_DIR}/support/cmake/module_common.cmake)
|
||||
include(${PROJECT_SOURCE_DIR}/ext/ghoul/support/cmake/message_macros.cmake)
|
||||
|
||||
begin_header("Configuring OpenSpace project")
|
||||
|
||||
# Bail out if the user tries to generate a 32 bit project.
|
||||
# Bail out if the user tries to generate a 32 bit project
|
||||
if (NOT ${CMAKE_SIZEOF_VOID_P} EQUAL 8)
|
||||
message(FATAL_ERROR "OpenSpace can only be generated for 64 bit architectures.")
|
||||
endif ()
|
||||
@@ -51,9 +45,7 @@ endif ()
|
||||
##########################################################################################
|
||||
# Cleanup project #
|
||||
##########################################################################################
|
||||
set(OPENSPACE_APPS_DIR "${OPENSPACE_BASE_DIR}/apps")
|
||||
|
||||
if (NOT EXISTS "${OPENSPACE_BASE_DIR}/ext/ghoul/CMakeLists.txt")
|
||||
if (NOT EXISTS "${PROJECT_SOURCE_DIR}/ext/ghoul/CMakeLists.txt")
|
||||
message(FATAL_ERROR "Git submodules are missing. Please run "
|
||||
"git submodule update --init --recursive to download the missing dependencies."
|
||||
)
|
||||
@@ -68,11 +60,13 @@ mark_as_advanced(CMAKE_BACKWARDS_COMPATIBILITY CMAKE_BUILD_TYPE CMAKE_DEBUG_POST
|
||||
)
|
||||
|
||||
# Set build output directories
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${OPENSPACE_CMAKE_EXT_DIR})
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${OPENSPACE_BASE_DIR}/bin)
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/support/cmake)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin)
|
||||
|
||||
# "OpenSpace Helper" is not a valid CMake target name under OLD
|
||||
cmake_policy(SET CMP0037 NEW)
|
||||
if (MSVC)
|
||||
# Force all builds to be multi-threaded and increase number of sections in obj files
|
||||
add_definitions(/MP /bigobj)
|
||||
endif ()
|
||||
|
||||
##########################################################################################
|
||||
# Main #
|
||||
@@ -106,9 +100,9 @@ else ()
|
||||
set(OPENSPACE_GIT_STATUS "")
|
||||
endif ()
|
||||
|
||||
option(OPENSPACE_WARNINGS_AS_ERRORS "Treat warnings as errors" OFF)
|
||||
|
||||
if (MSVC)
|
||||
option(OPENSPACE_BREAK_ON_FLOATING_POINT_EXCEPTION "Raise exceptions when encountering Inf's or Nan's in floating point numbers" OFF)
|
||||
|
||||
option(OPENSPACE_OPTIMIZATION_ENABLE_AVX "Enable AVX instruction set for compilation" OFF)
|
||||
option(OPENSPACE_OPTIMIZATION_ENABLE_AVX2 "Enable AVX2 instruction set for compilation" OFF)
|
||||
option(OPENSPACE_OPTIMIZATION_ENABLE_AVX512 "Enable AVX2 instruction set for compilation" OFF)
|
||||
@@ -132,37 +126,30 @@ if (MSVC)
|
||||
set(GHOUL_OPTIMIZATION_ENABLE_OTHER_OPTIMIZATIONS ${OPENSPACE_OPTIMIZATION_ENABLE_OTHER_OPTIMIZATIONS} CACHE BOOL "" FORCE)
|
||||
endif ()
|
||||
|
||||
if (UNIX)
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -stdlib=libc++")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++ -lc++ -lc++abi")
|
||||
else ()
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
#Can set to "RelWithDebInfo" or "Debug" also, but problems occur if this is blank by default
|
||||
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Default build type" FORCE)
|
||||
endif()
|
||||
if (NOT DEFINED CMAKE_CXX_FLAGS OR CMAKE_CXX_FLAGS MATCHES "")
|
||||
set(CMAKE_CXX_FLAGS " ")
|
||||
endif()
|
||||
STRING(FIND ${CMAKE_CXX_FLAGS} "GLM_ENABLE_EXPERIMENTAL" GLM_FLAG_POS)
|
||||
if (${GLM_FLAG_POS} EQUAL -1)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGLM_ENABLE_EXPERIMENTAL" CACHE STRING "" FORCE)
|
||||
endif()
|
||||
set(OpenGL_GL_PREFERENCE "GLVND" CACHE STRING "OpenGL Preference setting necessary for linux" FORCE)
|
||||
#Fix for gcc tolerating space in target name
|
||||
if (NOT DEFINED CMAKE_C_FLAGS OR CMAKE_C_FLAGS MATCHES "")
|
||||
set(CMAKE_C_FLAGS " ")
|
||||
endif()
|
||||
STRING(FIND ${CMAKE_C_FLAGS} "_GNU_SOURCE" GNUSOURCE_FLAG_POS)
|
||||
if (${GNUSOURCE_FLAG_POS} EQUAL -1)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_GNU_SOURCE" CACHE STRING "" FORCE)
|
||||
endif()
|
||||
if (UNIX AND NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
if (NOT CMAKE_BUILD_TYPE)
|
||||
# Can set to "RelWithDebInfo" or "Debug" also, but problems occur if this is blank by default
|
||||
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Default build type" FORCE)
|
||||
endif ()
|
||||
if (NOT DEFINED CMAKE_CXX_FLAGS OR CMAKE_CXX_FLAGS MATCHES "")
|
||||
set(CMAKE_CXX_FLAGS " ")
|
||||
endif ()
|
||||
STRING(FIND ${CMAKE_CXX_FLAGS} "GLM_ENABLE_EXPERIMENTAL" GLM_FLAG_POS)
|
||||
if (${GLM_FLAG_POS} EQUAL -1)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGLM_ENABLE_EXPERIMENTAL" CACHE STRING "" FORCE)
|
||||
endif ()
|
||||
set(OpenGL_GL_PREFERENCE "GLVND" CACHE STRING "OpenGL Preference setting necessary for linux" FORCE)
|
||||
# Fix for GCC tolerating space in target name
|
||||
if (NOT DEFINED CMAKE_C_FLAGS OR CMAKE_C_FLAGS MATCHES "")
|
||||
set(CMAKE_C_FLAGS " ")
|
||||
endif ()
|
||||
STRING(FIND ${CMAKE_C_FLAGS} "_GNU_SOURCE" GNUSOURCE_FLAG_POS)
|
||||
if (${GNUSOURCE_FLAG_POS} EQUAL -1)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_GNU_SOURCE" CACHE STRING "" FORCE)
|
||||
endif ()
|
||||
set(ASSIMP_BUILD_MINIZIP ON CACHE BOOL "Set to have assimp build minizip" FORCE)
|
||||
endif ()
|
||||
|
||||
add_subdirectory(ext)
|
||||
|
||||
add_subdirectory(src)
|
||||
|
||||
add_subdirectory(support/coding/codegen)
|
||||
@@ -176,12 +163,13 @@ add_custom_target(
|
||||
add_dependencies(run_codegen codegen)
|
||||
add_custom_command(
|
||||
OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/__codegen.h"
|
||||
COMMAND codegen ARGS "${OPENSPACE_BASE_DIR}/modules" "${OPENSPACE_BASE_DIR}/src"
|
||||
COMMAND codegen ARGS "modules" "src"
|
||||
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
|
||||
VERBATIM
|
||||
)
|
||||
set_folder_location(codegen-lib "support")
|
||||
set_folder_location(codegen "support")
|
||||
set_folder_location(run_codegen "support")
|
||||
set_target_properties(codegen-lib PROPERTIES FOLDER "support")
|
||||
set_target_properties(codegen PROPERTIES FOLDER "support")
|
||||
set_target_properties(run_codegen PROPERTIES FOLDER "support")
|
||||
|
||||
|
||||
# Qt
|
||||
@@ -197,6 +185,7 @@ if (APPLE)
|
||||
"~/Qt/5.11/clang_64/lib/cmake"
|
||||
"~/Qt/5.12/clang_64/lib/cmake"
|
||||
"~/Qt/5.15.1/clang_64/lib/cmake"
|
||||
"~/Qt/6.2.3/macos/lib/cmake"
|
||||
)
|
||||
endif ()
|
||||
|
||||
@@ -217,24 +206,24 @@ end_header("End: Configuring Modules")
|
||||
|
||||
|
||||
add_subdirectory(support/coding/codegen/tests)
|
||||
set_folder_location(run_test_codegen "Unit Tests/support")
|
||||
set_folder_location(codegentest "Unit Tests")
|
||||
set_target_properties(run_test_codegen PROPERTIES FOLDER "Unit Tests/support")
|
||||
set_target_properties(codegentest PROPERTIES FOLDER "Unit Tests")
|
||||
|
||||
|
||||
begin_header("Configuring Applications")
|
||||
add_subdirectory("${OPENSPACE_APPS_DIR}")
|
||||
add_subdirectory(apps)
|
||||
end_header("End: Configuring Applications")
|
||||
|
||||
|
||||
if (MSVC AND TARGET OpenSpace)
|
||||
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT OpenSpace)
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
|
||||
option(OPENSPACE_HAVE_TESTS "Activate the OpenSpace unit tests" ON)
|
||||
if (OPENSPACE_HAVE_TESTS)
|
||||
begin_header("Generating OpenSpace unit test")
|
||||
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/tests")
|
||||
add_subdirectory(tests)
|
||||
end_header()
|
||||
endif (OPENSPACE_HAVE_TESTS)
|
||||
|
||||
@@ -249,7 +238,7 @@ if (OPENSPACE_MODULE_WEBBROWSER AND CEF_ROOT)
|
||||
set(PROJECT_ARCH "x86_64")
|
||||
|
||||
if (WIN32)
|
||||
set(RESOURCE_FILE ${OPENSPACE_APPS_DIR}/OpenSpace/openspace.rc)
|
||||
set(RESOURCE_FILE openspace.rc)
|
||||
endif ()
|
||||
|
||||
# Add the CEF binary distribution's cmake/ directory to the module path and
|
||||
@@ -265,6 +254,6 @@ endif ()
|
||||
##########################################################################################
|
||||
|
||||
# Manage the CPack packaging
|
||||
include(${OPENSPACE_CMAKE_EXT_DIR}/packaging.cmake)
|
||||
include(${PROJECT_SOURCE_DIR}/support/cmake/packaging.cmake)
|
||||
|
||||
end_header("End: Configuring OpenSpace project")
|
||||
|
||||
@@ -27,7 +27,7 @@ Project maintainers have the right and responsibility to remove, edit, or reject
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at alexander.bock@me.com or vivian@amnh.org. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at alex@openspaceproject.com or vivian@amnh.org. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ Jonas Strandstedt
|
||||
Michal Marcinkowski
|
||||
Joakim Kilby
|
||||
Lovisa Hassler
|
||||
Mikael Petterson
|
||||
Mikael Petterson
|
||||
Erik Sundén
|
||||
Stefan Lindblad
|
||||
Corrie Roe
|
||||
|
||||
26
Jenkinsfile
vendored
26
Jenkinsfile
vendored
@@ -16,7 +16,7 @@ if (env.CHANGE_BRANCH) {
|
||||
def readDir() {
|
||||
def dirsl = [];
|
||||
new File("${workspace}").eachDir() {
|
||||
dirs -> println dirs.getName()
|
||||
dirs -> println dirs.getName()
|
||||
if (!dirs.getName().startsWith('.')) {
|
||||
dirsl.add(dirs.getName());
|
||||
}
|
||||
@@ -27,7 +27,7 @@ def readDir() {
|
||||
def moduleCMakeFlags() {
|
||||
def modules = [];
|
||||
// using new File doesn't work as it is not allowed in the sandbox
|
||||
|
||||
|
||||
if (isUnix()) {
|
||||
modules = sh(returnStdout: true, script: 'ls -d modules/*').trim().split('\n');
|
||||
};
|
||||
@@ -61,14 +61,14 @@ parallel tools: {
|
||||
recordIssues(
|
||||
id: 'tools-cppcheck',
|
||||
tool: cppCheck(pattern: 'build/cppcheck.xml')
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
cleanWs()
|
||||
} // node('tools')
|
||||
},
|
||||
linux_gcc_make: {
|
||||
if (env.USE_BUILD_OS_LINUX == 'true') {
|
||||
node('linux' && 'gcc') {
|
||||
node('linux-gcc') {
|
||||
stage('linux-gcc-make/scm') {
|
||||
deleteDir();
|
||||
gitHelper.checkoutGit(url, branch);
|
||||
@@ -101,7 +101,7 @@ linux_gcc_make: {
|
||||
testHelper.runUnitTests('bin/GhoulTest');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
stage('linux-gcc-make/test-openspace') {
|
||||
timeout(time: 2, unit: 'MINUTES') {
|
||||
testHelper.runUnitTests('bin/OpenSpaceTest');
|
||||
@@ -114,7 +114,7 @@ linux_gcc_make: {
|
||||
},
|
||||
linux_gcc_ninja: {
|
||||
if (env.USE_BUILD_OS_LINUX == 'true') {
|
||||
node('linux' && 'gcc') {
|
||||
node('linux-gcc') {
|
||||
stage('linux-gcc-ninja/scm') {
|
||||
deleteDir();
|
||||
gitHelper.checkoutGit(url, branch);
|
||||
@@ -158,7 +158,7 @@ linux_gcc_ninja: {
|
||||
},
|
||||
linux_clang_make: {
|
||||
if (env.USE_BUILD_OS_LINUX == 'true') {
|
||||
node('linux' && 'clang') {
|
||||
node('linux-clang') {
|
||||
stage('linux-clang-make/scm') {
|
||||
deleteDir()
|
||||
gitHelper.checkoutGit(url, branch);
|
||||
@@ -203,7 +203,7 @@ linux_clang_make: {
|
||||
},
|
||||
linux_clang_ninja: {
|
||||
if (env.USE_BUILD_OS_LINUX == 'true') {
|
||||
node('linux' && 'clang') {
|
||||
node('linux-clang') {
|
||||
stage('linux-clang-ninja/scm') {
|
||||
deleteDir()
|
||||
gitHelper.checkoutGit(url, branch);
|
||||
@@ -264,7 +264,7 @@ windows_msvc: {
|
||||
testHelper.runUnitTests('bin\\Debug\\codegentest');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
stage('windows-msvc/test-sgct') {
|
||||
timeout(time: 2, unit: 'MINUTES') {
|
||||
testHelper.runUnitTests('bin\\Debug\\SGCTTest');
|
||||
@@ -282,7 +282,7 @@ windows_msvc: {
|
||||
testHelper.runUnitTests('bin\\Debug\\OpenSpaceTest');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cleanWs()
|
||||
} // node('windows')
|
||||
}
|
||||
@@ -343,7 +343,7 @@ macos_make: {
|
||||
testHelper.runUnitTests('bin/Debug/OpenSpaceTest');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cleanWs()
|
||||
} // node('macos')
|
||||
}
|
||||
@@ -384,7 +384,7 @@ macos_xcode: {
|
||||
testHelper.runUnitTests('bin/Debug/OpenSpaceTest');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cleanWs()
|
||||
} // node('macos')
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2014-2022
|
||||
Copyright (c) 2014-2023
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||
software and associated documentation files (the "Software"), to deal in the Software
|
||||
@@ -15,4 +15,4 @@ INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||

|
||||
|
||||
# Background
|
||||
OpenSpace started as a collaboration between Sweden's [Linköping University](https://scivis.github.io) (LiU) and the [American Museum of Natural History](https://www.amnh.org) (AMNH). Development of the software began several years ago through a close collaboration with NASA Goddard's [Community Coordinated Modeling Center](https://ccmc.gsfc.nasa.gov) (CCMC) to model space weather forecasting and continued with visualizations of NASA's New Horizons mission to Pluto and ESA's Rosetta mission to 67P/Churyumov–Gerasimenko. This promising set of preliminary work provided a foundation for continued funding from NASA, the Swedish eScience Research Centre, and the Knut and Alice Wallenberg foundation, which has extended the collaboration to include the University of Utah's [Scientific Computing and Imaging](https://www.sci.utah.edu) (SCI) Institute, [New York University](https://www.nyu.edu)'s Tandon School of Engineering, multiple informal science institutions across the world, and multiple, international vendors.
|
||||
OpenSpace started as a collaboration between Sweden's [Linköping University](https://scivis.github.io) (LiU) and the [American Museum of Natural History](https://www.amnh.org) (AMNH). Development of the software began several years ago through a close collaboration with NASA Goddard's [Community Coordinated Modeling Center](https://ccmc.gsfc.nasa.gov) (CCMC) to model space weather forecasting and continued with visualizations of NASA's New Horizons mission to Pluto and ESA's Rosetta mission to 67P/Churyumov-Gerasimenko. This promising set of preliminary work provided a foundation for continued funding from NASA, the Swedish eScience Research Centre, and the Knut and Alice Wallenberg foundation, which has extended the collaboration to include the University of Utah's [Scientific Computing and Imaging](https://www.sci.utah.edu) (SCI) Institute, [New York University](https://www.nyu.edu)'s Tandon School of Engineering, multiple informal science institutions across the world, and multiple, international vendors.
|
||||
|
||||

|
||||
|
||||
@@ -37,11 +37,14 @@ OpenSpace requires at least support for [OpenGL](https://www.opengl.org/) versio
|
||||
This repository contains the source code and example profiles for OpenSpace, but does not contain any data. To build and install the application, please check out the [GitHub Wiki](https://github.com/OpenSpace/OpenSpace/wiki). Here, you will find two pages, a [build instruction](https://github.com/OpenSpace/OpenSpace/wiki/Compiling) for all operating systems and then additional instructions for [Windows](https://github.com/OpenSpace/OpenSpace/wiki/Compiling-Windows), [Linux (Ubuntu)](https://github.com/OpenSpace/OpenSpace/wiki/Compiling-Ubuntu), and [MacOS](https://github.com/OpenSpace/OpenSpace/wiki/Compiling-MacOS). Please note that the Apple Silicon series of chips do not support OpenGL natively and Metal 2 does not support `double` precision accuracy (see [here](https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf) Section 2.1), therefore only the Intel processors for MacOS are supported and maintained.
|
||||
|
||||
Requirements for compiling are:
|
||||
- CMake version 3.10 or above
|
||||
- C++ compiler supporting C++17 (MSVC 16.10, GCC9, Clang10)
|
||||
- CMake version 3.25 or above
|
||||
- C++ compiler supporting C++20 (MSVC 19.31, GCC11, Clang14, AppleClang 13.1.6)
|
||||
- [Boost](http://www.boost.org/)
|
||||
- [Qt](http://www.qt.io/download)
|
||||
|
||||
Feel free to create issues for missing features, bug reports, or compile problems or contact us via [email](mailto:openspace@amnh.org?subject=OpenSpace:). Regarding any issues, you are very welcome on our [Slack support channel](https://openspacesupport.slack.com) to which you can freely [sign-up](https://join.slack.com/t/openspacesupport/shared_invite/zt-37niq6y9-T0JaCIk4UoFLI4VF5U9Vsw).
|
||||
|
||||

|
||||
|
||||
# License
|
||||
The contents of this repository is under an [MIT license](https://github.com/OpenSpace/OpenSpace/blob/master/LICENSE.md).
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# OpenSpace #
|
||||
# #
|
||||
# Copyright (c) 2014-2022 #
|
||||
# Copyright (c) 2014-2023 #
|
||||
# #
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of this #
|
||||
# software and associated documentation files (the "Software"), to deal in the Software #
|
||||
|
||||
@@ -22,9 +22,9 @@
|
||||
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #
|
||||
##########################################################################################
|
||||
|
||||
include(${GHOUL_BASE_DIR}/support/cmake/copy_shared_libraries.cmake)
|
||||
include(${OPENSPACE_CMAKE_EXT_DIR}/application_definition.cmake)
|
||||
include(${OPENSPACE_CMAKE_EXT_DIR}/global_variables.cmake)
|
||||
include(${PROJECT_SOURCE_DIR}/ext/ghoul/support/cmake/copy_shared_libraries.cmake)
|
||||
include(${PROJECT_SOURCE_DIR}/support/cmake/application_definition.cmake)
|
||||
include(${PROJECT_SOURCE_DIR}/support/cmake/global_variables.cmake)
|
||||
|
||||
set(MACOSX_BUNDLE_ICON_FILE openspace.icns)
|
||||
|
||||
@@ -50,14 +50,14 @@ target_include_directories(OpenSpace-MinVR PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/ex
|
||||
target_include_directories(OpenSpace-MinVR PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/ext/minvr/external/GLFW/src/include)
|
||||
|
||||
|
||||
target_link_libraries(OpenSpace-MinVR openspace-core MinVR)
|
||||
target_link_libraries(OpenSpace-MinVR PUBLIC openspace-core MinVR)
|
||||
|
||||
# Web Browser and Web gui
|
||||
# Why not put these in the module's path? Because they do not have access to the
|
||||
# target as of July 2017, which is needed.
|
||||
if (OPENSPACE_MODULE_WEBBROWSER AND CEF_ROOT)
|
||||
if (WIN32)
|
||||
set(RESOURCE_FILE ${OPENSPACE_APPS_DIR}/OpenSpace-MinVR/openspace.rc)
|
||||
set(RESOURCE_FILE openspace.rc)
|
||||
endif ()
|
||||
|
||||
# Add the CEF binary distribution's cmake/ directory to the module path and
|
||||
@@ -71,16 +71,7 @@ elseif (OPENSPACE_MODULE_WEBBROWSER)
|
||||
message(WARNING "Web configured to be included, but no CEF_ROOT was found, please try configuring CMake again.")
|
||||
endif ()
|
||||
|
||||
if (OPENSPACE_MODULE_WEBGUI AND WEBGUI_MODULE_PATH)
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${WEBGUI_MODULE_PATH}/cmake")
|
||||
include(webgui_helpers)
|
||||
build_webgui_source(OpenSpace-MinVR)
|
||||
elseif(OPENSPACE_MODULE_WEBGUI)
|
||||
message(WARNING "WebGui is configured to be included, but the web source could not be found. Try configuring CMake again.")
|
||||
endif()
|
||||
# End Web Browser and Web gui
|
||||
|
||||
if (MSVC)
|
||||
# This library is used for being able to output the callstack if an exception escapes
|
||||
target_link_libraries(OpenSpace-MinVR Dbghelp.lib)
|
||||
endif()
|
||||
target_link_libraries(OpenSpace-MinVR PUBLIC Dbghelp.lib)
|
||||
endif ()
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
void appendNewInputEventsSinceLastCall(VRDataQueue* queue) override;
|
||||
};
|
||||
|
||||
constexpr const char* _loggerCat = "main_minvr";
|
||||
constexpr std::string_view _loggerCat = "main_minvr";
|
||||
|
||||
VRMain engine;
|
||||
Handler handler;
|
||||
@@ -86,7 +86,7 @@ struct {
|
||||
|
||||
bool HasInitializedGL = false;
|
||||
std::array<float, 30> LastFrametimes = { 1.f / 60.f }; // we can be optimistic here
|
||||
constexpr const char* MasterNode = "/MinVR/Desktop1";
|
||||
constexpr std::string_view MasterNode = "/MinVR/Desktop1";
|
||||
bool IsMasterNode = false;
|
||||
uint64_t FrameNumber = 0;
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> lastFrameTime;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# OpenSpace #
|
||||
# #
|
||||
# Copyright (c) 2014-2022 #
|
||||
# Copyright (c) 2014-2023 #
|
||||
# #
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of this #
|
||||
# software and associated documentation files (the "Software"), to deal in the Software #
|
||||
@@ -22,10 +22,8 @@
|
||||
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #
|
||||
##########################################################################################
|
||||
|
||||
include(${GHOUL_BASE_DIR}/support/cmake/copy_shared_libraries.cmake)
|
||||
include(${GHOUL_BASE_DIR}/support/cmake/message_macros.cmake)
|
||||
include(${OPENSPACE_CMAKE_EXT_DIR}/application_definition.cmake)
|
||||
include(${OPENSPACE_CMAKE_EXT_DIR}/global_variables.cmake)
|
||||
include(${PROJECT_SOURCE_DIR}/ext/ghoul/support/cmake/message_macros.cmake)
|
||||
include(${PROJECT_SOURCE_DIR}/support/cmake/application_definition.cmake)
|
||||
|
||||
# We are getting all_enabled_modules from the handle_applications.cmake file which gets
|
||||
# it from the main CMakeLists file
|
||||
@@ -44,14 +42,14 @@ if (OPENSPACE_OPENVR_SUPPORT)
|
||||
if (WIN32)
|
||||
find_path(SGCT_OPENVR_INCLUDE_DIRECTORY
|
||||
NAMES SGCTOpenVR.h
|
||||
PATHS ${OPENSPACE_BASE_DIR}/ext/sgct/additional_includes/openvr NO_DEFAULT_PATH
|
||||
PATHS ${PROJECT_SOURCE_DIR}/ext/sgct/additional_includes/openvr NO_DEFAULT_PATH
|
||||
REQUIRED
|
||||
)
|
||||
else ()
|
||||
find_path(SGCT_OPENVR_INCLUDE_DIRECTORY
|
||||
NAMES SGCTOpenVR.h
|
||||
PATH_SUFFIXES SGCTOpenVR
|
||||
PATHS ${OPENSPACE_BASE_DIR}/ext/sgct/additional_includes/openvr
|
||||
PATHS ${PROJECT_SOURCE_DIR}/ext/sgct/additional_includes/openvr
|
||||
REQUIRED
|
||||
)
|
||||
endif ()
|
||||
@@ -106,29 +104,38 @@ target_compile_definitions(OpenSpace PRIVATE
|
||||
${SPOUT_DEFINITIONS}
|
||||
)
|
||||
|
||||
if (OPENSPACE_BREAK_ON_FLOATING_POINT_EXCEPTION)
|
||||
target_compile_definitions(OpenSpace PRIVATE "OPENSPACE_BREAK_ON_FLOATING_POINT_EXCEPTION")
|
||||
endif ()
|
||||
|
||||
begin_header("Dependency: SGCT")
|
||||
|
||||
set(SGCT_TEXT OFF CACHE BOOL "" FORCE)
|
||||
set(SGCT_DEP_INCLUDE_FREETYPE OFF CACHE BOOL "" FORCE)
|
||||
set(SGCT_DEP_INCLUDE_FMT OFF CACHE BOOL "" FORCE)
|
||||
set(SGCT_DEP_INCLUDE_SCN OFF CACHE BOOL "" FORCE)
|
||||
set(SGCT_DEP_INCLUDE_CATCH2 OFF CACHE BOOL "" FORCE)
|
||||
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/ext/sgct)
|
||||
target_link_libraries(OpenSpace PRIVATE sgct)
|
||||
|
||||
set_folder_location(sgct "External")
|
||||
set_folder_location(glfw "External")
|
||||
set_folder_location(miniziplibstatic "External")
|
||||
set_folder_location(png16_static "External")
|
||||
set_folder_location(quat "External")
|
||||
set_folder_location(tinyxml2static "External")
|
||||
set_folder_location(vrpn "External")
|
||||
set_folder_location(zlibstatic "External")
|
||||
set_folder_location(SGCTTest "Unit Tests")
|
||||
set_target_properties(sgct PROPERTIES FOLDER "External")
|
||||
set_target_properties(glfw PROPERTIES FOLDER "External")
|
||||
if (TARGET SGCTTest)
|
||||
set_target_properties(SGCTTest PROPERTIES FOLDER "External")
|
||||
endif ()
|
||||
|
||||
if (UNIX AND (NOT APPLE))
|
||||
target_link_libraries(OpenSpace PRIVATE Xcursor Xinerama X11)
|
||||
endif ()
|
||||
|
||||
add_custom_command(TARGET OpenSpace POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ext/sgct/sgct.schema.json
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../config/schema/sgct.schema.json
|
||||
COMMAND_EXPAND_LISTS
|
||||
)
|
||||
|
||||
end_header("Dependency: SGCT")
|
||||
|
||||
begin_header("Dependency: Profile Editor")
|
||||
@@ -136,6 +143,18 @@ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/ext/launcher)
|
||||
target_link_libraries(OpenSpace PRIVATE openspace-ui-launcher)
|
||||
end_header("Dependency: Profile Editor")
|
||||
|
||||
if (WIN32)
|
||||
# Find the windeployqt application
|
||||
get_target_property(_qmake_executable Qt6::qmake IMPORTED_LOCATION)
|
||||
get_filename_component(_qt_bin_dir "${_qmake_executable}" DIRECTORY)
|
||||
find_program(WINDEPLOYQT_EXECUTABLE windeployqt HINTS "${_qt_bin_dir}")
|
||||
add_custom_command(
|
||||
TARGET OpenSpace POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E env PATH="${_qt_bin_dir}" "${WINDEPLOYQT_EXECUTABLE}" --verbose 0 --no-compiler-runtime --no-translations \"$<TARGET_FILE:OpenSpace>\"
|
||||
COMMENT "Deploying Qt libraries"
|
||||
)
|
||||
endif ()
|
||||
|
||||
|
||||
# Web Browser and Web gui
|
||||
# Why not put these in the module's path? Because they do not have access to the
|
||||
@@ -145,7 +164,7 @@ if (OPENSPACE_MODULE_WEBBROWSER AND CEF_ROOT)
|
||||
set(PROJECT_ARCH "x86_64")
|
||||
|
||||
if (WIN32)
|
||||
set(RESOURCE_FILE ${OPENSPACE_APPS_DIR}/OpenSpace/openspace.rc)
|
||||
set(RESOURCE_FILE openspace.rc)
|
||||
endif ()
|
||||
|
||||
# Add the CEF binary distribution's cmake/ directory to the module path and
|
||||
@@ -156,7 +175,7 @@ if (OPENSPACE_MODULE_WEBBROWSER AND CEF_ROOT)
|
||||
set_cef_targets("${CEF_ROOT}" OpenSpace)
|
||||
run_cef_platform_config("${CEF_ROOT}" "${CEF_TARGET}" "${WEBBROWSER_MODULE_PATH}")
|
||||
elseif ()
|
||||
message(WARNING "Web configured to be included, but no CEF_ROOT was found, please try configuring CMake again.")
|
||||
message(WARNING "Web configured to be included, but no CEF_ROOT was found, please try configuring CMake again")
|
||||
endif ()
|
||||
|
||||
if (MSVC)
|
||||
@@ -169,3 +188,10 @@ endif ()
|
||||
if (OPENSPACE_NVTOOLS_ENABLED)
|
||||
target_link_libraries(OpenSpace PRIVATE "${OPENSPACE_NVTOOLS_PATH}/lib/x64/nvToolsExt64_1.lib")
|
||||
endif ()
|
||||
|
||||
if (WIN32)
|
||||
add_custom_command(TARGET OpenSpace POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_RUNTIME_DLLS:OpenSpace> $<TARGET_FILE_DIR:OpenSpace>
|
||||
COMMAND_EXPAND_LISTS
|
||||
)
|
||||
endif ()
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# #
|
||||
# OpenSpace #
|
||||
# #
|
||||
# Copyright (c) 2014-2022 #
|
||||
# Copyright (c) 2014-2023 #
|
||||
# #
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy of this #
|
||||
# software and associated documentation files (the "Software"), to deal in the Software #
|
||||
@@ -22,7 +22,7 @@
|
||||
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #
|
||||
##########################################################################################
|
||||
|
||||
include(${OPENSPACE_CMAKE_EXT_DIR}/set_openspace_compile_settings.cmake)
|
||||
include(${PROJECT_SOURCE_DIR}/support/cmake/set_openspace_compile_settings.cmake)
|
||||
|
||||
set(HEADER_FILES
|
||||
include/filesystemaccess.h
|
||||
@@ -113,8 +113,6 @@ target_include_directories(
|
||||
openspace-ui-launcher
|
||||
PUBLIC
|
||||
include
|
||||
${OPENSPACE_APPS_DIR}/OpenSpace/ext/sgct/include
|
||||
${OPENSPACE_APPS_DIR}/OpenSpace/ext/sgct/sgct/ext/glm
|
||||
)
|
||||
target_link_libraries(
|
||||
openspace-ui-launcher
|
||||
@@ -125,13 +123,28 @@ target_link_libraries(
|
||||
Qt${QT_VERSION_MAJOR}::Gui
|
||||
Qt${QT_VERSION_MAJOR}::Widgets
|
||||
Qt${QT_VERSION_MAJOR}::Network
|
||||
PRIVATE
|
||||
sgct
|
||||
)
|
||||
|
||||
target_precompile_headers(openspace-ui-launcher PRIVATE
|
||||
<openspace/scene/profile.h>
|
||||
<ghoul/glm.h>
|
||||
<QAbstractItemDelegate>
|
||||
<QAbstractItemModel>
|
||||
<QDialog>
|
||||
<QLineEdit>
|
||||
<QObject>
|
||||
<QStyleOption>
|
||||
<QTextCursor>
|
||||
<QWidget>
|
||||
<filesystem>
|
||||
)
|
||||
|
||||
if (MSVC)
|
||||
set(MSVC_WARNINGS
|
||||
"/wd4619" # #pragma warning: there is no warning number (raised by Qt headers)
|
||||
"/wd4946" # reinterpret_cast used between related classes:
|
||||
)
|
||||
target_compile_options(openspace-ui-launcher INTERFACE ${MSVC_WARNINGS})
|
||||
|
||||
set(MSVC_WARNINGS
|
||||
"/wd4619" # #pragma warning: there is no warning number (raised by Qt headers)
|
||||
"/wd4946" # reinterpret_cast used between related classes:
|
||||
)
|
||||
target_compile_options(openspace-ui-launcher INTERFACE ${MSVC_WARNINGS})
|
||||
endif ()
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -29,6 +29,8 @@
|
||||
|
||||
#include "sgctedit/sgctedit.h"
|
||||
#include <openspace/scene/profile.h>
|
||||
#include <sgct/error.h>
|
||||
#include <sgct/readconfig.h>
|
||||
#include <QApplication>
|
||||
#include <optional>
|
||||
|
||||
@@ -79,15 +81,29 @@ public:
|
||||
*/
|
||||
std::string selectedWindowConfig() const;
|
||||
|
||||
/**
|
||||
* Returns true if the window configuration filename selected in the combo box
|
||||
* is a file in the user configurations section
|
||||
*
|
||||
* \return true if window configuration is a user configuration file
|
||||
*/
|
||||
bool isUserConfigSelected() const;
|
||||
|
||||
private:
|
||||
QWidget* createCentralWidget();
|
||||
void setBackgroundImage(const std::string& syncPath);
|
||||
|
||||
void openProfileEditor(const std::string& profile, bool isUserProfile);
|
||||
void openWindowEditor();
|
||||
void openWindowEditor(const std::string& winCfg, bool isUserWinCfg);
|
||||
void editRefusalDialog(const std::string& title, const std::string& msg,
|
||||
const std::string& detailedText);
|
||||
|
||||
void populateProfilesList(std::string preset);
|
||||
void populateWindowConfigsList(std::string preset);
|
||||
void handleReturnFromWindowEditor(const sgct::config::Cluster& cluster,
|
||||
std::filesystem::path savePath, const std::string& saveWindowCfgPath);
|
||||
void onNewWindowConfigSelection(int newIndex);
|
||||
bool versionCheck(sgct::config::GeneratorVersion& v) const;
|
||||
|
||||
const std::string _assetPath;
|
||||
const std::string _userAssetPath;
|
||||
@@ -95,14 +111,17 @@ private:
|
||||
const std::string _userConfigPath;
|
||||
const std::string _profilePath;
|
||||
const std::string _userProfilePath;
|
||||
const std::vector<std::string>& _readOnlyProfiles;
|
||||
bool _shouldLaunch = false;
|
||||
int _userAssetCount = 0;
|
||||
int _userConfigStartingIdx = 0;
|
||||
int _userConfigCount = 0;
|
||||
int _preDefinedConfigStartingIdx = 0;
|
||||
const std::string _sgctConfigName;
|
||||
int _windowConfigBoxIndexSgctCfgDefault = 0;
|
||||
|
||||
QComboBox* _profileBox = nullptr;
|
||||
QComboBox* _windowConfigBox = nullptr;
|
||||
QLabel* _backgroundImage = nullptr;
|
||||
QPushButton* _editWindowButton = nullptr;
|
||||
};
|
||||
#endif // __OPENSPACE_UI_LAUNCHER___LAUNCHERWINDOW___H__
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -33,6 +33,7 @@ class QCheckBox;
|
||||
class QComboBox;
|
||||
class QDialogButtonBox;
|
||||
class QGridLayout;
|
||||
class QLabel;
|
||||
class QLineEdit;
|
||||
class QListWidget;
|
||||
class QPushButton;
|
||||
@@ -58,7 +59,7 @@ private:
|
||||
void clearActionFields();
|
||||
void actionRejected();
|
||||
void chooseScripts();
|
||||
void appendScriptsToTextfield(std::string scripts);
|
||||
void appendScriptsToTextfield(std::vector<std::string> scripts);
|
||||
|
||||
openspace::Profile::Keybinding* selectedKeybinding();
|
||||
void keybindingAdd();
|
||||
@@ -77,6 +78,7 @@ private:
|
||||
struct {
|
||||
QListWidget* list = nullptr;
|
||||
QLineEdit* identifier = nullptr;
|
||||
QLabel* infoText = nullptr;
|
||||
QLineEdit* name = nullptr;
|
||||
QLineEdit* guiPath = nullptr;
|
||||
QLineEdit* documentation = nullptr;
|
||||
@@ -100,6 +102,8 @@ private:
|
||||
QPushButton* removeButton = nullptr;
|
||||
QDialogButtonBox* saveButtons = nullptr;
|
||||
} _keybindingWidgets;
|
||||
|
||||
QDialogButtonBox* _mainButton = nullptr;
|
||||
};
|
||||
|
||||
#endif // __OPENSPACE_UI_LAUNCHER___ACTIONDIALOG___H__
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -52,7 +52,7 @@ private:
|
||||
*
|
||||
* \param scripts #std::string scripts to be appended
|
||||
*/
|
||||
void appendScriptsToTextfield(std::string scripts);
|
||||
void appendScriptsToTextfield(std::vector<std::string> scripts);
|
||||
|
||||
std::vector<std::string>* _scripts = nullptr;
|
||||
std::vector<std::string> _scriptsData;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -52,6 +52,7 @@ private slots:
|
||||
|
||||
private:
|
||||
void createWidgets();
|
||||
QWidget* createNodeWidget();
|
||||
QWidget* createNavStateWidget();
|
||||
QWidget* createGeoWidget();
|
||||
|
||||
@@ -60,6 +61,12 @@ private:
|
||||
|
||||
std::optional<openspace::Profile::CameraType>* _camera = nullptr;
|
||||
QTabWidget* _tabWidget = nullptr;
|
||||
|
||||
struct {
|
||||
QLineEdit* anchor = nullptr;
|
||||
QLineEdit* height = nullptr;
|
||||
} _nodeState;
|
||||
|
||||
struct {
|
||||
QLineEdit* anchor = nullptr;
|
||||
QLineEdit* aim = nullptr;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -63,7 +63,7 @@ public:
|
||||
|
||||
private:
|
||||
void createWidgets();
|
||||
|
||||
|
||||
void listItemSelected();
|
||||
void valueChanged(const QString& text);
|
||||
void saveDeltaTimeValue();
|
||||
@@ -76,7 +76,7 @@ private:
|
||||
* Called to transition to editing a particular dt value (gui settings)
|
||||
*
|
||||
* \param index index in dt list
|
||||
* \param state \c true if the edit mode should be turned on, \c false otherwise
|
||||
* \param state `true` if the edit mode should be turned on, `false` otherwise
|
||||
*/
|
||||
void transitionEditMode(int index, bool state);
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -58,9 +58,7 @@ private:
|
||||
void listItemRemove();
|
||||
void parseSelections();
|
||||
|
||||
std::vector<QListWidgetItem*> _markedNodesListItems;
|
||||
std::vector<std::string>* _markedNodes;
|
||||
std::vector<std::string> _markedNodesData;
|
||||
|
||||
QListWidget* _list = nullptr;
|
||||
QPushButton* _removeButton = nullptr;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -47,15 +47,14 @@ public:
|
||||
* \param profileName The name of the profile to create
|
||||
* \param assetBasePath The path to the folder where the assets live
|
||||
* \param userAssetBasePath The path to the folder where the user assets live
|
||||
* \param profileName The path to the folder in which all profiles live
|
||||
* \param profilesReadOnly vector list of profile names that are read-only and must
|
||||
* not be overwritten
|
||||
* \param builtInProfileBasePath The path to the folder in which the built-in profiles
|
||||
* live
|
||||
* \param profileBasePath The path to the folder in which all profiles live
|
||||
* \param parent Pointer to parent Qt widget
|
||||
*/
|
||||
ProfileEdit(openspace::Profile& profile, const std::string& profileName,
|
||||
std::string assetBasePath, std::string userAssetBasePath,
|
||||
std::string profileBasePath,
|
||||
const std::vector<std::string>& profilesReadOnly, QWidget* parent);
|
||||
std::string builtInProfileBasePath, std::string profileBasePath, QWidget* parent);
|
||||
|
||||
/**
|
||||
* Gets the status of the save when the window is closed; was the file saved?
|
||||
@@ -102,8 +101,8 @@ private:
|
||||
const std::string _assetBasePath;
|
||||
const std::string _userAssetBasePath;
|
||||
const std::string _profileBasePath;
|
||||
const std::string _builtInProfilesPath;
|
||||
bool _saveSelected = false;
|
||||
const std::vector<std::string>& _readOnlyProfiles;
|
||||
|
||||
QLineEdit* _profileEdit = nullptr;
|
||||
QLabel* _modulesLabel = nullptr;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -83,7 +83,7 @@ private:
|
||||
QPushButton* _addButton = nullptr;
|
||||
QPushButton* _removeButton = nullptr;
|
||||
|
||||
QPushButton* _fillFromScriptLog = nullptr;
|
||||
QPushButton* _addFromScriptLog = nullptr;
|
||||
QLabel* _commandLabel = nullptr;
|
||||
QComboBox* _commandCombo = nullptr;
|
||||
QLabel* _propertyLabel = nullptr;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -34,10 +34,10 @@ class QPushButton;
|
||||
class ScriptlogDialog final : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ScriptlogDialog(QWidget* parent);
|
||||
ScriptlogDialog(QWidget* parent, std::string filter = "");
|
||||
|
||||
signals:
|
||||
void scriptsSelected(std::string script);
|
||||
void scriptsSelected(std::vector<std::string> script);
|
||||
|
||||
private:
|
||||
void createWidgets();
|
||||
@@ -50,7 +50,10 @@ private:
|
||||
QListWidget* _scriptlogList = nullptr;
|
||||
QLineEdit* _filter = nullptr;
|
||||
QPushButton* _reloadFile = nullptr;
|
||||
std::string _scriptLogFile;
|
||||
std::vector<std::string> _scripts;
|
||||
|
||||
std::string _fixedFilter;
|
||||
};
|
||||
|
||||
#endif // __OPENSPACE_UI_LAUNCHER___SCRIPTLOGDIALOG___H__
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#include <openspace/scene/profile.h>
|
||||
|
||||
class QCheckBox;
|
||||
class QComboBox;
|
||||
class QDateTimeEdit;
|
||||
class QLabel;
|
||||
@@ -63,6 +64,7 @@ private:
|
||||
QDateTimeEdit* _absoluteEdit = nullptr;
|
||||
QLabel* _relativeLabel = nullptr;
|
||||
QLineEdit* _relativeEdit = nullptr;
|
||||
QCheckBox* _startPaused = nullptr;
|
||||
};
|
||||
|
||||
#endif // __OPENSPACE_UI_LAUNCHER___TIMEDIALOG___H__
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -48,10 +48,12 @@ public:
|
||||
* \param winColors An array of QColor objects for window colors. The indexing of
|
||||
* this array matches the window indexing used elsewhere in the
|
||||
* class. This allows for a unique color for each window.
|
||||
* \param resetToDefault If set to true, all display and window settings will be
|
||||
* initialized to their default values.
|
||||
* \param parent The parent to which this widget belongs
|
||||
*/
|
||||
DisplayWindowUnion(const std::vector<QRect>& monitorSizeList,
|
||||
int nMaxWindows, const std::array<QColor, 4>& windowColors,
|
||||
int nMaxWindows, const std::array<QColor, 4>& windowColors, bool resetToDefault,
|
||||
QWidget* parent = nullptr);
|
||||
|
||||
/**
|
||||
@@ -59,7 +61,15 @@ public:
|
||||
*
|
||||
* \return vector of pointers of WindowControl objects
|
||||
*/
|
||||
std::vector<WindowControl*> windowControls() const;
|
||||
std::vector<WindowControl*> activeWindowControls() const;
|
||||
|
||||
/**
|
||||
* Returns a vector of pointers to the WindowControl objects for all windows, whether
|
||||
* they are visible or not.
|
||||
*
|
||||
* \return vector of pointers of all WindowControl objects
|
||||
*/
|
||||
std::vector<WindowControl*>& windowControls();
|
||||
|
||||
/**
|
||||
* When called will add a new window to the set of windows, which will, in turn, send
|
||||
@@ -73,6 +83,14 @@ public:
|
||||
*/
|
||||
void removeWindow();
|
||||
|
||||
/**
|
||||
* Returns the number of windows that are displayed (there can be more window
|
||||
* objects than are currently displayed).
|
||||
*
|
||||
* \return the number of displayed windows in the current configuration
|
||||
*/
|
||||
unsigned int numWindowsDisplayed() const;
|
||||
|
||||
signals:
|
||||
/**
|
||||
* This signal is emitted when a windowhas changed.
|
||||
@@ -92,7 +110,7 @@ signals:
|
||||
|
||||
private:
|
||||
void createWidgets(int nMaxWindows, std::vector<QRect> monitorResolutions,
|
||||
std::array<QColor, 4> windowColors);
|
||||
std::array<QColor, 4> windowColors, bool resetToDefault);
|
||||
void showWindows();
|
||||
|
||||
unsigned int _nWindowsDisplayed = 0;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -81,10 +81,10 @@ private:
|
||||
|
||||
std::vector<QRectF> _monitorDimensionsScaled;
|
||||
std::array<QRectF, 4> _windowRendering = {
|
||||
QRectF{ 0.f, 0.f, 0.f, 0.f },
|
||||
QRectF{ 0.f, 0.f, 0.f, 0.f },
|
||||
QRectF{ 0.f, 0.f, 0.f, 0.f },
|
||||
QRectF{ 0.f, 0.f, 0.f, 0.f }
|
||||
QRectF(0.f, 0.f, 0.f, 0.f),
|
||||
QRectF(0.f, 0.f, 0.f, 0.f),
|
||||
QRectF(0.f, 0.f, 0.f, 0.f),
|
||||
QRectF(0.f, 0.f, 0.f, 0.f)
|
||||
};
|
||||
int _nWindows = 1;
|
||||
const std::array<QColor, 4> _colorsForWindows;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -25,6 +25,8 @@
|
||||
#ifndef __OPENSPACE_UI_LAUNCHER___SETTINGSWIDGET___H__
|
||||
#define __OPENSPACE_UI_LAUNCHER___SETTINGSWIDGET___H__
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
#include <sgct/math.h>
|
||||
@@ -62,10 +64,86 @@ public:
|
||||
*/
|
||||
bool showUiOnFirstWindow() const;
|
||||
|
||||
/**
|
||||
* Sets the value of the checkbox for putting the GUI only on the first window.
|
||||
* If this is enabled, then the first window will draw2D but not draw3D. All
|
||||
* subsequent windows will be the opposite of this.
|
||||
*
|
||||
* \param setUiOnFirstWindow boolean value, if set true then the GUI will only
|
||||
* be on the first window
|
||||
*/
|
||||
void setShowUiOnFirstWindow(bool setUiOnFirstWindow);
|
||||
|
||||
/**
|
||||
* Sets value for whether or not the checkbox for having the UI only on the first
|
||||
* window is enabled. This checkbox should only be clickable if the number of
|
||||
* windows is 2 or more.
|
||||
*/
|
||||
void setEnableShowUiOnFirstWindowCheckbox(bool enable);
|
||||
|
||||
/**
|
||||
* Gets the value of the selection for which display first window should mirror if
|
||||
* the option to show the Ui in the first window is enabled. Note that this will
|
||||
* return a value even if the checkbox is not enabled.
|
||||
*
|
||||
* \return -1 if in a disabled state (e.g. when showUiOnFirstWindow() returns false)
|
||||
* 0 if no window graphics are selected (only the UI will appear)
|
||||
* (1-4) for which window's setting will be used for window 1 graphics
|
||||
*/
|
||||
int graphicsSelectionForShowUiOnFirstWindow() const;
|
||||
|
||||
/**
|
||||
* Sets value of the graphics selection combo box for which other window that the
|
||||
* first window will mirror.
|
||||
*
|
||||
* \param selection int value for the combo box selection.
|
||||
* 0 if no window graphics are selected (only the UI will appear)
|
||||
* (1-4) for which window's setting to use for window 1 graphics
|
||||
*/
|
||||
void setGraphicsSelectionForShowUiOnFirstWindow(int selection);
|
||||
|
||||
/**
|
||||
* Sets the value of the checkbox for enabling VSync.
|
||||
*
|
||||
* \param enableVsync boolean value, if set true then VSync is enabled
|
||||
*/
|
||||
void setVsync(bool enableVsync);
|
||||
|
||||
/**
|
||||
* Called when the number of windows that should be displayed changes.
|
||||
*
|
||||
* \param newCount The new number of windows included
|
||||
*/
|
||||
void nWindowsDisplayedChanged(int newCount);
|
||||
|
||||
/**
|
||||
* Gets the pointer to the QComboBox that selects the graphics for first window
|
||||
*
|
||||
* \return pointer to the QComboBox object
|
||||
*/
|
||||
QComboBox* firstWindowGraphicsSelection();
|
||||
|
||||
/**
|
||||
* Gets the pointer to the QCheckBox that selects if UI is in first window only
|
||||
*
|
||||
* \return pointer to the QCheckBox object
|
||||
*/
|
||||
QCheckBox* showUiOnFirstWindowCheckbox();
|
||||
|
||||
signals:
|
||||
void firstWindowGraphicsSelected(int selection);
|
||||
|
||||
private:
|
||||
sgct::quat _orientationValue = { 0.f, 0.f, 0.f, 0.f };
|
||||
void showUiOnFirstWindowClicked(bool checked);
|
||||
void firstWindowGraphicsSelectionChanged(const QString &text);
|
||||
|
||||
sgct::quat _orientationValue = sgct::quat(0.f, 0.f, 0.f, 0.f);
|
||||
QCheckBox* _checkBoxVsync = nullptr;
|
||||
QCheckBox* _showUiOnFirstWindow = nullptr;
|
||||
QComboBox* _firstWindowGraphicsSelection = nullptr;
|
||||
QBoxLayout* _firstWindowSelectionLayout = nullptr;
|
||||
int _stateOfUiOnFirstWindowPreviousCount = 1;
|
||||
bool _stateOfUiOnFirstWindowWhenDisabled = false;
|
||||
};
|
||||
|
||||
#endif // __OPENSPACE_UI_LAUNCHER___SETTINGSWIDGET___H__
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <QDialog>
|
||||
|
||||
#include <sgct/config.h>
|
||||
#include <sgctedit/windowcontrol.h>
|
||||
#include <QColor>
|
||||
#include <array>
|
||||
#include <filesystem>
|
||||
@@ -38,12 +39,16 @@ class SettingsWidget;
|
||||
class QBoxLayout;
|
||||
class QWidget;
|
||||
|
||||
const sgct::config::GeneratorVersion versionMin { "SgctWindowConfig", 1, 1 };
|
||||
const sgct::config::GeneratorVersion versionLegacy18 { "OpenSpace", 0, 18 };
|
||||
const sgct::config::GeneratorVersion versionLegacy19 { "OpenSpace", 0, 19 };
|
||||
|
||||
class SgctEdit final : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Constructor for SgctEdit class, the underlying class for the full window
|
||||
* configuration editor
|
||||
* configuration editor. Used when creating a new config.
|
||||
*
|
||||
* \param parent The Qt QWidget parent object
|
||||
* \param userConfigPath A string containing the file path of the user config
|
||||
@@ -51,6 +56,19 @@ public:
|
||||
*/
|
||||
SgctEdit(QWidget* parent, std::string userConfigPath);
|
||||
|
||||
/**
|
||||
* Constructor for SgctEdit class, the underlying class for the full window
|
||||
* configuration editor. Used when editing an existing config.
|
||||
*
|
||||
* \param cluster The #sgct::config::Cluster object containing all data of the
|
||||
* imported window cluster configuration.
|
||||
* \param configName The name of the window configuration filename
|
||||
* \param configBasePath The path to the folder where default config files reside
|
||||
* \param parent Pointer to parent Qt widget
|
||||
*/
|
||||
SgctEdit(sgct::config::Cluster& cluster, const std::string& configName,
|
||||
std::string& configBasePath, QWidget* parent);
|
||||
|
||||
/**
|
||||
* Returns the saved filename
|
||||
*
|
||||
@@ -65,9 +83,40 @@ public:
|
||||
*/
|
||||
sgct::config::Cluster cluster() const;
|
||||
|
||||
/**
|
||||
* Called when the number of windows that should be displayed changes.
|
||||
*
|
||||
* \param newCount The new number of windows included
|
||||
*/
|
||||
void nWindowsDisplayedChanged(int newCount);
|
||||
|
||||
/**
|
||||
* Called when the checkbox for GUI only on first window is clicked.
|
||||
*
|
||||
* \param checked true if GUI is selected for first window only.
|
||||
*/
|
||||
void firstWindowGuiOptionClicked(bool checked);
|
||||
|
||||
/**
|
||||
* Called when the QComboBox is selected and has a new value
|
||||
*
|
||||
* \param text the QString of the selected value
|
||||
*/
|
||||
void firstWindowGraphicsSelectionChanged(const QString& text);
|
||||
|
||||
private:
|
||||
void createWidgets(const std::vector<QRect>& monitorSizes);
|
||||
sgct::config::Cluster generateConfiguration() const;
|
||||
std::vector<QRect> createMonitorInfoSet();
|
||||
void createWidgets(const std::vector<QRect>& monitorSizes, unsigned int nWindows,
|
||||
bool setToDefaults);
|
||||
void generateConfiguration();
|
||||
void generateConfigSetupVsync();
|
||||
void generateConfigUsers();
|
||||
void generateConfigAddresses(sgct::config::Node& node);
|
||||
void generateConfigResizeWindowsAccordingToSelected(sgct::config::Node& node);
|
||||
void generateConfigIndividualWindowSettings(sgct::config::Node& node);
|
||||
void setupProjectionTypeInGui(sgct::config::Viewport& vPort, WindowControl* wCtrl);
|
||||
void setupStateOfUiOnFirstWindow(size_t nWindows);
|
||||
void deleteFromTags(sgct::config::Window& window);
|
||||
|
||||
void save();
|
||||
void apply();
|
||||
@@ -82,12 +131,14 @@ private:
|
||||
QColor(0x44, 0xAF, 0x69),
|
||||
QColor(0xF8, 0x33, 0x3C)
|
||||
};
|
||||
std::string _configurationFilename;
|
||||
|
||||
QBoxLayout* _layoutButtonBox = nullptr;
|
||||
QPushButton* _saveButton = nullptr;
|
||||
QPushButton* _cancelButton = nullptr;
|
||||
QPushButton* _applyButton = nullptr;
|
||||
std::string _saveTarget;
|
||||
bool _didImportValues = false;
|
||||
};
|
||||
|
||||
#endif // __OPENSPACE_UI_LAUNCHER___SGCTEDIT___H__
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -41,6 +41,14 @@ class QSpinBox;
|
||||
class WindowControl final : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum class ProjectionIndices {
|
||||
Planar = 0,
|
||||
Fisheye,
|
||||
SphericalMirror,
|
||||
Cylindrical,
|
||||
Equirectangular
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor for WindowControl class, which contains settings and configuration
|
||||
* for individual windows
|
||||
@@ -52,7 +60,8 @@ public:
|
||||
* \param winColor A QColor object for this window's unique color
|
||||
*/
|
||||
WindowControl(int monitorIndex, int windowIndex,
|
||||
const std::vector<QRect>& monitorDims, const QColor& winColor, QWidget* parent);
|
||||
const std::vector<QRect>& monitorDims, const QColor& winColor,
|
||||
bool resetToDefault, QWidget* parent);
|
||||
|
||||
/**
|
||||
* Makes the window label at top of a window control column visible
|
||||
@@ -66,20 +75,116 @@ public:
|
||||
*/
|
||||
void resetToDefaults();
|
||||
|
||||
sgct::config::Window generateWindowInformation() const;
|
||||
/**
|
||||
* Sets the window dimensions
|
||||
*
|
||||
* \param newDims The x, y dimensions to set the window to
|
||||
*/
|
||||
void setDimensions(QRectF newDims);
|
||||
|
||||
/**
|
||||
* Sets the monitor selection combobox
|
||||
*
|
||||
* \param monitorIndex The zero-based monitor index to set the combobox selection to
|
||||
*/
|
||||
void setMonitorSelection(int monitorIndex);
|
||||
|
||||
/**
|
||||
* Sets the window name in the text edit box
|
||||
*
|
||||
* \param windowName The window title to set
|
||||
*/
|
||||
void setWindowName(const std::string& windowName);
|
||||
|
||||
/**
|
||||
* Sets the window's decoration status. If set to true, then the window has a
|
||||
* border. If false it is borderless
|
||||
*
|
||||
* \param hasWindowDecoration boolean for if window has decoration (border)
|
||||
*/
|
||||
void setDecorationState(bool hasWindowDecoration);
|
||||
|
||||
/**
|
||||
* Generates window configuration (sgct::config::Window struct) based on the
|
||||
* GUI settings.
|
||||
*
|
||||
* \param window The sgct::config::Window struct that is passed into the function
|
||||
* and modified with the generated window content
|
||||
*/
|
||||
void generateWindowInformation(sgct::config::Window& window) const;
|
||||
|
||||
/**
|
||||
* Sets the window's projection type to planar, with the accompanying parameters
|
||||
* for horizontal and vertical FOV.
|
||||
*
|
||||
* \param hfov float value for horizontal field of view angle (degrees)
|
||||
* \param vfov float value for vertical field of view angle (degrees)
|
||||
*/
|
||||
void setProjectionPlanar(float hfov, float vfov);
|
||||
|
||||
/**
|
||||
* Sets the window's projection type to fisheye, with the accompanying quality
|
||||
* setting and spout option
|
||||
*
|
||||
* \param quality int value for number of vertical lines of resolution. This will
|
||||
* be compared against the QualityValues array in order to set the
|
||||
* correct combobox index
|
||||
* \param spoutOutput bool for enabling the spout output option
|
||||
*/
|
||||
void setProjectionFisheye(int quality, bool spoutOutput);
|
||||
|
||||
/**
|
||||
* Sets the window's projection type to spherical mirror, with the accompanying
|
||||
* quality setting
|
||||
*
|
||||
* \param quality int value for number of vertical lines of resolution. This will
|
||||
* be compared against the QualityValues array in order to set the
|
||||
* correct combobox index
|
||||
*/
|
||||
void setProjectionSphericalMirror(int quality);
|
||||
|
||||
/**
|
||||
* Sets the window's projection type to cylindrical, with the accompanying quality
|
||||
* setting and height offset value
|
||||
*
|
||||
* \param quality int value for number of vertical lines of resolution. This will
|
||||
* be compared against the QualityValues array in order to set the
|
||||
* correct combobox index
|
||||
* \param heightOffset float value for height offset to be applied
|
||||
*/
|
||||
void setProjectionCylindrical(int quality, float heightOffset);
|
||||
|
||||
/**
|
||||
* Sets the window's projection type to equirectangular, with the accompanying
|
||||
* quality setting and spout option
|
||||
*
|
||||
* \param quality int value for number of vertical lines of resolution. This will
|
||||
* be compared against the QualityValues array in order to set the
|
||||
* correct combobox index
|
||||
* \param spoutOutput bool for enabling the spout output option
|
||||
*/
|
||||
void setProjectionEquirectangular(int quality, bool spoutOutput);
|
||||
|
||||
/**
|
||||
* Controls the visibility of all projection controls, including those
|
||||
* that are only shown when the projection type is set to certain values.
|
||||
*
|
||||
* \param enable bool true if the projections controls should be visible
|
||||
*/
|
||||
void setVisibilityOfProjectionGui(bool enable);
|
||||
|
||||
/**
|
||||
* Returns an sgct::config::Projections struct containing the projection
|
||||
* information for this window.
|
||||
*
|
||||
* \return sgct::config::Projections object containing the projection information
|
||||
*/
|
||||
sgct::config::Projections generateProjectionInformation() const;
|
||||
|
||||
signals:
|
||||
void windowChanged(int monitorIndex, int windowIndex, const QRectF& newDimensions);
|
||||
|
||||
private:
|
||||
enum class ProjectionIndices {
|
||||
Planar = 0,
|
||||
Fisheye,
|
||||
SphericalMirror,
|
||||
Cylindrical,
|
||||
Equirectangular
|
||||
};
|
||||
|
||||
void createWidgets(const QColor& windowColor);
|
||||
QWidget* createPlanarWidget();
|
||||
QWidget* createFisheyeWidget();
|
||||
@@ -96,8 +201,8 @@ private:
|
||||
void onAspectRatioLockClicked();
|
||||
void onFovLockClicked();
|
||||
|
||||
sgct::config::Projections generateProjectionInformation() const;
|
||||
void updatePlanarLockedFov();
|
||||
void setQualityComboBoxFromLinesResolution(int lines, QComboBox* combo);
|
||||
|
||||
static constexpr float IdealAspectRatio = 16.f / 9.f;
|
||||
float _aspectRatioSize = IdealAspectRatio;
|
||||
@@ -118,33 +223,47 @@ private:
|
||||
QSpinBox* _offsetY = nullptr;
|
||||
QCheckBox* _windowDecoration = nullptr;
|
||||
QComboBox* _projectionType = nullptr;
|
||||
QLabel* _projectionLabel = nullptr;
|
||||
|
||||
struct {
|
||||
QWidget* widget = nullptr;
|
||||
QLabel* labelInfo = nullptr;
|
||||
QDoubleSpinBox* fovH = nullptr;
|
||||
QDoubleSpinBox* fovV = nullptr;
|
||||
QLabel* labelFovH = nullptr;
|
||||
QLabel* labelFovV = nullptr;
|
||||
QPushButton* buttonLockFov = nullptr;
|
||||
} _planar;
|
||||
|
||||
struct {
|
||||
QWidget* widget = nullptr;
|
||||
QLabel* labelInfo = nullptr;
|
||||
QComboBox* quality = nullptr;
|
||||
QLabel* labelQuality = nullptr;
|
||||
QCheckBox* spoutOutput = nullptr;
|
||||
} _fisheye;
|
||||
|
||||
struct {
|
||||
QWidget* widget = nullptr;
|
||||
QLabel* labelInfo = nullptr;
|
||||
QComboBox* quality = nullptr;
|
||||
QLabel* labelQuality = nullptr;
|
||||
} _sphericalMirror;
|
||||
|
||||
struct {
|
||||
QWidget* widget = nullptr;
|
||||
QLabel* labelInfo = nullptr;
|
||||
QComboBox* quality = nullptr;
|
||||
QLabel* labelQuality = nullptr;
|
||||
QDoubleSpinBox* heightOffset = nullptr;
|
||||
QLabel* labelHeightOffset = nullptr;
|
||||
} _cylindrical;
|
||||
|
||||
struct {
|
||||
QWidget* widget = nullptr;
|
||||
QLabel* labelInfo = nullptr;
|
||||
QComboBox* quality = nullptr;
|
||||
QLabel* labelQuality = nullptr;
|
||||
QCheckBox* spoutOutput = nullptr;
|
||||
} _equirectangular;
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ LauncherWindow QComboBox#config {
|
||||
border-radius: 3px;
|
||||
border-color: rgb(225, 225, 225);
|
||||
padding: 1px 18px 1px 3px;
|
||||
min-width: 6em;
|
||||
min-width: 14em;
|
||||
font-size: 10pt;
|
||||
font-family: Segoe UI;
|
||||
font-weight: bold;
|
||||
@@ -82,6 +82,11 @@ LauncherWindow QPushButton#small:hover {
|
||||
background: rgb(120, 120, 120);
|
||||
}
|
||||
|
||||
LauncherWindow QPushButton#small:disabled {
|
||||
color: rgb(180, 180, 180);
|
||||
background: rgb(160, 160, 160);
|
||||
}
|
||||
|
||||
/*
|
||||
* ProfileEdit
|
||||
*/
|
||||
@@ -115,7 +120,7 @@ PropertiesDialog QListWidget {
|
||||
*/
|
||||
AssetsDialog QTreeView {
|
||||
min-width: 40em;
|
||||
min-height: 40em;
|
||||
height: 15em;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -149,6 +154,13 @@ CameraDialog QLabel#error-message {
|
||||
min-width: 10em;
|
||||
}
|
||||
|
||||
CameraDialog QLabel#camera-description {
|
||||
color:rgb(96, 96, 96);
|
||||
margin: 1em;
|
||||
margin-top: 0.2em;
|
||||
margin-bottom: 0.4em;
|
||||
}
|
||||
|
||||
/*
|
||||
* ScriptlogDialog
|
||||
*/
|
||||
@@ -187,3 +199,8 @@ WindowControl QLabel#info {
|
||||
font-weight: normal;
|
||||
font-size: 8pt;
|
||||
}
|
||||
|
||||
WindowControl QLabel#notice {
|
||||
font-weight: normal;
|
||||
font-size: 11pt;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -87,7 +87,7 @@ void FileSystemAccess::parseChildFile(std::string filename, bool& hasDirHeaderBe
|
||||
else {
|
||||
std::string extension = filename.substr(filename.length()
|
||||
- _fileExtension.length());
|
||||
if (extension.compare(_fileExtension) != 0) {
|
||||
if (extension != _fileExtension) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/fmt.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <sgct/readconfig.h>
|
||||
#include <QComboBox>
|
||||
#include <QFile>
|
||||
#include <QLabel>
|
||||
@@ -41,50 +42,62 @@
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
#include <sgct/readconfig.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <Windows.h>
|
||||
#endif // WIN32
|
||||
|
||||
using namespace openspace;
|
||||
|
||||
namespace {
|
||||
constexpr const int ScreenWidth = 480;
|
||||
constexpr const int ScreenHeight = 640;
|
||||
constexpr int ScreenWidth = 480;
|
||||
constexpr int ScreenHeight = 640;
|
||||
|
||||
constexpr const int LeftRuler = 40;
|
||||
constexpr const int TopRuler = 80;
|
||||
constexpr const int ItemWidth = 240;
|
||||
constexpr const int ItemHeight = ItemWidth / 4;
|
||||
constexpr const int SmallItemWidth = 100;
|
||||
constexpr const int SmallItemHeight = SmallItemWidth / 4;
|
||||
constexpr int LeftRuler = 40;
|
||||
constexpr int TopRuler = 80;
|
||||
constexpr int ItemWidth = 260;
|
||||
constexpr int ItemHeight = ItemWidth / 4;
|
||||
constexpr int SmallItemWidth = 100;
|
||||
constexpr int SmallItemHeight = SmallItemWidth / 4;
|
||||
|
||||
namespace geometry {
|
||||
constexpr const QRect BackgroundImage(0, 0, ScreenWidth, ScreenHeight);
|
||||
constexpr const QRect LogoImage(LeftRuler, TopRuler, ItemWidth, ItemHeight);
|
||||
constexpr const QRect ChooseLabel(LeftRuler, TopRuler + 80, 151, 24);
|
||||
constexpr const QRect ProfileBox(
|
||||
LeftRuler, TopRuler + 110, ItemWidth, ItemHeight
|
||||
constexpr QRect BackgroundImage(0, 0, ScreenWidth, ScreenHeight);
|
||||
constexpr QRect LogoImage(LeftRuler, TopRuler, ItemWidth, ItemHeight);
|
||||
constexpr QRect ChooseLabel(LeftRuler, TopRuler + 80, 151, 24);
|
||||
constexpr QRect ProfileBox(LeftRuler, TopRuler + 110, ItemWidth, ItemHeight);
|
||||
constexpr QRect NewProfileButton(
|
||||
LeftRuler + 160, TopRuler + 180, SmallItemWidth, SmallItemHeight
|
||||
);
|
||||
constexpr const QRect NewProfileButton(
|
||||
LeftRuler + 140, TopRuler + 180, SmallItemWidth, SmallItemHeight
|
||||
);
|
||||
constexpr const QRect EditProfileButton(
|
||||
constexpr QRect EditProfileButton(
|
||||
LeftRuler, TopRuler + 180, SmallItemWidth, SmallItemHeight
|
||||
);
|
||||
constexpr const QRect OptionsLabel(LeftRuler, TopRuler + 230, 151, 24);
|
||||
constexpr const QRect WindowConfigBox(
|
||||
LeftRuler, TopRuler + 260, ItemWidth, ItemHeight
|
||||
constexpr QRect OptionsLabel(LeftRuler, TopRuler + 230, 151, 24);
|
||||
constexpr QRect WindowConfigBox(LeftRuler, TopRuler + 260, ItemWidth, ItemHeight);
|
||||
constexpr QRect NewWindowButton(
|
||||
LeftRuler + 160, TopRuler + 330, SmallItemWidth, SmallItemHeight
|
||||
);
|
||||
constexpr const QRect NewWindowButton(
|
||||
LeftRuler + 140, TopRuler + 330, SmallItemWidth, SmallItemHeight
|
||||
);
|
||||
constexpr const QRect EditWindowButton(
|
||||
constexpr QRect EditWindowButton(
|
||||
LeftRuler, TopRuler + 330, SmallItemWidth, SmallItemHeight
|
||||
);
|
||||
constexpr const QRect StartButton(
|
||||
constexpr QRect StartButton(
|
||||
LeftRuler, TopRuler + 400, ItemWidth, ItemHeight
|
||||
);
|
||||
} // geometry
|
||||
|
||||
std::optional<Profile> loadProfileFromFile(QWidget* parent, std::string filename) {
|
||||
// Verify that the file actually exists
|
||||
if (!std::filesystem::exists(filename)) {
|
||||
QMessageBox::critical(
|
||||
parent,
|
||||
"Exception",
|
||||
QString::fromStdString(fmt::format(
|
||||
"Could not open profile file '{}'", filename
|
||||
))
|
||||
);
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::ifstream inFile;
|
||||
try {
|
||||
inFile.open(filename, std::ifstream::in);
|
||||
@@ -128,11 +141,29 @@ namespace {
|
||||
|
||||
void saveProfile(QWidget* parent, const std::string& path, const Profile& p) {
|
||||
std::ofstream outFile;
|
||||
outFile.exceptions(std::ofstream::badbit | std::ofstream::failbit);
|
||||
try {
|
||||
outFile.open(path, std::ofstream::out);
|
||||
outFile << p.serialize();
|
||||
}
|
||||
catch (const std::ofstream::failure& e) {
|
||||
#ifdef WIN32
|
||||
if (std::filesystem::exists(path)) {
|
||||
// Check if the file is hidden, since that causes ofstream to fail
|
||||
DWORD res = GetFileAttributesA(path.c_str());
|
||||
if (res & FILE_ATTRIBUTE_HIDDEN) {
|
||||
QMessageBox::critical(
|
||||
parent,
|
||||
"Exception",
|
||||
QString::fromStdString(fmt::format(
|
||||
"Error writing data to file: '{}' as file is marked hidden",
|
||||
path
|
||||
))
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif // WIN32
|
||||
QMessageBox::critical(
|
||||
parent,
|
||||
"Exception",
|
||||
@@ -144,16 +175,12 @@ namespace {
|
||||
}
|
||||
|
||||
void saveWindowConfig(QWidget* parent, const std::filesystem::path& path,
|
||||
sgct::config::Cluster& cluster)
|
||||
const sgct::config::Cluster& cluster)
|
||||
{
|
||||
std::ofstream outFile;
|
||||
try {
|
||||
outFile.open(path, std::ofstream::out);
|
||||
sgct::config::GeneratorVersion genEntry = {
|
||||
"OpenSpace",
|
||||
OPENSPACE_VERSION_MAJOR,
|
||||
OPENSPACE_VERSION_MINOR
|
||||
};
|
||||
sgct::config::GeneratorVersion genEntry = versionMin;
|
||||
outFile << sgct::serializeConfig(
|
||||
cluster,
|
||||
genEntry
|
||||
@@ -186,7 +213,6 @@ LauncherWindow::LauncherWindow(bool profileEnabled,
|
||||
, _userProfilePath(
|
||||
absPath(globalConfig.pathTokens.at("USER_PROFILES")).string() + '/'
|
||||
)
|
||||
, _readOnlyProfiles(globalConfig.readOnlyProfiles)
|
||||
, _sgctConfigName(sgctConfigName)
|
||||
{
|
||||
Q_INIT_RESOURCE(resources);
|
||||
@@ -215,9 +241,10 @@ LauncherWindow::LauncherWindow(bool profileEnabled,
|
||||
populateProfilesList(globalConfig.profile);
|
||||
_profileBox->setEnabled(profileEnabled);
|
||||
|
||||
populateWindowConfigsList(_sgctConfigName);
|
||||
_windowConfigBox->setEnabled(sgctConfigEnabled);
|
||||
|
||||
populateWindowConfigsList(_sgctConfigName);
|
||||
// Trigger currentIndexChanged so the preview file read is performed
|
||||
_windowConfigBox->currentIndexChanged(_windowConfigBox->currentIndex());
|
||||
|
||||
std::filesystem::path p = absPath(
|
||||
globalConfig.pathTokens.at("SYNC") + "/http/launcher_images"
|
||||
@@ -312,13 +339,31 @@ QWidget* LauncherWindow::createCentralWidget() {
|
||||
connect(
|
||||
newWindowButton, &QPushButton::released,
|
||||
[this]() {
|
||||
openWindowEditor();
|
||||
openWindowEditor("", true);
|
||||
}
|
||||
);
|
||||
newWindowButton->setObjectName("small");
|
||||
newWindowButton->setGeometry(geometry::NewWindowButton);
|
||||
newWindowButton->setCursor(Qt::PointingHandCursor);
|
||||
|
||||
_editWindowButton = new QPushButton("Edit", centralWidget);
|
||||
connect(
|
||||
_editWindowButton,
|
||||
&QPushButton::released,
|
||||
[this]() {
|
||||
std::filesystem::path pathSelected = absPath(selectedWindowConfig());
|
||||
bool isUserConfig = isUserConfigSelected();
|
||||
std::string fileSelected = pathSelected.generic_string();
|
||||
if (std::filesystem::is_regular_file(pathSelected)) {
|
||||
openWindowEditor(fileSelected, isUserConfig);
|
||||
}
|
||||
}
|
||||
);
|
||||
_editWindowButton->setVisible(true);
|
||||
_editWindowButton->setObjectName("small");
|
||||
_editWindowButton->setGeometry(geometry::EditWindowButton);
|
||||
_editWindowButton->setCursor(Qt::PointingHandCursor);
|
||||
|
||||
return centralWidget;
|
||||
}
|
||||
|
||||
@@ -411,11 +456,24 @@ void LauncherWindow::populateProfilesList(std::string preset) {
|
||||
++_userAssetCount;
|
||||
}
|
||||
std::sort(profiles.begin(), profiles.end());
|
||||
for (const fs::directory_entry& p : profiles) {
|
||||
for (const fs::directory_entry& profile : profiles) {
|
||||
std::filesystem::path path = profile.path();
|
||||
_profileBox->addItem(
|
||||
QString::fromStdString(p.path().stem().string()),
|
||||
QString::fromStdString(p.path().string())
|
||||
QString::fromStdString(path.stem().string()),
|
||||
QString::fromStdString(path.string())
|
||||
);
|
||||
|
||||
// Add toooltip
|
||||
std::optional<Profile> p = loadProfileFromFile(this, path.string());
|
||||
int idx = _profileBox->count() - 1;
|
||||
if (p.has_value() && (*p).meta.has_value()) {
|
||||
const std::optional<std::string>& d = (*p).meta.value().description;
|
||||
if (d.has_value()) {
|
||||
// Tooltip has to be 'rich text' to linebreak properly
|
||||
QString tooltip = QString::fromStdString(fmt::format("<p>{}</p>", *d));
|
||||
_profileBox->setItemData(idx, tooltip, Qt::ToolTipRole);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_profileBox->addItem(QString::fromStdString("--- OpenSpace Profiles ---"));
|
||||
@@ -435,11 +493,23 @@ void LauncherWindow::populateProfilesList(std::string preset) {
|
||||
|
||||
// Add sorted items to list
|
||||
for (const fs::directory_entry& profile : profiles) {
|
||||
std::string abc = profile.path().string();
|
||||
std::filesystem::path path = profile.path();
|
||||
_profileBox->addItem(
|
||||
QString::fromStdString(profile.path().stem().string()),
|
||||
QString::fromStdString(profile.path().string())
|
||||
QString::fromStdString(path.stem().string()),
|
||||
QString::fromStdString(path.string())
|
||||
);
|
||||
|
||||
// Add toooltip
|
||||
std::optional<Profile> p = loadProfileFromFile(this, path.string());
|
||||
int idx = _profileBox->count() - 1;
|
||||
if (p.has_value() && (*p).meta.has_value()) {
|
||||
const std::optional<std::string>& d = (*p).meta.value().description;
|
||||
if (d.has_value()) {
|
||||
// Tooltip has to be 'rich text' to linebreak properly
|
||||
QString tooltip = QString::fromStdString(fmt::format("<p>{}</p>", *d));
|
||||
_profileBox->setItemData(idx, tooltip, Qt::ToolTipRole);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try to find the requested profile and set it as the current one
|
||||
@@ -481,15 +551,26 @@ bool handleConfigurationFile(QComboBox& box, const std::filesystem::directory_en
|
||||
void LauncherWindow::populateWindowConfigsList(std::string preset) {
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
// Disconnect the signal for new window config selection during population process
|
||||
disconnect(
|
||||
_windowConfigBox,
|
||||
QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
nullptr,
|
||||
nullptr
|
||||
);
|
||||
_windowConfigBox->clear();
|
||||
|
||||
_userConfigCount = 0;
|
||||
_userConfigStartingIdx = 0;
|
||||
_preDefinedConfigStartingIdx = 0;
|
||||
_windowConfigBox->addItem(QString::fromStdString("--- User Configurations ---"));
|
||||
const QStandardItemModel* model =
|
||||
qobject_cast<const QStandardItemModel*>(_windowConfigBox->model());
|
||||
|
||||
model->item(_userConfigCount)->setEnabled(false);
|
||||
++_userConfigCount;
|
||||
_userConfigCount++;
|
||||
_userConfigStartingIdx++;
|
||||
_preDefinedConfigStartingIdx++;
|
||||
|
||||
bool hasXmlConfig = false;
|
||||
|
||||
@@ -504,14 +585,16 @@ void LauncherWindow::populateWindowConfigsList(std::string preset) {
|
||||
for (const fs::directory_entry& p : files) {
|
||||
bool isConfigFile = handleConfigurationFile(*_windowConfigBox, p);
|
||||
if (isConfigFile) {
|
||||
++_userConfigCount;
|
||||
_userConfigCount++;
|
||||
_userConfigStartingIdx++;
|
||||
_preDefinedConfigStartingIdx++;
|
||||
}
|
||||
|
||||
hasXmlConfig |= p.path().extension() == ".xml";
|
||||
}
|
||||
_windowConfigBox->addItem(QString::fromStdString("--- OpenSpace Configurations ---"));
|
||||
model = qobject_cast<const QStandardItemModel*>(_windowConfigBox->model());
|
||||
model->item(_userConfigCount)->setEnabled(false);
|
||||
_preDefinedConfigStartingIdx++;
|
||||
|
||||
if (std::filesystem::exists(_configPath)) {
|
||||
// Sort files
|
||||
@@ -545,7 +628,10 @@ void LauncherWindow::populateWindowConfigsList(std::string preset) {
|
||||
}
|
||||
|
||||
// Always add the .cfg sgct default as first item
|
||||
_windowConfigBox->insertItem(0, QString::fromStdString(_sgctConfigName));
|
||||
_windowConfigBox->insertItem(
|
||||
_windowConfigBoxIndexSgctCfgDefault,
|
||||
QString::fromStdString(_sgctConfigName)
|
||||
);
|
||||
// Try to find the requested configuration file and set it as the current one. As we
|
||||
// have support for function-generated configuration files that will not be in the
|
||||
// list we need to add a preset that doesn't exist a file for
|
||||
@@ -555,12 +641,67 @@ void LauncherWindow::populateWindowConfigsList(std::string preset) {
|
||||
}
|
||||
else {
|
||||
// Add the requested preset at the top
|
||||
_windowConfigBox->insertItem(1, QString::fromStdString(preset));
|
||||
_windowConfigBox->insertItem(
|
||||
_windowConfigBoxIndexSgctCfgDefault + 1,
|
||||
QString::fromStdString(preset)
|
||||
);
|
||||
// Increment the user config count because there is an additional option added
|
||||
// before the user config options
|
||||
_userConfigCount++;
|
||||
_windowConfigBox->setCurrentIndex(1);
|
||||
_userConfigStartingIdx++;
|
||||
_preDefinedConfigStartingIdx++;
|
||||
_windowConfigBox->setCurrentIndex(_windowConfigBoxIndexSgctCfgDefault + 1);
|
||||
}
|
||||
connect(
|
||||
_windowConfigBox,
|
||||
QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
this,
|
||||
&LauncherWindow::onNewWindowConfigSelection
|
||||
);
|
||||
// Call combobox selected callback to refresh the file status of the current selection
|
||||
onNewWindowConfigSelection(_windowConfigBox->currentIndex());
|
||||
}
|
||||
|
||||
void LauncherWindow::onNewWindowConfigSelection(int newIndex) {
|
||||
std::filesystem::path pathSelected = absPath(selectedWindowConfig());
|
||||
std::string fileSelected = pathSelected.string();
|
||||
if (newIndex == _windowConfigBoxIndexSgctCfgDefault) {
|
||||
_editWindowButton->setEnabled(false);
|
||||
_editWindowButton->setToolTip(
|
||||
"Cannot edit the 'Default' configuration since it is not a file"
|
||||
);
|
||||
}
|
||||
else if (newIndex >= _preDefinedConfigStartingIdx) {
|
||||
_editWindowButton->setEnabled(false);
|
||||
_editWindowButton->setToolTip(
|
||||
QString::fromStdString(fmt::format(
|
||||
"Cannot edit '{}'\nsince it is one of the configuration "
|
||||
"files provided in the OpenSpace installation", fileSelected))
|
||||
);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
sgct::config::GeneratorVersion previewGenVersion =
|
||||
sgct::readConfigGenerator(fileSelected);
|
||||
if (!versionCheck(previewGenVersion)) {
|
||||
_editWindowButton->setEnabled(false);
|
||||
_editWindowButton->setToolTip(QString::fromStdString(fmt::format(
|
||||
"This file does not meet the minimum required version of {}.",
|
||||
versionMin.versionString())));
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (const std::runtime_error&) {
|
||||
// Ignore an exception here because clicking the edit button will
|
||||
// bring up an explanatory error message
|
||||
}
|
||||
_editWindowButton->setEnabled(true);
|
||||
_editWindowButton->setToolTip("");
|
||||
}
|
||||
}
|
||||
|
||||
bool LauncherWindow::versionCheck(sgct::config::GeneratorVersion& v) const {
|
||||
return (v.versionCheck(versionMin) || v == versionLegacy18 || v == versionLegacy19);
|
||||
}
|
||||
|
||||
void LauncherWindow::openProfileEditor(const std::string& profile, bool isUserProfile) {
|
||||
@@ -572,7 +713,6 @@ void LauncherWindow::openProfileEditor(const std::string& profile, bool isUserPr
|
||||
}
|
||||
else {
|
||||
// Otherwise, we want to load that profile
|
||||
|
||||
std::string fullProfilePath = saveProfilePath + profile + ".profile";
|
||||
p = loadProfileFromFile(this, fullProfilePath);
|
||||
if (!p.has_value()) {
|
||||
@@ -585,8 +725,8 @@ void LauncherWindow::openProfileEditor(const std::string& profile, bool isUserPr
|
||||
profile,
|
||||
_assetPath,
|
||||
_userAssetPath,
|
||||
_profilePath,
|
||||
saveProfilePath,
|
||||
_readOnlyProfiles,
|
||||
this
|
||||
);
|
||||
editor.exec();
|
||||
@@ -604,18 +744,111 @@ void LauncherWindow::openProfileEditor(const std::string& profile, bool isUserPr
|
||||
}
|
||||
}
|
||||
|
||||
void LauncherWindow::openWindowEditor() {
|
||||
SgctEdit editor(this, _userConfigPath);
|
||||
int ret = editor.exec();
|
||||
if (ret == QDialog::DialogCode::Accepted) {
|
||||
sgct::config::Cluster cluster = editor.cluster();
|
||||
void LauncherWindow::editRefusalDialog(const std::string& title, const std::string& msg,
|
||||
const std::string& detailedText)
|
||||
{
|
||||
QMessageBox msgBox(this);
|
||||
msgBox.setText(QString::fromStdString(msg));
|
||||
msgBox.setWindowTitle(QString::fromStdString(title));
|
||||
msgBox.setDetailedText(QString::fromStdString(detailedText));
|
||||
msgBox.setIcon(QMessageBox::Warning);
|
||||
msgBox.exec();
|
||||
}
|
||||
|
||||
std::filesystem::path savePath = editor.saveFilename();
|
||||
saveWindowConfig(this, savePath, cluster);
|
||||
// Truncate path to convert this back to path relative to _userConfigPath
|
||||
std::string p = savePath.string().substr(_userConfigPath.size());
|
||||
populateWindowConfigsList(p);
|
||||
void LauncherWindow::openWindowEditor(const std::string& winCfg, bool isUserWinCfg) {
|
||||
using namespace sgct;
|
||||
|
||||
std::string saveWindowCfgPath = isUserWinCfg ? _userConfigPath : _configPath;
|
||||
int ret = QDialog::DialogCode::Rejected;
|
||||
config::Cluster preview;
|
||||
if (winCfg.empty()) {
|
||||
SgctEdit editor(this, _userConfigPath);
|
||||
ret = editor.exec();
|
||||
if (ret == QDialog::DialogCode::Accepted) {
|
||||
handleReturnFromWindowEditor(
|
||||
editor.cluster(),
|
||||
editor.saveFilename(),
|
||||
saveWindowCfgPath
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
config::GeneratorVersion previewGenVersion = readConfigGenerator(winCfg);
|
||||
loadFileAndSchemaThenValidate(
|
||||
winCfg,
|
||||
_configPath + "/schema/sgct.schema.json",
|
||||
"This configuration file is unable to generate a proper display"
|
||||
);
|
||||
loadFileAndSchemaThenValidate(
|
||||
winCfg,
|
||||
_configPath + "/schema/sgcteditor.schema.json",
|
||||
"This configuration file is valid for generating a display, but "
|
||||
"its format does not match the window editor requirements and "
|
||||
"cannot be opened in the editor"
|
||||
);
|
||||
if (versionCheck(previewGenVersion)) {
|
||||
try {
|
||||
preview = readConfig(
|
||||
winCfg,
|
||||
"This configuration file is unable to generate a proper display "
|
||||
"due to a problem detected in the readConfig function"
|
||||
);
|
||||
}
|
||||
catch (const std::runtime_error& e) {
|
||||
//Re-throw an SGCT error exception with the runtime exception message
|
||||
throw std::runtime_error(
|
||||
fmt::format(
|
||||
"Importing of this configuration file failed because of a "
|
||||
"problem detected in the readConfig function:\n\n{}", e.what()
|
||||
)
|
||||
);
|
||||
}
|
||||
SgctEdit editor(
|
||||
preview,
|
||||
winCfg,
|
||||
saveWindowCfgPath,
|
||||
this
|
||||
);
|
||||
ret = editor.exec();
|
||||
if (ret == QDialog::DialogCode::Accepted) {
|
||||
handleReturnFromWindowEditor(
|
||||
editor.cluster(),
|
||||
editor.saveFilename(),
|
||||
saveWindowCfgPath
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
editRefusalDialog(
|
||||
"File Format Version Error",
|
||||
fmt::format(
|
||||
"File '{}' does not meet the minimum required version of {}.",
|
||||
winCfg, versionMin.versionString()
|
||||
),
|
||||
""
|
||||
);
|
||||
}
|
||||
}
|
||||
catch (const std::runtime_error& e) {
|
||||
editRefusalDialog(
|
||||
"Format Validation Error",
|
||||
fmt::format("Parsing error found in file '{}'", winCfg),
|
||||
e.what()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LauncherWindow::handleReturnFromWindowEditor(const sgct::config::Cluster& cluster,
|
||||
std::filesystem::path savePath,
|
||||
const std::string& saveWindowCfgPath)
|
||||
{
|
||||
savePath.replace_extension(".json");
|
||||
saveWindowConfig(this, savePath, cluster);
|
||||
// Truncate path to convert this back to path relative to _userConfigPath
|
||||
std::string p = std::filesystem::proximate(savePath, saveWindowCfgPath).string();
|
||||
populateWindowConfigsList(p);
|
||||
}
|
||||
|
||||
bool LauncherWindow::wasLaunchSelected() const {
|
||||
@@ -639,3 +872,8 @@ std::string LauncherWindow::selectedWindowConfig() const {
|
||||
return "${USER_CONFIG}/" + _windowConfigBox->currentText().toStdString();
|
||||
}
|
||||
}
|
||||
|
||||
bool LauncherWindow::isUserConfigSelected() const {
|
||||
int selectedIndex = _windowConfigBox->currentIndex();
|
||||
return (selectedIndex <= _userConfigCount);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -75,62 +75,58 @@ ActionDialog::ActionDialog(QWidget* parent,
|
||||
}
|
||||
|
||||
void ActionDialog::createWidgets() {
|
||||
// Column 0 Column 1 Column 2
|
||||
// *----------------------*---------------*----------------*
|
||||
// | Actions | Row 0
|
||||
// | | Identifier | [oooooooooooo] | Row 1
|
||||
// | | Name | [oooooooooooo] | Row 2
|
||||
// | | GUI Path | [oooooooooooo] | Row 3
|
||||
// | | Documentation | [oooooooooooo] | Row 4
|
||||
// | | Is Local | [] [choosescr] | Row 5
|
||||
// | | Script | [oooooooooooo] | Row 6
|
||||
// *----------------------*---------------*----------------*
|
||||
// | [+] [-] | | <Save> <Cancel>| Row 7
|
||||
// *----------------------*---------------*----------------*
|
||||
// |=======================================================| Row 8
|
||||
// | Keybindings | Row 9
|
||||
// *----------------------*---------------*----------------|
|
||||
// | | Modifier | []S []C []A | Row 10
|
||||
// | | Key | DDDDDDDDDDDD> | Row 11
|
||||
// | | Add actions | DDDDDDDDDDDD> | Row 12
|
||||
// | | Action | [oooooooooooo] | Row 13
|
||||
// *----------------------*---------------*----------------*
|
||||
// | [+] [-] | | <Save> <Cancel>| Row 14
|
||||
// *----------------------*---------------*----------------*
|
||||
// |=======================================================| Row 14
|
||||
// *----------------------*---------------*----------------*
|
||||
// | | <Save> <Cancel>| Row 15
|
||||
// *----------------------*---------------*----------------*
|
||||
// Column 0 Column 1 Column 2 Col3
|
||||
// *----------------------*---------------*----------|------*
|
||||
// | Actions | Row 0
|
||||
// | | Identifier | [oooooo] | Info | Row 1
|
||||
// | | Name | [ooooooooooooo] | Row 2
|
||||
// | | GUI Path | [ooooooooooooo] | Row 3
|
||||
// | | Documentation | [ooooooooooooo] | Row 4
|
||||
// | | Is Local | [] [choosescr] | Row 5
|
||||
// | | Script | [ooooooooooooo] | Row 6
|
||||
// *----------------------*---------------*-----------------*
|
||||
// | [+] [-] | | <Save> <Cancel> | Row 7
|
||||
// *----------------------*---------------*-----------------*
|
||||
// |========================================================| Row 8
|
||||
// | Keybindings | Row 9
|
||||
// *----------------------*---------------*-----------------|
|
||||
// | | Modifier | []S []C []A | Row 10
|
||||
// | | Key | DDDDDDDDDDDD> | Row 11
|
||||
// | | Add actions | DDDDDDDDDDDD> | Row 12
|
||||
// | | Action | [ooooooooooooo] | Row 13
|
||||
// *----------------------*---------------*-----------------*
|
||||
// | [+] [-] | | <Save> <Cancel> | Row 14
|
||||
// *----------------------*---------------*-----------------*
|
||||
// |========================================================| Row 16
|
||||
// *----------------------*---------------*-----------------*
|
||||
// | | <Save> <Cancel> | Row 17
|
||||
// *----------------------*---------------*-----------------*
|
||||
|
||||
QGridLayout* layout = new QGridLayout(this);
|
||||
|
||||
createActionWidgets(layout);
|
||||
clearActionFields();
|
||||
|
||||
layout->addWidget(new Line, 8, 0, 1, 3);
|
||||
layout->addWidget(new Line, 8, 0, 1, 4);
|
||||
|
||||
createKeyboardWidgets(layout);
|
||||
clearKeybindingFields();
|
||||
|
||||
layout->addWidget(new Line, 16, 0, 1, 3);
|
||||
|
||||
QDialogButtonBox* buttonBox = new QDialogButtonBox;
|
||||
buttonBox->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel);
|
||||
layout->addWidget(new Line, 16, 0, 1, 4);
|
||||
|
||||
_mainButton = new QDialogButtonBox;
|
||||
_mainButton->setStandardButtons(QDialogButtonBox::Close);
|
||||
QObject::connect(
|
||||
buttonBox, &QDialogButtonBox::accepted,
|
||||
this, &ActionDialog::applyChanges
|
||||
);
|
||||
QObject::connect(
|
||||
buttonBox, &QDialogButtonBox::rejected,
|
||||
_mainButton, &QDialogButtonBox::rejected,
|
||||
this, &ActionDialog::reject
|
||||
);
|
||||
layout->addWidget(buttonBox, 17, 2, Qt::AlignRight);
|
||||
layout->addWidget(_mainButton, 17, 2, Qt::AlignRight);
|
||||
}
|
||||
|
||||
void ActionDialog::createActionWidgets(QGridLayout* layout) {
|
||||
QLabel* title = new QLabel("Actions");
|
||||
title->setObjectName("heading");
|
||||
layout->addWidget(title, 0, 0, 1, 3);
|
||||
layout->addWidget(title, 0, 0, 1, 4);
|
||||
|
||||
_actionWidgets.list = new QListWidget;
|
||||
_actionWidgets.list->setToolTip(
|
||||
@@ -161,8 +157,31 @@ void ActionDialog::createActionWidgets(QGridLayout* layout) {
|
||||
"separated hierarchical structure is suggested to prevent name clashes"
|
||||
);
|
||||
_actionWidgets.identifier->setEnabled(false);
|
||||
connect(
|
||||
_actionWidgets.identifier, &QLineEdit::textEdited,
|
||||
[this]() {
|
||||
// Check if the identifier is legal
|
||||
std::string identifier = _actionWidgets.identifier->text().toStdString();
|
||||
bool isLegal = identifier.find_first_of("\t\n. ") == std::string::npos;
|
||||
if (isLegal) {
|
||||
_actionWidgets.infoText->clear();
|
||||
_actionWidgets.infoText->setHidden(true);
|
||||
}
|
||||
else {
|
||||
_actionWidgets.infoText->setText(
|
||||
"Identifier must not contain whitespace or ."
|
||||
);
|
||||
_actionWidgets.infoText->setHidden(false);
|
||||
}
|
||||
}
|
||||
);
|
||||
layout->addWidget(_actionWidgets.identifier, 1, 2);
|
||||
|
||||
_actionWidgets.infoText = new QLabel;
|
||||
_actionWidgets.infoText->setHidden(true);
|
||||
_actionWidgets.infoText->setObjectName("error-message");
|
||||
layout->addWidget(_actionWidgets.infoText, 1, 3);
|
||||
|
||||
layout->addWidget(new QLabel("Name"), 2, 1);
|
||||
_actionWidgets.name = new QLineEdit;
|
||||
_actionWidgets.name->setToolTip(
|
||||
@@ -170,7 +189,7 @@ void ActionDialog::createActionWidgets(QGridLayout* layout) {
|
||||
"name should be as concise and informative as possible"
|
||||
);
|
||||
_actionWidgets.name->setEnabled(false);
|
||||
layout->addWidget(_actionWidgets.name, 2, 2);
|
||||
layout->addWidget(_actionWidgets.name, 2, 2, 1, 2);
|
||||
|
||||
layout->addWidget(new QLabel("GUI Path"), 3, 1);
|
||||
_actionWidgets.guiPath = new QLineEdit;
|
||||
@@ -180,7 +199,7 @@ void ActionDialog::createActionWidgets(QGridLayout* layout) {
|
||||
"character that denotes the root folder"
|
||||
);
|
||||
_actionWidgets.guiPath->setEnabled(false);
|
||||
layout->addWidget(_actionWidgets.guiPath, 3, 2);
|
||||
layout->addWidget(_actionWidgets.guiPath, 3, 2, 1, 2);
|
||||
|
||||
layout->addWidget(new QLabel("Documentation"), 4, 1);
|
||||
_actionWidgets.documentation = new QLineEdit;
|
||||
@@ -191,7 +210,7 @@ void ActionDialog::createActionWidgets(QGridLayout* layout) {
|
||||
"parameters that that action can consume"
|
||||
);
|
||||
_actionWidgets.documentation->setEnabled(false);
|
||||
layout->addWidget(_actionWidgets.documentation, 4, 2);
|
||||
layout->addWidget(_actionWidgets.documentation, 4, 2, 1, 2);
|
||||
|
||||
layout->addWidget(new QLabel("Is Local"), 5, 1);
|
||||
_actionWidgets.isLocal = new QCheckBox;
|
||||
@@ -204,7 +223,7 @@ void ActionDialog::createActionWidgets(QGridLayout* layout) {
|
||||
"instances as well"
|
||||
);
|
||||
_actionWidgets.isLocal->setEnabled(false);
|
||||
layout->addWidget(_actionWidgets.isLocal, 5, 2);
|
||||
layout->addWidget(_actionWidgets.isLocal, 5, 2, 1, 2);
|
||||
|
||||
_actionWidgets.chooseScripts = new QPushButton("Choose Scripts");
|
||||
_actionWidgets.chooseScripts->setToolTip(
|
||||
@@ -215,7 +234,7 @@ void ActionDialog::createActionWidgets(QGridLayout* layout) {
|
||||
this, &ActionDialog::chooseScripts
|
||||
);
|
||||
_actionWidgets.chooseScripts->setEnabled(false);
|
||||
layout->addWidget(_actionWidgets.chooseScripts, 5, 2, Qt::AlignRight);
|
||||
layout->addWidget(_actionWidgets.chooseScripts, 5, 2, 1, 2, Qt::AlignRight);
|
||||
|
||||
layout->addWidget(new QLabel("Script"), 6, 1);
|
||||
_actionWidgets.script = new QTextEdit;
|
||||
@@ -226,7 +245,7 @@ void ActionDialog::createActionWidgets(QGridLayout* layout) {
|
||||
"variable does not exist"
|
||||
);
|
||||
_actionWidgets.script->setEnabled(false);
|
||||
layout->addWidget(_actionWidgets.script, 6, 2);
|
||||
layout->addWidget(_actionWidgets.script, 6, 2, 1, 2);
|
||||
|
||||
|
||||
// + / - buttons
|
||||
@@ -270,13 +289,13 @@ void ActionDialog::createActionWidgets(QGridLayout* layout) {
|
||||
_actionWidgets.saveButtons, &QDialogButtonBox::rejected,
|
||||
this, &ActionDialog::actionRejected
|
||||
);
|
||||
layout->addWidget(_actionWidgets.saveButtons, 7, 2, Qt::AlignRight);
|
||||
layout->addWidget(_actionWidgets.saveButtons, 7, 2, 1, 2, Qt::AlignRight);
|
||||
}
|
||||
|
||||
void ActionDialog::createKeyboardWidgets(QGridLayout* layout) {
|
||||
QLabel* title = new QLabel("Keybindings");
|
||||
title->setObjectName("heading");
|
||||
layout->addWidget(title);
|
||||
layout->addWidget(title, 9, 0, 1, 4);
|
||||
|
||||
_keybindingWidgets.list = new QListWidget;
|
||||
_keybindingWidgets.list->setToolTip(
|
||||
@@ -311,7 +330,7 @@ void ActionDialog::createKeyboardWidgets(QGridLayout* layout) {
|
||||
_keybindingWidgets.altModifier = new QCheckBox("Alt");
|
||||
_keybindingWidgets.altModifier->setEnabled(false);
|
||||
containerLayout->addWidget(_keybindingWidgets.altModifier);
|
||||
layout->addWidget(container, 10, 2);
|
||||
layout->addWidget(container, 10, 2, 1, 2);
|
||||
}
|
||||
|
||||
layout->addWidget(new QLabel("Key"), 11, 1);
|
||||
@@ -342,7 +361,7 @@ void ActionDialog::createKeyboardWidgets(QGridLayout* layout) {
|
||||
);
|
||||
}
|
||||
);
|
||||
layout->addWidget(_keybindingWidgets.key, 11, 2);
|
||||
layout->addWidget(_keybindingWidgets.key, 11, 2, 1, 2);
|
||||
|
||||
layout->addWidget(new QLabel("Action chooser"), 12, 1);
|
||||
_keybindingWidgets.action = new QComboBox;
|
||||
@@ -361,7 +380,7 @@ void ActionDialog::createKeyboardWidgets(QGridLayout* layout) {
|
||||
);
|
||||
|
||||
_keybindingWidgets.action->setEnabled(false);
|
||||
layout->addWidget(_keybindingWidgets.action, 12, 2);
|
||||
layout->addWidget(_keybindingWidgets.action, 12, 2, 1, 2);
|
||||
|
||||
layout->addWidget(new QLabel("Action"), 13, 1);
|
||||
_keybindingWidgets.actionText = new QLineEdit;
|
||||
@@ -373,10 +392,10 @@ void ActionDialog::createKeyboardWidgets(QGridLayout* layout) {
|
||||
"it is defined in an asset included in this profile, you can enter the "
|
||||
"identifier of that action manually here to associate a key with it. If the "
|
||||
"identifer does not exist, an error will be logged when trying to bind the key "
|
||||
"at startup."
|
||||
"at startup"
|
||||
);
|
||||
_keybindingWidgets.actionText->setEnabled(false);
|
||||
layout->addWidget(_keybindingWidgets.actionText, 13, 2);
|
||||
layout->addWidget(_keybindingWidgets.actionText, 13, 2, 1, 2);
|
||||
|
||||
|
||||
// +/- buttons
|
||||
@@ -424,13 +443,7 @@ void ActionDialog::createKeyboardWidgets(QGridLayout* layout) {
|
||||
this, &ActionDialog::keybindingRejected
|
||||
);
|
||||
|
||||
layout->addWidget(_keybindingWidgets.saveButtons, 14, 2, Qt::AlignRight);
|
||||
}
|
||||
|
||||
void ActionDialog::applyChanges() {
|
||||
*_actions = std::move(_actionData);
|
||||
*_keybindings = std::move(_keybindingsData);
|
||||
accept();
|
||||
layout->addWidget(_keybindingWidgets.saveButtons, 14, 2, 1, 2, Qt::AlignRight);
|
||||
}
|
||||
|
||||
Profile::Action* ActionDialog::selectedAction() {
|
||||
@@ -476,6 +489,10 @@ void ActionDialog::actionRemove() {
|
||||
_keybindingsData.erase(_keybindingsData.begin() + i);
|
||||
delete _keybindingWidgets.list->takeItem(static_cast<int>(i));
|
||||
i--;
|
||||
//Save the updated keybindings to the profile
|
||||
if (_keybindings) {
|
||||
*_keybindings = _keybindingsData;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// If the user chooses 'No' at least once, we have to bail
|
||||
@@ -494,6 +511,10 @@ void ActionDialog::actionRemove() {
|
||||
_keybindingWidgets.action->addItem(QString::fromStdString(a.identifier));
|
||||
}
|
||||
clearKeybindingFields();
|
||||
//Save the updated actions to the profile
|
||||
if (_actions) {
|
||||
*_actions = _actionData;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -523,12 +544,21 @@ void ActionDialog::actionSelected() {
|
||||
_actionWidgets.addButton->setEnabled(false);
|
||||
_actionWidgets.removeButton->setEnabled(true);
|
||||
_actionWidgets.saveButtons->setEnabled(true);
|
||||
if (_mainButton) {
|
||||
_mainButton->setEnabled(false);
|
||||
}
|
||||
_actionWidgets.list->setEnabled(false);
|
||||
}
|
||||
else {
|
||||
// No action selected
|
||||
_actionWidgets.addButton->setEnabled(true);
|
||||
_actionWidgets.removeButton->setEnabled(false);
|
||||
_actionWidgets.saveButtons->setEnabled(false);
|
||||
//Keybinding panel must also be in valid state to re-enable main start button
|
||||
if (_mainButton && !_keybindingWidgets.saveButtons->isEnabled()) {
|
||||
_mainButton->setEnabled(true);
|
||||
}
|
||||
_actionWidgets.list->setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -557,7 +587,7 @@ void ActionDialog::actionSaved() {
|
||||
this,
|
||||
"Duplicate identifier",
|
||||
"The chosen identifier was already used in another action. Identifiers "
|
||||
"have to be unique. Please choose a different identfier."
|
||||
"have to be unique. Please choose a different identfier"
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -587,7 +617,11 @@ void ActionDialog::actionSaved() {
|
||||
|
||||
|
||||
action->name = _actionWidgets.name->text().toStdString();
|
||||
action->guiPath = _actionWidgets.guiPath->text().toStdString();
|
||||
std::string guiPath = _actionWidgets.guiPath->text().toStdString();
|
||||
if (!guiPath.starts_with('/')) {
|
||||
guiPath = "/" + guiPath;
|
||||
}
|
||||
action->guiPath = guiPath;
|
||||
action->documentation = _actionWidgets.documentation->text().toStdString();
|
||||
action->isLocal = _actionWidgets.isLocal->isChecked();
|
||||
action->script = _actionWidgets.script->toPlainText().toStdString();
|
||||
@@ -599,6 +633,10 @@ void ActionDialog::actionSaved() {
|
||||
for (const Profile::Action& a : _actionData) {
|
||||
_keybindingWidgets.action->addItem(QString::fromStdString(a.identifier));
|
||||
}
|
||||
//Save the updated actions to the profile
|
||||
if (_actions) {
|
||||
*_actions = _actionData;
|
||||
}
|
||||
clearKeybindingFields();
|
||||
clearActionFields();
|
||||
}
|
||||
@@ -607,6 +645,8 @@ void ActionDialog::clearActionFields() {
|
||||
_actionWidgets.list->setCurrentRow(-1);
|
||||
_actionWidgets.identifier->clear();
|
||||
_actionWidgets.identifier->setEnabled(false);
|
||||
_actionWidgets.infoText->clear();
|
||||
_actionWidgets.infoText->setHidden(true);
|
||||
_actionWidgets.name->clear();
|
||||
_actionWidgets.name->setEnabled(false);
|
||||
_actionWidgets.guiPath->clear();
|
||||
@@ -619,6 +659,7 @@ void ActionDialog::clearActionFields() {
|
||||
_actionWidgets.script->clear();
|
||||
_actionWidgets.script->setEnabled(false);
|
||||
_actionWidgets.saveButtons->setEnabled(false);
|
||||
_actionWidgets.list->setEnabled(true);
|
||||
}
|
||||
|
||||
void ActionDialog::actionRejected() {
|
||||
@@ -633,12 +674,17 @@ void ActionDialog::actionRejected() {
|
||||
|
||||
void ActionDialog::chooseScripts() {
|
||||
ScriptlogDialog d(this);
|
||||
connect(&d, &ScriptlogDialog::scriptsSelected, this, &ActionDialog::appendScriptsToTextfield);
|
||||
connect(
|
||||
&d, &ScriptlogDialog::scriptsSelected,
|
||||
this, &ActionDialog::appendScriptsToTextfield
|
||||
);
|
||||
d.exec();
|
||||
}
|
||||
|
||||
void ActionDialog::appendScriptsToTextfield(std::string scripts) {
|
||||
_actionWidgets.script->append(QString::fromStdString(std::move(scripts)));
|
||||
void ActionDialog::appendScriptsToTextfield(std::vector<std::string> scripts) {
|
||||
for (std::string script : scripts) {
|
||||
_actionWidgets.script->append(QString::fromStdString(std::move(script)));
|
||||
}
|
||||
}
|
||||
|
||||
Profile::Keybinding* ActionDialog::selectedKeybinding() {
|
||||
@@ -664,6 +710,10 @@ void ActionDialog::keybindingRemove() {
|
||||
clearKeybindingFields();
|
||||
_keybindingsData.erase(_keybindingsData.begin() + i);
|
||||
delete _keybindingWidgets.list->takeItem(static_cast<int>(i));
|
||||
//Save the updated keybindings to the profile
|
||||
if (_keybindings) {
|
||||
*_keybindings = _keybindingsData;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -705,12 +755,21 @@ void ActionDialog::keybindingSelected() {
|
||||
_keybindingWidgets.saveButtons->button(QDialogButtonBox::Save)->setEnabled(
|
||||
_keybindingWidgets.key->currentIndex() > 0
|
||||
);
|
||||
if (_mainButton) {
|
||||
_mainButton->setEnabled(false);
|
||||
}
|
||||
_keybindingWidgets.list->setEnabled(false);
|
||||
}
|
||||
else {
|
||||
// No keybinding selected
|
||||
_keybindingWidgets.addButton->setEnabled(true);
|
||||
_keybindingWidgets.removeButton->setEnabled(false);
|
||||
_keybindingWidgets.saveButtons->setEnabled(false);
|
||||
//Action panel must also be in valid state to re-enable main start button
|
||||
if (_mainButton && !_actionWidgets.saveButtons->isEnabled()) {
|
||||
_mainButton->setEnabled(true);
|
||||
}
|
||||
_keybindingWidgets.list->setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -719,6 +778,16 @@ void ActionDialog::keybindingActionSelected(int) {
|
||||
}
|
||||
|
||||
void ActionDialog::keybindingSaved() {
|
||||
if (_keybindingWidgets.key->currentIndex() == -1) {
|
||||
QMessageBox::critical(this, "Missing key", "Key must have an assignment");
|
||||
return;
|
||||
}
|
||||
//A selection can be made from the combo box without typing text, but selecting from
|
||||
//the combo will fill the text, so using the text box as criteria covers both cases.
|
||||
if (_keybindingWidgets.actionText->text().isEmpty()) {
|
||||
QMessageBox::critical(this, "Missing action", "Key action must not be empty");
|
||||
return;
|
||||
}
|
||||
Profile::Keybinding* keybinding = selectedKeybinding();
|
||||
ghoul_assert(keybinding, "There must be a selected keybinding at this point");
|
||||
|
||||
@@ -738,6 +807,10 @@ void ActionDialog::keybindingSaved() {
|
||||
keybinding->action = _keybindingWidgets.actionText->text().toStdString();
|
||||
|
||||
updateListItem(_keybindingWidgets.list->currentItem(), *keybinding);
|
||||
//Save the updated keybindings to the profile
|
||||
if (_keybindings) {
|
||||
*_keybindings = _keybindingsData;
|
||||
}
|
||||
clearKeybindingFields();
|
||||
}
|
||||
|
||||
@@ -755,8 +828,15 @@ void ActionDialog::clearKeybindingFields() {
|
||||
_keybindingWidgets.action->setEnabled(false);
|
||||
_keybindingWidgets.actionText->clear();
|
||||
_keybindingWidgets.actionText->setEnabled(false);
|
||||
_keybindingWidgets.list->setEnabled(true);
|
||||
}
|
||||
|
||||
void ActionDialog::keybindingRejected() {
|
||||
bool isKeyEmpty = (_keybindingsData.back().key.key == Key::Unknown);
|
||||
bool isActionEmpty = _keybindingsData.back().action.empty();
|
||||
if (isKeyEmpty || isActionEmpty) {
|
||||
delete _keybindingWidgets.list->takeItem(_keybindingWidgets.list->count() - 1);
|
||||
_keybindingsData.erase(_keybindingsData.begin() + _keybindingsData.size() - 1);
|
||||
}
|
||||
clearKeybindingFields();
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -109,6 +109,8 @@ void AdditionalScriptsDialog::chooseScripts() {
|
||||
d.exec();
|
||||
}
|
||||
|
||||
void AdditionalScriptsDialog::appendScriptsToTextfield(std::string scripts) {
|
||||
_textScripts->append(QString::fromStdString(std::move(scripts)));
|
||||
void AdditionalScriptsDialog::appendScriptsToTextfield(std::vector<std::string> scripts) {
|
||||
for (std::string script : scripts) {
|
||||
_textScripts->append(QString::fromStdString(std::move(script)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -158,7 +158,7 @@ AssetsDialog::AssetsDialog(QWidget* parent, openspace::Profile* profile,
|
||||
_assetTree->setToolTip(
|
||||
"Expand arrow entries to browse assets in this OpenSpace installation. "
|
||||
"Enable checkbox to include an asset. Those assets highlighted in red are "
|
||||
"present in the profile but do not exist in this OpenSpace installation."
|
||||
"present in the profile but do not exist in this OpenSpace installation"
|
||||
);
|
||||
_assetTree->setAlternatingRowColors(true);
|
||||
_assetTree->setModel(&_assetTreeModel);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -29,8 +29,8 @@
|
||||
#include <QColor>
|
||||
|
||||
namespace {
|
||||
constexpr const char* Header1 = "Asset";
|
||||
constexpr const char* Header2 = "Enabled";
|
||||
constexpr std::string_view Header1 = "Asset";
|
||||
constexpr std::string_view Header2 = "Enabled";
|
||||
|
||||
struct ImportElement {
|
||||
std::string line;
|
||||
@@ -140,8 +140,8 @@ AssetTreeModel::AssetTreeModel(QObject* parent)
|
||||
{
|
||||
_rootItem = std::make_unique<AssetTreeItem>(
|
||||
std::vector<QVariant> {
|
||||
QString::fromStdString(Header1),
|
||||
QString::fromStdString(Header2)
|
||||
QString::fromStdString(std::string(Header1)),
|
||||
QString::fromStdString(std::string(Header2))
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -156,7 +156,10 @@ void AssetTreeModel::importModelData(const std::string& assetBasePath,
|
||||
std::string assetList = assets.useQtFileSystemModelToTraverseDir(assetBasePath);
|
||||
assetList += assets.useQtFileSystemModelToTraverseDir(userAssetBasePath, true);
|
||||
std::istringstream iss(assetList);
|
||||
ImportElement rootElem = { "", 0, false };
|
||||
ImportElement rootElem = {
|
||||
.line = "",
|
||||
.level = 0,
|
||||
};
|
||||
|
||||
if (importGetNextLine(rootElem, iss)) {
|
||||
importInsertItem(iss, _rootItem.get(), rootElem, 0);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -29,14 +29,16 @@
|
||||
#include <QDoubleValidator>
|
||||
#include <QFrame>
|
||||
#include <QGridLayout>
|
||||
#include <QKeyEvent>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QKeyEvent>
|
||||
#include <QTabWidget>
|
||||
#include <QTabWidget>
|
||||
#include <QPlainTextEdit>
|
||||
|
||||
namespace {
|
||||
constexpr const int CameraTypeNav = 0;
|
||||
constexpr const int CameraTypeGeo = 1;
|
||||
constexpr int CameraTypeNode = 0;
|
||||
constexpr int CameraTypeNav = 1;
|
||||
constexpr int CameraTypeGeo = 2;
|
||||
|
||||
template <class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
|
||||
template <class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
|
||||
@@ -53,6 +55,19 @@ namespace {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isNumericalLargerThan(QLineEdit* le, float limit) {
|
||||
QString s = le->text();
|
||||
bool validConversion = false;
|
||||
float value = s.toFloat(&validConversion);
|
||||
if (!validConversion) {
|
||||
return false;
|
||||
}
|
||||
if (value > limit) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
CameraDialog::CameraDialog(QWidget* parent,
|
||||
@@ -66,6 +81,14 @@ CameraDialog::CameraDialog(QWidget* parent,
|
||||
if (_camera->has_value()) {
|
||||
const openspace::Profile::CameraType& type = **_camera;
|
||||
std::visit(overloaded {
|
||||
[this](const openspace::Profile::CameraGoToNode& node) {
|
||||
_tabWidget->setCurrentIndex(CameraTypeNode);
|
||||
_nodeState.anchor->setText(QString::fromStdString(node.anchor));
|
||||
if (node.height.has_value()) {
|
||||
_nodeState.height->setText(QString::number(*node.height, 'g', 17));
|
||||
}
|
||||
tabSelect(CameraTypeNode);
|
||||
},
|
||||
[this](const openspace::Profile::CameraNavState& nav) {
|
||||
_tabWidget->setCurrentIndex(CameraTypeNav);
|
||||
_navState.anchor->setText(QString::fromStdString(nav.anchor));
|
||||
@@ -114,7 +137,11 @@ CameraDialog::CameraDialog(QWidget* parent,
|
||||
}, type);
|
||||
}
|
||||
else {
|
||||
_tabWidget->setCurrentIndex(CameraTypeNav);
|
||||
_tabWidget->setCurrentIndex(CameraTypeNode);
|
||||
|
||||
_nodeState.anchor->clear();
|
||||
_nodeState.height->clear();
|
||||
|
||||
_navState.anchor->clear();
|
||||
_navState.aim->clear();
|
||||
_navState.refFrame->clear();
|
||||
@@ -138,6 +165,7 @@ void CameraDialog::createWidgets() {
|
||||
QBoxLayout* layout = new QVBoxLayout(this);
|
||||
_tabWidget = new QTabWidget;
|
||||
connect(_tabWidget, &QTabWidget::tabBarClicked, this, &CameraDialog::tabSelect);
|
||||
_tabWidget->addTab(createNodeWidget(), "Scene Graph Node");
|
||||
_tabWidget->addTab(createNavStateWidget(), "Navigation State");
|
||||
_tabWidget->addTab(createGeoWidget(), "Geo State");
|
||||
layout->addWidget(_tabWidget);
|
||||
@@ -162,135 +190,235 @@ void CameraDialog::createWidgets() {
|
||||
}
|
||||
}
|
||||
|
||||
QWidget* CameraDialog::createNavStateWidget() {
|
||||
QWidget* box = new QWidget;
|
||||
QGridLayout* layout = new QGridLayout(box);
|
||||
QWidget* CameraDialog::createNodeWidget() {
|
||||
QWidget* tab = new QWidget;
|
||||
QVBoxLayout* mainLayout = new QVBoxLayout(tab);
|
||||
|
||||
layout->addWidget(new QLabel("Anchor:"), 0, 0);
|
||||
_navState.anchor = new QLineEdit;
|
||||
_navState.anchor->setToolTip("Anchor camera to this node");
|
||||
layout->addWidget(_navState.anchor, 0, 1);
|
||||
|
||||
layout->addWidget(new QLabel("Aim:"), 1, 0);
|
||||
_navState.aim = new QLineEdit;
|
||||
_navState.aim->setToolTip(
|
||||
"If specified, camera will be aimed at this node while keeping the anchor node "
|
||||
"in the same view location"
|
||||
QLabel* description = new QLabel;
|
||||
description->setWordWrap(true);
|
||||
description->setAlignment(Qt::AlignCenter);
|
||||
description->setObjectName("camera-description");
|
||||
description->setText(
|
||||
"Set the camera position based on a given scene graph node. \n \n "
|
||||
"Automatically computes a position that frames the object, and if possible, "
|
||||
"shows it from Sun-lit side. The exact position might change between start-ups."
|
||||
);
|
||||
_navState.aim->setPlaceholderText("optional");
|
||||
layout->addWidget(_navState.aim, 1, 1);
|
||||
|
||||
layout->addWidget(new QLabel("Reference Frame:"), 2, 0);
|
||||
_navState.refFrame = new QLineEdit;
|
||||
_navState.refFrame->setToolTip("Camera location in reference to this frame");
|
||||
_navState.refFrame->setPlaceholderText("optional");
|
||||
layout->addWidget(_navState.refFrame, 2, 1);
|
||||
mainLayout->addWidget(description);
|
||||
|
||||
layout->addWidget(new QLabel("Position:"), 3, 0);
|
||||
{
|
||||
QWidget* posBox = new QWidget;
|
||||
QBoxLayout* posLayout = new QHBoxLayout(posBox);
|
||||
posLayout->setContentsMargins(0, 0, 0, 0);
|
||||
posLayout->addWidget(new QLabel("X [m]"));
|
||||
_navState.positionX = new QLineEdit;
|
||||
_navState.positionX->setValidator(new QDoubleValidator);
|
||||
_navState.positionX->setToolTip("Camera position vector (x) [m]");
|
||||
posLayout->addWidget(_navState.positionX);
|
||||
QWidget* box = new QWidget;
|
||||
QGridLayout* layout = new QGridLayout(box);
|
||||
|
||||
posLayout->addWidget(new QLabel("Y [m]"));
|
||||
_navState.positionY = new QLineEdit;
|
||||
_navState.positionY->setValidator(new QDoubleValidator);
|
||||
_navState.positionY->setToolTip("Camera position vector (y) [m]");
|
||||
posLayout->addWidget(_navState.positionY);
|
||||
layout->addWidget(new QLabel("Anchor Node:"), 0, 0);
|
||||
_nodeState.anchor = new QLineEdit;
|
||||
_nodeState.anchor->setToolTip("Anchor camera to this scene graph node");
|
||||
layout->addWidget(_nodeState.anchor, 0, 1);
|
||||
|
||||
posLayout->addWidget(new QLabel("Z [m]"));
|
||||
_navState.positionZ = new QLineEdit;
|
||||
_navState.positionZ->setValidator(new QDoubleValidator);
|
||||
_navState.positionZ->setToolTip("Camera position vector (z) [m]");
|
||||
posLayout->addWidget(_navState.positionZ);
|
||||
layout->addWidget(posBox, 3, 1);
|
||||
layout->addWidget(new QLabel("Height [m]:"), 1, 0);
|
||||
_nodeState.height = new QLineEdit;
|
||||
_nodeState.height->setValidator(new QDoubleValidator);
|
||||
_nodeState.height->setToolTip(
|
||||
"If specified, the camera will placed at the given height away from object. "
|
||||
"The height is computed from the bounding sphere of the anchor node"
|
||||
);
|
||||
_nodeState.height->setPlaceholderText("optional");
|
||||
layout->addWidget(_nodeState.height, 1, 1);
|
||||
|
||||
mainLayout->addWidget(box);
|
||||
}
|
||||
|
||||
layout->addWidget(new QLabel("Up:"), 4, 0);
|
||||
// Add spacer at the end to prevent previous components from growing as much
|
||||
mainLayout->addSpacerItem(
|
||||
new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding)
|
||||
);
|
||||
|
||||
return tab;
|
||||
}
|
||||
|
||||
QWidget* CameraDialog::createNavStateWidget() {
|
||||
QWidget* tab = new QWidget;
|
||||
QVBoxLayout* mainLayout = new QVBoxLayout(tab);
|
||||
|
||||
QLabel* description = new QLabel;
|
||||
description->setWordWrap(true);
|
||||
description->setAlignment(Qt::AlignCenter);
|
||||
description->setObjectName("camera-description");
|
||||
description->setText(
|
||||
"Set the camera position from a navigation state. \n"
|
||||
"Allows for setting an exact view or camera position at start-up."
|
||||
);
|
||||
|
||||
mainLayout->addWidget(description);
|
||||
|
||||
{
|
||||
QWidget* upBox = new QWidget;
|
||||
QBoxLayout* upLayout = new QHBoxLayout(upBox);
|
||||
upLayout->setContentsMargins(0, 0, 0, 0);
|
||||
upLayout->addWidget(new QLabel("X"));
|
||||
_navState.upX = new QLineEdit;
|
||||
_navState.upX->setValidator(new QDoubleValidator);
|
||||
_navState.upX->setToolTip("Camera up vector (x)");
|
||||
_navState.upX->setPlaceholderText("semioptional");
|
||||
upLayout->addWidget(_navState.upX);
|
||||
QWidget* box = new QWidget;
|
||||
QGridLayout* layout = new QGridLayout(box);
|
||||
|
||||
upLayout->addWidget(new QLabel("Y"));
|
||||
_navState.upY = new QLineEdit;
|
||||
_navState.upY->setValidator(new QDoubleValidator);
|
||||
_navState.upY->setToolTip("Camera up vector (y)");
|
||||
_navState.upY->setPlaceholderText("semioptional");
|
||||
upLayout->addWidget(_navState.upY);
|
||||
layout->addWidget(new QLabel("Anchor:"), 0, 0);
|
||||
_navState.anchor = new QLineEdit;
|
||||
_navState.anchor->setToolTip("Anchor camera to this node");
|
||||
layout->addWidget(_navState.anchor, 0, 1);
|
||||
|
||||
upLayout->addWidget(new QLabel("Z"));
|
||||
_navState.upZ = new QLineEdit;
|
||||
_navState.upZ->setValidator(new QDoubleValidator);
|
||||
_navState.upZ->setToolTip("Camera up vector (z)");
|
||||
_navState.upZ->setPlaceholderText("semioptional");
|
||||
upLayout->addWidget(_navState.upZ);
|
||||
layout->addWidget(upBox, 4, 1);
|
||||
layout->addWidget(new QLabel("Aim:"), 1, 0);
|
||||
_navState.aim = new QLineEdit;
|
||||
_navState.aim->setToolTip(
|
||||
"If specified, camera will be aimed at this node while keeping the anchor node "
|
||||
"in the same view location"
|
||||
);
|
||||
_navState.aim->setPlaceholderText("optional");
|
||||
layout->addWidget(_navState.aim, 1, 1);
|
||||
|
||||
layout->addWidget(new QLabel("Reference Frame:"), 2, 0);
|
||||
_navState.refFrame = new QLineEdit;
|
||||
_navState.refFrame->setToolTip("Camera location in reference to this frame");
|
||||
_navState.refFrame->setPlaceholderText("optional");
|
||||
layout->addWidget(_navState.refFrame, 2, 1);
|
||||
|
||||
layout->addWidget(new QLabel("Position:"), 3, 0);
|
||||
{
|
||||
QWidget* posBox = new QWidget;
|
||||
QBoxLayout* posLayout = new QHBoxLayout(posBox);
|
||||
posLayout->setContentsMargins(0, 0, 0, 0);
|
||||
posLayout->addWidget(new QLabel("X [m]"));
|
||||
_navState.positionX = new QLineEdit;
|
||||
_navState.positionX->setValidator(new QDoubleValidator);
|
||||
_navState.positionX->setToolTip("Camera position vector (x) [m]");
|
||||
posLayout->addWidget(_navState.positionX);
|
||||
|
||||
posLayout->addWidget(new QLabel("Y [m]"));
|
||||
_navState.positionY = new QLineEdit;
|
||||
_navState.positionY->setValidator(new QDoubleValidator);
|
||||
_navState.positionY->setToolTip("Camera position vector (y) [m]");
|
||||
posLayout->addWidget(_navState.positionY);
|
||||
|
||||
posLayout->addWidget(new QLabel("Z [m]"));
|
||||
_navState.positionZ = new QLineEdit;
|
||||
_navState.positionZ->setValidator(new QDoubleValidator);
|
||||
_navState.positionZ->setToolTip("Camera position vector (z) [m]");
|
||||
posLayout->addWidget(_navState.positionZ);
|
||||
layout->addWidget(posBox, 3, 1);
|
||||
}
|
||||
|
||||
layout->addWidget(new QLabel("Up:"), 4, 0);
|
||||
{
|
||||
QWidget* upBox = new QWidget;
|
||||
QBoxLayout* upLayout = new QHBoxLayout(upBox);
|
||||
upLayout->setContentsMargins(0, 0, 0, 0);
|
||||
upLayout->addWidget(new QLabel("X"));
|
||||
_navState.upX = new QLineEdit;
|
||||
_navState.upX->setValidator(new QDoubleValidator);
|
||||
_navState.upX->setToolTip("Camera up vector (x)");
|
||||
_navState.upX->setPlaceholderText("semioptional");
|
||||
upLayout->addWidget(_navState.upX);
|
||||
|
||||
upLayout->addWidget(new QLabel("Y"));
|
||||
_navState.upY = new QLineEdit;
|
||||
_navState.upY->setValidator(new QDoubleValidator);
|
||||
_navState.upY->setToolTip("Camera up vector (y)");
|
||||
_navState.upY->setPlaceholderText("semioptional");
|
||||
upLayout->addWidget(_navState.upY);
|
||||
|
||||
upLayout->addWidget(new QLabel("Z"));
|
||||
_navState.upZ = new QLineEdit;
|
||||
_navState.upZ->setValidator(new QDoubleValidator);
|
||||
_navState.upZ->setToolTip("Camera up vector (z)");
|
||||
_navState.upZ->setPlaceholderText("semioptional");
|
||||
upLayout->addWidget(_navState.upZ);
|
||||
layout->addWidget(upBox, 4, 1);
|
||||
}
|
||||
|
||||
layout->addWidget(new QLabel("Yaw angle:"), 5, 0);
|
||||
_navState.yaw = new QLineEdit;
|
||||
_navState.yaw->setValidator(new QDoubleValidator);
|
||||
_navState.yaw->setToolTip("Yaw angle +/- 360 degrees");
|
||||
_navState.yaw->setPlaceholderText("optional");
|
||||
layout->addWidget(_navState.yaw, 5, 1);
|
||||
|
||||
layout->addWidget(new QLabel("Pitch angle:"), 6, 0);
|
||||
_navState.pitch = new QLineEdit;
|
||||
_navState.pitch->setValidator(new QDoubleValidator);
|
||||
_navState.pitch->setToolTip("Pitch angle +/- 360 degrees");
|
||||
_navState.pitch->setPlaceholderText("optional");
|
||||
layout->addWidget(_navState.pitch, 6, 1);
|
||||
|
||||
mainLayout->addWidget(box);
|
||||
}
|
||||
|
||||
layout->addWidget(new QLabel("Yaw angle:"), 5, 0);
|
||||
_navState.yaw = new QLineEdit;
|
||||
_navState.yaw->setValidator(new QDoubleValidator);
|
||||
_navState.yaw->setToolTip("Yaw angle +/- 360 degrees");
|
||||
_navState.yaw->setPlaceholderText("optional");
|
||||
layout->addWidget(_navState.yaw, 5, 1);
|
||||
|
||||
layout->addWidget(new QLabel("Pitch angle:"), 6, 0);
|
||||
_navState.pitch = new QLineEdit;
|
||||
_navState.pitch->setValidator(new QDoubleValidator);
|
||||
_navState.pitch->setToolTip("Pitch angle +/- 360 degrees");
|
||||
_navState.pitch->setPlaceholderText("optional");
|
||||
layout->addWidget(_navState.pitch, 6, 1);
|
||||
|
||||
return box;
|
||||
return tab;
|
||||
}
|
||||
|
||||
QWidget* CameraDialog::createGeoWidget() {
|
||||
QWidget* box = new QWidget;
|
||||
QGridLayout* layout = new QGridLayout(box);
|
||||
QWidget* tab = new QWidget;
|
||||
QVBoxLayout* mainLayout = new QVBoxLayout(tab);
|
||||
|
||||
layout->addWidget(new QLabel("Anchor:"), 0, 0);
|
||||
_geoState.anchor = new QLineEdit;
|
||||
_geoState.anchor->setToolTip("Anchor camera to this globe (planet/moon)");
|
||||
layout->addWidget(_geoState.anchor, 0, 1);
|
||||
QLabel* description = new QLabel;
|
||||
description->setWordWrap(true);
|
||||
description->setAlignment(Qt::AlignCenter);
|
||||
description->setObjectName("camera-description");
|
||||
description->setText(
|
||||
"Sets the camera position from a geodetic position of a globe (e.g a planet/moon)."
|
||||
);
|
||||
|
||||
layout->addWidget(new QLabel("Latitude"), 1, 0);
|
||||
_geoState.latitude = new QLineEdit;
|
||||
_geoState.latitude->setValidator(new QDoubleValidator);
|
||||
_geoState.latitude->setToolTip("Latitude of camera focus point (+/- 90 degrees)");
|
||||
layout->addWidget(_geoState.latitude, 1, 1);
|
||||
mainLayout->addWidget(description);
|
||||
|
||||
layout->addWidget(new QLabel("Longitude"), 2, 0);
|
||||
_geoState.longitude = new QLineEdit;
|
||||
_geoState.longitude->setValidator(new QDoubleValidator);
|
||||
_geoState.longitude->setToolTip("Longitude of camera focus point (+/- 180 degrees)");
|
||||
layout->addWidget(_geoState.longitude, 2, 1);
|
||||
{
|
||||
|
||||
layout->addWidget(new QLabel("Altitude [m]"), 3, 0);
|
||||
_geoState.altitude = new QLineEdit;
|
||||
_geoState.altitude->setValidator(new QDoubleValidator);
|
||||
_geoState.altitude->setToolTip("Altitude of camera (meters)");
|
||||
_geoState.altitude->setPlaceholderText("optional");
|
||||
layout->addWidget(_geoState.altitude, 3, 1);
|
||||
QWidget* box = new QWidget;
|
||||
QGridLayout* layout = new QGridLayout(box);
|
||||
|
||||
return box;
|
||||
layout->addWidget(new QLabel("Anchor:"), 0, 0);
|
||||
_geoState.anchor = new QLineEdit;
|
||||
_geoState.anchor->setToolTip("Anchor camera to this globe (planet/moon)");
|
||||
layout->addWidget(_geoState.anchor, 0, 1);
|
||||
|
||||
layout->addWidget(new QLabel("Latitude"), 1, 0);
|
||||
_geoState.latitude = new QLineEdit;
|
||||
_geoState.latitude->setValidator(new QDoubleValidator);
|
||||
_geoState.latitude->setToolTip("Latitude of camera focus point (+/- 90 degrees)");
|
||||
layout->addWidget(_geoState.latitude, 1, 1);
|
||||
|
||||
layout->addWidget(new QLabel("Longitude"), 2, 0);
|
||||
_geoState.longitude = new QLineEdit;
|
||||
_geoState.longitude->setValidator(new QDoubleValidator);
|
||||
_geoState.longitude->setToolTip("Longitude of camera focus point (+/- 180 degrees)");
|
||||
layout->addWidget(_geoState.longitude, 2, 1);
|
||||
|
||||
layout->addWidget(new QLabel("Altitude [m]"), 3, 0);
|
||||
_geoState.altitude = new QLineEdit;
|
||||
_geoState.altitude->setValidator(new QDoubleValidator);
|
||||
_geoState.altitude->setToolTip("Altitude of camera (meters)");
|
||||
_geoState.altitude->setPlaceholderText("optional");
|
||||
layout->addWidget(_geoState.altitude, 3, 1);
|
||||
|
||||
mainLayout->addWidget(box);
|
||||
}
|
||||
|
||||
// Add spacer at the end to prevent previous components from growing as much
|
||||
mainLayout->addSpacerItem(
|
||||
new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding)
|
||||
);
|
||||
|
||||
return tab;
|
||||
}
|
||||
|
||||
bool CameraDialog::areRequiredFormsFilledAndValid() {
|
||||
bool allFormsOk = true;
|
||||
_errorMsg->clear();
|
||||
|
||||
if (_tabWidget->currentIndex() == CameraTypeNode) {
|
||||
if (_nodeState.anchor->text().isEmpty()) {
|
||||
allFormsOk = false;
|
||||
addErrorMsg("Anchor is empty");
|
||||
}
|
||||
if (!_nodeState.height->text().isEmpty()) {
|
||||
if (!isNumericalLargerThan(_nodeState.height, 0.f)) {
|
||||
allFormsOk = false;
|
||||
addErrorMsg("Height must be larger than zero");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_tabWidget->currentIndex() == CameraTypeNav) {
|
||||
if (_navState.anchor->text().isEmpty()) {
|
||||
allFormsOk = false;
|
||||
@@ -355,6 +483,7 @@ bool CameraDialog::areRequiredFormsFilledAndValid() {
|
||||
addErrorMsg("Longitude value is not in +/- 180.0 range");
|
||||
}
|
||||
}
|
||||
|
||||
return allFormsOk;
|
||||
}
|
||||
|
||||
@@ -372,7 +501,15 @@ void CameraDialog::approved() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_tabWidget->currentIndex() == CameraTypeNav) {
|
||||
if (_tabWidget->currentIndex() == CameraTypeNode) {
|
||||
openspace::Profile::CameraGoToNode node;
|
||||
node.anchor = _nodeState.anchor->text().toStdString();
|
||||
if (!_nodeState.height->text().isEmpty()) {
|
||||
node.height = _nodeState.height->text().toDouble();
|
||||
}
|
||||
*_camera = std::move(node);
|
||||
}
|
||||
else if (_tabWidget->currentIndex() == CameraTypeNav) {
|
||||
openspace::Profile::CameraNavState nav;
|
||||
nav.anchor = _navState.anchor->text().toStdString();
|
||||
nav.aim = _navState.aim->text().toStdString();
|
||||
@@ -384,11 +521,11 @@ void CameraDialog::approved() {
|
||||
!_navState.upY->text().isEmpty() &&
|
||||
!_navState.upZ->text().isEmpty())
|
||||
{
|
||||
glm::dvec3 u = {
|
||||
glm::dvec3 u = glm::dvec3(
|
||||
_navState.upX->text().toDouble(),
|
||||
_navState.upY->text().toDouble(),
|
||||
_navState.upZ->text().toDouble()
|
||||
};
|
||||
);
|
||||
nav.up = u;
|
||||
}
|
||||
else {
|
||||
@@ -425,10 +562,13 @@ void CameraDialog::approved() {
|
||||
void CameraDialog::tabSelect(int tabIndex) {
|
||||
_errorMsg->clear();
|
||||
|
||||
if (tabIndex == 0) {
|
||||
if (tabIndex == CameraTypeNode) {
|
||||
_nodeState.anchor->setFocus(Qt::OtherFocusReason);
|
||||
}
|
||||
else if (tabIndex == CameraTypeNav) {
|
||||
_navState.anchor->setFocus(Qt::OtherFocusReason);
|
||||
}
|
||||
else if (tabIndex == 1) {
|
||||
else if (tabIndex == CameraTypeGeo) {
|
||||
_geoState.anchor->setFocus(Qt::OtherFocusReason);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -457,8 +457,8 @@ bool HorizonsDialog::isValidInput() {
|
||||
// Range 1 to 2147483647 (max of 32 bit int).
|
||||
// Horizons read the step size into a 32 bit int, but verifies the input on their
|
||||
// website as a uint32_t. If step size over 32 bit int is sent, this error message is
|
||||
// recived: Cannot read numeric value -- re-enter
|
||||
if (step < 1 || step > std::numeric_limits<int32_t>::max()) {
|
||||
// received: Cannot read numeric value -- re-enter
|
||||
if (step < 1) {
|
||||
_errorMsg->setText(QString::fromStdString(fmt::format(
|
||||
"Step size is outside valid range 1 to '{}'",
|
||||
std::numeric_limits<int32_t>::max()
|
||||
@@ -734,9 +734,8 @@ bool HorizonsDialog::handleRequest() {
|
||||
std::string newName = _horizonsFile.file().filename().stem().string();
|
||||
|
||||
std::filesystem::path oldFile = _horizonsFile.file();
|
||||
std::filesystem::path newFile = _horizonsFile.file().replace_filename(
|
||||
newName + "_error.txt"
|
||||
);
|
||||
std::filesystem::path newFile = oldFile;
|
||||
newFile.replace_filename(newName + "_error.txt");
|
||||
|
||||
std::filesystem::rename(oldFile, newFile);
|
||||
|
||||
@@ -986,7 +985,7 @@ bool HorizonsDialog::handleResult(openspace::HorizonsResultCode& result) {
|
||||
appendLog(msg, HorizonsDialog::LogLevel::Error);
|
||||
|
||||
msg = fmt::format(
|
||||
"Try to use '@{}' as observer to search for possible matches.",
|
||||
"Try to use '@{}' as observer to search for possible matches",
|
||||
_observerName
|
||||
);
|
||||
appendLog(msg, HorizonsDialog::LogLevel::Info);
|
||||
@@ -998,7 +997,7 @@ bool HorizonsDialog::handleResult(openspace::HorizonsResultCode& result) {
|
||||
case HorizonsResultCode::ErrorObserverTargetSame: {
|
||||
std::string msg = fmt::format(
|
||||
"The observer '{}' and target '{}' are the same. Please use another "
|
||||
"observer for the current target.", _observerName, _targetName
|
||||
"observer for the current target", _observerName, _targetName
|
||||
);
|
||||
appendLog(msg, HorizonsDialog::LogLevel::Error);
|
||||
styleLabel(_targetLabel, IsDirty::Yes);
|
||||
@@ -1011,7 +1010,7 @@ bool HorizonsDialog::handleResult(openspace::HorizonsResultCode& result) {
|
||||
std::string msg = fmt::format(
|
||||
"There is not enough data to compute the state of target '{}' in "
|
||||
"relation to the observer '{}' for the time range '{}' to '{}'. Try to "
|
||||
"use another observer for the current target or another time range.",
|
||||
"use another observer for the current target or another time range",
|
||||
_targetName, _observerName, _startTime, _endTime
|
||||
);
|
||||
appendLog(msg, HorizonsDialog::LogLevel::Error);
|
||||
@@ -1028,7 +1027,7 @@ bool HorizonsDialog::handleResult(openspace::HorizonsResultCode& result) {
|
||||
|
||||
msg = fmt::format(
|
||||
"Did not find what you were looking for? Use '@{}' as observer to search "
|
||||
"for alternatives.", _observerName
|
||||
"for alternatives", _observerName
|
||||
);
|
||||
appendLog(msg, HorizonsDialog::LogLevel::Info);
|
||||
styleLabel(_centerLabel, IsDirty::Yes);
|
||||
@@ -1104,8 +1103,7 @@ bool HorizonsDialog::handleResult(openspace::HorizonsResultCode& result) {
|
||||
appendLog(msg, HorizonsDialog::LogLevel::Error);
|
||||
|
||||
msg = fmt::format(
|
||||
"Try to use '{}*' as target to search for possible matches.",
|
||||
_targetName
|
||||
"Try to use '{}*' as target to search for possible matches", _targetName
|
||||
);
|
||||
appendLog(msg, HorizonsDialog::LogLevel::Info);
|
||||
styleLabel(_targetLabel, IsDirty::Yes);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -38,7 +38,6 @@
|
||||
MarkNodesDialog::MarkNodesDialog(QWidget* parent, std::vector<std::string>* markedNodes)
|
||||
: QDialog(parent)
|
||||
, _markedNodes(markedNodes)
|
||||
, _markedNodesData(*_markedNodes)
|
||||
{
|
||||
setWindowTitle("Mark Interesting Nodes");
|
||||
createWidgets();
|
||||
@@ -55,13 +54,13 @@ void MarkNodesDialog::createWidgets() {
|
||||
);
|
||||
_list->setAlternatingRowColors(true);
|
||||
_list->setMovement(QListView::Free);
|
||||
_list->setDragDropMode(QListView::InternalMove);
|
||||
_list->setResizeMode(QListView::Adjust);
|
||||
|
||||
for (size_t i = 0; i < _markedNodesData.size(); ++i) {
|
||||
_markedNodesListItems.push_back(
|
||||
new QListWidgetItem(QString::fromStdString(_markedNodesData[i]))
|
||||
);
|
||||
_list->addItem(_markedNodesListItems[i]);
|
||||
for (size_t i = 0; i < _markedNodes->size(); ++i) {
|
||||
QListWidgetItem* item =
|
||||
new QListWidgetItem(QString::fromStdString(_markedNodes->at(i)));
|
||||
_list->addItem(item);
|
||||
}
|
||||
layout->addWidget(_list);
|
||||
|
||||
@@ -102,23 +101,11 @@ void MarkNodesDialog::listItemAdded() {
|
||||
}
|
||||
|
||||
std::string itemToAdd = _newNode->text().toStdString();
|
||||
const auto it = std::find(
|
||||
_markedNodesData.cbegin(), _markedNodesData.cend(),
|
||||
itemToAdd
|
||||
);
|
||||
if (it != _markedNodesData.end()) {
|
||||
_list->setCurrentRow(
|
||||
static_cast<int>(std::distance(_markedNodesData.cbegin(), it))
|
||||
);
|
||||
}
|
||||
else {
|
||||
_markedNodesData.push_back(itemToAdd);
|
||||
_markedNodesListItems.push_back(new QListWidgetItem(_newNode->text()));
|
||||
_list->addItem(_markedNodesListItems.back());
|
||||
QListWidgetItem* item = new QListWidgetItem(_newNode->text());
|
||||
_list->addItem(item);
|
||||
|
||||
// Scroll down to that blank line highlighted
|
||||
_list->setCurrentItem(_markedNodesListItems.back());
|
||||
}
|
||||
// Scroll down to that blank line highlighted
|
||||
_list->setCurrentItem(item);
|
||||
|
||||
// Blank-out entry again
|
||||
_newNode->clear();
|
||||
@@ -127,18 +114,16 @@ void MarkNodesDialog::listItemAdded() {
|
||||
void MarkNodesDialog::listItemRemove() {
|
||||
QListWidgetItem* item = _list->currentItem();
|
||||
int index = _list->row(item);
|
||||
|
||||
if (index < 0 || index >= static_cast<int>(_markedNodesListItems.size())) {
|
||||
return;
|
||||
}
|
||||
|
||||
_list->takeItem(index);
|
||||
_markedNodesData.erase(_markedNodesData.begin() + index);
|
||||
_markedNodesListItems.erase(_markedNodesListItems.begin() + index);
|
||||
}
|
||||
|
||||
void MarkNodesDialog::parseSelections() {
|
||||
*_markedNodes = std::move(_markedNodesData);
|
||||
std::vector<std::string> nodes;
|
||||
for (int i = 0; i < _list->count(); i++) {
|
||||
QString node = _list->item(i)->text();
|
||||
nodes.push_back(node.toStdString());
|
||||
}
|
||||
*_markedNodes = std::move(nodes);
|
||||
accept();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -37,7 +37,11 @@
|
||||
using namespace openspace;
|
||||
|
||||
namespace {
|
||||
const Profile::Module Blank = { "", "", "" };
|
||||
const Profile::Module Blank = {
|
||||
.name = "",
|
||||
.loadedInstruction = std::nullopt,
|
||||
.notLoadedInstruction = std::nullopt
|
||||
};
|
||||
} // namespace
|
||||
|
||||
ModulesDialog::ModulesDialog(QWidget* parent,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -98,15 +98,15 @@ namespace {
|
||||
ProfileEdit::ProfileEdit(Profile& profile, const std::string& profileName,
|
||||
std::string assetBasePath,
|
||||
std::string userAssetBasePath,
|
||||
std::string builtInProfileBasePath,
|
||||
std::string profileBasePath,
|
||||
const std::vector<std::string>& readOnlyProfiles,
|
||||
QWidget* parent)
|
||||
: QDialog(parent)
|
||||
, _profile(profile)
|
||||
, _assetBasePath(std::move(assetBasePath))
|
||||
, _userAssetBasePath(std::move(userAssetBasePath))
|
||||
, _profileBasePath(std::move(profileBasePath))
|
||||
, _readOnlyProfiles(readOnlyProfiles)
|
||||
, _builtInProfilesPath(std::move(builtInProfileBasePath))
|
||||
{
|
||||
setWindowTitle("Profile Editor");
|
||||
createWidgets(profileName);
|
||||
@@ -184,9 +184,8 @@ void ProfileEdit::createWidgets(const std::string& profileName) {
|
||||
QGridLayout* container = new QGridLayout;
|
||||
container->setColumnStretch(1, 1);
|
||||
|
||||
_keybindingsLabel = new QLabel("Keybindings");
|
||||
_keybindingsLabel = new QLabel("Actions & Keybindings");
|
||||
_keybindingsLabel->setObjectName("heading");
|
||||
_keybindingsLabel->setWordWrap(true);
|
||||
container->addWidget(_keybindingsLabel, 0, 0);
|
||||
|
||||
QPushButton* keybindingsProperties = new QPushButton("Edit");
|
||||
@@ -345,7 +344,9 @@ void ProfileEdit::initSummaryTextForEachCategory() {
|
||||
QString::fromStdString(summarizeProperties(_profile.properties))
|
||||
);
|
||||
|
||||
_keybindingsLabel->setText(labelText(_profile.keybindings.size(), "Keybindings"));
|
||||
_keybindingsLabel->setText(
|
||||
labelText(_profile.keybindings.size(), "Actions & Keybindings")
|
||||
);
|
||||
_keybindingsEdit->setText(QString::fromStdString(
|
||||
summarizeKeybindings(_profile.keybindings, _profile.actions)
|
||||
));
|
||||
@@ -365,7 +366,7 @@ void ProfileEdit::duplicateProfile() {
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr const char Separator = '_';
|
||||
constexpr char Separator = '_';
|
||||
int version = 0;
|
||||
if (size_t it = profile.rfind(Separator); it != std::string::npos) {
|
||||
// If the value exists, we have a profile that potentially already has a version
|
||||
@@ -488,17 +489,21 @@ void ProfileEdit::approved() {
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = std::find(_readOnlyProfiles.begin(), _readOnlyProfiles.end(), profileName);
|
||||
if (it == _readOnlyProfiles.end()) {
|
||||
_saveSelected = true;
|
||||
_errorMsg->setText("");
|
||||
accept();
|
||||
}
|
||||
else {
|
||||
std::filesystem::path p = fmt::format(
|
||||
"{}/{}.profile", _builtInProfilesPath, profileName
|
||||
);
|
||||
if (std::filesystem::exists(p)) {
|
||||
// The filename exists in the OpenSpace-provided folder, so we don't want to allow
|
||||
// a user to overwrite it
|
||||
_errorMsg->setText(
|
||||
"This is a read-only profile. Click 'Duplicate' or rename & save"
|
||||
);
|
||||
}
|
||||
else {
|
||||
_saveSelected = true;
|
||||
_errorMsg->setText("");
|
||||
accept();
|
||||
}
|
||||
}
|
||||
|
||||
void ProfileEdit::keyPressEvent(QKeyEvent* evt) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "profile/propertiesdialog.h"
|
||||
|
||||
#include "profile/line.h"
|
||||
#include "profile/scriptlogdialog.h"
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <QComboBox>
|
||||
#include <QDialogButtonBox>
|
||||
@@ -92,17 +93,17 @@ void PropertiesDialog::createWidgets() {
|
||||
|
||||
box->addStretch();
|
||||
|
||||
_addFromScriptLog = new QPushButton("Add from ScriptLog");
|
||||
connect(
|
||||
_addFromScriptLog, &QPushButton::clicked,
|
||||
this, &PropertiesDialog::selectLineFromScriptLog
|
||||
);
|
||||
box->addWidget(_addFromScriptLog);
|
||||
|
||||
layout->addLayout(box);
|
||||
}
|
||||
layout->addWidget(new Line);
|
||||
{
|
||||
_fillFromScriptLog = new QPushButton("Fill from ScriptLog");
|
||||
connect(
|
||||
_fillFromScriptLog, &QPushButton::clicked,
|
||||
this, &PropertiesDialog::selectLineFromScriptLog
|
||||
);
|
||||
layout->addWidget(_fillFromScriptLog);
|
||||
|
||||
_commandLabel = new QLabel("Property Set Command");
|
||||
layout->addWidget(_commandLabel);
|
||||
|
||||
@@ -315,6 +316,7 @@ void PropertiesDialog::transitionToEditMode() {
|
||||
_saveButton->setDisabled(true);
|
||||
_cancelButton->setDisabled(true);
|
||||
_buttonBox->setDisabled(true);
|
||||
_addFromScriptLog->setDisabled(true);
|
||||
|
||||
_commandLabel->setText("<font color='black'>Property Set Command</font>");
|
||||
_propertyLabel->setText("<font color='black'>Property</font>");
|
||||
@@ -330,6 +332,7 @@ void PropertiesDialog::transitionFromEditMode() {
|
||||
_saveButton->setDisabled(false);
|
||||
_cancelButton->setDisabled(false);
|
||||
_buttonBox->setDisabled(false);
|
||||
_addFromScriptLog->setDisabled(false);
|
||||
|
||||
_commandLabel->setText("<font color='light gray'>Property Set Command</font>");
|
||||
_propertyLabel->setText("<font color='light gray'>Property</font>");
|
||||
@@ -339,7 +342,6 @@ void PropertiesDialog::transitionFromEditMode() {
|
||||
}
|
||||
|
||||
void PropertiesDialog::editBoxDisabled(bool disabled) {
|
||||
_fillFromScriptLog->setDisabled(disabled);
|
||||
_commandLabel->setDisabled(disabled);
|
||||
_commandCombo->setDisabled(disabled);
|
||||
_propertyLabel->setDisabled(disabled);
|
||||
@@ -352,7 +354,7 @@ void PropertiesDialog::editBoxDisabled(bool disabled) {
|
||||
|
||||
void PropertiesDialog::parseSelections() {
|
||||
// Handle case with only one remaining but empty line
|
||||
if ((_propertyData.size() == 1) && (_propertyData.at(0).name.compare("") == 0)) {
|
||||
if ((_propertyData.size() == 1) && _propertyData.at(0).name.empty()) {
|
||||
_propertyData.clear();
|
||||
}
|
||||
*_properties = std::move(_propertyData);
|
||||
@@ -374,91 +376,52 @@ void PropertiesDialog::keyPressEvent(QKeyEvent* evt) {
|
||||
}
|
||||
|
||||
void PropertiesDialog::selectLineFromScriptLog() {
|
||||
QComboBox* comboBox = new QComboBox;
|
||||
|
||||
QFile file(QString::fromStdString(absPath("${LOGS}/scriptLog.txt").string()));
|
||||
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
QTextStream in(&file);
|
||||
while (!in.atEnd()) {
|
||||
QString line = in.readLine();
|
||||
// removing return from a few statments
|
||||
// these are usually generated by gui panels
|
||||
line.remove(QRegularExpression("^return "));
|
||||
|
||||
if (line.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!line.startsWith("openspace.setPropertyValue")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
comboBox->addItem(line);
|
||||
}
|
||||
}
|
||||
|
||||
QDialog dialog;
|
||||
|
||||
ScriptlogDialog d(this, "openspace.setPropertyValue");
|
||||
connect(
|
||||
&dialog, &QDialog::finished,
|
||||
[this, comboBox](int result) {
|
||||
if (result == QDialog::Rejected) {
|
||||
return;
|
||||
&d, &ScriptlogDialog::scriptsSelected,
|
||||
[this](std::vector<std::string> scripts) {
|
||||
for (const std::string& script : scripts) {
|
||||
listItemAdded();
|
||||
|
||||
QString text = QString::fromStdString(script);
|
||||
if (!text.startsWith("openspace.setPropertyValue")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We have a string that is of the form:
|
||||
// openspace.setPropertyValue('prop', value);
|
||||
if (text.startsWith("openspace.setPropertyValueSingle")) {
|
||||
_commandCombo->setCurrentIndex(0);
|
||||
std::string_view prefix = "openspace.setPropertyValueSingle";
|
||||
text = text.mid(static_cast<int>(prefix.size()) + 1); // +1 for (
|
||||
}
|
||||
else {
|
||||
// command == "openspace.setPropertyValue"
|
||||
_commandCombo->setCurrentIndex(1);
|
||||
std::string_view prefix = "openspace.setPropertyValue";
|
||||
text = text.mid(static_cast<int>(prefix.size()) + 1); // +1 for (
|
||||
}
|
||||
|
||||
// Remove everything past the closing brace
|
||||
text = text.left(text.indexOf(")"));
|
||||
QStringList textList = text.split(",");
|
||||
|
||||
if (textList.size() < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove the string markers around the property
|
||||
QString property = textList[0].mid(1, textList[0].size() - 2);
|
||||
|
||||
textList.removeFirst();
|
||||
QString value = textList.join(",");
|
||||
|
||||
|
||||
_propertyEdit->setText(property.trimmed());
|
||||
_valueEdit->setText(value.trimmed());
|
||||
listItemSave();
|
||||
}
|
||||
|
||||
QString text = comboBox->currentText();
|
||||
if (!text.startsWith("openspace.setPropertyValue")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We have a string that is of the form:
|
||||
// openspace.setPropertyValue('prop', value);
|
||||
|
||||
if (text.startsWith("openspace.setPropertyValueSingle")) {
|
||||
_commandCombo->setCurrentIndex(0);
|
||||
std::string_view prefix = "openspace.setPropertyValueSingle";
|
||||
text = text.mid(static_cast<int>(prefix.size()) + 1); // +1 for (
|
||||
}
|
||||
else {
|
||||
// command == "openspace.setPropertyValue"
|
||||
_commandCombo->setCurrentIndex(1);
|
||||
std::string_view prefix = "openspace.setPropertyValue";
|
||||
text = text.mid(static_cast<int>(prefix.size()) + 1); // +1 for (
|
||||
}
|
||||
|
||||
// Remove everything past the closing brace
|
||||
text = text.left(text.indexOf(")"));
|
||||
QStringList textList = text.split(",");
|
||||
|
||||
if (textList.size() < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove the string markers around the property
|
||||
QString property = textList[0].mid(1, textList[0].size() - 2);
|
||||
|
||||
textList.removeFirst();
|
||||
QString value = textList.join(",");
|
||||
|
||||
|
||||
_propertyEdit->setText(property.trimmed());
|
||||
_valueEdit->setText(value.trimmed());
|
||||
}
|
||||
);
|
||||
|
||||
QLayout* layout = new QVBoxLayout;
|
||||
QLabel* label = new QLabel("Select a line from the Script Log to add");
|
||||
layout->addWidget(label);
|
||||
|
||||
layout->addWidget(comboBox);
|
||||
|
||||
QDialogButtonBox* bb = new QDialogButtonBox(
|
||||
QDialogButtonBox::Ok | QDialogButtonBox::Cancel
|
||||
);
|
||||
connect(bb, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
|
||||
connect(bb, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
|
||||
layout->addWidget(bb);
|
||||
|
||||
dialog.setLayout(layout);
|
||||
dialog.exec();
|
||||
d.exec();
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <ghoul/fmt.h>
|
||||
#include <QGridLayout>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QFileDialog>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QListWidget>
|
||||
@@ -39,8 +40,10 @@
|
||||
#include <QPushButton>
|
||||
#include <QTextStream>
|
||||
|
||||
ScriptlogDialog::ScriptlogDialog(QWidget* parent)
|
||||
ScriptlogDialog::ScriptlogDialog(QWidget* parent, std::string filter)
|
||||
: QDialog(parent)
|
||||
, _scriptLogFile(openspace::global::configuration->scriptLog)
|
||||
, _fixedFilter(std::move(filter))
|
||||
{
|
||||
setWindowTitle("Scriptlog");
|
||||
createWidgets();
|
||||
@@ -63,10 +66,31 @@ void ScriptlogDialog::createWidgets() {
|
||||
QGridLayout* layout = new QGridLayout(this);
|
||||
{
|
||||
QLabel* heading = new QLabel(QString::fromStdString(fmt::format(
|
||||
"Choose commands from \"{}\"", openspace::global::configuration->scriptLog
|
||||
"Choose commands from \"{}\"", _scriptLogFile
|
||||
)));
|
||||
heading->setObjectName("heading");
|
||||
layout->addWidget(heading, 0, 0, 1, 2);
|
||||
|
||||
QPushButton* open = new QPushButton;
|
||||
open->setIcon(open->style()->standardIcon(QStyle::SP_FileIcon));
|
||||
connect(
|
||||
open, &QPushButton::clicked,
|
||||
[this, heading]() {
|
||||
QString file = QFileDialog::getOpenFileName(
|
||||
this,
|
||||
"Select log file",
|
||||
"",
|
||||
"*.txt"
|
||||
);
|
||||
_scriptLogFile = file.toStdString();
|
||||
|
||||
heading->setText(QString::fromStdString(fmt::format(
|
||||
"Choose commands from \"{}\"", _scriptLogFile
|
||||
)));
|
||||
loadScriptFile();
|
||||
}
|
||||
);
|
||||
layout->addWidget(open, 0, 1, Qt::AlignRight);
|
||||
}
|
||||
|
||||
_filter = new QLineEdit;
|
||||
@@ -100,7 +124,9 @@ void ScriptlogDialog::createWidgets() {
|
||||
}
|
||||
|
||||
void ScriptlogDialog::loadScriptFile() {
|
||||
std::string log = absPath(openspace::global::configuration->scriptLog).string();
|
||||
_scripts.clear();
|
||||
|
||||
std::string log = absPath(_scriptLogFile).string();
|
||||
QFile file(QString::fromStdString(log));
|
||||
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
QTextStream in(&file);
|
||||
@@ -126,26 +152,24 @@ void ScriptlogDialog::updateScriptList() {
|
||||
int index = -1;
|
||||
_scriptlogList->clear();
|
||||
for (const std::string& script : _scripts) {
|
||||
if (script.find(filter) != std::string::npos) {
|
||||
bool foundDynamic = script.find(filter) != std::string::npos;
|
||||
bool foundStatic =
|
||||
_fixedFilter.empty() ? true : script.find(_fixedFilter) != std::string::npos;
|
||||
if (foundDynamic && foundStatic) {
|
||||
if (script == selection && index == -1) {
|
||||
index = _scriptlogList->count();
|
||||
}
|
||||
_scriptlogList->addItem(QString::fromStdString(script));
|
||||
}
|
||||
}
|
||||
_scriptlogList->setCurrentRow(index != -1 ? index : 0);
|
||||
}
|
||||
|
||||
void ScriptlogDialog::saveChosenScripts() {
|
||||
std::string chosenScripts;
|
||||
std::vector<std::string> chosenScripts;
|
||||
QList<QListWidgetItem*> itemList = _scriptlogList->selectedItems();
|
||||
for (int i = 0; i < itemList.size(); ++i) {
|
||||
chosenScripts += itemList.at(i)->text().toStdString();
|
||||
if (i < itemList.size()) {
|
||||
chosenScripts += "\n";
|
||||
}
|
||||
for (QListWidgetItem* item : _scriptlogList->selectedItems()) {
|
||||
chosenScripts.push_back(item->text().toStdString());
|
||||
}
|
||||
emit scriptsSelected(chosenScripts);
|
||||
|
||||
accept();
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "profile/timedialog.h"
|
||||
|
||||
#include "profile/line.h"
|
||||
#include <QCheckBox>
|
||||
#include <QComboBox>
|
||||
#include <QDateTimeEdit>
|
||||
#include <QDialogButtonBox>
|
||||
@@ -52,7 +53,8 @@ TimeDialog::TimeDialog(QWidget* parent, std::optional<openspace::Profile::Time>*
|
||||
if (_timeData.value.empty()) {
|
||||
_timeData.value = "0d";
|
||||
}
|
||||
_relativeEdit->setSelection(0, _relativeEdit->text().length());
|
||||
int len = static_cast<int>(_relativeEdit->text().length());
|
||||
_relativeEdit->setSelection(0, len);
|
||||
}
|
||||
else {
|
||||
_absoluteEdit->setSelectedSection(QDateTimeEdit::YearSection);
|
||||
@@ -62,6 +64,8 @@ TimeDialog::TimeDialog(QWidget* parent, std::optional<openspace::Profile::Time>*
|
||||
_timeData.type = Profile::Time::Type::Relative;
|
||||
_timeData.value = "0d";
|
||||
}
|
||||
_startPaused->setChecked(_timeData.startPaused);
|
||||
|
||||
_initializedAsAbsolute = (_timeData.type == Profile::Time::Type::Absolute);
|
||||
enableAccordingToType(static_cast<int>(_timeData.type));
|
||||
}
|
||||
@@ -97,6 +101,14 @@ void TimeDialog::createWidgets() {
|
||||
);
|
||||
layout->addWidget(_relativeEdit);
|
||||
}
|
||||
{
|
||||
_startPaused = new QCheckBox("Start with time paused");
|
||||
_startPaused->setChecked(false);
|
||||
_startPaused->setToolTip(
|
||||
"If this is checked, the profile will start with the delta time paused"
|
||||
);
|
||||
layout->addWidget(_startPaused);
|
||||
}
|
||||
layout->addWidget(new Line);
|
||||
{
|
||||
QDialogButtonBox* buttons = new QDialogButtonBox;
|
||||
@@ -143,7 +155,7 @@ void TimeDialog::enableFormatForAbsolute(bool enableAbs) {
|
||||
}
|
||||
|
||||
void TimeDialog::approved() {
|
||||
constexpr const int Relative = static_cast<int>(Profile::Time::Type::Relative);
|
||||
constexpr int Relative = static_cast<int>(Profile::Time::Type::Relative);
|
||||
if (_typeCombo->currentIndex() == Relative) {
|
||||
if (_relativeEdit->text().isEmpty()) {
|
||||
*_time = std::nullopt;
|
||||
@@ -152,6 +164,7 @@ void TimeDialog::approved() {
|
||||
Profile::Time t;
|
||||
t.type = Profile::Time::Type::Relative;
|
||||
t.value = _relativeEdit->text().toStdString();
|
||||
t.startPaused = _startPaused->isChecked();
|
||||
*_time = t;
|
||||
}
|
||||
}
|
||||
@@ -163,6 +176,7 @@ void TimeDialog::approved() {
|
||||
_absoluteEdit->date().toString("yyyy-MM-dd").toStdString(),
|
||||
_absoluteEdit->time().toString().toStdString()
|
||||
);
|
||||
t.startPaused = _startPaused->isChecked();
|
||||
*_time = t;
|
||||
}
|
||||
accept();
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -36,26 +36,34 @@
|
||||
DisplayWindowUnion::DisplayWindowUnion(const std::vector<QRect>& monitorSizeList,
|
||||
int nMaxWindows,
|
||||
const std::array<QColor, 4>& windowColors,
|
||||
QWidget* parent)
|
||||
bool resetToDefault, QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
createWidgets(nMaxWindows, monitorSizeList, windowColors);
|
||||
createWidgets(
|
||||
nMaxWindows,
|
||||
monitorSizeList,
|
||||
windowColors,
|
||||
resetToDefault
|
||||
);
|
||||
showWindows();
|
||||
}
|
||||
|
||||
void DisplayWindowUnion::createWidgets(int nMaxWindows,
|
||||
std::vector<QRect> monitorResolutions,
|
||||
std::array<QColor, 4> windowColors)
|
||||
std::array<QColor, 4> windowColors,
|
||||
bool resetToDefault)
|
||||
{
|
||||
// Add all window controls (some will be hidden from GUI initially)
|
||||
for (unsigned int i = 0; i < nMaxWindows; ++i) {
|
||||
const unsigned int monitorNumForThisWindow = (nMaxWindows > 3 && i >= 2) ? 1 : 0;
|
||||
for (int i = 0; i < nMaxWindows; ++i) {
|
||||
const int monitorNumForThisWindow =
|
||||
(monitorResolutions.size() > 1 && i >= 2) ? 1 : 0;
|
||||
|
||||
WindowControl* ctrl = new WindowControl(
|
||||
monitorNumForThisWindow,
|
||||
i,
|
||||
monitorResolutions,
|
||||
windowColors[i],
|
||||
resetToDefault,
|
||||
this
|
||||
);
|
||||
_windowControl.push_back(ctrl);
|
||||
@@ -119,7 +127,7 @@ void DisplayWindowUnion::createWidgets(int nMaxWindows,
|
||||
layout->addStretch();
|
||||
}
|
||||
|
||||
std::vector<WindowControl*> DisplayWindowUnion::windowControls() const {
|
||||
std::vector<WindowControl*> DisplayWindowUnion::activeWindowControls() const {
|
||||
std::vector<WindowControl*> res;
|
||||
res.reserve(_nWindowsDisplayed);
|
||||
for (unsigned int i = 0; i < _nWindowsDisplayed; ++i) {
|
||||
@@ -128,6 +136,10 @@ std::vector<WindowControl*> DisplayWindowUnion::windowControls() const {
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<WindowControl*>& DisplayWindowUnion::windowControls() {
|
||||
return _windowControl;
|
||||
}
|
||||
|
||||
void DisplayWindowUnion::addWindow() {
|
||||
if (_nWindowsDisplayed < _windowControl.size()) {
|
||||
_windowControl[_nWindowsDisplayed]->resetToDefaults();
|
||||
@@ -143,6 +155,10 @@ void DisplayWindowUnion::removeWindow() {
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int DisplayWindowUnion::numWindowsDisplayed() const {
|
||||
return _nWindowsDisplayed;
|
||||
}
|
||||
|
||||
void DisplayWindowUnion::showWindows() {
|
||||
for (size_t i = 0; i < _windowControl.size(); ++i) {
|
||||
_windowControl[i]->setVisible(i < _nWindowsDisplayed);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -31,7 +31,7 @@ namespace {
|
||||
constexpr int WindowOpacity = 170;
|
||||
|
||||
QRectF computeUnion(const std::vector<QRect>& monitorResolutions) {
|
||||
QRectF res = { 0.f, 0.f, 0.f, 0.f };
|
||||
QRectF res = QRectF(0.f, 0.f, 0.f, 0.f);
|
||||
for (const QRect& m : monitorResolutions) {
|
||||
res |= m;
|
||||
}
|
||||
@@ -145,12 +145,12 @@ void MonitorBox::paintEvent(QPaintEvent*) {
|
||||
void MonitorBox::windowDimensionsChanged(unsigned int mIdx, unsigned int wIdx,
|
||||
const QRectF& newDimensions)
|
||||
{
|
||||
_windowRendering[wIdx] = {
|
||||
_windowRendering[wIdx] = QRectF(
|
||||
_monitorDimensionsScaled[mIdx].x() + newDimensions.left() * _monitorScaleFactor,
|
||||
_monitorDimensionsScaled[mIdx].y() + newDimensions.top() * _monitorScaleFactor,
|
||||
newDimensions.width() * _monitorScaleFactor,
|
||||
newDimensions.height() * _monitorScaleFactor
|
||||
};
|
||||
);
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -41,7 +41,7 @@ OrientationDialog::OrientationDialog(sgct::quat& orientation, QWidget* parent)
|
||||
{
|
||||
QString pitchTip = "Pitch or elevation: negative numbers tilt the camera "
|
||||
"downwards; positive numbers tilt upwards.\nThe allowed range is [-90, 90]. "
|
||||
"Internally, this corresponds to the x value in the quaternion.";
|
||||
"Internally, this corresponds to the x value in the quaternion";
|
||||
|
||||
QLabel* labelPitch = new QLabel("Pitch");
|
||||
labelPitch->setToolTip(pitchTip);
|
||||
@@ -58,7 +58,7 @@ OrientationDialog::OrientationDialog(sgct::quat& orientation, QWidget* parent)
|
||||
{
|
||||
QString rollTip = "Roll or bank: negative numbers rotate the camera counter-"
|
||||
"clockwise; positive numbers clockwise.\nThe allowed range is [-180, 180]. "
|
||||
"Internally, this corresponds to the z value in the quaternion.";
|
||||
"Internally, this corresponds to the z value in the quaternion";
|
||||
|
||||
QLabel* labelRoll = new QLabel("Roll");
|
||||
labelRoll->setToolTip(rollTip);
|
||||
@@ -75,7 +75,7 @@ OrientationDialog::OrientationDialog(sgct::quat& orientation, QWidget* parent)
|
||||
{
|
||||
QString yawTip = "Yaw, heading, or azimuth: negative numbers pan the camera "
|
||||
"to the left; positive numbers pan to the\nright. The allowed range is "
|
||||
"[-360, 360]. Internally, this corresponds to the y value in the quaternion.";
|
||||
"[-360, 360]. Internally, this corresponds to the y value in the quaternion";
|
||||
|
||||
QLabel* labelYaw = new QLabel;
|
||||
labelYaw ->setText("Yaw");
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -36,16 +36,34 @@ SettingsWidget::SettingsWidget(sgct::quat orientation, QWidget* parent)
|
||||
QBoxLayout* layout = new QVBoxLayout(this);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
_showUiOnFirstWindow = new QCheckBox("Show only user interface on the first window");
|
||||
_showUiOnFirstWindow = new QCheckBox(
|
||||
"Show user interface only on first window using graphics:"
|
||||
);
|
||||
_showUiOnFirstWindow->setChecked(false);
|
||||
_showUiOnFirstWindow->setEnabled(false);
|
||||
_showUiOnFirstWindow->setToolTip(
|
||||
"If enabled the first window is marked as a GUI window resulting in the user "
|
||||
"interface only being shown on that window and the rendering is suppressed on "
|
||||
"this first window. The remaining windows will render normally but they will not "
|
||||
"show the user interface"
|
||||
"interface only being shown\non that window and the rendering is suppressed on "
|
||||
"this first window. The remaining windows will render\nnormally but they will "
|
||||
"not show the user interface"
|
||||
);
|
||||
layout->addWidget(_showUiOnFirstWindow);
|
||||
|
||||
_firstWindowSelectionLayout = new QHBoxLayout;
|
||||
|
||||
_firstWindowGraphicsSelection = new QComboBox();
|
||||
_firstWindowGraphicsSelection->setToolTip(
|
||||
"Select the contents of the first window to match one of the other windows"
|
||||
);
|
||||
_firstWindowGraphicsSelection->setFixedWidth(150);
|
||||
connect(
|
||||
_showUiOnFirstWindow, &QCheckBox::clicked,
|
||||
this, &SettingsWidget::showUiOnFirstWindowClicked
|
||||
);
|
||||
|
||||
_firstWindowSelectionLayout->addWidget(_showUiOnFirstWindow);
|
||||
_firstWindowSelectionLayout->addWidget(_firstWindowGraphicsSelection);
|
||||
_firstWindowSelectionLayout->addStretch();
|
||||
layout->addLayout(_firstWindowSelectionLayout);
|
||||
|
||||
_checkBoxVsync = new QCheckBox("Enable VSync");
|
||||
_checkBoxVsync->setToolTip(
|
||||
@@ -78,5 +96,75 @@ bool SettingsWidget::vsync() const {
|
||||
}
|
||||
|
||||
bool SettingsWidget::showUiOnFirstWindow() const {
|
||||
return _showUiOnFirstWindow->isChecked();
|
||||
return (_showUiOnFirstWindow->isChecked() && _showUiOnFirstWindow->isEnabled());
|
||||
}
|
||||
|
||||
void SettingsWidget::setShowUiOnFirstWindow(bool setUiOnFirstWindow) {
|
||||
_showUiOnFirstWindow->setChecked(setUiOnFirstWindow);
|
||||
}
|
||||
|
||||
void SettingsWidget::setEnableShowUiOnFirstWindowCheckbox(bool enable) {
|
||||
_showUiOnFirstWindow->setEnabled(enable);
|
||||
_firstWindowGraphicsSelection->setEnabled(enable);
|
||||
}
|
||||
|
||||
int SettingsWidget::graphicsSelectionForShowUiOnFirstWindow() const {
|
||||
return _firstWindowGraphicsSelection->currentIndex();
|
||||
}
|
||||
|
||||
void SettingsWidget::setGraphicsSelectionForShowUiOnFirstWindow(int selection) {
|
||||
_firstWindowGraphicsSelection->setCurrentIndex(selection);
|
||||
}
|
||||
|
||||
void SettingsWidget::setVsync(bool enableVsync) {
|
||||
_checkBoxVsync->setChecked(enableVsync);
|
||||
}
|
||||
|
||||
void SettingsWidget::nWindowsDisplayedChanged(int newCount) {
|
||||
constexpr int CountOneWindow = 1;
|
||||
constexpr int CountTwoWindows = 2;
|
||||
int graphicsSelect = _firstWindowGraphicsSelection->currentIndex();
|
||||
graphicsSelect = std::max(0, graphicsSelect);
|
||||
|
||||
QList<QString> graphicsOptions = {"None (GUI only)"};
|
||||
for (int i = CountOneWindow; i <= newCount; ++i) {
|
||||
graphicsOptions.append("Window " + QString::number(i));
|
||||
}
|
||||
_firstWindowGraphicsSelection->clear();
|
||||
_firstWindowGraphicsSelection->addItems(graphicsOptions);
|
||||
setEnableShowUiOnFirstWindowCheckbox(newCount > CountOneWindow);
|
||||
if (graphicsSelect > newCount) {
|
||||
graphicsSelect = newCount;
|
||||
}
|
||||
_firstWindowGraphicsSelection->setCurrentIndex(graphicsSelect);
|
||||
|
||||
if (newCount == CountOneWindow) {
|
||||
_stateOfUiOnFirstWindowWhenDisabled = _showUiOnFirstWindow->isChecked();
|
||||
_showUiOnFirstWindow->setChecked(false);
|
||||
_firstWindowGraphicsSelection->setEnabled(false);
|
||||
}
|
||||
else if (newCount == CountTwoWindows &&
|
||||
_stateOfUiOnFirstWindowPreviousCount == CountOneWindow)
|
||||
{
|
||||
if (_stateOfUiOnFirstWindowWhenDisabled) {
|
||||
_showUiOnFirstWindow->setChecked(true);
|
||||
}
|
||||
_firstWindowGraphicsSelection->setEnabled(_showUiOnFirstWindow->isChecked());
|
||||
}
|
||||
else {
|
||||
_firstWindowGraphicsSelection->setEnabled(_showUiOnFirstWindow->isChecked());
|
||||
}
|
||||
_stateOfUiOnFirstWindowPreviousCount = newCount;
|
||||
}
|
||||
|
||||
void SettingsWidget::showUiOnFirstWindowClicked(bool checked) {
|
||||
_firstWindowGraphicsSelection->setEnabled(checked);
|
||||
}
|
||||
|
||||
QComboBox* SettingsWidget::firstWindowGraphicsSelection() {
|
||||
return _firstWindowGraphicsSelection;
|
||||
}
|
||||
|
||||
QCheckBox* SettingsWidget::showUiOnFirstWindowCheckbox() {
|
||||
return _showUiOnFirstWindow;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -27,9 +27,9 @@
|
||||
#include <sgctedit/displaywindowunion.h>
|
||||
#include <sgctedit/monitorbox.h>
|
||||
#include <sgctedit/settingswidget.h>
|
||||
#include <sgctedit/windowcontrol.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <QApplication>
|
||||
#include <QCheckBox>
|
||||
#include <QFileDialog>
|
||||
#include <QFrame>
|
||||
#include <QMessageBox>
|
||||
@@ -39,7 +39,7 @@
|
||||
#include <filesystem>
|
||||
|
||||
namespace {
|
||||
constexpr QRect MonitorWidgetSize = { 0, 0, 500, 500 };
|
||||
constexpr QRect MonitorWidgetSize = QRect(0, 0, 500, 500);
|
||||
constexpr int MaxNumberWindows = 4;
|
||||
|
||||
// Returns true if the windows are not ordered correctly. 'Correct' in this means that
|
||||
@@ -48,10 +48,10 @@ namespace {
|
||||
// https://github.com/OpenSpace/OpenSpace/issues/507
|
||||
// is fixed
|
||||
bool hasWindowIssues(const sgct::config::Cluster& cluster) {
|
||||
sgct::ivec2 size = {
|
||||
sgct::ivec2 size = sgct::ivec2(
|
||||
std::numeric_limits<int>::max(),
|
||||
std::numeric_limits<int>::max()
|
||||
};
|
||||
);
|
||||
for (const sgct::config::Window& window : cluster.nodes.front().windows) {
|
||||
if (window.size.x <= size.x && window.size.y <= size.y) {
|
||||
size = window.size;
|
||||
@@ -65,15 +65,202 @@ namespace {
|
||||
// We got to the end without running into any problems, so we are golden
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
|
||||
template <class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
|
||||
} // namespace
|
||||
|
||||
SgctEdit::SgctEdit(QWidget* parent, std::string userConfigPath)
|
||||
: QDialog(parent)
|
||||
, _userConfigPath(std::move(userConfigPath))
|
||||
{
|
||||
QList<QScreen*> screens = qApp->screens();
|
||||
setWindowTitle("Window Configuration Editor");
|
||||
|
||||
createWidgets(createMonitorInfoSet(), 1, true);
|
||||
}
|
||||
|
||||
SgctEdit::SgctEdit(sgct::config::Cluster& cluster, const std::string& configName,
|
||||
std::string& configBasePath, QWidget* parent)
|
||||
: QDialog(parent)
|
||||
, _cluster(cluster)
|
||||
, _userConfigPath(configBasePath)
|
||||
, _configurationFilename(configName)
|
||||
, _didImportValues(true)
|
||||
{
|
||||
setWindowTitle("Window Configuration Editor");
|
||||
size_t nWindows = _cluster.nodes.front().windows.size();
|
||||
std::vector<QRect> monitorSizes = createMonitorInfoSet();
|
||||
createWidgets(monitorSizes, static_cast<unsigned int>(nWindows), false);
|
||||
size_t existingWindowsControlSize = _displayWidget->windowControls().size();
|
||||
for (size_t i = 0; i < nWindows; ++i) {
|
||||
sgct::config::Window& w = _cluster.nodes.front().windows[i];
|
||||
WindowControl* wCtrl = _displayWidget->windowControls()[i];
|
||||
if (i < existingWindowsControlSize && wCtrl) {
|
||||
unsigned int monitorNum = 0;
|
||||
if (w.monitor) {
|
||||
monitorNum = static_cast<unsigned int>(w.monitor.value());
|
||||
if (monitorNum > (monitorSizes.size() - 1)) {
|
||||
monitorNum = 0;
|
||||
}
|
||||
}
|
||||
unsigned int posX = 0;
|
||||
unsigned int posY = 0;
|
||||
wCtrl->setMonitorSelection(monitorNum);
|
||||
if (w.pos.has_value()) {
|
||||
posX = w.pos.value().x;
|
||||
posY = w.pos.value().y;
|
||||
// Convert offsets to coordinates relative to the selected monitor bounds,
|
||||
// since window offsets are stored n the sgct config file relative to the
|
||||
// coordinates of the total "canvas" of all displays
|
||||
if (monitorSizes.size() > monitorNum) {
|
||||
posX -= monitorSizes[monitorNum].x();
|
||||
posY -= monitorSizes[monitorNum].y();
|
||||
}
|
||||
}
|
||||
QRectF newDims(
|
||||
posX,
|
||||
posY,
|
||||
w.size.x,
|
||||
w.size.y
|
||||
);
|
||||
wCtrl->setDimensions(newDims);
|
||||
if (w.name.has_value()) {
|
||||
wCtrl->setWindowName(w.name.value());
|
||||
}
|
||||
wCtrl->setDecorationState(w.isDecorated.value());
|
||||
}
|
||||
setupProjectionTypeInGui(w.viewports.back(), wCtrl);
|
||||
}
|
||||
setupStateOfUiOnFirstWindow(nWindows);
|
||||
_settingsWidget->setVsync(
|
||||
_cluster.settings &&
|
||||
_cluster.settings.value().display &&
|
||||
_cluster.settings.value().display.value().swapInterval
|
||||
);
|
||||
}
|
||||
|
||||
void SgctEdit::setupStateOfUiOnFirstWindow(size_t nWindows) {
|
||||
bool firstWindowGuiIsEnabled = (nWindows > 1);
|
||||
int graphicsSelectionForFirstWindow = 0;
|
||||
int nGuiRenderTagsFound = 0;
|
||||
_settingsWidget->nWindowsDisplayedChanged(nWindows);
|
||||
|
||||
for (size_t i = 0; i < nWindows; ++i) {
|
||||
sgct::config::Window& w = _cluster.nodes.front().windows[i];
|
||||
//First window needs to have "GUI" tag if this mode is set
|
||||
if (i == 0) {
|
||||
firstWindowGuiIsEnabled =
|
||||
(std::find(w.tags.begin(), w.tags.end(), "GUI") != w.tags.end());
|
||||
if (std::find(w.tags.begin(), w.tags.end(), "GUI_No_Render") != w.tags.end())
|
||||
{
|
||||
graphicsSelectionForFirstWindow = 0;
|
||||
nGuiRenderTagsFound++;
|
||||
}
|
||||
for (int winNum = 0; winNum <= 4; ++winNum) {
|
||||
std::string tagToLookFor = "GUI_Render_Win" + std::to_string(winNum);
|
||||
if (std::find(w.tags.begin(), w.tags.end(), tagToLookFor) != w.tags.end())
|
||||
{
|
||||
graphicsSelectionForFirstWindow = winNum;
|
||||
nGuiRenderTagsFound++;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If first window only renders 2D, and all subsequent windows do not, then
|
||||
// will enable the checkbox option for showing GUI only on first window
|
||||
if (w.draw2D.has_value()) {
|
||||
firstWindowGuiIsEnabled &= (i == 0) ? w.draw2D.value() : !w.draw2D.value();
|
||||
}
|
||||
else {
|
||||
firstWindowGuiIsEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ((nGuiRenderTagsFound > 1) ||
|
||||
(graphicsSelectionForFirstWindow > static_cast<int>(nWindows)))
|
||||
{
|
||||
graphicsSelectionForFirstWindow = 0;
|
||||
}
|
||||
|
||||
_settingsWidget->setShowUiOnFirstWindow(firstWindowGuiIsEnabled);
|
||||
if (firstWindowGuiIsEnabled) {
|
||||
// Call these again in order to ensure that GUI is configured correctly based on
|
||||
// the values read from the config file
|
||||
_settingsWidget->setEnableShowUiOnFirstWindowCheckbox(true);
|
||||
_settingsWidget->nWindowsDisplayedChanged(nWindows);
|
||||
}
|
||||
_settingsWidget->setGraphicsSelectionForShowUiOnFirstWindow(
|
||||
graphicsSelectionForFirstWindow
|
||||
);
|
||||
}
|
||||
|
||||
void SgctEdit::setupProjectionTypeInGui(sgct::config::Viewport& vPort,
|
||||
WindowControl* wCtrl)
|
||||
{
|
||||
std::visit(overloaded{
|
||||
[&](sgct::config::CylindricalProjection p) {
|
||||
if (p.quality && p.heightOffset) {
|
||||
wCtrl->setProjectionCylindrical(
|
||||
*p.quality,
|
||||
*p.heightOffset
|
||||
);
|
||||
}
|
||||
},
|
||||
[&](sgct::config::EquirectangularProjection p) {
|
||||
if (p.quality) {
|
||||
wCtrl->setProjectionEquirectangular(
|
||||
*p.quality,
|
||||
false
|
||||
);
|
||||
}
|
||||
},
|
||||
[&](sgct::config::FisheyeProjection p) {
|
||||
if (p.quality) {
|
||||
wCtrl->setProjectionFisheye(
|
||||
*p.quality,
|
||||
false
|
||||
);
|
||||
}
|
||||
},
|
||||
[&](sgct::config::PlanarProjection p) {
|
||||
wCtrl->setProjectionPlanar(
|
||||
(std::abs(p.fov.left) + std::abs(p.fov.right)),
|
||||
(std::abs(p.fov.up) + std::abs(p.fov.down))
|
||||
);
|
||||
},
|
||||
[&](sgct::config::SphericalMirrorProjection p) {
|
||||
if (p.quality) {
|
||||
wCtrl->setProjectionSphericalMirror(
|
||||
*p.quality
|
||||
);
|
||||
}
|
||||
},
|
||||
[&](sgct::config::SpoutOutputProjection p) {
|
||||
if (p.quality) {
|
||||
if (p.mapping ==
|
||||
sgct::config::SpoutOutputProjection::Mapping::Equirectangular)
|
||||
{
|
||||
wCtrl->setProjectionEquirectangular(
|
||||
*p.quality,
|
||||
true
|
||||
);
|
||||
}
|
||||
else if (p.mapping ==
|
||||
sgct::config::SpoutOutputProjection::Mapping::Fisheye)
|
||||
{
|
||||
wCtrl->setProjectionFisheye(
|
||||
*p.quality,
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
[&](sgct::config::NoProjection) {},
|
||||
[&](sgct::config::ProjectionPlane) {},
|
||||
[&](sgct::config::SpoutFlatProjection) {}
|
||||
}, vPort.projection);
|
||||
}
|
||||
|
||||
std::vector<QRect> SgctEdit::createMonitorInfoSet() {
|
||||
QList<QScreen*> screens = qApp->screens();
|
||||
int nScreensManaged = std::min(static_cast<int>(screens.length()), 4);
|
||||
std::vector<QRect> monitorSizes;
|
||||
for (int s = 0; s < nScreensManaged; ++s) {
|
||||
@@ -88,15 +275,16 @@ SgctEdit::SgctEdit(QWidget* parent, std::string userConfigPath)
|
||||
static_cast<int>(actualHeight * screens[s]->devicePixelRatio())
|
||||
);
|
||||
}
|
||||
|
||||
createWidgets(monitorSizes);
|
||||
return monitorSizes;
|
||||
}
|
||||
|
||||
void SgctEdit::createWidgets(const std::vector<QRect>& monitorSizes) {
|
||||
void SgctEdit::createWidgets(const std::vector<QRect>& monitorSizes,
|
||||
unsigned int nWindows, bool setToDefaults)
|
||||
{
|
||||
QBoxLayout* layout = new QVBoxLayout(this);
|
||||
layout->setSizeConstraint(QLayout::SetFixedSize);
|
||||
|
||||
sgct::quat orientation = { 0.f, 0.f, 0.f, 0.f };
|
||||
sgct::quat orientation = sgct::quat(0.f, 0.f, 0.f, 0.f);
|
||||
if (_cluster.scene.has_value() && _cluster.scene->orientation.has_value()) {
|
||||
orientation = *_cluster.scene->orientation;
|
||||
}
|
||||
@@ -118,6 +306,7 @@ void SgctEdit::createWidgets(const std::vector<QRect>& monitorSizes) {
|
||||
monitorSizes,
|
||||
MaxNumberWindows,
|
||||
_colorsForWindows,
|
||||
setToDefaults,
|
||||
this
|
||||
);
|
||||
connect(
|
||||
@@ -128,7 +317,10 @@ void SgctEdit::createWidgets(const std::vector<QRect>& monitorSizes) {
|
||||
_displayWidget, &DisplayWindowUnion::nWindowsChanged,
|
||||
monitorBox, &MonitorBox::nWindowsDisplayedChanged
|
||||
);
|
||||
_displayWidget->addWindow();
|
||||
|
||||
for (unsigned int i = 0; i < nWindows; ++i) {
|
||||
_displayWidget->addWindow();
|
||||
}
|
||||
|
||||
displayLayout->addWidget(_displayWidget);
|
||||
|
||||
@@ -137,7 +329,33 @@ void SgctEdit::createWidgets(const std::vector<QRect>& monitorSizes) {
|
||||
|
||||
_settingsWidget = new SettingsWidget(orientation, this);
|
||||
layout->addWidget(_settingsWidget);
|
||||
|
||||
connect(
|
||||
_displayWidget, &DisplayWindowUnion::nWindowsChanged,
|
||||
_settingsWidget, &SettingsWidget::nWindowsDisplayedChanged
|
||||
);
|
||||
|
||||
connect(
|
||||
_displayWidget, &DisplayWindowUnion::nWindowsChanged,
|
||||
this, &SgctEdit::nWindowsDisplayedChanged
|
||||
);
|
||||
|
||||
if (_settingsWidget->firstWindowGraphicsSelection()) {
|
||||
connect(
|
||||
_settingsWidget->firstWindowGraphicsSelection(),
|
||||
&QComboBox::currentTextChanged,
|
||||
this,
|
||||
&SgctEdit::firstWindowGraphicsSelectionChanged
|
||||
);
|
||||
}
|
||||
if (_settingsWidget->showUiOnFirstWindowCheckbox()) {
|
||||
connect(
|
||||
_settingsWidget->showUiOnFirstWindowCheckbox(),
|
||||
&QCheckBox::clicked,
|
||||
this,
|
||||
&SgctEdit::firstWindowGuiOptionClicked
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
QHBoxLayout* layoutButtonBox = new QHBoxLayout;
|
||||
layoutButtonBox->addStretch(1);
|
||||
@@ -147,19 +365,20 @@ void SgctEdit::createWidgets(const std::vector<QRect>& monitorSizes) {
|
||||
layout->addWidget(bottomBorder);
|
||||
|
||||
_cancelButton = new QPushButton("Cancel");
|
||||
_cancelButton->setToolTip("Cancel changes.");
|
||||
_cancelButton->setToolTip("Cancel changes");
|
||||
_cancelButton->setFocusPolicy(Qt::NoFocus);
|
||||
connect(_cancelButton, &QPushButton::released, this, &SgctEdit::reject);
|
||||
layoutButtonBox->addWidget(_cancelButton);
|
||||
|
||||
_saveButton = new QPushButton("Save As");
|
||||
_saveButton->setToolTip("Save configuration changes.");
|
||||
_saveButton = _didImportValues ?
|
||||
new QPushButton("Save") : new QPushButton("Save As");
|
||||
_saveButton->setToolTip("Save configuration changes");
|
||||
_saveButton->setFocusPolicy(Qt::NoFocus);
|
||||
connect(_saveButton, &QPushButton::released, this, &SgctEdit::save);
|
||||
layoutButtonBox->addWidget(_saveButton);
|
||||
|
||||
_applyButton = new QPushButton("Apply Without Saving");
|
||||
_applyButton->setToolTip("Apply configuration changes without saving to file.");
|
||||
_applyButton->setToolTip("Apply configuration changes without saving to file");
|
||||
_applyButton->setFocusPolicy(Qt::NoFocus);
|
||||
connect(_applyButton, &QPushButton::released, this, &SgctEdit::apply);
|
||||
layoutButtonBox->addWidget(_applyButton);
|
||||
@@ -173,8 +392,8 @@ std::filesystem::path SgctEdit::saveFilename() const {
|
||||
}
|
||||
|
||||
void SgctEdit::save() {
|
||||
sgct::config::Cluster cluster = generateConfiguration();
|
||||
if (hasWindowIssues(cluster)) {
|
||||
generateConfiguration();
|
||||
if (hasWindowIssues(_cluster)) {
|
||||
int ret = QMessageBox::warning(
|
||||
this,
|
||||
"Window Sizes Incompatible",
|
||||
@@ -183,34 +402,39 @@ void SgctEdit::save() {
|
||||
"window 2 has to be bigger than window 3 (if it exists), and window 3 has to "
|
||||
"be bigger than window 4.\nOtherwise, rendering errors might occur.\n\nAre "
|
||||
"you sure you want to continue?",
|
||||
QMessageBox::StandardButtons(QMessageBox::Yes || QMessageBox::No)
|
||||
QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No)
|
||||
);
|
||||
if (ret == QMessageBox::No) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
QString fileName = QFileDialog::getSaveFileName(
|
||||
this,
|
||||
"Save Window Configuration File",
|
||||
QString::fromStdString(_userConfigPath),
|
||||
"Window Configuration (*.json)",
|
||||
nullptr
|
||||
#ifdef __linux__
|
||||
// Linux in Qt5 and Qt6 crashes when trying to access the native dialog here
|
||||
, QFileDialog::DontUseNativeDialog
|
||||
#endif
|
||||
);
|
||||
if (!fileName.isEmpty()) {
|
||||
_saveTarget = fileName.toStdString();
|
||||
_cluster = std::move(cluster);
|
||||
if (_didImportValues) {
|
||||
_saveTarget = _configurationFilename;
|
||||
accept();
|
||||
}
|
||||
else {
|
||||
QString fileName = QFileDialog::getSaveFileName(
|
||||
this,
|
||||
"Save Window Configuration File",
|
||||
QString::fromStdString(_userConfigPath),
|
||||
"Window Configuration (*.json)",
|
||||
nullptr
|
||||
#ifdef __linux__
|
||||
// Linux in Qt5 and Qt6 crashes when trying to access the native dialog here
|
||||
, QFileDialog::DontUseNativeDialog
|
||||
#endif
|
||||
);
|
||||
if (!fileName.isEmpty()) {
|
||||
_saveTarget = fileName.toStdString();
|
||||
accept();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SgctEdit::apply() {
|
||||
sgct::config::Cluster cluster = generateConfiguration();
|
||||
if (hasWindowIssues(cluster)) {
|
||||
generateConfiguration();
|
||||
if (hasWindowIssues(_cluster)) {
|
||||
int ret = QMessageBox::warning(
|
||||
this,
|
||||
"Window Sizes Incompatible",
|
||||
@@ -235,60 +459,166 @@ void SgctEdit::apply() {
|
||||
std::filesystem::create_directories(absPath(userCfgTempDir));
|
||||
}
|
||||
_saveTarget = userCfgTempDir + "/apply-without-saving.json";
|
||||
_cluster = std::move(cluster);
|
||||
accept();
|
||||
}
|
||||
|
||||
sgct::config::Cluster SgctEdit::generateConfiguration() const {
|
||||
sgct::config::Cluster cluster;
|
||||
void SgctEdit::generateConfiguration() {
|
||||
_cluster.scene = sgct::config::Scene();
|
||||
_cluster.scene->orientation = _settingsWidget->orientation();
|
||||
if (_cluster.nodes.empty()) {
|
||||
_cluster.nodes.push_back(sgct::config::Node());
|
||||
}
|
||||
sgct::config::Node& node = _cluster.nodes.back();
|
||||
|
||||
sgct::config::Scene scene;
|
||||
scene.orientation = _settingsWidget->orientation();
|
||||
cluster.scene = std::move(scene);
|
||||
|
||||
cluster.masterAddress = "localhost";
|
||||
generateConfigSetupVsync();
|
||||
generateConfigUsers();
|
||||
generateConfigAddresses(node);
|
||||
generateConfigResizeWindowsAccordingToSelected(node);
|
||||
generateConfigIndividualWindowSettings(node);
|
||||
}
|
||||
|
||||
void SgctEdit::generateConfigSetupVsync() {
|
||||
if (_settingsWidget->vsync()) {
|
||||
sgct::config::Settings::Display display;
|
||||
display.swapInterval = 1;
|
||||
|
||||
sgct::config::Settings settings;
|
||||
settings.display = display;
|
||||
|
||||
cluster.settings = settings;
|
||||
if (!_cluster.settings || !_cluster.settings->display ||
|
||||
!_cluster.settings->display->swapInterval)
|
||||
{
|
||||
sgct::config::Settings::Display display;
|
||||
display.swapInterval = 1;
|
||||
sgct::config::Settings settings;
|
||||
settings.display = display;
|
||||
_cluster.settings = settings;
|
||||
}
|
||||
}
|
||||
|
||||
sgct::config::Node node;
|
||||
node.address = "localhost";
|
||||
node.port = 20401;
|
||||
|
||||
// Save Windows
|
||||
unsigned int windowIndex = 0;
|
||||
for (WindowControl* wCtrl : _displayWidget->windowControls()) {
|
||||
sgct::config::Window window = wCtrl->generateWindowInformation();
|
||||
|
||||
window.id = windowIndex++;
|
||||
node.windows.push_back(std::move(window));
|
||||
else {
|
||||
_cluster.settings = std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
if (_settingsWidget->showUiOnFirstWindow()) {
|
||||
sgct::config::Window& window = node.windows.front();
|
||||
window.viewports.back().isTracked = false;
|
||||
window.tags.push_back("GUI");
|
||||
window.draw2D = true;
|
||||
window.draw3D = false;
|
||||
void SgctEdit::generateConfigUsers() {
|
||||
if (!_didImportValues) {
|
||||
sgct::config::User user;
|
||||
user.eyeSeparation = 0.065f;
|
||||
user.position = { 0.f, 0.f, 4.f };
|
||||
_cluster.users = { user };
|
||||
}
|
||||
}
|
||||
|
||||
cluster.nodes.push_back(node);
|
||||
void SgctEdit::generateConfigAddresses(sgct::config::Node& node) {
|
||||
if (!_didImportValues) {
|
||||
_cluster.masterAddress = "localhost";
|
||||
node.address = "localhost";
|
||||
node.port = 20401;
|
||||
}
|
||||
}
|
||||
|
||||
sgct::config::User user;
|
||||
user.eyeSeparation = 0.065f;
|
||||
user.position = { 0.f, 0.f, 4.f };
|
||||
cluster.users = { user };
|
||||
void SgctEdit::generateConfigResizeWindowsAccordingToSelected(sgct::config::Node& node) {
|
||||
std::vector<WindowControl*> windowControls = _displayWidget->activeWindowControls();
|
||||
for (size_t wIdx = 0; wIdx < windowControls.size(); ++wIdx) {
|
||||
if (node.windows.size() <= wIdx) {
|
||||
node.windows.push_back(sgct::config::Window());
|
||||
}
|
||||
if (windowControls[wIdx]) {
|
||||
windowControls[wIdx]->generateWindowInformation(
|
||||
node.windows[wIdx]
|
||||
);
|
||||
}
|
||||
}
|
||||
while (node.windows.size() > windowControls.size()) {
|
||||
node.windows.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
return cluster;
|
||||
void SgctEdit::generateConfigIndividualWindowSettings(sgct::config::Node& node) {
|
||||
for (size_t i = 0; i < node.windows.size(); ++i) {
|
||||
// First apply default settings to each window...
|
||||
node.windows[i].id = static_cast<int>(i);
|
||||
node.windows[i].draw2D = true;
|
||||
node.windows[i].draw3D = true;
|
||||
node.windows[i].viewports.back().isTracked = true;
|
||||
deleteFromTags(node.windows[i]);
|
||||
// If "show UI on first window" option is enabled, then modify the settings
|
||||
// depending on if this is the first window or not
|
||||
if (_settingsWidget->showUiOnFirstWindow()) {
|
||||
if (i == 0) {
|
||||
node.windows[i].tags.push_back("GUI");
|
||||
int selectedGraphics =
|
||||
_settingsWidget->graphicsSelectionForShowUiOnFirstWindow();
|
||||
|
||||
if (selectedGraphics == 0) {
|
||||
node.windows[i].viewports.back().isTracked = false;
|
||||
node.windows[i].tags.push_back("GUI_No_Render");
|
||||
}
|
||||
else if (selectedGraphics > 0 &&
|
||||
selectedGraphics <= static_cast<int>(node.windows.size()))
|
||||
{
|
||||
node.windows[i].tags.push_back("GUI_Render_Win" +
|
||||
std::to_string(selectedGraphics));
|
||||
//Set first window viewport to mirror the selected window's viewport
|
||||
node.windows[i].viewports =
|
||||
node.windows[(selectedGraphics - 1)].viewports;
|
||||
}
|
||||
node.windows[i].draw2D = true;
|
||||
node.windows[i].draw3D = (selectedGraphics > 0);
|
||||
}
|
||||
else {
|
||||
node.windows[i].draw2D = false;
|
||||
node.windows[i].draw3D = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SgctEdit::deleteFromTags(sgct::config::Window& window) {
|
||||
constexpr std::array<std::string_view, 6> Tags = {
|
||||
"GUI",
|
||||
"GUI_No_Render",
|
||||
"GUI_Render_Win1",
|
||||
"GUI_Render_Win2",
|
||||
"GUI_Render_Win3",
|
||||
"GUI_Render_Win4"
|
||||
};
|
||||
for (std::string_view tag : Tags) {
|
||||
window.tags.erase(
|
||||
std::remove(window.tags.begin(), window.tags.end(), tag),
|
||||
window.tags.end()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
sgct::config::Cluster SgctEdit::cluster() const {
|
||||
return _cluster;
|
||||
}
|
||||
|
||||
void SgctEdit::firstWindowGraphicsSelectionChanged(const QString&) {
|
||||
if (!_settingsWidget)
|
||||
return;
|
||||
|
||||
int newSetting = _settingsWidget->graphicsSelectionForShowUiOnFirstWindow();
|
||||
|
||||
if (_settingsWidget->showUiOnFirstWindow()) {
|
||||
_displayWidget->activeWindowControls()[0]->setVisibilityOfProjectionGui(
|
||||
newSetting == 1
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void SgctEdit::nWindowsDisplayedChanged(int newCount) {
|
||||
if (!_settingsWidget) {
|
||||
return;
|
||||
}
|
||||
if (newCount == 1) {
|
||||
_displayWidget->activeWindowControls()[0]->setVisibilityOfProjectionGui(true);
|
||||
}
|
||||
else {
|
||||
firstWindowGraphicsSelectionChanged("");
|
||||
}
|
||||
}
|
||||
|
||||
void SgctEdit::firstWindowGuiOptionClicked(bool checked) {
|
||||
if (checked) {
|
||||
firstWindowGraphicsSelectionChanged("");
|
||||
}
|
||||
else {
|
||||
_displayWidget->activeWindowControls()[0]->setVisibilityOfProjectionGui(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -36,31 +36,39 @@
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QSpinBox>
|
||||
#include <numbers>
|
||||
|
||||
namespace {
|
||||
std::array<std::string, 4> MonitorNames = {
|
||||
"Primary", "Secondary", "Tertiary", "Quaternary"
|
||||
};
|
||||
|
||||
constexpr int nQualityTypes = 10;
|
||||
|
||||
const QList<QString> QualityTypes = {
|
||||
"Low (256)", "Medium (512)", "High (1K)", "1.5K (1536)", "2K (2048)", "4K (4096)",
|
||||
"8K (8192)", "16K (16384)", "32K (32768)", "64K (65536)"
|
||||
};
|
||||
|
||||
constexpr int QualityValues[10] = {
|
||||
constexpr int QualityValues[nQualityTypes] = {
|
||||
256, 512, 1024, 1536, 2048, 4096, 8192, 16384, 32768, 65536
|
||||
};
|
||||
|
||||
constexpr std::array<QRectF, 4> DefaultWindowSizes = {
|
||||
QRectF{ 50.f, 50.f, 1280.f, 720.f },
|
||||
QRectF{ 150.f, 150.f, 1280.f, 720.f },
|
||||
QRectF{ 50.f, 50.f, 1280.f, 720.f },
|
||||
QRectF{ 150.f, 150.f, 1280.f, 720.f }
|
||||
const QList<QString> ProjectionTypes = {
|
||||
"Planar Projection", "Fisheye", "Spherical Mirror Projection",
|
||||
"Cylindrical Projection", "Equirectangular Projection"
|
||||
};
|
||||
|
||||
constexpr int LineEditWidthFixedWindowSize = 50;
|
||||
constexpr float DefaultFovH = 80.f;
|
||||
constexpr float DefaultFovV = 50.534f;
|
||||
constexpr std::array<QRectF, 4> DefaultWindowSizes = {
|
||||
QRectF(50.f, 50.f, 1280.f, 720.f),
|
||||
QRectF(150.f, 150.f, 1280.f, 720.f),
|
||||
QRectF(50.f, 50.f, 1280.f, 720.f),
|
||||
QRectF(150.f, 150.f, 1280.f, 720.f)
|
||||
};
|
||||
|
||||
constexpr int LineEditWidthFixedWindowSize = 64;
|
||||
constexpr float DefaultFovLongEdge = 80.f;
|
||||
constexpr float DefaultFovShortEdge = 50.534f;
|
||||
constexpr float DefaultHeightOffset = 0.f;
|
||||
constexpr int MaxWindowSizePixels = 10000;
|
||||
constexpr double FovEpsilon = 0.00001;
|
||||
@@ -80,7 +88,7 @@ namespace {
|
||||
|
||||
WindowControl::WindowControl(int monitorIndex, int windowIndex,
|
||||
const std::vector<QRect>& monitorDims,
|
||||
const QColor& winColor, QWidget* parent)
|
||||
const QColor& winColor, bool resetToDefault, QWidget* parent)
|
||||
: QWidget(parent)
|
||||
, _monitorIndexDefault(monitorIndex)
|
||||
, _windowIndex(windowIndex)
|
||||
@@ -89,7 +97,9 @@ WindowControl::WindowControl(int monitorIndex, int windowIndex,
|
||||
, _unlockIcon(":/images/outline_unlocked.png")
|
||||
{
|
||||
createWidgets(winColor);
|
||||
resetToDefaults();
|
||||
if (resetToDefault) {
|
||||
resetToDefaults();
|
||||
}
|
||||
}
|
||||
|
||||
void WindowControl::createWidgets(const QColor& windowColor) {
|
||||
@@ -118,7 +128,7 @@ void WindowControl::createWidgets(const QColor& windowColor) {
|
||||
)));
|
||||
layout->addWidget(_windowNumber, 0, 0, 1, 8, Qt::AlignCenter);
|
||||
{
|
||||
QString tip = "The name for the window (displayed in title bar).";
|
||||
QString tip = "The name for the window (displayed in title bar)";
|
||||
|
||||
QLabel* labelName = new QLabel("Name");
|
||||
labelName->setToolTip(tip);
|
||||
@@ -128,7 +138,7 @@ void WindowControl::createWidgets(const QColor& windowColor) {
|
||||
_windowName->setToolTip(tip);
|
||||
layout->addWidget(_windowName, 1, 1, 1, 7);
|
||||
}
|
||||
QString tip = "The monitor where this window is located.";
|
||||
QString tip = "The monitor where this window is located";
|
||||
|
||||
_monitor = new QComboBox;
|
||||
_monitor->addItems(monitorNames(_monitorResolutions));
|
||||
@@ -207,7 +217,7 @@ void WindowControl::createWidgets(const QColor& windowColor) {
|
||||
QLabel* offset = new QLabel("Offset");
|
||||
offset->setToolTip(
|
||||
"The x,y location of the window's upper left corner from monitor's "
|
||||
"upper-left corner origin (pixels)."
|
||||
"upper-left corner origin (pixels)"
|
||||
);
|
||||
offset->setFixedWidth(55);
|
||||
layout->addWidget(offset, 4, 0);
|
||||
@@ -289,14 +299,23 @@ void WindowControl::createWidgets(const QColor& windowColor) {
|
||||
QBoxLayout* projectionLayout = new QVBoxLayout(projectionGroup);
|
||||
projectionLayout->setContentsMargins(0, 0, 0, 0);
|
||||
projectionLayout->setSpacing(0);
|
||||
_projectionLabel = new QLabel(
|
||||
"Projection information not shown while user interface is set to display "
|
||||
"on the first window only"
|
||||
);
|
||||
_projectionLabel->setWordWrap(true);
|
||||
_projectionLabel->setObjectName("notice");
|
||||
_projectionLabel->setVisible(false);
|
||||
_projectionLabel->setEnabled(false);
|
||||
projectionLayout->addWidget(_projectionLabel);
|
||||
|
||||
_projectionType = new QComboBox;
|
||||
_projectionType->addItems({
|
||||
"Planar Projection",
|
||||
"Fisheye",
|
||||
"Spherical Mirror Projection",
|
||||
"Cylindrical Projection",
|
||||
"Equirectangular Projection"
|
||||
ProjectionTypes[0],
|
||||
ProjectionTypes[1],
|
||||
ProjectionTypes[2],
|
||||
ProjectionTypes[3],
|
||||
ProjectionTypes[4]
|
||||
});
|
||||
_projectionType->setToolTip("Select from the supported window projection types");
|
||||
_projectionType->setCurrentIndex(0);
|
||||
@@ -340,25 +359,25 @@ QWidget* WindowControl::createPlanarWidget() {
|
||||
QGridLayout* layout = new QGridLayout(widget);
|
||||
layout->setColumnStretch(1, 1);
|
||||
|
||||
QLabel* info = new QLabel(
|
||||
_planar.labelInfo = new QLabel(
|
||||
"This projection type is the 'regular' projection with a horizontal and a "
|
||||
"vertical field of view, given in degrees. The wider the field of view, the "
|
||||
"more content is shown at the same time, but everything becomes smaller. Very "
|
||||
"large values will introduce distorions on the corners"
|
||||
);
|
||||
info->setObjectName("info");
|
||||
info->setWordWrap(true);
|
||||
layout->addWidget(info, 0, 0, 1, 3);
|
||||
_planar.labelInfo->setObjectName("info");
|
||||
_planar.labelInfo->setWordWrap(true);
|
||||
layout->addWidget(_planar.labelInfo, 0, 0, 1, 3);
|
||||
|
||||
QLabel* fovH = new QLabel("Horizontal FOV");
|
||||
_planar.labelFovH = new QLabel("Horizontal FOV");
|
||||
QString hfovTip = "The total horizontal field of view of the viewport (degrees)";
|
||||
fovH->setToolTip(hfovTip);
|
||||
layout->addWidget(fovH, 1, 0);
|
||||
_planar.labelFovH->setToolTip(hfovTip);
|
||||
layout->addWidget(_planar.labelFovH, 1, 0);
|
||||
|
||||
_planar.fovH = new QDoubleSpinBox;
|
||||
_planar.fovH->setMinimum(FovEpsilon);
|
||||
_planar.fovH->setMaximum(180.0 - FovEpsilon);
|
||||
_planar.fovH->setValue(DefaultFovH);
|
||||
_planar.fovH->setValue(DefaultFovLongEdge);
|
||||
_planar.fovH->setEnabled(false);
|
||||
_planar.fovH->setToolTip(hfovTip);
|
||||
_planar.fovH->setSizePolicy(
|
||||
@@ -367,16 +386,16 @@ QWidget* WindowControl::createPlanarWidget() {
|
||||
);
|
||||
layout->addWidget(_planar.fovH, 1, 1);
|
||||
|
||||
QLabel* fovV = new QLabel("Vertical FOV");
|
||||
_planar.labelFovV = new QLabel("Vertical FOV");
|
||||
QString vfovTip = "The total vertical field of view of the viewport (degrees). "
|
||||
"Internally,\nthe values for 'up' & 'down' will each be half this value";
|
||||
fovV->setToolTip(vfovTip);
|
||||
layout->addWidget(fovV, 2, 0);
|
||||
_planar.labelFovV->setToolTip(vfovTip);
|
||||
layout->addWidget(_planar.labelFovV, 2, 0);
|
||||
|
||||
_planar.fovV = new QDoubleSpinBox;
|
||||
_planar.fovV->setMinimum(FovEpsilon);
|
||||
_planar.fovV->setMaximum(180.0 - FovEpsilon);
|
||||
_planar.fovV->setValue(DefaultFovV);
|
||||
_planar.fovV->setValue(DefaultFovShortEdge);
|
||||
_planar.fovV->setEnabled(false);
|
||||
_planar.fovV->setToolTip(vfovTip);
|
||||
_planar.fovV->setSizePolicy(
|
||||
@@ -385,21 +404,20 @@ QWidget* WindowControl::createPlanarWidget() {
|
||||
);
|
||||
layout->addWidget(_planar.fovV, 2, 1);
|
||||
|
||||
QPushButton* lockFov = new QPushButton;
|
||||
lockFov->setIcon(_lockIcon);
|
||||
lockFov->setToolTip(
|
||||
_planar.buttonLockFov = new QPushButton;
|
||||
_planar.buttonLockFov->setIcon(_lockIcon);
|
||||
_planar.buttonLockFov->setToolTip(
|
||||
"Locks and scales the Horizontal & Vertical field-of-view to the ideal settings "
|
||||
"based on the provided aspect ratio"
|
||||
);
|
||||
lockFov->setFocusPolicy(Qt::NoFocus);
|
||||
layout->addWidget(lockFov, 1, 2, 2, 1);
|
||||
_planar.buttonLockFov->setFocusPolicy(Qt::NoFocus);
|
||||
layout->addWidget(_planar.buttonLockFov, 1, 2, 2, 1);
|
||||
connect(
|
||||
lockFov, &QPushButton::released,
|
||||
[this, lockFov]() {
|
||||
lockFov->setIcon(_fovLocked ? _lockIcon : _unlockIcon);
|
||||
}
|
||||
_planar.buttonLockFov,
|
||||
&QPushButton::released,
|
||||
this,
|
||||
&WindowControl::onFovLockClicked
|
||||
);
|
||||
connect(lockFov, &QPushButton::released, this, &WindowControl::onFovLockClicked);
|
||||
|
||||
return widget;
|
||||
}
|
||||
@@ -416,22 +434,22 @@ QWidget* WindowControl::createFisheyeWidget() {
|
||||
QGridLayout* layout = new QGridLayout(widget);
|
||||
layout->setColumnStretch(1, 1);
|
||||
|
||||
QLabel* info = new QLabel(
|
||||
_fisheye.labelInfo = new QLabel(
|
||||
"This projection provides a rendering in a format that is suitable for "
|
||||
"planetariums and other immersive environments. A field-of-view of 180 degrees "
|
||||
"is presented as a circular image in the center of the screen. For this "
|
||||
"projection a square window is suggested, but not necessary."
|
||||
"projection a square window is suggested, but not necessary"
|
||||
);
|
||||
info->setObjectName("info");
|
||||
info->setWordWrap(true);
|
||||
layout->addWidget(info, 0, 0, 1, 2);
|
||||
_fisheye.labelInfo->setObjectName("info");
|
||||
_fisheye.labelInfo->setWordWrap(true);
|
||||
layout->addWidget(_fisheye.labelInfo, 0, 0, 1, 2);
|
||||
|
||||
QLabel* qualityFisheye = new QLabel("Quality");
|
||||
_fisheye.labelQuality = new QLabel("Quality");
|
||||
QString qualityTip = "Determines the pixel resolution of the projection rendering. "
|
||||
"The higher resolution,\nthe better the rendering quality, but at the expense of "
|
||||
"increased rendering times";
|
||||
qualityFisheye->setToolTip(qualityTip);
|
||||
layout->addWidget(qualityFisheye, 1, 0);
|
||||
_fisheye.labelQuality->setToolTip(qualityTip);
|
||||
layout->addWidget(_fisheye.labelQuality, 1, 0);
|
||||
|
||||
_fisheye.quality = new QComboBox;
|
||||
_fisheye.quality->addItems(QualityTypes);
|
||||
@@ -461,22 +479,22 @@ QWidget* WindowControl::createSphericalMirrorWidget() {
|
||||
QGridLayout* layout = new QGridLayout(widget);
|
||||
layout->setColumnStretch(1, 1);
|
||||
|
||||
QLabel* info = new QLabel(
|
||||
_sphericalMirror.labelInfo = new QLabel(
|
||||
"This projection is rendering a image suite for use with a spherical mirror "
|
||||
"projection as described by Paul Bourke (http://paulbourke.net/dome/mirrordome/) "
|
||||
"and which is a low-cost yet effective way to provide content for a sphericalal "
|
||||
"display surface using a regular projector."
|
||||
"display surface using a regular projector"
|
||||
);
|
||||
info->setObjectName("info");
|
||||
info->setWordWrap(true);
|
||||
layout->addWidget(info, 0, 0, 1, 2);
|
||||
_sphericalMirror.labelInfo->setObjectName("info");
|
||||
_sphericalMirror.labelInfo->setWordWrap(true);
|
||||
layout->addWidget(_sphericalMirror.labelInfo, 0, 0, 1, 2);
|
||||
|
||||
QLabel* qualitySphericalMirror = new QLabel("Quality");
|
||||
_sphericalMirror.labelQuality = new QLabel("Quality");
|
||||
QString qualityTip = "Determines the pixel resolution of the projection rendering. "
|
||||
"The higher resolution,\nthe better the rendering quality, but at the expense of "
|
||||
"increased rendering times";
|
||||
qualitySphericalMirror->setToolTip(qualityTip);
|
||||
layout->addWidget(qualitySphericalMirror, 1, 0);
|
||||
_sphericalMirror.labelQuality->setToolTip(qualityTip);
|
||||
layout->addWidget(_sphericalMirror.labelQuality, 1, 0);
|
||||
|
||||
_sphericalMirror.quality = new QComboBox;
|
||||
_sphericalMirror.quality->addItems(QualityTypes);
|
||||
@@ -484,7 +502,6 @@ QWidget* WindowControl::createSphericalMirrorWidget() {
|
||||
_sphericalMirror.quality->setCurrentIndex(2);
|
||||
layout->addWidget(_sphericalMirror.quality, 1, 1);
|
||||
|
||||
|
||||
return widget;
|
||||
}
|
||||
|
||||
@@ -499,22 +516,22 @@ QWidget* WindowControl::createCylindricalWidget() {
|
||||
QGridLayout* layout = new QGridLayout(widget);
|
||||
layout->setColumnStretch(1, 1);
|
||||
|
||||
QLabel* info = new QLabel(
|
||||
_cylindrical.labelInfo = new QLabel(
|
||||
"This projection type provides a cylindrical rendering that covers 360 degrees "
|
||||
"around the camera, which can be useful in immersive environments that are not "
|
||||
"spherical, but where, for example, all walls of a room are covered with "
|
||||
"projectors."
|
||||
"projectors"
|
||||
);
|
||||
info->setObjectName("info");
|
||||
info->setWordWrap(true);
|
||||
layout->addWidget(info, 0, 0, 1, 2);
|
||||
_cylindrical.labelInfo->setObjectName("info");
|
||||
_cylindrical.labelInfo->setWordWrap(true);
|
||||
layout->addWidget(_cylindrical.labelInfo, 0, 0, 1, 2);
|
||||
|
||||
QLabel* qualityCylindrical = new QLabel("Quality");
|
||||
_cylindrical.labelQuality = new QLabel("Quality");
|
||||
QString qualityTip = "Determines the pixel resolution of the projection rendering. "
|
||||
"The higher resolution,\nthe better the rendering quality, but at the expense of "
|
||||
"increased rendering times";
|
||||
qualityCylindrical->setToolTip(qualityTip);
|
||||
layout->addWidget(qualityCylindrical, 1, 0);
|
||||
_cylindrical.labelQuality->setToolTip(qualityTip);
|
||||
layout->addWidget(_cylindrical.labelQuality, 1, 0);
|
||||
|
||||
_cylindrical.quality = new QComboBox;
|
||||
_cylindrical.quality->addItems(QualityTypes);
|
||||
@@ -522,13 +539,13 @@ QWidget* WindowControl::createCylindricalWidget() {
|
||||
_cylindrical.quality->setCurrentIndex(2);
|
||||
layout->addWidget(_cylindrical.quality, 1, 1);
|
||||
|
||||
QLabel* heightOffset = new QLabel("Height Offset");
|
||||
_cylindrical.labelHeightOffset = new QLabel("Height Offset");
|
||||
QString heightTip = "Offsets the height from which the cylindrical projection is "
|
||||
"generated.\nThis is, in general, only necessary if the user position is offset "
|
||||
"and\ncountering that offset is desired in order to continue producing\na "
|
||||
"'standard' cylindrical projection";
|
||||
heightOffset->setToolTip(heightTip);
|
||||
layout->addWidget(heightOffset, 2, 0);
|
||||
_cylindrical.labelHeightOffset->setToolTip(heightTip);
|
||||
layout->addWidget(_cylindrical.labelHeightOffset, 2, 0);
|
||||
|
||||
_cylindrical.heightOffset = new QDoubleSpinBox;
|
||||
_cylindrical.heightOffset->setMinimum(-1000000.0);
|
||||
@@ -552,22 +569,22 @@ QWidget* WindowControl::createEquirectangularWidget() {
|
||||
QGridLayout* layout = new QGridLayout(widget);
|
||||
layout->setColumnStretch(1, 1);
|
||||
|
||||
QLabel* info = new QLabel(
|
||||
_equirectangular.labelInfo = new QLabel(
|
||||
"This projection provides the rendering as an image in equirectangular "
|
||||
"projection, which is a common display type for 360 surround video. When "
|
||||
"uploading a video in equirectangular projection to YouTube, for example, it "
|
||||
"will use it as a 360 video."
|
||||
"will use it as a 360 video"
|
||||
);
|
||||
info->setObjectName("info");
|
||||
info->setWordWrap(true);
|
||||
layout->addWidget(info, 0, 0, 1, 2);
|
||||
_equirectangular.labelInfo->setObjectName("info");
|
||||
_equirectangular.labelInfo->setWordWrap(true);
|
||||
layout->addWidget(_equirectangular.labelInfo, 0, 0, 1, 2);
|
||||
|
||||
QLabel* qualityEquirectangular = new QLabel("Quality");
|
||||
_equirectangular.labelQuality = new QLabel("Quality");
|
||||
QString qualityTip = "Determines the pixel resolution of the projection rendering. "
|
||||
"The higher resolution,\nthe better the rendering quality, but at the expense of "
|
||||
"increased rendering times";
|
||||
qualityEquirectangular->setToolTip(qualityTip);
|
||||
layout->addWidget(qualityEquirectangular, 1, 0);
|
||||
_equirectangular.labelQuality->setToolTip(qualityTip);
|
||||
layout->addWidget(_equirectangular.labelQuality, 1, 0);
|
||||
|
||||
_equirectangular.quality = new QComboBox;
|
||||
_equirectangular.quality->addItems(QualityTypes);
|
||||
@@ -614,8 +631,8 @@ void WindowControl::resetToDefaults() {
|
||||
_fisheye.spoutOutput->setChecked(false);
|
||||
_equirectangular.spoutOutput->setChecked(false);
|
||||
_projectionType->setCurrentIndex(static_cast<int>(ProjectionIndices::Planar));
|
||||
_planar.fovV->setValue(DefaultFovH);
|
||||
_planar.fovV->setValue(DefaultFovV);
|
||||
_planar.fovV->setValue(DefaultFovLongEdge);
|
||||
_planar.fovV->setValue(DefaultFovShortEdge);
|
||||
_cylindrical.heightOffset->setValue(DefaultHeightOffset);
|
||||
_fisheye.quality->setCurrentIndex(2);
|
||||
_sphericalMirror.quality->setCurrentIndex(2);
|
||||
@@ -624,10 +641,30 @@ void WindowControl::resetToDefaults() {
|
||||
emit windowChanged(_monitorIndexDefault, _windowIndex, _windowDimensions);
|
||||
}
|
||||
|
||||
void WindowControl::setDimensions(QRectF newDims) {
|
||||
_windowDimensions = newDims;
|
||||
_sizeX->setValue(_windowDimensions.width());
|
||||
_sizeY->setValue(_windowDimensions.height());
|
||||
_offsetX->setValue(_windowDimensions.x());
|
||||
_offsetY->setValue(_windowDimensions.y());
|
||||
}
|
||||
|
||||
void WindowControl::setMonitorSelection(int monitorIndex) {
|
||||
_monitor->setCurrentIndex(monitorIndex);
|
||||
}
|
||||
|
||||
void WindowControl::showWindowLabel(bool show) {
|
||||
_windowNumber->setVisible(show);
|
||||
}
|
||||
|
||||
void WindowControl::setWindowName(const std::string& windowName) {
|
||||
_windowName->setText(QString::fromStdString(windowName));
|
||||
}
|
||||
|
||||
void WindowControl::setDecorationState(bool hasWindowDecoration) {
|
||||
_windowDecoration->setChecked(hasWindowDecoration);
|
||||
}
|
||||
|
||||
sgct::config::Projections WindowControl::generateProjectionInformation() const {
|
||||
ProjectionIndices type =
|
||||
static_cast<WindowControl::ProjectionIndices>(_projectionType->currentIndex());
|
||||
@@ -705,31 +742,98 @@ sgct::config::Projections WindowControl::generateProjectionInformation() const {
|
||||
}
|
||||
}
|
||||
|
||||
sgct::config::Window WindowControl::generateWindowInformation() const {
|
||||
sgct::config::Window window;
|
||||
void WindowControl::generateWindowInformation(sgct::config::Window& window) const {
|
||||
window.size = { _sizeX->text().toInt(), _sizeY->text().toInt() };
|
||||
window.monitor = _monitor->currentIndex();
|
||||
QRect resolution = _monitorResolutions[_monitor->currentIndex()];
|
||||
window.pos = {
|
||||
window.pos = sgct::ivec2(
|
||||
resolution.x() + _offsetX->text().toInt(),
|
||||
resolution.y() + _offsetY->text().toInt()
|
||||
};
|
||||
);
|
||||
|
||||
sgct::config::Viewport vp;
|
||||
vp.isTracked = true;
|
||||
vp.position = { 0.f, 0.f };
|
||||
vp.size = { 1.f, 1.f };
|
||||
vp.position = sgct::vec2(0.f, 0.f);
|
||||
vp.size = sgct::vec2(1.f, 1.f);
|
||||
vp.projection = generateProjectionInformation();
|
||||
window.viewports.clear();
|
||||
window.viewports.push_back(vp);
|
||||
|
||||
window.isDecorated = _windowDecoration->isChecked();
|
||||
if (window.isFullScreen) {
|
||||
window.monitor = _monitor->currentIndex();
|
||||
}
|
||||
|
||||
if (!_windowName->text().isEmpty()) {
|
||||
window.name = _windowName->text().toStdString();
|
||||
}
|
||||
return window;
|
||||
}
|
||||
|
||||
void WindowControl::setProjectionPlanar(float hfov, float vfov) {
|
||||
_planar.fovH->setValue(hfov);
|
||||
_planar.fovV->setValue(vfov);
|
||||
_projectionType->setCurrentIndex(static_cast<int>(ProjectionIndices::Planar));
|
||||
}
|
||||
|
||||
void WindowControl::setProjectionFisheye(int quality, bool spoutOutput) {
|
||||
setQualityComboBoxFromLinesResolution(quality, _fisheye.quality);
|
||||
_fisheye.spoutOutput->setChecked(spoutOutput);
|
||||
_projectionType->setCurrentIndex(static_cast<int>(ProjectionIndices::Fisheye));
|
||||
}
|
||||
|
||||
void WindowControl::setProjectionSphericalMirror(int quality) {
|
||||
setQualityComboBoxFromLinesResolution(quality, _sphericalMirror.quality);
|
||||
_projectionType->setCurrentIndex(
|
||||
static_cast<int>(ProjectionIndices::SphericalMirror)
|
||||
);
|
||||
}
|
||||
|
||||
void WindowControl::setProjectionCylindrical(int quality, float heightOffset) {
|
||||
setQualityComboBoxFromLinesResolution(quality, _cylindrical.quality);
|
||||
_cylindrical.heightOffset->setValue(heightOffset);
|
||||
_projectionType->setCurrentIndex(static_cast<int>(ProjectionIndices::Cylindrical));
|
||||
}
|
||||
|
||||
void WindowControl::setProjectionEquirectangular(int quality, bool spoutOutput) {
|
||||
setQualityComboBoxFromLinesResolution(quality, _equirectangular.quality);
|
||||
_equirectangular.spoutOutput->setChecked(spoutOutput);
|
||||
_projectionType->setCurrentIndex(
|
||||
static_cast<int>(ProjectionIndices::Equirectangular)
|
||||
);
|
||||
}
|
||||
|
||||
void WindowControl::setVisibilityOfProjectionGui(bool enable) {
|
||||
_projectionType->setVisible(enable);
|
||||
_planar.labelInfo->setVisible(enable);
|
||||
_planar.fovH->setVisible(enable);
|
||||
_planar.labelFovH->setVisible(enable);
|
||||
_planar.fovV->setVisible(enable);
|
||||
_planar.labelFovV->setVisible(enable);
|
||||
_planar.buttonLockFov->setVisible(enable);
|
||||
_fisheye.labelInfo->setVisible(enable);
|
||||
_fisheye.quality->setVisible(enable);
|
||||
_fisheye.labelQuality->setVisible(enable);
|
||||
_fisheye.spoutOutput->setVisible(enable);
|
||||
_sphericalMirror.labelInfo->setVisible(enable);
|
||||
_sphericalMirror.quality->setVisible(enable);
|
||||
_sphericalMirror.labelQuality->setVisible(enable);
|
||||
_cylindrical.labelInfo->setVisible(enable);
|
||||
_cylindrical.heightOffset->setVisible(enable);
|
||||
_cylindrical.labelHeightOffset->setVisible(enable);
|
||||
_cylindrical.quality->setVisible(enable);
|
||||
_cylindrical.labelQuality->setVisible(enable);
|
||||
_equirectangular.labelInfo->setVisible(enable);
|
||||
_equirectangular.quality->setVisible(enable);
|
||||
_equirectangular.labelQuality->setVisible(enable);
|
||||
_equirectangular.spoutOutput->setVisible(enable);
|
||||
|
||||
_projectionLabel->setVisible(!enable);
|
||||
}
|
||||
|
||||
void WindowControl::setQualityComboBoxFromLinesResolution(int lines, QComboBox* combo) {
|
||||
ghoul_assert(combo, "Invalid pointer");
|
||||
for (unsigned int v = 0; v < nQualityTypes; ++v) {
|
||||
if (lines == QualityValues[v]) {
|
||||
combo->setCurrentIndex(v);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WindowControl::onSizeXChanged(int newValue) {
|
||||
@@ -813,17 +917,25 @@ void WindowControl::onFovLockClicked() {
|
||||
_planar.fovH->setEnabled(true);
|
||||
_planar.fovV->setEnabled(true);
|
||||
}
|
||||
_planar.buttonLockFov->setIcon(_fovLocked ? _lockIcon : _unlockIcon);
|
||||
}
|
||||
|
||||
void WindowControl::updatePlanarLockedFov() {
|
||||
const float aspectRatio = _windowDimensions.width() / _windowDimensions.height();
|
||||
const float ratio = aspectRatio / IdealAspectRatio;
|
||||
if (ratio >= 1.f) {
|
||||
_planar.fovH->setValue(std::min(DefaultFovH * ratio, 180.f));
|
||||
_planar.fovV->setValue(DefaultFovV);
|
||||
bool landscapeOrientation = (_windowDimensions.width() >= _windowDimensions.height());
|
||||
float aspectRatio;
|
||||
if (landscapeOrientation) {
|
||||
aspectRatio = _windowDimensions.width() / _windowDimensions.height();
|
||||
}
|
||||
else {
|
||||
_planar.fovH->setValue(DefaultFovH);
|
||||
_planar.fovV->setValue(std::min(DefaultFovV / ratio, 180.f));
|
||||
aspectRatio = _windowDimensions.height() / _windowDimensions.width();
|
||||
}
|
||||
|
||||
float adjustedFov = 2.f * atan(aspectRatio * tan(DefaultFovShortEdge
|
||||
* std::numbers::pi_v<float> / 180.f / 2.f));
|
||||
// Convert to degrees and limit to 180°
|
||||
adjustedFov *= 180.f / std::numbers::pi_v<float>;
|
||||
adjustedFov = std::min(adjustedFov, 180.f);
|
||||
|
||||
_planar.fovH->setValue(landscapeOrientation ? adjustedFov : DefaultFovShortEdge);
|
||||
_planar.fovV->setValue(landscapeOrientation ? DefaultFovShortEdge : adjustedFov);
|
||||
}
|
||||
|
||||
Submodule apps/OpenSpace/ext/sgct updated: 13fd7b200e...2a4e0fa3fc
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -28,21 +28,16 @@
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/engine/windowdelegate.h>
|
||||
#include <openspace/interaction/joystickinputstate.h>
|
||||
#include <openspace/scripting/scriptengine.h>
|
||||
#include <openspace/util/keys.h>
|
||||
#include <openspace/openspace.h>
|
||||
#include <ghoul/ghoul.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/fmt.h>
|
||||
#include <ghoul/glm.h>
|
||||
#include <ghoul/cmdparser/commandlineparser.h>
|
||||
#include <ghoul/cmdparser/multiplecommand.h>
|
||||
#include <ghoul/cmdparser/singlecommand.h>
|
||||
#include <ghoul/filesystem/file.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/logging/consolelog.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/logging/visualstudiooutputlog.h>
|
||||
#include <ghoul/lua/ghoul_lua.h>
|
||||
#include <ghoul/misc/assert.h>
|
||||
#include <ghoul/misc/boolean.h>
|
||||
#include <ghoul/opengl/ghoul_gl.h>
|
||||
#include <ghoul/misc/stacktrace.h>
|
||||
#ifdef WIN32
|
||||
#define GLFW_EXPOSE_NATIVE_WIN32
|
||||
#endif
|
||||
@@ -54,25 +49,17 @@
|
||||
#include <sgct/log.h>
|
||||
#include <sgct/projection/fisheye.h>
|
||||
#include <sgct/projection/nonlinearprojection.h>
|
||||
#include <sgct/screencapture.h>
|
||||
#include <sgct/settings.h>
|
||||
#include <sgct/user.h>
|
||||
#include <sgct/viewport.h>
|
||||
#include <sgct/window.h>
|
||||
#include <stb_image.h>
|
||||
#include <Tracy.hpp>
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <tracy/Tracy.hpp>
|
||||
#include <iostream>
|
||||
#include <string_view>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <openspace/openspace.h>
|
||||
#include <ghoul/misc/stacktrace.h>
|
||||
#include <ghoul/fmt.h>
|
||||
#include <Windows.h>
|
||||
#include <dbghelp.h>
|
||||
#include <shellapi.h>
|
||||
#include <shlobj.h>
|
||||
#endif // WIN32
|
||||
|
||||
#ifdef OPENVR_SUPPORT
|
||||
@@ -87,17 +74,22 @@
|
||||
#include "nvToolsExt.h"
|
||||
#endif // OPENSPACE_HAS_NVTOOLS
|
||||
|
||||
#ifdef OPENSPACE_BREAK_ON_FLOATING_POINT_EXCEPTION
|
||||
#include <float.h>
|
||||
#endif // OPENSPACE_BREAK_ON_FLOATING_POINT_EXCEPTION
|
||||
|
||||
#include <launcherwindow.h>
|
||||
#include <QApplication>
|
||||
#include <QMessageBox>
|
||||
|
||||
using namespace openspace;
|
||||
using namespace sgct;
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr const char* _loggerCat = "main";
|
||||
constexpr const char* SpoutTag = "Spout";
|
||||
constexpr const char* OpenVRTag = "OpenVR";
|
||||
constexpr std::string_view _loggerCat = "main";
|
||||
constexpr std::string_view SpoutTag = "Spout";
|
||||
constexpr std::string_view OpenVRTag = "OpenVR";
|
||||
|
||||
// @TODO (abock, 2020-04-09): These state variables should disappear
|
||||
const Window* currentWindow = nullptr;
|
||||
@@ -105,6 +97,7 @@ const BaseViewport* currentViewport = nullptr;
|
||||
Frustum::Mode currentFrustumMode;
|
||||
glm::mat4 currentModelViewProjectionMatrix;
|
||||
glm::mat4 currentModelMatrix;
|
||||
glm::ivec2 currentDrawResolution;
|
||||
|
||||
#ifdef OPENVR_SUPPORT
|
||||
Window* FirstOpenVRWindow = nullptr;
|
||||
@@ -118,7 +111,7 @@ Window* FirstOpenVRWindow = nullptr;
|
||||
/**
|
||||
* This struct stores all information about a single render window. Depending on the
|
||||
* frame setup, each window can be mono or stereo, the information of which is stored in
|
||||
* the \c leftOrMain and \c right members respectively.
|
||||
* the `leftOrMain` and `right` members respectively.
|
||||
*/
|
||||
struct SpoutWindow {
|
||||
/// The left framebuffer (or main, if there is no stereo rendering)
|
||||
@@ -226,21 +219,20 @@ void checkJoystickStatus() {
|
||||
state.isConnected = true;
|
||||
state.name = glfwGetJoystickName(i);
|
||||
|
||||
std::fill(state.axes.begin(), state.axes.end(), 0.f);
|
||||
std::fill(state.buttons.begin(), state.buttons.end(), JoystickAction::Idle);
|
||||
|
||||
// Check axes and buttons
|
||||
glfwGetJoystickAxes(i, &state.nAxes);
|
||||
glfwGetJoystickButtons(i, &state.nButtons);
|
||||
state.axes.resize(state.nAxes);
|
||||
state.buttons.resize(state.nButtons);
|
||||
|
||||
std::fill(state.axes.begin(), state.axes.end(), 0.f);
|
||||
std::fill(state.buttons.begin(), state.buttons.end(), JoystickAction::Idle);
|
||||
}
|
||||
|
||||
const float* axes = glfwGetJoystickAxes(i, &state.nAxes);
|
||||
state.axes.resize(state.nAxes);
|
||||
std::memcpy(state.axes.data(), axes, state.nAxes * sizeof(float));
|
||||
|
||||
const unsigned char* buttons = glfwGetJoystickButtons(i, &state.nButtons);
|
||||
state.buttons.resize(state.nButtons);
|
||||
|
||||
for (int j = 0; j < state.nButtons; ++j) {
|
||||
const bool currentlyPressed = buttons[j] == GLFW_PRESS;
|
||||
|
||||
@@ -272,11 +264,20 @@ void checkJoystickStatus() {
|
||||
}
|
||||
}
|
||||
|
||||
bool isGuiWindow(sgct::Window* window) {
|
||||
if (global::windowDelegate->hasGuiWindow()) {
|
||||
return window->hasTag("GUI");
|
||||
}
|
||||
|
||||
const sgct::Window* first = Engine::instance().windows().front().get();
|
||||
return window->id() == first->id();
|
||||
}
|
||||
|
||||
//
|
||||
// Init function
|
||||
//
|
||||
void mainInitFunc(GLFWwindow*) {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
LTRACE("main::mainInitFunc(begin)");
|
||||
|
||||
@@ -393,7 +394,7 @@ void mainInitFunc(GLFWwindow*) {
|
||||
|
||||
|
||||
void mainPreSyncFunc() {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
LTRACE("main::mainPreSyncFunc(begin)");
|
||||
|
||||
try {
|
||||
@@ -413,7 +414,7 @@ void mainPreSyncFunc() {
|
||||
|
||||
|
||||
void mainPostSyncPreDrawFunc() {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
#ifdef OPENSPACE_HAS_NVTOOLS
|
||||
nvtxRangePush("postSyncPreDraw");
|
||||
@@ -439,7 +440,7 @@ void mainPostSyncPreDrawFunc() {
|
||||
|
||||
|
||||
void mainRenderFunc(const sgct::RenderData& data) {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
#ifdef OPENSPACE_HAS_NVTOOLS
|
||||
nvtxRangePush("render");
|
||||
@@ -449,6 +450,7 @@ void mainRenderFunc(const sgct::RenderData& data) {
|
||||
currentWindow = &data.window;
|
||||
currentViewport = &data.viewport;
|
||||
currentFrustumMode = data.frustumMode;
|
||||
currentDrawResolution = glm::ivec2(data.bufferSize.x, data.bufferSize.y);
|
||||
|
||||
glm::vec3 pos;
|
||||
std::memcpy(
|
||||
@@ -527,12 +529,13 @@ void mainRenderFunc(const sgct::RenderData& data) {
|
||||
|
||||
|
||||
void mainDraw2DFunc(const sgct::RenderData& data) {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
LTRACE("main::mainDraw2DFunc(begin)");
|
||||
|
||||
currentWindow = &data.window;
|
||||
currentViewport = &data.viewport;
|
||||
currentFrustumMode = data.frustumMode;
|
||||
currentDrawResolution = glm::ivec2(data.bufferSize.x, data.bufferSize.y);
|
||||
|
||||
try {
|
||||
global::openSpaceEngine->drawOverlays();
|
||||
@@ -552,7 +555,7 @@ void mainDraw2DFunc(const sgct::RenderData& data) {
|
||||
|
||||
|
||||
void mainPostDrawFunc() {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
LTRACE("main::mainPostDrawFunc(begin)");
|
||||
|
||||
#ifdef OPENVR_SUPPORT
|
||||
@@ -570,15 +573,17 @@ void mainPostDrawFunc() {
|
||||
|
||||
|
||||
void mainKeyboardCallback(sgct::Key key, sgct::Modifier modifiers, sgct::Action action,
|
||||
int)
|
||||
int, sgct::Window* window)
|
||||
{
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
LTRACE("main::mainKeyboardCallback(begin)");
|
||||
|
||||
const openspace::Key k = openspace::Key(key);
|
||||
const KeyModifier m = KeyModifier(modifiers);
|
||||
const KeyAction a = KeyAction(action);
|
||||
global::openSpaceEngine->keyboardCallback(k, m, a);
|
||||
const IsGuiWindow isGui = IsGuiWindow(isGuiWindow(window));
|
||||
|
||||
global::openSpaceEngine->keyboardCallback(k, m, a, isGui);
|
||||
|
||||
LTRACE("main::mainKeyboardCallback(begin)");
|
||||
}
|
||||
@@ -586,44 +591,50 @@ void mainKeyboardCallback(sgct::Key key, sgct::Modifier modifiers, sgct::Action
|
||||
|
||||
|
||||
void mainMouseButtonCallback(sgct::MouseButton key, sgct::Modifier modifiers,
|
||||
sgct::Action action)
|
||||
sgct::Action action, sgct::Window* window)
|
||||
{
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
LTRACE("main::mainMouseButtonCallback(begin)");
|
||||
|
||||
const openspace::MouseButton k = openspace::MouseButton(key);
|
||||
const openspace::MouseAction a = openspace::MouseAction(action);
|
||||
const openspace::KeyModifier m = openspace::KeyModifier(modifiers);
|
||||
global::openSpaceEngine->mouseButtonCallback(k, a, m);
|
||||
const IsGuiWindow isGui = IsGuiWindow(isGuiWindow(window));
|
||||
|
||||
global::openSpaceEngine->mouseButtonCallback(k, a, m, isGui);
|
||||
|
||||
LTRACE("main::mainMouseButtonCallback(end)");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void mainMousePosCallback(double x, double y) {
|
||||
ZoneScoped
|
||||
global::openSpaceEngine->mousePositionCallback(x, y);
|
||||
void mainMousePosCallback(double x, double y, sgct::Window* window) {
|
||||
ZoneScoped;
|
||||
const IsGuiWindow isGui = IsGuiWindow(isGuiWindow(window));
|
||||
global::openSpaceEngine->mousePositionCallback(x, y, isGui);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void mainMouseScrollCallback(double posX, double posY) {
|
||||
ZoneScoped
|
||||
void mainMouseScrollCallback(double posX, double posY, sgct::Window* window) {
|
||||
ZoneScoped;
|
||||
LTRACE("main::mainMouseScrollCallback(begin");
|
||||
|
||||
global::openSpaceEngine->mouseScrollWheelCallback(posX, posY);
|
||||
const IsGuiWindow isGui = IsGuiWindow(isGuiWindow(window));
|
||||
global::openSpaceEngine->mouseScrollWheelCallback(posX, posY, isGui);
|
||||
|
||||
LTRACE("main::mainMouseScrollCallback(end)");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void mainCharCallback(unsigned int codepoint, int modifiers) {
|
||||
ZoneScoped
|
||||
void mainCharCallback(unsigned int codepoint, int modifiers, sgct::Window* window) {
|
||||
ZoneScoped;
|
||||
|
||||
const KeyModifier m = KeyModifier(modifiers);
|
||||
global::openSpaceEngine->charCallback(codepoint, m);
|
||||
const IsGuiWindow isGui = IsGuiWindow(isGuiWindow(window));
|
||||
|
||||
global::openSpaceEngine->charCallback(codepoint, m, isGui);
|
||||
}
|
||||
|
||||
|
||||
@@ -640,7 +651,7 @@ void mainDropCallback(int amount, const char** paths) {
|
||||
|
||||
|
||||
std::vector<std::byte> mainEncodeFun() {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
LTRACE("main::mainEncodeFun(begin)");
|
||||
|
||||
std::vector<std::byte> data = global::openSpaceEngine->encode();
|
||||
@@ -651,8 +662,8 @@ std::vector<std::byte> mainEncodeFun() {
|
||||
|
||||
|
||||
|
||||
void mainDecodeFun(const std::vector<std::byte>& data, unsigned int) {
|
||||
ZoneScoped
|
||||
void mainDecodeFun(const std::vector<std::byte>& data) {
|
||||
ZoneScoped;
|
||||
LTRACE("main::mainDecodeFun(begin)");
|
||||
|
||||
global::openSpaceEngine->decode(data);
|
||||
@@ -663,7 +674,7 @@ void mainDecodeFun(const std::vector<std::byte>& data, unsigned int) {
|
||||
|
||||
|
||||
void mainLogCallback(Log::Level level, std::string_view message) {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
switch (level) {
|
||||
case Log::Level::Debug:
|
||||
@@ -687,62 +698,53 @@ void setSgctDelegateFunctions() {
|
||||
WindowDelegate& sgctDelegate = *global::windowDelegate;
|
||||
sgctDelegate.terminate = []() { Engine::instance().terminate(); };
|
||||
sgctDelegate.setBarrier = [](bool enabled) {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
sgct::Window::setBarrier(enabled);
|
||||
};
|
||||
sgctDelegate.setSynchronization = [](bool enabled) {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
sgct::ClusterManager::instance().setUseIgnoreSync(enabled);
|
||||
};
|
||||
sgctDelegate.windowHasResized = []() {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
return currentWindow->isWindowResized();
|
||||
};
|
||||
sgctDelegate.averageDeltaTime = []() {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
return Engine::instance().statistics().avgDt(
|
||||
Engine::instance().currentFrameNumber()
|
||||
);
|
||||
return Engine::instance().statistics().avgDt();
|
||||
};
|
||||
sgctDelegate.minDeltaTime = []() {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
return Engine::instance().statistics().minDt();
|
||||
};
|
||||
sgctDelegate.maxDeltaTime = []() {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
return Engine::instance().statistics().maxDt();
|
||||
};
|
||||
sgctDelegate.deltaTime = []() {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
return Engine::instance().statistics().dt();
|
||||
};
|
||||
sgctDelegate.applicationTime = []() {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
return sgct::Engine::getTime();
|
||||
return time();
|
||||
};
|
||||
sgctDelegate.currentWindowSize = []() {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
return glm::ivec2(currentWindow->resolution().x, currentWindow->resolution().y);
|
||||
};
|
||||
sgctDelegate.currentSubwindowSize = []() {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
if (currentWindow->viewports().size() > 1) {
|
||||
const Viewport& viewport = *currentWindow->viewports().front();
|
||||
return glm::ivec2(
|
||||
currentWindow->resolution().x * viewport.size().x,
|
||||
currentWindow->resolution().y * viewport.size().y
|
||||
);
|
||||
}
|
||||
switch (currentWindow->stereoMode()) {
|
||||
case Window::StereoMode::SideBySide:
|
||||
case Window::StereoMode::SideBySideInverted:
|
||||
@@ -758,35 +760,31 @@ void setSgctDelegateFunctions() {
|
||||
);
|
||||
default:
|
||||
return glm::ivec2(
|
||||
currentWindow->resolution().x,
|
||||
currentWindow->resolution().y
|
||||
currentWindow->resolution().x * currentViewport->size().x,
|
||||
currentWindow->resolution().y * currentViewport->size().y
|
||||
);
|
||||
}
|
||||
};
|
||||
sgctDelegate.currentDrawBufferResolution = []() {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
Viewport* viewport = currentWindow->viewports().front().get();
|
||||
if (viewport != nullptr) {
|
||||
const Viewport* viewport = dynamic_cast<const Viewport*>(currentViewport);
|
||||
if (viewport) {
|
||||
if (viewport->hasSubViewports() && viewport->nonLinearProjection()) {
|
||||
ivec2 dim = viewport->nonLinearProjection()->cubemapResolution();
|
||||
return glm::ivec2(dim.x, dim.y);
|
||||
}
|
||||
else if (currentWindow->viewports().size() > 1) {
|
||||
// @TODO (abock, 2020-04-09) This should probably be based on the current
|
||||
// viewport?
|
||||
ivec2 dim = currentWindow->finalFBODimensions();
|
||||
return glm::ivec2(dim.x * viewport->size().x, dim.y * viewport->size().y);
|
||||
}
|
||||
else {
|
||||
ivec2 dim = currentWindow->finalFBODimensions();
|
||||
return glm::ivec2(dim.x, dim.y);
|
||||
}
|
||||
}
|
||||
return glm::ivec2(-1, -1);
|
||||
else {
|
||||
return currentDrawResolution;
|
||||
}
|
||||
};
|
||||
sgctDelegate.currentViewportSize = []() {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
if (currentViewport != nullptr) {
|
||||
vec2 size = currentViewport->size();
|
||||
@@ -794,14 +792,45 @@ void setSgctDelegateFunctions() {
|
||||
}
|
||||
return glm::ivec2(-1, -1);
|
||||
};
|
||||
sgctDelegate.currentViewportResolution = []() {
|
||||
ZoneScoped;
|
||||
|
||||
if (currentViewport != nullptr) {
|
||||
ivec2 res = currentWindow->resolution();
|
||||
vec2 size = currentViewport->size();
|
||||
return glm::ivec2(size.x * res.x, size.y * res.y);
|
||||
}
|
||||
return glm::ivec2(-1, -1);
|
||||
};
|
||||
sgctDelegate.dpiScaling = []() {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
vec2 scale = currentWindow->scale();
|
||||
return glm::vec2(scale.x, scale.y);
|
||||
};
|
||||
sgctDelegate.firstWindowResolution = []() {
|
||||
ZoneScoped;
|
||||
sgct::Window* window = Engine::instance().windows().front().get();
|
||||
return glm::ivec2(window->resolution().x, window->resolution().y);
|
||||
};
|
||||
sgctDelegate.guiWindowResolution = []() {
|
||||
ZoneScoped;
|
||||
const Window* guiWindow = nullptr;
|
||||
for (const std::unique_ptr<Window>& window : Engine::instance().windows()) {
|
||||
if (window->hasTag("GUI")) {
|
||||
guiWindow = window.get();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!guiWindow) {
|
||||
guiWindow = Engine::instance().windows().front().get();
|
||||
}
|
||||
|
||||
return glm::ivec2(guiWindow->resolution().x, guiWindow->resolution().y);
|
||||
};
|
||||
sgctDelegate.osDpiScaling = []() {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
// Detect which DPI scaling to use
|
||||
// 1. If there is a GUI window, use the GUI window's content scale value
|
||||
@@ -831,7 +860,7 @@ void setSgctDelegateFunctions() {
|
||||
return scale.x;
|
||||
};
|
||||
sgctDelegate.hasGuiWindow = []() {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
for (const std::unique_ptr<Window>& window : Engine::instance().windows()) {
|
||||
if (window->hasTag("GUI")) {
|
||||
@@ -841,76 +870,87 @@ void setSgctDelegateFunctions() {
|
||||
return false;
|
||||
};
|
||||
sgctDelegate.isGuiWindow = []() {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
return currentWindow->hasTag("GUI");
|
||||
};
|
||||
sgctDelegate.isMaster = []() {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
return Engine::instance().isMaster();
|
||||
};
|
||||
sgctDelegate.modelMatrix = []() {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
return currentModelMatrix;
|
||||
};
|
||||
sgctDelegate.setNearFarClippingPlane = [](float nearPlane, float farPlane) {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
Engine::instance().setNearAndFarClippingPlanes(nearPlane, farPlane);
|
||||
};
|
||||
sgctDelegate.isFisheyeRendering = []() {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
return dynamic_cast<FisheyeProjection*>(
|
||||
currentWindow->viewports().front()->nonLinearProjection()
|
||||
) != nullptr;
|
||||
};
|
||||
sgctDelegate.takeScreenshot = [](bool applyWarping, std::vector<int> windowIds) {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
Settings::instance().setCaptureFromBackBuffer(applyWarping);
|
||||
Engine::instance().takeScreenshot(std::move(windowIds));
|
||||
return Engine::instance().screenShotNumber();
|
||||
};
|
||||
sgctDelegate.resetScreenshotNumber = []() {
|
||||
ZoneScoped;
|
||||
Engine::instance().resetScreenshotNumber();
|
||||
};
|
||||
sgctDelegate.swapBuffer = []() {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
GLFWwindow* w = glfwGetCurrentContext();
|
||||
glfwSwapBuffers(w);
|
||||
glfwPollEvents();
|
||||
};
|
||||
sgctDelegate.nWindows = []() {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
return static_cast<int>(Engine::instance().windows().size());
|
||||
};
|
||||
sgctDelegate.currentWindowId = []() {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
return currentWindow->id();
|
||||
};
|
||||
sgctDelegate.firstWindowId = []() {
|
||||
ZoneScoped;
|
||||
|
||||
return Engine::instance().windows().front()->id();
|
||||
};
|
||||
sgctDelegate.openGLProcedureAddress = [](const char* func) {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
return glfwGetProcAddress(func);
|
||||
};
|
||||
sgctDelegate.getHorizFieldOfView = []() {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
return static_cast<double>(
|
||||
Engine::instance().windows().front()->horizFieldOfViewDegrees()
|
||||
);
|
||||
};
|
||||
sgctDelegate.setHorizFieldOfView = [](float hFovDeg) {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
Engine::instance().windows().front()->setHorizFieldOfView(hFovDeg);
|
||||
for (std::unique_ptr<sgct::Window> const& w : Engine::instance().windows()) {
|
||||
w->setHorizFieldOfView(hFovDeg);
|
||||
}
|
||||
};
|
||||
#ifdef WIN32
|
||||
sgctDelegate.getNativeWindowHandle = [](size_t windowIndex) -> void* {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
Window* w = Engine::instance().windows()[windowIndex].get();
|
||||
if (w) {
|
||||
@@ -921,7 +961,7 @@ void setSgctDelegateFunctions() {
|
||||
};
|
||||
#endif // WIN32
|
||||
sgctDelegate.frustumMode = []() {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
switch (currentFrustumMode) {
|
||||
default:
|
||||
@@ -931,13 +971,51 @@ void setSgctDelegateFunctions() {
|
||||
}
|
||||
};
|
||||
sgctDelegate.swapGroupFrameNumber = []() -> uint64_t {
|
||||
ZoneScoped
|
||||
ZoneScoped;
|
||||
|
||||
return currentWindow->swapGroupFrameNumber();
|
||||
};
|
||||
sgctDelegate.setScreenshotFolder = [](std::string path) {
|
||||
Settings::instance().setCapturePath(std::move(path));
|
||||
};
|
||||
sgctDelegate.showStatistics = [](bool enabled) {
|
||||
Engine::instance().setStatsGraphVisibility(enabled);
|
||||
};
|
||||
sgctDelegate.numberOfNodes = []() {
|
||||
return ClusterManager::instance().numberOfNodes();
|
||||
};
|
||||
sgctDelegate.currentNode = []() {
|
||||
return ClusterManager::instance().thisNodeId();
|
||||
};
|
||||
sgctDelegate.mousePositionViewportRelative = [](glm::vec2 mousePosition) {
|
||||
for (const std::unique_ptr<Window>& window : Engine::instance().windows()) {
|
||||
if (isGuiWindow(window.get())) {
|
||||
sgct::ivec2 res = window->resolution();
|
||||
for (const std::unique_ptr<Viewport>& viewport : window->viewports()) {
|
||||
sgct::vec2 pos = viewport->position();
|
||||
sgct::vec2 size = viewport->size();
|
||||
glm::vec4 bounds = glm::vec4(
|
||||
pos.x * res.x,
|
||||
(1.0 - pos.y - size.y) * res.y,
|
||||
(pos.x + size.x) * res.x,
|
||||
(1.0 - pos.y) * res.y
|
||||
);
|
||||
|
||||
if (
|
||||
(mousePosition.x >= bounds.x && mousePosition.x <= bounds.z) &&
|
||||
(mousePosition.y >= bounds.y && mousePosition.y <= bounds.w)
|
||||
) {
|
||||
return glm::vec2(
|
||||
res.x * (mousePosition.x - bounds.x) / (bounds.z - bounds.x),
|
||||
res.y * (mousePosition.y - bounds.y) / (bounds.w - bounds.y)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mousePosition;
|
||||
};
|
||||
}
|
||||
|
||||
void checkCommandLineForSettings(int& argc, char** argv, bool& hasSGCT, bool& hasProfile,
|
||||
@@ -1037,6 +1115,11 @@ std::string selectedSgctProfileFromLauncher(LauncherWindow& lw, bool hasCliSGCTC
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
#ifdef OPENSPACE_BREAK_ON_FLOATING_POINT_EXCEPTION
|
||||
_clearfp();
|
||||
_controlfp(_controlfp(0, 0) & ~(_EM_ZERODIVIDE | _EM_OVERFLOW), _MCW_EM);
|
||||
#endif // OPENSPACE_BREAK_ON_FLOATING_POINT_EXCEPTION
|
||||
|
||||
#ifdef WIN32
|
||||
SetUnhandledExceptionFilter(generateMiniDump);
|
||||
#endif // WIN32
|
||||
@@ -1054,7 +1137,6 @@ int main(int argc, char* argv[]) {
|
||||
LogMgr.addLog(std::make_unique<ghoul::logging::VisualStudioOutputLog>());
|
||||
}
|
||||
#endif // WIN32
|
||||
|
||||
}
|
||||
|
||||
ghoul::initialize();
|
||||
@@ -1083,10 +1165,10 @@ int main(int argc, char* argv[]) {
|
||||
commandlineArguments.configurationName, "--file", "-f",
|
||||
"Provides the path to the OpenSpace configuration file. Only the '${TEMPORARY}' "
|
||||
"path token is available and any other path has to be specified relative to the "
|
||||
"current working directory."
|
||||
"current working directory"
|
||||
));
|
||||
|
||||
parser.addCommand(std::make_unique<ghoul::cmdparser::SingleCommand<std::string>>(
|
||||
parser.addCommand(std::make_unique<ghoul::cmdparser::MultipleCommand<std::string>>(
|
||||
commandlineArguments.configurationOverride, "--config", "-c",
|
||||
"Provides the ability to pass arbitrary Lua code to the application that will be "
|
||||
"evaluated after the configuration file has been loaded but before the other "
|
||||
@@ -1094,7 +1176,9 @@ int main(int argc, char* argv[]) {
|
||||
"configuration file without editing the file on disk, for example in a "
|
||||
"planetarium environment. Please not that the Lua script must not contain any - "
|
||||
"or they will be interpreted as a new command. Similar, in Bash, ${...} will be "
|
||||
"evaluated before it is passed to OpenSpace."
|
||||
"evaluated before it is passed to OpenSpace. Windows does not approve of using \""
|
||||
"either, so it is recommended to deliniate strings with [[ ]] instead. For "
|
||||
"example: OpenSpace --config Profile=[[jwst]]"
|
||||
));
|
||||
|
||||
// setCommandLine returns a reference to the vector that will be filled later
|
||||
@@ -1102,10 +1186,16 @@ int main(int argc, char* argv[]) {
|
||||
{ argv, argv + argc }
|
||||
);
|
||||
|
||||
bool showHelp = parser.execute();
|
||||
if (showHelp) {
|
||||
std::cout << parser.helpText();
|
||||
exit(EXIT_SUCCESS);
|
||||
try {
|
||||
bool showHelp = parser.execute();
|
||||
if (showHelp) {
|
||||
std::cout << parser.helpText();
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
catch (const ghoul::RuntimeError& e) {
|
||||
LFATALC(e.component, e.message);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// Take an actual copy of the arguments
|
||||
std::vector<std::string> arguments = sgctArguments;
|
||||
@@ -1159,10 +1249,14 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
// Loading configuration from disk
|
||||
LDEBUG("Loading configuration from disk");
|
||||
std::string override;
|
||||
for (const std::string& arg : commandlineArguments.configurationOverride) {
|
||||
override += arg + ";";
|
||||
}
|
||||
*global::configuration = configuration::loadConfigurationFromFile(
|
||||
configurationFilePath.string(),
|
||||
size,
|
||||
commandlineArguments.configurationOverride
|
||||
override
|
||||
);
|
||||
|
||||
// Determining SGCT configuration file
|
||||
@@ -1172,12 +1266,7 @@ int main(int argc, char* argv[]) {
|
||||
}
|
||||
catch (const documentation::SpecificationError& e) {
|
||||
LFATALC("main", "Loading of configuration file failed");
|
||||
for (const documentation::TestResult::Offense& o : e.result.offenses) {
|
||||
LERRORC(o.offender, ghoul::to_string(o.reason));
|
||||
}
|
||||
for (const documentation::TestResult::Warning& w : e.result.warnings) {
|
||||
LWARNINGC(w.offender, ghoul::to_string(w.reason));
|
||||
}
|
||||
logError(e);
|
||||
ghoul::deinitialize();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@@ -1227,6 +1316,19 @@ int main(int argc, char* argv[]) {
|
||||
QApplication app(qac, nullptr);
|
||||
#endif // __APPLE__
|
||||
|
||||
std::string pwd = std::filesystem::current_path().string();
|
||||
if (size_t it = pwd.find_first_of("'\"[]"); it != std::string::npos) {
|
||||
QMessageBox::warning(
|
||||
nullptr,
|
||||
"OpenSpace",
|
||||
QString::fromStdString(fmt::format(
|
||||
"The OpenSpace folder is started must not contain any of \"'\", "
|
||||
"\"\"\", [, or ]. Path is: '{}'. Unexpected errors will occur when "
|
||||
"proceeding to run the software", pwd
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
LauncherWindow win(
|
||||
!hasProfile,
|
||||
*global::configuration,
|
||||
@@ -1249,11 +1351,12 @@ int main(int argc, char* argv[]) {
|
||||
windowConfiguration,
|
||||
labelFromCfgFile
|
||||
);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
glfwInit();
|
||||
}
|
||||
if (global::configuration->profile.empty()) {
|
||||
LFATAL("Cannot launch with an empty profile");
|
||||
LFATAL("Cannot launch without a profile");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@@ -1344,7 +1447,7 @@ int main(int argc, char* argv[]) {
|
||||
Engine::instance().setSyncParameters(false, 15.f * 60.f);
|
||||
|
||||
LINFO("Starting rendering loop");
|
||||
Engine::instance().render();
|
||||
Engine::instance().exec();
|
||||
LINFO("Ending rendering loop");
|
||||
|
||||
global::openSpaceEngine->deinitializeGL();
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #
|
||||
##########################################################################################
|
||||
|
||||
include(${OPENSPACE_CMAKE_EXT_DIR}/application_definition.cmake)
|
||||
include(${PROJECT_SOURCE_DIR}/support/cmake/application_definition.cmake)
|
||||
|
||||
set_source_files_properties(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/openspace.icns
|
||||
@@ -47,7 +47,7 @@ if (OPENSPACE_MODULE_WEBBROWSER AND CEF_ROOT)
|
||||
set(CMAKE_BUILD_TYPE Debug CACHE STRING "CMAKE_BUILD_TYPE")
|
||||
|
||||
if (WIN32)
|
||||
set(RESOURCE_FILE ${OPENSPACE_APPS_DIR}/OpenSpace/openspace.rc)
|
||||
set(RESOURCE_FILE openspace.rc)
|
||||
endif ()
|
||||
|
||||
# Add the CEF binary distribution's cmake/ directory to the module path and
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -68,7 +68,7 @@ int main(int, char**) {
|
||||
progressBar.print(static_cast<int>(progress * 100.f));
|
||||
});
|
||||
}
|
||||
std::cout << "Done synchronizing." << std::endl;
|
||||
std::cout << "Done synchronizing" << std::endl;
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #
|
||||
##########################################################################################
|
||||
|
||||
include(${OPENSPACE_CMAKE_EXT_DIR}/application_definition.cmake)
|
||||
include(${PROJECT_SOURCE_DIR}/support/cmake/application_definition.cmake)
|
||||
|
||||
set_source_files_properties(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/openspace.icns
|
||||
@@ -47,7 +47,7 @@ if (OPENSPACE_MODULE_WEBBROWSER AND CEF_ROOT)
|
||||
set(CMAKE_BUILD_TYPE Debug CACHE STRING "CMAKE_BUILD_TYPE")
|
||||
|
||||
if (WIN32)
|
||||
set(RESOURCE_FILE ${OPENSPACE_APPS_DIR}/OpenSpace/openspace.rc)
|
||||
set(RESOURCE_FILE openspace.rc)
|
||||
endif ()
|
||||
|
||||
# Add the CEF binary distribution's cmake/ directory to the module path and
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2022 *
|
||||
* Copyright (c) 2014-2023 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
@@ -29,8 +29,6 @@
|
||||
#include <ghoul/ghoul.h>
|
||||
#include <ghoul/opengl/ghoul_gl.h>
|
||||
#include <ghoul/io/texture/texturereader.h>
|
||||
#include <ghoul/io/texture/texturereaderdevil.h>
|
||||
#include <ghoul/io/texture/texturereaderfreeimage.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/logging/consolelog.h>
|
||||
@@ -64,19 +62,6 @@ namespace {
|
||||
const std::string _loggerCat = "TaskRunner Main";
|
||||
}
|
||||
|
||||
void initTextureReaders() {
|
||||
#ifdef GHOUL_USE_DEVIL
|
||||
ghoul::io::TextureReader::ref().addReader(
|
||||
std::make_unique<ghoul::io::TextureReaderDevIL>()
|
||||
);
|
||||
#endif // GHOUL_USE_DEVIL
|
||||
#ifdef GHOUL_USE_FREEIMAGE
|
||||
ghoul::io::TextureReader::ref().addReader(
|
||||
std::make_unique<ghoul::io::TextureReaderFreeImage>()
|
||||
);
|
||||
#endif // GHOUL_USE_FREEIMAGE
|
||||
}
|
||||
|
||||
void performTasks(const std::string& path) {
|
||||
using namespace openspace;
|
||||
|
||||
@@ -102,7 +87,7 @@ void performTasks(const std::string& path) {
|
||||
};
|
||||
task.perform(onProgress);
|
||||
}
|
||||
std::cout << "Done performing tasks." << std::endl;
|
||||
std::cout << "Done performing tasks" << std::endl;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
@@ -127,8 +112,8 @@ int main(int argc, char** argv) {
|
||||
|
||||
// Register the base path as the directory where the configuration file lives
|
||||
std::filesystem::path base = configFile.parent_path();
|
||||
constexpr const char* BasePathToken = "${BASE}";
|
||||
FileSys.registerPathToken(BasePathToken, base);
|
||||
constexpr std::string_view BasePathToken = "${BASE}";
|
||||
FileSys.registerPathToken(BasePathToken.data(), base);
|
||||
|
||||
// Using same configuration for size as in apps/OpenSpace/main.cpp
|
||||
glm::ivec2 size = glm::ivec2(1920, 1080);
|
||||
|
||||
@@ -30,11 +30,10 @@
|
||||
},
|
||||
{
|
||||
"fullscreen": true,
|
||||
"monitor": 1,
|
||||
"name": "OpenSpace",
|
||||
"draw2d": false,
|
||||
"stereo": "none",
|
||||
"pos": { "x": 0, "y": 0 },
|
||||
"pos": { "x": 1920, "y": 1080 },
|
||||
"size": { "x": 1920, "y": 1080 },
|
||||
"viewports": [
|
||||
{
|
||||
|
||||
124
config/portrait_with_gui.json
Normal file
124
config/portrait_with_gui.json
Normal file
@@ -0,0 +1,124 @@
|
||||
{
|
||||
"masteraddress": "localhost",
|
||||
"externalcontrolport": 20500,
|
||||
"settings": {
|
||||
"display": {
|
||||
"swapinterval": 0
|
||||
}
|
||||
},
|
||||
"nodes": [
|
||||
{
|
||||
"address": "localhost",
|
||||
"port": 20401,
|
||||
"windows": [
|
||||
{
|
||||
"border": true,
|
||||
"draw2d": true,
|
||||
"draw3d": false,
|
||||
"id": 0,
|
||||
"monitor": 0,
|
||||
"name": "GUI",
|
||||
"pos": {
|
||||
"x": 50,
|
||||
"y": 50
|
||||
},
|
||||
"size": {
|
||||
"x": 1280,
|
||||
"y": 960
|
||||
},
|
||||
"res": {
|
||||
"x": 2560,
|
||||
"y": 1920
|
||||
},
|
||||
"tags": [
|
||||
"GUI",
|
||||
"GUI_No_Render"
|
||||
],
|
||||
"viewports": [
|
||||
{
|
||||
"pos": {
|
||||
"x": 0.0,
|
||||
"y": 0.0
|
||||
},
|
||||
"projection": {
|
||||
"fov": {
|
||||
"down": 25.264999389648438,
|
||||
"left": 40.0,
|
||||
"right": 40.0,
|
||||
"up": 25.264999389648438
|
||||
},
|
||||
"type": "PlanarProjection"
|
||||
},
|
||||
"size": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"tracked": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"border": true,
|
||||
"draw2d": false,
|
||||
"draw3d": true,
|
||||
"id": 1,
|
||||
"monitor": 0,
|
||||
"name": "Portrait View",
|
||||
"pos": {
|
||||
"x": 1350,
|
||||
"y": 50
|
||||
},
|
||||
"size": {
|
||||
"x": 540,
|
||||
"y": 960
|
||||
},
|
||||
"res": {
|
||||
"x": 1080,
|
||||
"y": 1920
|
||||
},
|
||||
"viewports": [
|
||||
{
|
||||
"pos": {
|
||||
"x": 0.0,
|
||||
"y": 0.0
|
||||
},
|
||||
"projection": {
|
||||
"fov": {
|
||||
"down": 40.0,
|
||||
"left": 25.264999389648438,
|
||||
"right": 25.264999389648438,
|
||||
"up": 40.0
|
||||
},
|
||||
"type": "PlanarProjection"
|
||||
},
|
||||
"size": {
|
||||
"x": 1.0,
|
||||
"y": 1.0
|
||||
},
|
||||
"tracked": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"scene": {
|
||||
"orientation": {
|
||||
"w": 0.0,
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 0.0
|
||||
}
|
||||
},
|
||||
"users": [
|
||||
{
|
||||
"eyeseparation": 0.06499999761581421,
|
||||
"pos": {
|
||||
"x": 0.0,
|
||||
"y": 0.0,
|
||||
"z": 4.0
|
||||
}
|
||||
}
|
||||
],
|
||||
"version": 1
|
||||
}
|
||||
322
config/schema/sgcteditor.schema.json
Normal file
322
config/schema/sgcteditor.schema.json
Normal file
@@ -0,0 +1,322 @@
|
||||
{
|
||||
"$id": "schema2e",
|
||||
|
||||
"$defs": {
|
||||
"cylindricalprojection": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"const": "CylindricalProjection",
|
||||
"default": "CylindricalProjection",
|
||||
"readOnly": true
|
||||
},
|
||||
"quality": {
|
||||
"$ref": "sgct.schema.json#/$defs/projectionquality"
|
||||
},
|
||||
"heightOffset": {
|
||||
"type": "number",
|
||||
"title": "Height Offset",
|
||||
"description": "Offsets the height from which the cylindrical projection is generated. This is, in general, only necessary if the user position is offset and you want to counter that offset to continue producing a “standard” cylindrical projection"
|
||||
}
|
||||
},
|
||||
"required": [ "type" ],
|
||||
"additionalProperties": false,
|
||||
"description": "This projection method renders the scene into a view that can be mapped on the inside or outside of a cylinder. This projection method is support by some live media curation tools. The forward-facing direction will be at the left border of the image unless changed via the rotation option"
|
||||
},
|
||||
|
||||
"fisheyeprojection": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"const": "FisheyeProjection",
|
||||
"default": "FisheyeProjection",
|
||||
"readOnly": true
|
||||
},
|
||||
"quality": {
|
||||
"$ref": "sgct.schema.json#/$defs/projectionquality"
|
||||
}
|
||||
},
|
||||
"required": [ "type" ],
|
||||
"additionalProperties": false,
|
||||
"description": "Describes a fisheye projection that is used to render into its parent Viewport. This uses a default of 180 degrees field of view and has a 1:1 aspect ratio. This projection type counts as a non-linear projection, which requires 4-6 render passes of the application, meaning that the application might render slower when using these kind of projections than a flat projection. In either case, the application does not need to be aware of the projection as this abstract is handled internally and the applications draw method is only called multiple times per frame with different projection methods that are used to create the full fisheye projection"
|
||||
},
|
||||
|
||||
"planarprojection": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"const": "PlanarProjection",
|
||||
"default": "PlanarProjection",
|
||||
"readOnly": true
|
||||
},
|
||||
"fov": {
|
||||
"$ref": "sgct.schema.json#/$defs/fovhorizontalvertical",
|
||||
"title": "Camera Field-of-View",
|
||||
"description": "This element describes the field of view used the camera in this planar projection"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"description": "Describes a projection for the Viewport that is a flat projection described by simple frustum, which may be asymmetric"
|
||||
},
|
||||
|
||||
"sphericalmirrorprojection": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"const": "SphericalMirrorProjection",
|
||||
"default": "SphericalMirrorProjection",
|
||||
"readOnly": true
|
||||
},
|
||||
"quality": {
|
||||
"$ref": "sgct.schema.json#/$defs/projectionquality"
|
||||
}
|
||||
},
|
||||
"required": [ "type" ],
|
||||
"additionalProperties": false,
|
||||
"description": "Used to create a projection used for Paul Bourke's spherical mirror setup (see here), which makes it possible to use an off-the-shelf projector to create a planetarium-like environment by bouncing the image of a shiny metal mirror. Please note that this is not the only way to produce these kind of images. Depending on your setup and availability of warping meshes, it might suffice to use the FisheyeProjection node type instead and add a single mesh to the parent Viewport instead. The config folder in SGCT contains an example of this using a default 16x9 warping mesh. This projection type specifically deals with the case where you have four different meshes, one for the bottom, top, left, and right parts of the distorted image"
|
||||
},
|
||||
|
||||
"spoutoutputprojection": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"const": "SpoutOutputProjection",
|
||||
"default": "SpoutOutputProjection",
|
||||
"readOnly": true
|
||||
},
|
||||
"quality": {
|
||||
"$ref": "sgct.schema.json#/$defs/projectionquality"
|
||||
},
|
||||
"mapping": {
|
||||
"type": "string",
|
||||
"enum": [ "fisheye", "equirectangular" ],
|
||||
"title": "Mapping",
|
||||
"description": "Determines the type of sharing that occurs with this projection and thus how many and which texture is shared via Spout. For the “fisheye” and “equirectangular”, only the single, final reprojected image is shared, for the “cubemap” method, all selected cubemaps will be provided through the Spout interface. The default value is “cubemap”"
|
||||
},
|
||||
"mappingspoutname": {
|
||||
"type": "string",
|
||||
"title": "Mapping Spout Name",
|
||||
"description": "Sets the name of the texture if the mapping type is 'fisheye' or 'equirectangular'. If the mapping is 'cubemap', this value is ignored"
|
||||
}
|
||||
},
|
||||
"required": [ "type", "mapping" ],
|
||||
"additionalProperties": false,
|
||||
"description": "Provides the ability to share a fully reprojected image using the Spout library. This library only supports the Windows operating system, so this projection will only work on Windows machines. Spout's functionality is the abilty to shared textures between different applications on the same machine, making it possible to render images using SGCT and making them available to other real-time applications on the same machine for further processing. Spout uses a textual name for accessing which texture should be used for sharing. The SpoutOutputProjection has three different output types, outputting each cube map face, sharing a fisheye image, or sharing an equirectangular projection, as determined by the mapping attribute"
|
||||
},
|
||||
|
||||
"projection": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/$defs/planarprojection",
|
||||
"title": "Planar Projection"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/fisheyeprojection",
|
||||
"title": "Fisheye Projection"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/sphericalmirrorprojection",
|
||||
"title": "Spherical Mirror Projection"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/spoutoutputprojection",
|
||||
"title": "Spout Output Projection"
|
||||
},
|
||||
{
|
||||
"$ref": "#/$defs/cylindricalprojection",
|
||||
"title": "Cylindrical Projection"
|
||||
},
|
||||
{
|
||||
"$ref": "sgct.schema.json#/$defs/equirectangularprojection",
|
||||
"title": "Equirectangular Projection"
|
||||
}
|
||||
],
|
||||
"title": "Projection"
|
||||
},
|
||||
|
||||
"node": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"address": {
|
||||
"$ref": "sgct.schema.json#/$defs/address"
|
||||
},
|
||||
"port": {
|
||||
"$ref": "sgct.schema.json#/$defs/port"
|
||||
},
|
||||
"windows": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"border": {
|
||||
"$ref": "sgct.schema.json#/$defs/windowborder"
|
||||
},
|
||||
"draw2d": {
|
||||
"$ref": "sgct.schema.json#/$defs/draw2d"
|
||||
},
|
||||
"draw3d": {
|
||||
"$ref": "sgct.schema.json#/$defs/draw3d"
|
||||
},
|
||||
"monitor": {
|
||||
"$ref": "sgct.schema.json#/$defs/monitor"
|
||||
},
|
||||
"id": {
|
||||
"$ref": "sgct.schema.json#/$defs/id"
|
||||
},
|
||||
"name": {
|
||||
"$ref": "sgct.schema.json#/$defs/windowname"
|
||||
},
|
||||
"pos": {
|
||||
"$ref": "sgct.schema.json#/$defs/windowpos"
|
||||
},
|
||||
"size": {
|
||||
"$ref": "sgct.schema.json#/$defs/windowsize"
|
||||
},
|
||||
"tags": {
|
||||
"$ref": "sgct.schema.json#/$defs/tags"
|
||||
},
|
||||
"viewports": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"pos": {
|
||||
"$ref": "sgct.schema.json#/$defs/viewportpos"
|
||||
},
|
||||
"size": {
|
||||
"$ref": "sgct.schema.json#/$defs/viewportsize"
|
||||
},
|
||||
"projection": {
|
||||
"$ref": "sgct.schema.json#/$defs/projection"
|
||||
},
|
||||
"tracked": {
|
||||
"$ref": "sgct.schema.json#/$defs/tracked"
|
||||
}
|
||||
}
|
||||
},
|
||||
"title": "Viewports"
|
||||
}
|
||||
},
|
||||
"required": [ "pos", "size", "viewports" ]
|
||||
},
|
||||
"title": "Windows",
|
||||
"description": "Specifies a single window that is used to render content into. There can be an arbitrary(-ish) number of windows for each node and they all will be created and initialized at start time. Each window has at least one Viewport that specifies exactly where in the window the rendering occurs with which parameters"
|
||||
}
|
||||
},
|
||||
"required": [ "address", "port", "windows" ],
|
||||
"additionalProperties": false,
|
||||
"description": "Defines a single computing node that is contained in the described cluster. In general this corresponds to a single computer, but it is also possible to create multiple nodes on a local machine by using the 127.0.0.x IP address with x from 0 to 255. It is not possible to create multiple nodes on the same remote computer, however"
|
||||
},
|
||||
|
||||
"scene": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"orientation": {
|
||||
"$ref": "sgct.schema.json#/$defs/quat",
|
||||
"title": "Orientation",
|
||||
"description": "Describes a fixed orientation of the global scene"
|
||||
}
|
||||
},
|
||||
"required": [ "orientation" ],
|
||||
"additionalProperties": false,
|
||||
"description": "Determines an overall orientation of the scene. It consists only of an Orientation, which is included in the projection matrix that is passed to the rendering function callback of the specific application. This node can be used to customize the rendering for a specific rendering window. A common use-case in planetariums, for example, is to account for a tilt in the display system by providing an Orientation with the same pitch as the planetarium surface. This makes it possible to reuse the same application between the planetarium dome and fixed setups without the need for special care"
|
||||
},
|
||||
|
||||
"display": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"swapinterval": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"title": "Swap Interval",
|
||||
"description": "Determines the swap interval for the application. This determines the amount of V-Sync that should occur for the application. The two most common values for this are 0 for disabling V-Sync and 1 for regular V-Sync. The number provided determines the number of screen updates to wait before swapping the backbuffers and returning. For example on a 60Hz monitor, swapinterval=\"1\" would lead to a maximum of 60Hz frame rate, swapinterval=\"2\" would lead to a maximum of 30Hz frame rate. Using the same values for a 144Hz monitor would be a refresh rate of 144 and 72 respectively. The default value is 0, meaning that V-Sync is disabled"
|
||||
}
|
||||
},
|
||||
"title": "Display",
|
||||
"additionalProperties": false,
|
||||
"description": "Settings specific for the handling of display-related settings for the whole application"
|
||||
},
|
||||
|
||||
"settings": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"display": {
|
||||
"$ref": "#/$defs/display"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"description": "Controls global settings that affect the overall behavior of the SGCT library that are not limited just to a single window"
|
||||
},
|
||||
|
||||
"user": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"title": "Name",
|
||||
"description": "Specifies the name of this user. Each user needs to have a unique name, but there also has to be exactly one user present that has an empty name (or without a name attribute) which is used as the default user"
|
||||
},
|
||||
"eyeseparation": {
|
||||
"type": "number",
|
||||
"minimum": 0.0,
|
||||
"title": "Eye Separation",
|
||||
"description": "Determines the eye separation used for stereoscopic viewports. If no viewports in the configuration are using stereo, this setting is ignored"
|
||||
},
|
||||
"pos": {
|
||||
"$ref": "sgct.schema.json#/$defs/vec3",
|
||||
"title": "Position",
|
||||
"description": "A linear offset of the user position. Must define three float attributes x, y, and z. The default values are x=0, y=0, z=0, meaning that no linear offset is applied to the user's position"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [ "pos" ],
|
||||
"description": "Specifies a user position and parameters. In most cases, only a single unnamed user is necessary. However, in more general cases, it is possible to assign Users to specific Viewports to provide a more fine-grained control over the rendering that occurs in that viewport"
|
||||
}
|
||||
},
|
||||
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"masteraddress": {
|
||||
"$ref": "sgct.schema.json#/$defs/masteraddress"
|
||||
},
|
||||
"nodes": {
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/$defs/node" },
|
||||
"title": "Nodes"
|
||||
},
|
||||
"scene": {
|
||||
"$ref": "#/$defs/scene",
|
||||
"title": "Scene"
|
||||
},
|
||||
"settings": {
|
||||
"$ref": "#/$defs/settings",
|
||||
"title": "Settings"
|
||||
},
|
||||
"version": {
|
||||
"type": "integer"
|
||||
},
|
||||
"users": {
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/$defs/user" },
|
||||
"title": "Users"
|
||||
},
|
||||
"generator": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": { "type": "string" },
|
||||
"major": { "type": "integer" },
|
||||
"minor": { "type": "integer" }
|
||||
},
|
||||
"required": [ "name", "major", "minor" ]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"version", "masteraddress", "scene", "users", "generator"
|
||||
]
|
||||
}
|
||||
@@ -18,6 +18,7 @@
|
||||
"stereo": "none",
|
||||
"pos": { "x": 50, "y": 50 },
|
||||
"size": { "x": 1280, "y": 720 },
|
||||
"res": { "x": 2560, "y": 1440 },
|
||||
"viewports": [
|
||||
{
|
||||
"tracked": true,
|
||||
|
||||
71
config/single_gui_with_graphics.json
Normal file
71
config/single_gui_with_graphics.json
Normal file
@@ -0,0 +1,71 @@
|
||||
{
|
||||
"version": 1,
|
||||
"masteraddress": "localhost",
|
||||
"externalcontrolport": 20500,
|
||||
"settings": {
|
||||
"display": {
|
||||
"swapinterval": 0
|
||||
}
|
||||
},
|
||||
"nodes": [
|
||||
{
|
||||
"address": "localhost",
|
||||
"port": 20401,
|
||||
"windows": [
|
||||
{
|
||||
"name": "GUI",
|
||||
"tags": [ "GUI" ],
|
||||
"fullscreen": false,
|
||||
"draw3d": false,
|
||||
"blitwindowid": 1,
|
||||
"stereo": "none",
|
||||
"pos": { "x": 50, "y": 50 },
|
||||
"size": { "x": 1280, "y": 720 },
|
||||
"viewports": [
|
||||
{
|
||||
"pos": { "x": 0.0, "y": 0.0 },
|
||||
"size": { "x": 1.0, "y": 1.0 },
|
||||
"projection": {
|
||||
"type": "PlanarProjection",
|
||||
"fov": {
|
||||
"hfov": 80.0,
|
||||
"vfov": 50.534015846724
|
||||
},
|
||||
"orientation": { "yaw": 0.0, "pitch": 0.0, "roll": 0.0 }
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "OpenSpace",
|
||||
"fullscreen": false,
|
||||
"draw2d": false,
|
||||
"stereo": "none",
|
||||
"pos": { "x": 50, "y": 50 },
|
||||
"size": { "x": 1280, "y": 720 },
|
||||
"viewports": [
|
||||
{
|
||||
"tracked": true,
|
||||
"pos": { "x": 0.0, "y": 0.0 },
|
||||
"size": { "x": 1.0, "y": 1.0 },
|
||||
"projection": {
|
||||
"type": "PlanarProjection",
|
||||
"fov": {
|
||||
"hfov": 80.0,
|
||||
"vfov": 50.534015846724
|
||||
},
|
||||
"orientation": { "yaw": 0.0, "pitch": 0.0, "roll": 0.0 }
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"users": [
|
||||
{
|
||||
"eyeseparation": 0.065,
|
||||
"pos": { "x": 0.0, "y": 0.0, "z": 0.0 }
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -53,7 +53,7 @@
|
||||
"users": [
|
||||
{
|
||||
"eyeseparation": 0.065,
|
||||
"pos": { "x": 0.0, "y": 0.0, "z": 4.0 }
|
||||
"pos": { "x": 0.0, "y": 0.0, "z": 0.0 }
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -25,7 +25,8 @@
|
||||
"pos": { "x": 0.0, "y": 0.0 },
|
||||
"size": { "x": 1.0, "y": 1.0 },
|
||||
"projection": {
|
||||
"PlanarProjection": {
|
||||
"type": "SpoutFlatProjection",
|
||||
"planarprojection": {
|
||||
"fov": {
|
||||
"hfov": 80.0,
|
||||
"vfov": 50.534015846724
|
||||
@@ -38,11 +39,10 @@
|
||||
"b": 0.1,
|
||||
"a": 1.0
|
||||
},
|
||||
"drawMain": true,
|
||||
"height": "1080",
|
||||
"drawmain": true,
|
||||
"height": 1080,
|
||||
"mappingspoutname": "OS_FLAT",
|
||||
"type": "SpoutFlatProjection",
|
||||
"width": "1920"
|
||||
"width": 1920
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
"users": [
|
||||
{
|
||||
"eyeseparation": 0.065,
|
||||
"pos": { "x": 0.0, "y": 0.0, "z": 4.0 }
|
||||
"pos": { "x": 0.0, "y": 0.0, "z": 0.0 }
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
6
data/assets/actions/default_actions.asset
Normal file
6
data/assets/actions/default_actions.asset
Normal file
@@ -0,0 +1,6 @@
|
||||
asset.require("actions/trails/toggle_all_trails")
|
||||
asset.require("actions/trails/toggle_trails_planets_moons")
|
||||
asset.require("actions/planets/planet_lighting")
|
||||
asset.require("actions/system/undo_event_fades")
|
||||
asset.require("actions/trails/toggle_all_minor_moon_trails")
|
||||
asset.require("actions/trails/on_off_all_minor_moons")
|
||||
117
data/assets/actions/nightsky/camera.asset
Normal file
117
data/assets/actions/nightsky/camera.asset
Normal file
@@ -0,0 +1,117 @@
|
||||
local LookUp = {
|
||||
Identifier = "os.nightsky.LookUp",
|
||||
Name = "Look up",
|
||||
Command = [[
|
||||
local currentNavState = openspace.navigation.getNavigationState()
|
||||
local newNavState = {
|
||||
Pitch = math.pi,
|
||||
Anchor = currentNavState["Anchor"],
|
||||
Yaw = currentNavState["Yaw"],
|
||||
Position = currentNavState["Position"],
|
||||
Up = currentNavState["Up"]
|
||||
}
|
||||
openspace.navigation.setNavigationState(newNavState)
|
||||
]],
|
||||
Documentation = "Sets the view to be looking at the zenith",
|
||||
GuiPath = "/Night Sky/View",
|
||||
IsLocal = false
|
||||
}
|
||||
|
||||
local LevelHorizonYaw = {
|
||||
Identifier = "os.nightsky.LevelHorizonYaw",
|
||||
Name = "Level Horizon Yaw",
|
||||
Command = [[
|
||||
local currentNavState = openspace.navigation.getNavigationState()
|
||||
local newNavState = {
|
||||
Pitch = currentNavState["Pitch"],
|
||||
Anchor = currentNavState["Anchor"],
|
||||
Yaw = 0.0,
|
||||
Position = currentNavState["Position"],
|
||||
Up = currentNavState["Up"]
|
||||
}
|
||||
openspace.navigation.setNavigationState(newNavState)
|
||||
]],
|
||||
Documentation = "Levels the horizon horizontally.",
|
||||
GuiPath = "/Night Sky/View",
|
||||
IsLocal = false
|
||||
}
|
||||
|
||||
local LevelHorizonPitch = {
|
||||
Identifier = "os.nightsky.LevelHorizonPitch",
|
||||
Name = "Level Horizon Pitch",
|
||||
Command = [[
|
||||
local currentNavState = openspace.navigation.getNavigationState()
|
||||
local newNavState = {
|
||||
Pitch = math.pi / 2.0,
|
||||
Anchor = currentNavState["Anchor"],
|
||||
Yaw = currentNavState["Yaw"],
|
||||
Position = currentNavState["Position"],
|
||||
Up = currentNavState["Up"]
|
||||
}
|
||||
openspace.navigation.setNavigationState(newNavState)
|
||||
]],
|
||||
Documentation = "Levels the view to the horizon.",
|
||||
GuiPath = "/Night Sky/View",
|
||||
IsLocal = false
|
||||
}
|
||||
|
||||
local LookingNorth = {
|
||||
Identifier = "os.nightsky.LookingNorth",
|
||||
Name = "Looking North",
|
||||
Command = [[
|
||||
local currentNavState = openspace.navigation.getNavigationState()
|
||||
local newNavState = {
|
||||
Pitch = math.pi / 2.0,
|
||||
Anchor = currentNavState["Anchor"],
|
||||
Yaw = currentNavState["Yaw"],
|
||||
Position = currentNavState["Position"],
|
||||
Up = { 0.0, 0.0, 1.0 }
|
||||
}
|
||||
openspace.navigation.setNavigationState(newNavState)
|
||||
]],
|
||||
Documentation = "Sets the view for a horizon looking North.",
|
||||
GuiPath = "/Night Sky/View",
|
||||
IsLocal = false
|
||||
}
|
||||
|
||||
local LookingSouth = {
|
||||
Identifier = "os.nightsky.LookingSouth",
|
||||
Name = "Looking South",
|
||||
Command = [[
|
||||
local currentNavState = openspace.navigation.getNavigationState()
|
||||
local newNavState = {
|
||||
Pitch = math.pi / 2.0,
|
||||
Anchor = currentNavState["Anchor"],
|
||||
Yaw = currentNavState["Yaw"],
|
||||
Position = currentNavState["Position"],
|
||||
Up = { 0.0, 0.0, -1.0 }
|
||||
}
|
||||
openspace.navigation.setNavigationState(newNavState)
|
||||
]],
|
||||
Documentation = "Sets the view for a horizon looking South.",
|
||||
GuiPath = "/Night Sky/View",
|
||||
IsLocal = false
|
||||
}
|
||||
|
||||
|
||||
asset.onInitialize(function()
|
||||
openspace.action.registerAction(LookUp)
|
||||
openspace.action.registerAction(LevelHorizonYaw)
|
||||
openspace.action.registerAction(LevelHorizonPitch)
|
||||
openspace.action.registerAction(LookingNorth)
|
||||
openspace.action.registerAction(LookingSouth)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function()
|
||||
openspace.action.removeAction(LookingSouth)
|
||||
openspace.action.removeAction(LookingNorth)
|
||||
openspace.action.removeAction(LevelHorizonPitch)
|
||||
openspace.action.removeAction(LevelHorizonYaw)
|
||||
openspace.action.removeAction(LookUp)
|
||||
end)
|
||||
|
||||
asset.export("LookUp", LookUp.Identifier)
|
||||
asset.export("LevelHorizonYaw", LevelHorizonYaw.Identifier)
|
||||
asset.export("LevelHorizonPitch", LevelHorizonPitch.Identifier)
|
||||
asset.export("LookingNorth", LookingNorth.Identifier)
|
||||
asset.export("LookingSouth", LookingSouth.Identifier)
|
||||
31
data/assets/actions/nightsky/daytime.asset
Normal file
31
data/assets/actions/nightsky/daytime.asset
Normal file
@@ -0,0 +1,31 @@
|
||||
local EnableDimming = {
|
||||
Identifier = "os.nightsky.EnableDimming",
|
||||
Name = "Enable atmosphere dimming",
|
||||
Command = [[openspace.setPropertyValue("{daytime_hidden}.Renderable.DimInAtmosphere", true)]],
|
||||
Documentation = "Sets items like the stars and constellations to be hidden during the day",
|
||||
GuiPath = "/Night Sky/Daytime",
|
||||
IsLocal = false
|
||||
}
|
||||
|
||||
local DisableDimming = {
|
||||
Identifier = "os.nightsky.DisableDimming",
|
||||
Name = "Disable atmosphere dimming",
|
||||
Command = [[openspace.setPropertyValue("{daytime_hidden}.Renderable.DimInAtmosphere", false)]],
|
||||
Documentation = "Sets items like the stars and constellations to be shown during the day",
|
||||
GuiPath = "/Night Sky/Daytime",
|
||||
IsLocal = false
|
||||
}
|
||||
|
||||
|
||||
asset.onInitialize(function()
|
||||
openspace.action.registerAction(EnableDimming)
|
||||
openspace.action.registerAction(DisableDimming)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function()
|
||||
openspace.action.removeAction(DisableDimming)
|
||||
openspace.action.removeAction(EnableDimming)
|
||||
end)
|
||||
|
||||
asset.export("EnableDimming", EnableDimming.Identifier)
|
||||
asset.export("EnableDimming", DisableDimming.Identifier)
|
||||
@@ -1,89 +1,92 @@
|
||||
local ctx_enable_action = {
|
||||
Identifier = "os.mars.ctx.fadein",
|
||||
local CTXFadeIn = {
|
||||
Identifier = "os.mars.CTXFadeIn",
|
||||
Name = "Fade in CTX",
|
||||
Command = [[
|
||||
openspace.setPropertyValueSingle("Scene.Mars.Renderable.Layers.ColorLayers.CTX_blended_01.Enabled", true)
|
||||
openspace.setPropertyValueSingle("Scene.Mars.Renderable.Layers.ColorLayers.CTX_blended_01.Settings.Opacity", 0)
|
||||
openspace.setPropertyValueSingle("Scene.Mars.Renderable.Layers.ColorLayers.CTX_blended_01.Settings.Opacity", 1, 2.0)]],
|
||||
openspace.setPropertyValueSingle("Scene.Mars.Renderable.Layers.ColorLayers.CTX_blended_01.Settings.Opacity", 0.0)
|
||||
openspace.setPropertyValueSingle("Scene.Mars.Renderable.Layers.ColorLayers.CTX_blended_01.Settings.Opacity", 1.0, 2.0)]],
|
||||
Documentation = "Enables and fades in CTX layer for Mars",
|
||||
GuiPath = "/Solar System/Mars",
|
||||
IsLocal = true
|
||||
}
|
||||
asset.export("ctx_enable_action", ctx_enable_action.Identifier)
|
||||
|
||||
local ctx_disable_action = {
|
||||
Identifier = "os.mars.ctx.fadedout",
|
||||
Name = "Fade out CTX Layer",
|
||||
Command = [[openspace.setPropertyValueSingle("Scene.Mars.Renderable.Layers.ColorLayers.CTX_blended_01.Settings.Opacity", 0, 2.0)]],
|
||||
local CTXFadeOut = {
|
||||
Identifier = "os.mars.CTXFadeOut",
|
||||
Name = "Fade out CTX layer",
|
||||
Command = [[openspace.setPropertyValueSingle("Scene.Mars.Renderable.Layers.ColorLayers.CTX_blended_01.Settings.Opacity", 0.0, 2.0)]],
|
||||
Documentation = "Fade out CTX",
|
||||
GuiPath = "/Solar System/Mars",
|
||||
IsLocal = true
|
||||
}
|
||||
asset.export("ctx_disable_action", ctx_disable_action.Identifier)
|
||||
|
||||
local hirise_enable_action = {
|
||||
Identifier = "os.mars.hirise.fadein",
|
||||
local HiriseFadeIn = {
|
||||
Identifier = "os.mars.HiriseFadeIn",
|
||||
Name = "Fade in HiRISE",
|
||||
Command = [[
|
||||
openspace.setPropertyValueSingle("Scene.Mars.Renderable.Layers.ColorLayers.HiRISE-PSP.Enabled", true)
|
||||
openspace.setPropertyValueSingle("Scene.Mars.Renderable.Layers.ColorLayers.HiRISE-PSP.Settings.Opacity", 0)
|
||||
openspace.setPropertyValueSingle("Scene.Mars.Renderable.Layers.ColorLayers.HiRISE-PSP.Settings.Opacity", 1, 2.0)]],
|
||||
openspace.setPropertyValueSingle("Scene.Mars.Renderable.Layers.ColorLayers.HiRISE-PSP.Settings.Opacity", 0.0)
|
||||
openspace.setPropertyValueSingle("Scene.Mars.Renderable.Layers.ColorLayers.HiRISE-PSP.Settings.Opacity", 1.0, 2.0)]],
|
||||
Documentation = "Enables and fades in HiRise layer for Mars",
|
||||
GuiPath = "/Solar System/Mars",
|
||||
IsLocal = true
|
||||
}
|
||||
asset.export("hirise_enable_action", hirise_enable_action.Identifier)
|
||||
|
||||
local hirise_disable_action = {
|
||||
Identifier = "os.mars.hirise.fadedout",
|
||||
local HiriseFadeOut = {
|
||||
Identifier = "os.mars.HiriseFadeOut",
|
||||
Name = "Fade out HiRISE",
|
||||
Command = [[openspace.setPropertyValueSingle("Scene.Mars.Renderable.Layers.ColorLayers.HiRISE-PSP.Settings.Opacity", 0, 2.0)]],
|
||||
Command = [[openspace.setPropertyValueSingle("Scene.Mars.Renderable.Layers.ColorLayers.HiRISE-PSP.Settings.Opacity", 0.0, 2.0)]],
|
||||
Documentation = "Fade out HiRISE layer for Mars",
|
||||
GuiPath = "/Solar System/Mars",
|
||||
IsLocal = true
|
||||
}
|
||||
asset.export("hirise_disable_action", hirise_disable_action.Identifier)
|
||||
|
||||
local lshirise_enable_action = {
|
||||
Identifier = "os.mars.lshirise.fadein",
|
||||
Name = "Fade in HiRISE Local Set",
|
||||
local LocalSetHiriseFadeIn = {
|
||||
Identifier = "os.mars.LocalSetHiriseFadeIn",
|
||||
Name = "Fade in HiRISE local set",
|
||||
Command = [[
|
||||
openspace.setPropertyValueSingle("Scene.Mars.Renderable.Layers.ColorLayers.HiRISE-LS.Enabled", true)
|
||||
openspace.setPropertyValueSingle("Scene.Mars.Renderable.Layers.HeightLayers.HiRISE-LS-DEM.Enabled", true)
|
||||
openspace.setPropertyValueSingle("Scene.Mars.Renderable.Layers.ColorLayers.HiRISE-LS.Settings.Opacity", 0)
|
||||
openspace.setPropertyValueSingle("Scene.Mars.Renderable.Layers.ColorLayers.HiRISE-LS.Settings.Opacity", 1, 2.0)]],
|
||||
openspace.setPropertyValueSingle("Scene.Mars.Renderable.Layers.ColorLayers.HiRISE-LS.Settings.Opacity", 0.0)
|
||||
openspace.setPropertyValueSingle("Scene.Mars.Renderable.Layers.ColorLayers.HiRISE-LS.Settings.Opacity", 1.0, 2.0)]],
|
||||
Documentation = "Enables and fades in HiRise local set layers for Mars (including height)",
|
||||
GuiPath = "/Solar System/Mars",
|
||||
IsLocal = true
|
||||
}
|
||||
asset.export("lshirise_enable_action", lshirise_enable_action.Identifier)
|
||||
|
||||
local lshirise_disable_action = {
|
||||
Identifier = "os.mars.lshirise.fadedout",
|
||||
Name = "Fade out HiRISE Local Set",
|
||||
Command = [[openspace.setPropertyValueSingle("Scene.Mars.Renderable.Layers.ColorLayers.HiRISE-LS.Settings.Opacity", 0, 2.0)
|
||||
openspace.setPropertyValueSingle("Scene.Mars.Renderable.Layers.HeightLayers.HiRISE-LS-DEM.Enabled", false)]],
|
||||
local LocalSetHiriseFadeOut = {
|
||||
Identifier = "os.mars.LocalSetHiriseFadeOut",
|
||||
Name = "Fade out HiRISE local set",
|
||||
Command = [[
|
||||
openspace.setPropertyValueSingle("Scene.Mars.Renderable.Layers.ColorLayers.HiRISE-LS.Settings.Opacity", 0.0, 2.0)
|
||||
openspace.setPropertyValueSingle("Scene.Mars.Renderable.Layers.HeightLayers.HiRISE-LS-DEM.Enabled", false)
|
||||
]],
|
||||
Documentation = "Fade out HiRISE local set layer for Mars",
|
||||
GuiPath = "/Solar System/Mars",
|
||||
IsLocal = true
|
||||
}
|
||||
asset.export("lshirise_disable_action", lshirise_disable_action.Identifier)
|
||||
|
||||
|
||||
asset.onInitialize(function()
|
||||
openspace.action.registerAction(ctx_enable_action)
|
||||
openspace.action.registerAction(ctx_disable_action)
|
||||
openspace.action.registerAction(hirise_enable_action)
|
||||
openspace.action.registerAction(hirise_disable_action)
|
||||
openspace.action.registerAction(lshirise_enable_action)
|
||||
openspace.action.registerAction(lshirise_disable_action)
|
||||
openspace.action.registerAction(CTXFadeIn)
|
||||
openspace.action.registerAction(CTXFadeOut)
|
||||
openspace.action.registerAction(HiriseFadeIn)
|
||||
openspace.action.registerAction(HiriseFadeOut)
|
||||
openspace.action.registerAction(LocalSetHiriseFadeIn)
|
||||
openspace.action.registerAction(LocalSetHiriseFadeOut)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function()
|
||||
openspace.action.removeAction(lshirise_disable_action)
|
||||
openspace.action.removeAction(lshirise_enable_action)
|
||||
openspace.action.removeAction(hirise_disable_action)
|
||||
openspace.action.removeAction(hirise_enable_action)
|
||||
openspace.action.removeAction(ctx_disable_action)
|
||||
openspace.action.removeAction(ctx_enable_action)
|
||||
openspace.action.removeAction(LocalSetHiriseFadeOut)
|
||||
openspace.action.removeAction(LocalSetHiriseFadeIn)
|
||||
openspace.action.removeAction(HiriseFadeOut)
|
||||
openspace.action.removeAction(HiriseFadeIn)
|
||||
openspace.action.removeAction(CTXFadeOut)
|
||||
openspace.action.removeAction(CTXFadeIn)
|
||||
end)
|
||||
|
||||
asset.export("CTXFadeIn", CTXFadeIn.Identifier)
|
||||
asset.export("CTXFadeOut", CTXFadeOut.Identifier)
|
||||
asset.export("HiriseFadeIn", HiriseFadeIn.Identifier)
|
||||
asset.export("HiriseFadeOut", HiriseFadeOut.Identifier)
|
||||
asset.export("LocalSetHiriseFadeIn", LocalSetHiriseFadeIn.Identifier)
|
||||
asset.export("LocalSetHiriseFadeOut", LocalSetHiriseFadeOut.Identifier)
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
local function getIlluminationCommand(node, global)
|
||||
local commandString = "local node = \"" .. node .. "\"\n"
|
||||
if (node == "Current Focus") then
|
||||
local function illuminationCommand(node, global)
|
||||
local commandString = "local node = '" .. node .. "'\n"
|
||||
if (node == "Current Focus") then
|
||||
commandString = "local node = openspace.navigation.getNavigationState().Anchor\n"
|
||||
end
|
||||
if (global) then
|
||||
commandString = commandString .. [[
|
||||
if (openspace.hasProperty("Scene."..node..".Renderable.UseAccurateNormals")) then
|
||||
if (openspace.hasProperty("Scene."..node..".Renderable.UseAccurateNormals")) then
|
||||
local list = openspace.getProperty("Scene." .. node .. ".Renderable.Layers.NightLayers.*.Enabled")
|
||||
if (#list > 0) then
|
||||
openspace.setPropertyValue("Scene." .. node .. ".Renderable.Layers.NightLayers.*.Enabled", false)
|
||||
else
|
||||
openspace.setPropertyValueSingle("Scene." .. node .. ".Renderable.PerformShading", false)
|
||||
openspace.setPropertyValueSingle("Scene." .. node .. ".Renderable.PerformShading", false)
|
||||
end
|
||||
if openspace.hasSceneGraphNode(node .. "Atmosphere") then
|
||||
openspace.setPropertyValueSingle("Scene." .. node .. "Atmosphere.Renderable.SunFollowingCamera", true)
|
||||
@@ -28,7 +28,7 @@ local list = openspace.getProperty("Scene." .. node .. ".Renderable.Layers.Night
|
||||
if (#list > 0) then
|
||||
openspace.setPropertyValue(list[1], true)
|
||||
else
|
||||
openspace.setPropertyValueSingle("Scene." .. node .. ".Renderable.PerformShading", true)
|
||||
openspace.setPropertyValueSingle("Scene." .. node .. ".Renderable.PerformShading", true)
|
||||
end
|
||||
if openspace.hasSceneGraphNode(node .. "Atmosphere") then
|
||||
openspace.setPropertyValueSingle("Scene." .. node .. "Atmosphere.Renderable.SunFollowingCamera", false)
|
||||
@@ -43,18 +43,18 @@ end]]
|
||||
return commandString
|
||||
end
|
||||
|
||||
local function getIlluminationAction(node, node_lower, global)
|
||||
local function illuminationAction(node, nodeLower, global)
|
||||
local actionString = "_standard_illumination"
|
||||
local actionName = "Standard Illumination"
|
||||
local actionCommand = getIlluminationCommand(node, global)
|
||||
local actionName = "standard illumination"
|
||||
local actionCommand = illuminationCommand(node, global)
|
||||
if (global) then
|
||||
actionString = "_global_illumination"
|
||||
actionName = "Global Illumination"
|
||||
actionCommand = getIlluminationCommand(node, global)
|
||||
actionName = "global illumination"
|
||||
actionCommand = illuminationCommand(node, global)
|
||||
end
|
||||
|
||||
local action = {
|
||||
Identifier = "os." .. string.gsub(node_lower, "%s+", "") .. actionString,
|
||||
Identifier = "os." .. string.gsub(nodeLower, "%s+", "") .. actionString,
|
||||
Name = node .. " " .. actionName,
|
||||
Command = actionCommand,
|
||||
Documentation = "Enables " .. string.lower(actionName) .. " for" .. node,
|
||||
@@ -64,63 +64,105 @@ local function getIlluminationAction(node, node_lower, global)
|
||||
return action
|
||||
end
|
||||
|
||||
local current_focus_global = getIlluminationAction("Current Focus", "current_focus", true)
|
||||
asset.export("current_focus_global", current_focus_global.Identifier)
|
||||
local current_focus_standard = getIlluminationAction("Current Focus", "current_focus", false)
|
||||
asset.export("current_focus_standard", current_focus_standard.Identifier)
|
||||
local CurrentFocusGlobal = illuminationAction("Current Focus", "current_focus", true)
|
||||
local CurrentFocusStandard = illuminationAction("Current Focus", "current_focus", false)
|
||||
|
||||
local earth_global = getIlluminationAction("Earth", "earth", true)
|
||||
asset.export("earth_global", earth_global.Identifier)
|
||||
local earth_standard = getIlluminationAction("Earth", "earth", false)
|
||||
asset.export("earth_standard", earth_standard.Identifier)
|
||||
local EarthGlobal = illuminationAction("Earth", "earth", true)
|
||||
local EarthStandard = illuminationAction("Earth", "earth", false)
|
||||
|
||||
local mars_global = getIlluminationAction("Mars", "mars", true)
|
||||
asset.export("mars_global", mars_global.Identifier)
|
||||
local mars_standard = getIlluminationAction("Mars", "mars", false)
|
||||
asset.export("mars_standard", mars_standard.Identifier)
|
||||
local MarsGlobal = illuminationAction("Mars", "mars", true)
|
||||
local MarsStandard = illuminationAction("Mars", "mars", false)
|
||||
|
||||
local venus_global = getIlluminationAction("Venus", "venus", true)
|
||||
asset.export("venus_global", venus_global.Identifier)
|
||||
local venus_standard = getIlluminationAction("Venus", "venus", false)
|
||||
asset.export("venus_standard", venus_standard.Identifier)
|
||||
local VenusGlobal = illuminationAction("Venus", "venus", true)
|
||||
local VenusStandard = illuminationAction("Venus", "venus", false)
|
||||
|
||||
local titan_global = getIlluminationAction("Titan", "titan", true)
|
||||
asset.export("titan_global", titan_global.Identifier)
|
||||
local titan_standard = getIlluminationAction("Titan", "titan", false)
|
||||
asset.export("titan_standard", titan_standard.Identifier)
|
||||
local TitanGlobal = illuminationAction("Titan", "titan", true)
|
||||
local TitanStandard = illuminationAction("Titan", "titan", false)
|
||||
|
||||
local saturn_global = getIlluminationAction("Saturn", "saturn", true)
|
||||
asset.export("saturn_global", saturn_global.Identifier)
|
||||
local saturn_standard = getIlluminationAction("Saturn", "saturn", false)
|
||||
asset.export("titan_standard", saturn_standard.Identifier)
|
||||
local SaturnGlobal = illuminationAction("Saturn", "saturn", true)
|
||||
local SaturnStandard = illuminationAction("Saturn", "saturn", false)
|
||||
|
||||
|
||||
-- handling Earth special
|
||||
-- if we have #2258 we can do all globes with night layers instead of just earth
|
||||
-- if we have #1826 we can do the default night layer instead of the first
|
||||
local AllGlobesGlobalIllumination = {
|
||||
Identifier = "os.AllGlobesGlobalIllumination",
|
||||
Name = "All globes global illumination",
|
||||
Command = [[
|
||||
openspace.setPropertyValue("{planet_solarSystem}.Renderable.PerformShading", false)
|
||||
openspace.setPropertyValue("{moon_solarSystem}.Renderable.PerformShading", false)
|
||||
openspace.setPropertyValue("Scene.*Atmosphere.Renderable.SunFollowingCamera", true)
|
||||
openspace.setPropertyValue("Scene.*.Renderable.ShadowsComponent.DistanceFraction", 3000)
|
||||
openspace.setPropertyValue("Scene.Earth.Renderable.Layers.NightLayers.Earth_at_Night_2012.Enabled", false)
|
||||
]],
|
||||
Documentation = "Enables global illumination for all globes",
|
||||
GuiPath = "/Solar System",
|
||||
IsLocal = true
|
||||
}
|
||||
|
||||
local AllGlobesStandardIllumination = {
|
||||
Identifier = "os.AllGlobesStandardIllumination",
|
||||
Name = "All globes standard illumination",
|
||||
Command = [[
|
||||
openspace.setPropertyValue("{planet_solarSystem}.Renderable.PerformShading", true)
|
||||
openspace.setPropertyValue("{moon_solarSystem}.Renderable.PerformShading", true)
|
||||
openspace.setPropertyValue("Scene.*Atmosphere.Renderable.SunFollowingCamera", false)
|
||||
openspace.setPropertyValue("Scene.*.Renderable.ShadowsComponent.DistanceFraction", 40)
|
||||
openspace.setPropertyValueSingle("Scene.Earth.Renderable.Layers.NightLayers.Earth_at_Night_2012.Enabled", true)
|
||||
openspace.setPropertyValueSingle("Scene.Earth.Renderable.PerformShading", false)
|
||||
]],
|
||||
Documentation = "Disables global illumination for all globes",
|
||||
GuiPath = "/Solar System",
|
||||
IsLocal = true
|
||||
}
|
||||
|
||||
|
||||
asset.onInitialize(function()
|
||||
openspace.action.registerAction(current_focus_global)
|
||||
openspace.action.registerAction(current_focus_standard)
|
||||
openspace.action.registerAction(earth_global)
|
||||
openspace.action.registerAction(earth_standard)
|
||||
openspace.action.registerAction(mars_global)
|
||||
openspace.action.registerAction(mars_standard)
|
||||
openspace.action.registerAction(venus_global)
|
||||
openspace.action.registerAction(venus_standard)
|
||||
openspace.action.registerAction(titan_global)
|
||||
openspace.action.registerAction(titan_standard)
|
||||
openspace.action.registerAction(saturn_global)
|
||||
openspace.action.registerAction(saturn_standard)
|
||||
openspace.action.registerAction(CurrentFocusGlobal)
|
||||
openspace.action.registerAction(CurrentFocusStandard)
|
||||
openspace.action.registerAction(EarthGlobal)
|
||||
openspace.action.registerAction(EarthStandard)
|
||||
openspace.action.registerAction(MarsGlobal)
|
||||
openspace.action.registerAction(MarsStandard)
|
||||
openspace.action.registerAction(VenusGlobal)
|
||||
openspace.action.registerAction(VenusStandard)
|
||||
openspace.action.registerAction(TitanGlobal)
|
||||
openspace.action.registerAction(TitanStandard)
|
||||
openspace.action.registerAction(SaturnGlobal)
|
||||
openspace.action.registerAction(SaturnStandard)
|
||||
openspace.action.registerAction(AllGlobesGlobalIllumination)
|
||||
openspace.action.registerAction(AllGlobesStandardIllumination)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function()
|
||||
openspace.action.removeAction(saturn_standard)
|
||||
openspace.action.removeAction(saturn_global)
|
||||
openspace.action.removeAction(titan_standard)
|
||||
openspace.action.removeAction(titan_global)
|
||||
openspace.action.removeAction(venus_standard)
|
||||
openspace.action.removeAction(venus_global)
|
||||
openspace.action.removeAction(mars_standard)
|
||||
openspace.action.removeAction(mars_global)
|
||||
openspace.action.removeAction(earth_standard)
|
||||
openspace.action.removeAction(earth_global)
|
||||
openspace.action.removeAction(current_focus_standard)
|
||||
openspace.action.removeAction(current_focus_global)
|
||||
openspace.action.removeAction(AllGlobesStandardIllumination)
|
||||
openspace.action.removeAction(AllGlobesGlobalIllumination)
|
||||
openspace.action.removeAction(SaturnStandard)
|
||||
openspace.action.removeAction(SaturnGlobal)
|
||||
openspace.action.removeAction(TitanStandard)
|
||||
openspace.action.removeAction(TitanGlobal)
|
||||
openspace.action.removeAction(VenusStandard)
|
||||
openspace.action.removeAction(VenusGlobal)
|
||||
openspace.action.removeAction(MarsStandard)
|
||||
openspace.action.removeAction(MarsGlobal)
|
||||
openspace.action.removeAction(EarthStandard)
|
||||
openspace.action.removeAction(EarthGlobal)
|
||||
openspace.action.removeAction(CurrentFocusStandard)
|
||||
openspace.action.removeAction(CurrentFocusGlobal)
|
||||
end)
|
||||
|
||||
asset.export("CurrentFocusGlobal", CurrentFocusGlobal.Identifier)
|
||||
asset.export("CurrentFocusStandard", CurrentFocusStandard.Identifier)
|
||||
asset.export("EarthGlobal", EarthGlobal.Identifier)
|
||||
asset.export("EarthStandard", EarthStandard.Identifier)
|
||||
asset.export("MarsGlobal", MarsGlobal.Identifier)
|
||||
asset.export("MarsStandard", MarsStandard.Identifier)
|
||||
asset.export("VenusGlobal", VenusGlobal.Identifier)
|
||||
asset.export("VenusStandard", VenusStandard.Identifier)
|
||||
asset.export("TitanGlobal", TitanGlobal.Identifier)
|
||||
asset.export("TitanStandard", TitanStandard.Identifier)
|
||||
asset.export("SaturnGlobal", SaturnGlobal.Identifier)
|
||||
asset.export("SaturnStandard", SaturnStandard.Identifier)
|
||||
asset.export("AllGlobesGlobalIllumination", AllGlobesGlobalIllumination.Identifier)
|
||||
asset.export("AllGlobesStandardIllumination", AllGlobesStandardIllumination.Identifier)
|
||||
|
||||
@@ -1,127 +1,131 @@
|
||||
local function getScaleCommand(identifier, scale, speed)
|
||||
local command = 'openspace.setPropertyValue("' .. identifier .. '.Scale.Scale", '
|
||||
local function scaleCommand(identifier, scale, speed)
|
||||
local command = [[openspace.setPropertyValue("]] .. identifier .. [[.Scale.Scale", ]]
|
||||
command = command .. scale .. ", " .. speed
|
||||
if (scale == 1) then
|
||||
command = command .. ")"
|
||||
else
|
||||
command = command .. ', "CubicEaseOut")'
|
||||
command = command .. [[, "CubicEaseOut")]]
|
||||
end
|
||||
return command
|
||||
end
|
||||
|
||||
local function getScaleAction(identifier, scale, name, speed)
|
||||
local function scaleAction(identifier, scale, name, speed)
|
||||
local actionString = "Grow"
|
||||
if (scale == 1) then
|
||||
actionString = "Shrink"
|
||||
end
|
||||
local action = {
|
||||
return {
|
||||
Identifier = "os." .. actionString .. "_" .. identifier,
|
||||
Name = actionString .. " " .. name,
|
||||
Command = getScaleCommand(identifier, scale, speed),
|
||||
Command = scaleCommand(identifier, scale, speed),
|
||||
Documentation = "Scales " .. name .. " to " .. scale .. "x",
|
||||
GuiPath = "/Solar System/Scale",
|
||||
IsLocal = true
|
||||
}
|
||||
return action
|
||||
end
|
||||
|
||||
local function getToggleScaleAction(identifier, scale, name, speedup, speedown)
|
||||
local action = {
|
||||
local function toggleScaleAction(identifier, scale, name, speedup, speeddown)
|
||||
return {
|
||||
Identifier = "os.toggle_" .. string.gsub(name, "%s+", "") .. "_scale",
|
||||
Name = "Toggle " .. name .. " Scale",
|
||||
Name = "Toggle " .. name .. " scale",
|
||||
Command = [[
|
||||
local list = openspace.getProperty("]] .. identifier .. [[.Scale.Scale");
|
||||
local list = openspace.getProperty("]] .. identifier .. [[.Scale.Scale")
|
||||
if #list == 0 then
|
||||
openspace.printWarning("No planets to resize");
|
||||
openspace.printWarning("No planets to resize")
|
||||
else
|
||||
local prop = list[1];
|
||||
local currentScale = openspace.getPropertyValue(prop);
|
||||
local newScale = 1;
|
||||
local prop = list[1]
|
||||
local currentScale = openspace.getPropertyValue(prop)
|
||||
local newScale = 1
|
||||
if (currentScale == 1) then
|
||||
]] .. getScaleCommand(identifier, scale, speedup) .. [[
|
||||
]] .. scaleCommand(identifier, scale, speedup) .. [[
|
||||
else
|
||||
]] .. getScaleCommand(identifier, 1, speedown) .. [[
|
||||
]] .. scaleCommand(identifier, 1, speeddown) .. [[
|
||||
end
|
||||
end
|
||||
]],
|
||||
GuiPath = "/Solar System/Scale",
|
||||
Documentation = "Toggle the scale of " .. name,
|
||||
IsLocal = true
|
||||
GuiPath = "/Solar System/Scale",
|
||||
Documentation = "Toggle the scale of " .. name,
|
||||
IsLocal = true
|
||||
}
|
||||
return action
|
||||
end
|
||||
|
||||
local grow_planets = getScaleAction("{planet_solarSystem}", 3400, "Planets", 3)
|
||||
asset.export("grow_planets", grow_planets.Identifier)
|
||||
local shrink_planets = getScaleAction("{planet_solarSystem}", 1, "Planets", 2)
|
||||
asset.export("shrink_planets", shrink_planets.Identifier)
|
||||
local toggle_planet_scale = getToggleScaleAction("{planet_solarSystem}", 3400, "Planets", 3, 2)
|
||||
asset.export("toggle_planet_scale", toggle_planet_scale.Identifier)
|
||||
local GrowPlanets = scaleAction("{planet_solarSystem}", 3400, "Planets", 3)
|
||||
local ShrinkPlanets = scaleAction("{planet_solarSystem}", 1, "Planets", 2)
|
||||
local TogglePlanetScale = toggleScaleAction("{planet_solarSystem}", 3400, "Planets", 3, 2)
|
||||
|
||||
local grow_inner_planets = getScaleAction("{planet_terrestrial}", 3400, "Inner Planets", 3)
|
||||
asset.export("grow_inner_planets", grow_inner_planets.Identifier)
|
||||
local shrink_inner_planets = getScaleAction("{planet_terrestrial}", 1, "Inner Planets", 2)
|
||||
asset.export("shrink_inner_planets", shrink_inner_planets.Identifier)
|
||||
local toggle_inner_planet_scale = getToggleScaleAction("{planet_terrestrial}", 3400, "Inner Planets", 3, 2)
|
||||
asset.export("toggle_inner_planet_scale", toggle_inner_planet_scale.Identifier)
|
||||
local GrowInnerPlanets = scaleAction("{planet_terrestrial}", 3400, "Inner Planets", 3)
|
||||
local ShrinkInnerPlanets = scaleAction("{planet_terrestrial}", 1, "Inner Planets", 2)
|
||||
local ToggleInnerPlanetScale = toggleScaleAction("{planet_terrestrial}", 3400, "Inner Planets", 3, 2)
|
||||
|
||||
local grow_outter_planets = getScaleAction("{planet_giants}", 3400, "Outter Planets", 3)
|
||||
asset.export("grow_outter_planets", grow_outter_planets.Identifier)
|
||||
local shrink_outter_planets = getScaleAction("{planet_giants}", 1, "Outter Planets", 2)
|
||||
asset.export("shrink_outter_planets", shrink_outter_planets.Identifier)
|
||||
local toggle_outter_planet_scale = getToggleScaleAction("{planet_giants}", 3400, "Outter Planets", 3, 2)
|
||||
asset.export("toggle_outter_planet_scale", toggle_outter_planet_scale.Identifier)
|
||||
local GrowOuterPlanets = scaleAction("{planet_giants}", 3400, "Outer Planets", 3)
|
||||
local ShrinkOuterPlanets = scaleAction("{planet_giants}", 1, "Outer Planets", 2)
|
||||
local ToggleOuterPlanetScale = toggleScaleAction("{planet_giants}", 3400, "Outer Planets", 3, 2)
|
||||
|
||||
local grow_jupiter_moons = getScaleAction("{moon_jupiter}", 50, "Jupiter Moons", 3)
|
||||
asset.export("grow_jupiter_moons", grow_jupiter_moons.Identifier)
|
||||
local shrink_jupiter_moons = getScaleAction("{moon_jupiter}", 1, "Jupiter Moons", 2)
|
||||
asset.export("shrink_jupiter_moons", shrink_jupiter_moons.Identifier)
|
||||
local toggle_jupiter_moon_scales = getToggleScaleAction("{moon_jupiter}", 50, "Jupiter Moons", 3, 2)
|
||||
asset.export("toggle_jupiter_moon_scales", toggle_jupiter_moon_scales.Identifier)
|
||||
local GrowJupiterMoons = scaleAction("{moon_jupiter}", 50, "Jupiter Moons", 3)
|
||||
local ShrinkJupiterMoons = scaleAction("{moon_jupiter}", 1, "Jupiter Moons", 2)
|
||||
local ToggleJupiterMoonScales = toggleScaleAction("{moon_jupiter}", 50, "Jupiter Moons", 3, 2)
|
||||
|
||||
local GrowMoon = scaleAction("Scene.Moon", 25, "Moon", 3)
|
||||
local ShrinkMoon = scaleAction("Scene.Moon", 1, "Moon", 2)
|
||||
local ToggleMoonScale = toggleScaleAction("Scene.Moon", 25, "Moon", 3, 2)
|
||||
|
||||
local grow_moon = getScaleAction("Scene.Moon", 25, "Moon", 3)
|
||||
asset.export("grow_moon", grow_moon.Identifier)
|
||||
local shrink_moon = getScaleAction("Scene.Moon", 1, "Moon", 2)
|
||||
asset.export("shrink_moon", shrink_moon.Identifier)
|
||||
local toggle_moon_scale = getToggleScaleAction("Scene.Moon", 25, "Moon", 3, 2)
|
||||
asset.export("toggle_moon_scale", toggle_moon_scale.Identifier)
|
||||
|
||||
asset.onInitialize(function()
|
||||
openspace.action.registerAction(grow_planets)
|
||||
openspace.action.registerAction(shrink_planets)
|
||||
openspace.action.registerAction(toggle_planet_scale)
|
||||
openspace.action.registerAction(GrowPlanets)
|
||||
openspace.action.registerAction(ShrinkPlanets)
|
||||
openspace.action.registerAction(TogglePlanetScale)
|
||||
|
||||
openspace.action.registerAction(grow_inner_planets)
|
||||
openspace.action.registerAction(shrink_inner_planets)
|
||||
openspace.action.registerAction(toggle_inner_planet_scale)
|
||||
openspace.action.registerAction(GrowInnerPlanets)
|
||||
openspace.action.registerAction(ShrinkInnerPlanets)
|
||||
openspace.action.registerAction(ToggleInnerPlanetScale)
|
||||
|
||||
openspace.action.registerAction(grow_outter_planets)
|
||||
openspace.action.registerAction(shrink_outter_planets)
|
||||
openspace.action.registerAction(toggle_outter_planet_scale)
|
||||
openspace.action.registerAction(GrowOuterPlanets)
|
||||
openspace.action.registerAction(ShrinkOuterPlanets)
|
||||
openspace.action.registerAction(ToggleOuterPlanetScale)
|
||||
|
||||
openspace.action.registerAction(grow_jupiter_moons)
|
||||
openspace.action.registerAction(shrink_jupiter_moons)
|
||||
openspace.action.registerAction(toggle_jupiter_moon_scales)
|
||||
openspace.action.registerAction(GrowJupiterMoons)
|
||||
openspace.action.registerAction(ShrinkJupiterMoons)
|
||||
openspace.action.registerAction(ToggleJupiterMoonScales)
|
||||
|
||||
openspace.action.registerAction(grow_moon)
|
||||
openspace.action.registerAction(shrink_moon)
|
||||
openspace.action.registerAction(toggle_moon_scale)
|
||||
openspace.action.registerAction(GrowMoon)
|
||||
openspace.action.registerAction(ShrinkMoon)
|
||||
openspace.action.registerAction(ToggleMoonScale)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function()
|
||||
openspace.action.removeAction(toggle_moon_scale)
|
||||
openspace.action.removeAction(shrink_moon)
|
||||
openspace.action.removeAction(grow_moon)
|
||||
openspace.action.removeAction(ToggleMoonScale)
|
||||
openspace.action.removeAction(ShrinkMoon)
|
||||
openspace.action.removeAction(GrowMoon)
|
||||
|
||||
openspace.action.removeAction(toggle_outter_planet_scale)
|
||||
openspace.action.removeAction(shrink_outter_planets)
|
||||
openspace.action.removeAction(grow_outter_planets)
|
||||
openspace.action.removeAction(ToggleJupiterMoonScales)
|
||||
openspace.action.removeAction(ShrinkJupiterMoons)
|
||||
openspace.action.removeAction(GrowJupiterMoons)
|
||||
|
||||
openspace.action.removeAction(toggle_inner_planet_scale)
|
||||
openspace.action.removeAction(shrink_inner_planets)
|
||||
openspace.action.removeAction(grow_inner_planets)
|
||||
openspace.action.removeAction(ToggleOuterPlanetScale)
|
||||
openspace.action.removeAction(ShrinkOuterPlanets)
|
||||
openspace.action.removeAction(GrowOuterPlanets)
|
||||
|
||||
openspace.action.removeAction(toggle_planet_scale)
|
||||
openspace.action.removeAction(shrink_planets)
|
||||
openspace.action.removeAction(grow_planets)
|
||||
openspace.action.removeAction(ToggleInnerPlanetScale)
|
||||
openspace.action.removeAction(ShrinkInnerPlanets)
|
||||
openspace.action.removeAction(GrowInnerPlanets)
|
||||
|
||||
openspace.action.removeAction(TogglePlanetScale)
|
||||
openspace.action.removeAction(ShrinkPlanets)
|
||||
openspace.action.removeAction(GrowPlanets)
|
||||
end)
|
||||
|
||||
asset.export("GrowPlanets", GrowPlanets.Identifier)
|
||||
asset.export("ShrinkPlanets", ShrinkPlanets.Identifier)
|
||||
asset.export("TogglePlanetScale", TogglePlanetScale.Identifier)
|
||||
asset.export("GrowInnerPlanets", GrowInnerPlanets.Identifier)
|
||||
asset.export("ShrinkInnerPlanets", ShrinkInnerPlanets.Identifier)
|
||||
asset.export("ToggleInnerPlanetScale", ToggleInnerPlanetScale.Identifier)
|
||||
asset.export("GrowOuterPlanets", GrowOuterPlanets.Identifier)
|
||||
asset.export("ShrinkOuterPlanets", ShrinkOuterPlanets.Identifier)
|
||||
asset.export("ToggleOuterPlanetScale", ToggleOuterPlanetScale.Identifier)
|
||||
asset.export("GrowJupiterMoons", GrowJupiterMoons.Identifiers)
|
||||
asset.export("ShrinkJupiterMoons", ShrinkJupiterMoons.Identifier)
|
||||
asset.export("ToggleJupiterMoonScales", ToggleJupiterMoonScales.Identifier)
|
||||
asset.export("GrowMoon", GrowMoon.Identifier)
|
||||
asset.export("ShrinkMoon", ShrinkMoon.Identifier)
|
||||
asset.export("ToggleMoonScale", ToggleMoonScale.Identifier)
|
||||
|
||||
@@ -1,28 +1,32 @@
|
||||
local undo_event_fade = {
|
||||
Identifier = "os.undo_event_fade",
|
||||
Name = "Undo All Event Fading",
|
||||
local UndoEventFade = {
|
||||
Identifier = "os.UndoEventFade",
|
||||
Name = "Undo all event fading",
|
||||
Command = [[
|
||||
openspace.setPropertyValue("Scene.*.Renderable.Fade", 1.0, 0.5);
|
||||
openspace.setPropertyValue("Scene.*.Renderable.Fade", 1.0, 0.5)
|
||||
]],
|
||||
Documentation = [[Sets the 'Fade' value of all renderables to 1. This internval values is managed by events.]],
|
||||
Documentation = [[Sets the 'Fade' value of all renderables to 1. This internval values
|
||||
is managed by events]],
|
||||
GuiPath = "/System/Rendering",
|
||||
IsLocal = true
|
||||
}
|
||||
asset.export("undo_event_fade", undo_event_fade.Identifier)
|
||||
|
||||
|
||||
asset.onInitialize(function()
|
||||
openspace.action.registerAction(undo_event_fade)
|
||||
openspace.action.registerAction(UndoEventFade)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function()
|
||||
openspace.action.removeAction(undo_event_fade)
|
||||
openspace.action.removeAction(UndoEventFade)
|
||||
end)
|
||||
|
||||
asset.export("UndoEventFade", UndoEventFade.Identifier)
|
||||
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Actions - Undo All Event Fading",
|
||||
Version = "1.0",
|
||||
Description = [[ Asset providing debug ability to undo all event fading.]],
|
||||
Description = "Asset providing debug ability to undo all event fading",
|
||||
Author = "OpenSpace Team",
|
||||
URL = "http://openspaceproject.com",
|
||||
License = "MIT license"
|
||||
|
||||
84
data/assets/actions/trails/on_off_all_minor_moons.asset
Normal file
84
data/assets/actions/trails/on_off_all_minor_moons.asset
Normal file
@@ -0,0 +1,84 @@
|
||||
local MinorMoonsOn = {
|
||||
Identifier = "os.MinorMoonsOn",
|
||||
Name = "Turn on minor moons and trails",
|
||||
Command = [[
|
||||
local trails = openspace.getProperty("{moonTrail_minor}.Renderable.Enabled")
|
||||
local trails_fade = openspace.getProperty("{moonTrail_minor}.Renderable.Fade")
|
||||
|
||||
local moons = openspace.getProperty("{moon_minor}.Renderable.Enabled")
|
||||
local moons_fade = openspace.getProperty("{moon_minor}.Renderable.Fade")
|
||||
|
||||
for i, v in pairs(trails_fade) do
|
||||
openspace.setPropertyValueSingle(trails[i], true)
|
||||
openspace.setPropertyValueSingle(v, 1, 2, "Linear")
|
||||
end
|
||||
|
||||
for i, v in pairs(moons_fade) do
|
||||
openspace.setPropertyValueSingle(moons[i], true)
|
||||
openspace.setPropertyValueSingle(v, 1, 2, "Linear")
|
||||
end
|
||||
]],
|
||||
Documentation = "Turn ON minor moons and their trails for all planets in the solar system",
|
||||
GuiPath = "/Solar System/Minor Moons",
|
||||
IsLocal = true
|
||||
}
|
||||
|
||||
local MinorMoonsOff = {
|
||||
Identifier = "os.MinorMoonsOff",
|
||||
Name = "Turn off minor moons and trails",
|
||||
Command = [[
|
||||
local trails = openspace.getProperty("{moonTrail_minor}.Renderable.Enabled")
|
||||
local trails_fade = openspace.getProperty("{moonTrail_minor}.Renderable.Fade")
|
||||
|
||||
local moons = openspace.getProperty("{moon_minor}.Renderable.Enabled")
|
||||
local moons_fade = openspace.getProperty("{moon_minor}.Renderable.Fade")
|
||||
|
||||
for i, v in pairs(trails_fade) do
|
||||
openspace.setPropertyValueSingle(
|
||||
v,
|
||||
0,
|
||||
2,
|
||||
"Linear",
|
||||
"openspace.setPropertyValueSingle('" .. trails[i] .. "', false)"
|
||||
)
|
||||
end
|
||||
|
||||
for i, v in pairs(moons_fade) do
|
||||
openspace.setPropertyValueSingle(
|
||||
v,
|
||||
0,
|
||||
2,
|
||||
"Linear",
|
||||
"openspace.setPropertyValueSingle('" .. moons[i] .. "', false)"
|
||||
)
|
||||
end
|
||||
]],
|
||||
Documentation = "Turn OFF minor moons and their trails for all planets in the solar system",
|
||||
GuiPath = "/Solar System/Minor Moons",
|
||||
IsLocal = true
|
||||
}
|
||||
|
||||
|
||||
asset.onInitialize(function()
|
||||
openspace.action.registerAction(MinorMoonsOn)
|
||||
openspace.action.registerAction(MinorMoonsOff)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function()
|
||||
openspace.action.removeAction(MinorMoonsOff)
|
||||
openspace.action.removeAction(MinorMoonsOn)
|
||||
end)
|
||||
|
||||
asset.export("MinorMoonsOn", MinorMoonsOn.Identifier)
|
||||
asset.export("MinorMoonsOff", MinorMoonsOff.Identifier)
|
||||
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Actions - Turn ON/OFF all Minor Moons",
|
||||
Version = "1.0",
|
||||
Description = "Asset providing actions to turn ON/OFF all minor moons and their trails",
|
||||
Author = "OpenSpace Team",
|
||||
URL = "http://openspaceproject.com",
|
||||
License = "MIT license"
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
local ToggleDwarfPlanetTrails = {
|
||||
Identifier = "os.ToggleDwarfPlanetTrails",
|
||||
Name = "Toggle dwarf planet trails",
|
||||
Command = [[
|
||||
local list = openspace.getProperty("{planetTrail_dwarf}.Renderable.Enabled")
|
||||
for _,v in pairs(list) do
|
||||
openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v))
|
||||
end
|
||||
]],
|
||||
Documentation = "Toggle on/off trails for all dwarf planets in the solar system",
|
||||
GuiPath = "/Trails",
|
||||
IsLocal = true
|
||||
}
|
||||
|
||||
|
||||
asset.onInitialize(function()
|
||||
openspace.action.registerAction(ToggleDwarfPlanetTrails)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function()
|
||||
openspace.action.removeAction(ToggleDwarfPlanetTrails)
|
||||
end)
|
||||
|
||||
asset.export("ToggleDwarfPlanetTrails", ToggleDwarfPlanetTrails.Identifier)
|
||||
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Actions - Toggle Dwarf Planet Trails",
|
||||
Version = "1.0",
|
||||
Description = "Asset providing actions to toggle all dwarf planet trails on and off",
|
||||
Author = "OpenSpace Team",
|
||||
URL = "http://openspaceproject.com",
|
||||
License = "MIT license"
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
local ToggleMinorMoonTrails = {
|
||||
Identifier = "os.ToggleMinorMoonTrails",
|
||||
Name = "Toggle minor moon trails",
|
||||
Command = [[
|
||||
local list = openspace.getProperty("{moonTrail_minor}.Renderable.Enabled")
|
||||
for _,v in pairs(list) do
|
||||
openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v))
|
||||
end
|
||||
]],
|
||||
Documentation = "Toggle on/off minor moon trails for all planets in the solar system",
|
||||
GuiPath = "/Trails",
|
||||
IsLocal = true
|
||||
}
|
||||
|
||||
|
||||
asset.onInitialize(function()
|
||||
openspace.action.registerAction(ToggleMinorMoonTrails)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function()
|
||||
openspace.action.removeAction(ToggleMinorMoonTrails)
|
||||
end)
|
||||
|
||||
asset.export("ToggleMinorMoonTrails", ToggleMinorMoonTrails.Identifier)
|
||||
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Actions - Toggle Minor Moon Trails",
|
||||
Version = "1.0",
|
||||
Description = "Asset providing actions to toggle all minor moon trails on and off",
|
||||
Author = "OpenSpace Team",
|
||||
URL = "http://openspaceproject.com",
|
||||
License = "MIT license"
|
||||
}
|
||||
@@ -1,67 +1,81 @@
|
||||
local fade_up_trails = {
|
||||
Identifier = "os.fade_up_trails",
|
||||
Name = "Show All Trails",
|
||||
local FadeUpTrails = {
|
||||
Identifier = "os.FadeUpTrails",
|
||||
Name = "Show all trails",
|
||||
Command = [[
|
||||
openspace.setPropertyValue("Scene.*Trail.Renderable.Fade", 1, 2);
|
||||
openspace.setPropertyValue("Scene.*trail.Renderable.Fade", 1, 2);
|
||||
local capList = openspace.getProperty("Scene.*Trail.Renderable.Fade")
|
||||
for _,v in ipairs(capList) do
|
||||
openspace.setPropertyValueSingle(v, 1, 2)
|
||||
end
|
||||
local list = openspace.getProperty("Scene.*trail.Renderable.Fade")
|
||||
for _,v in ipairs(list) do
|
||||
openspace.setPropertyValueSingle(v, 1, 2)
|
||||
end
|
||||
]],
|
||||
Documentation = "Fade up all enabled trails in the Scene",
|
||||
GuiPath = "/Trails",
|
||||
IsLocal = true
|
||||
}
|
||||
asset.export("fade_up_trails", fade_up_trails.Identifier)
|
||||
|
||||
local fade_down_trails = {
|
||||
Identifier = "os.fade_down_trails",
|
||||
Name = "Hide All Trails",
|
||||
local FadeDownTrails = {
|
||||
Identifier = "os.FadeDownTrails",
|
||||
Name = "Hide all trails",
|
||||
Command = [[
|
||||
openspace.setPropertyValue("Scene.*Trail.Renderable.Fade", 0, 2);
|
||||
openspace.setPropertyValue("Scene.*trail.Renderable.Fade", 0, 2);
|
||||
local capList = openspace.getProperty("Scene.*Trail.Renderable.Fade")
|
||||
for _,v in ipairs(capList) do
|
||||
openspace.setPropertyValueSingle(v, 0, 2)
|
||||
end
|
||||
local list = openspace.getProperty("Scene.*trail.Renderable.Fade")
|
||||
for _,v in ipairs(list) do
|
||||
openspace.setPropertyValueSingle(v, 0, 2)
|
||||
end
|
||||
]],
|
||||
Documentation = "Fade down all enabled trails in the Scene",
|
||||
GuiPath = "/Trails",
|
||||
IsLocal = true
|
||||
}
|
||||
asset.export("fade_down_trails", fade_down_trails.Identifier)
|
||||
|
||||
local toggle_trails = {
|
||||
Identifier = "os.toggle_trails",
|
||||
Name = "Toggle All Trails",
|
||||
local ToggleTrails = {
|
||||
Identifier = "os.ToggleTrails",
|
||||
Name = "Toggle all trails",
|
||||
Command = [[
|
||||
local capList = openspace.getProperty("*Trail.Renderable.Fade");
|
||||
local list = openspace.getProperty("*trail.Renderable.Fade");
|
||||
local capList = openspace.getProperty("*Trail.Renderable.Fade")
|
||||
local list = openspace.getProperty("*trail.Renderable.Fade")
|
||||
if (#capList == 0) and (#list == 0) then
|
||||
openspace.printWarning("No trails to toggle");
|
||||
openspace.printWarning("No trails to toggle")
|
||||
else
|
||||
local prop;
|
||||
local prop
|
||||
if #capList > 0 then
|
||||
prop = capList[1];
|
||||
prop = capList[1]
|
||||
else
|
||||
prop = list[1];
|
||||
prop = list[1]
|
||||
end
|
||||
local currentFade = openspace.getPropertyValue(prop);
|
||||
local newFade = 0;
|
||||
local currentFade = openspace.getPropertyValue(prop)
|
||||
local newFade = 0
|
||||
if currentFade < 1 then
|
||||
newFade = 1;
|
||||
newFade = 1
|
||||
end
|
||||
openspace.setPropertyValue("Scene.*Trail.Renderable.Fade", newFade, 2);
|
||||
openspace.setPropertyValue("Scene.*trail.Renderable.Fade", newFade, 2);
|
||||
openspace.setPropertyValue("Scene.*Trail.Renderable.Fade", newFade, 2)
|
||||
openspace.setPropertyValue("Scene.*trail.Renderable.Fade", newFade, 2)
|
||||
end
|
||||
]],
|
||||
Documentation = "Toggle fade for all trails in the Scene",
|
||||
GuiPath = "/Trails",
|
||||
IsLocal = true
|
||||
}
|
||||
asset.export("toggle_trails", toggle_trails.Identifier)
|
||||
|
||||
|
||||
asset.onInitialize(function()
|
||||
openspace.action.registerAction(fade_up_trails)
|
||||
openspace.action.registerAction(fade_down_trails)
|
||||
openspace.action.registerAction(toggle_trails)
|
||||
openspace.action.registerAction(FadeUpTrails)
|
||||
openspace.action.registerAction(FadeDownTrails)
|
||||
openspace.action.registerAction(ToggleTrails)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function()
|
||||
openspace.action.removeAction(toggle_trails)
|
||||
openspace.action.removeAction(fade_down_trails)
|
||||
openspace.action.removeAction(fade_up_trails)
|
||||
openspace.action.removeAction(ToggleTrails)
|
||||
openspace.action.removeAction(FadeDownTrails)
|
||||
openspace.action.removeAction(FadeUpTrails)
|
||||
end)
|
||||
|
||||
asset.export("FadeUpTrails", FadeUpTrails.Identifier)
|
||||
asset.export("FadeDownTrails", FadeDownTrails.Identifier)
|
||||
asset.export("ToggleTrails", ToggleTrails.Identifier)
|
||||
|
||||
@@ -1,24 +1,29 @@
|
||||
local toggle_trails = {
|
||||
Identifier = "os_default.toggle_trails",
|
||||
Name = "Toggle Planet and Moon Trails (Instant)",
|
||||
local ToggleTrailsInstant = {
|
||||
Identifier = "os.ToggleTrailsInstant",
|
||||
Name = "Toggle planet and moon trails (instant)",
|
||||
Command = [[
|
||||
local list = openspace.getProperty("{planetTrail_solarSystem}.Renderable.Enabled");
|
||||
for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end
|
||||
|
||||
local moonlist = openspace.getProperty("{moonTrail_solarSystem}.Renderable.Enabled");
|
||||
for _,v in pairs(moonlist) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end
|
||||
local list = openspace.getProperty("{planetTrail_solarSystem}.Renderable.Enabled")
|
||||
for _,v in pairs(list) do
|
||||
openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v))
|
||||
end
|
||||
|
||||
local moonlist = openspace.getProperty("{moonTrail_solarSystem}.Renderable.Enabled")
|
||||
for _,v in pairs(moonlist) do
|
||||
openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v))
|
||||
end
|
||||
]],
|
||||
Documentation = "Toggles the visibility of planet and moon trails",
|
||||
GuiPath = "/Solar System",
|
||||
IsLocal = false,
|
||||
}
|
||||
IsLocal = false
|
||||
}
|
||||
|
||||
|
||||
asset.onInitialize(function()
|
||||
openspace.action.registerAction(toggle_trails)
|
||||
openspace.action.registerAction(ToggleTrailsInstant)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function()
|
||||
openspace.action.removeAction(toggle_trails)
|
||||
openspace.action.removeAction(ToggleTrailsInstant)
|
||||
end)
|
||||
|
||||
asset.export(toggle_trails)
|
||||
asset.export("ToggleTrailsInstant", ToggleTrailsInstant.Identifier)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
local toggle_trail = {
|
||||
Identifier = "os.toggle_trail",
|
||||
Name = "Toggle Trail",
|
||||
local ToggleTrail = {
|
||||
Identifier = "os.ToggleTrail",
|
||||
Name = "Toggle trail",
|
||||
Command = [[
|
||||
local node
|
||||
if is_declared("args") then
|
||||
@@ -40,15 +40,14 @@ local toggle_trail = {
|
||||
]],
|
||||
Documentation = [[Toggles the visibility of the associated trail of a scene graph node.
|
||||
This action takes optional arguments to 1) determine which trail to hide (as the
|
||||
'Node') and 2) the transition direction (as 'After' and 'Before').]],
|
||||
'Node') and 2) the transition direction (as 'After' and 'Before')]],
|
||||
GuiPath = "/Trails",
|
||||
IsLocal = true
|
||||
}
|
||||
asset.export("toggle_trail", toggle_trail.Identifier)
|
||||
|
||||
local hide_trail = {
|
||||
Identifier = "os.hide_trail",
|
||||
Name = "Hide Trail",
|
||||
local HideTrail = {
|
||||
Identifier = "os.HideTrail",
|
||||
Name = "Hide trail",
|
||||
Command = [[
|
||||
local node
|
||||
if is_declared("args") then
|
||||
@@ -56,7 +55,7 @@ local hide_trail = {
|
||||
else
|
||||
node = openspace.navigation.getNavigationState().Anchor
|
||||
end
|
||||
|
||||
|
||||
if openspace.hasSceneGraphNode(node .. "Trail") then
|
||||
openspace.setPropertyValueSingle("Scene." .. node .. "Trail.Renderable.Fade", 0.0, 1.0)
|
||||
elseif openspace.hasSceneGraphNode(node .. "_trail") then
|
||||
@@ -69,11 +68,10 @@ local hide_trail = {
|
||||
GuiPath = "/Trails",
|
||||
IsLocal = true
|
||||
}
|
||||
asset.export("hide_trail", hide_trail.Identifier)
|
||||
|
||||
local show_trail = {
|
||||
Identifier = "os.show_trail",
|
||||
Name = "Show Trail",
|
||||
local ShowTrail = {
|
||||
Identifier = "os.ShowTrail",
|
||||
Name = "Show trail",
|
||||
Command = [[
|
||||
local node
|
||||
if is_declared("args") then
|
||||
@@ -81,7 +79,7 @@ local show_trail = {
|
||||
else
|
||||
node = openspace.navigation.getNavigationState().Anchor
|
||||
end
|
||||
|
||||
|
||||
if openspace.hasSceneGraphNode(node .. "Trail") then
|
||||
openspace.setPropertyValueSingle("Scene." .. node .. "Trail.Renderable.Fade", 1.0, 1.0)
|
||||
elseif openspace.hasSceneGraphNode(node .. "_trail") then
|
||||
@@ -94,25 +92,30 @@ local show_trail = {
|
||||
GuiPath = "/Trails",
|
||||
IsLocal = true
|
||||
}
|
||||
asset.export("show_trail", show_trail.Identifier)
|
||||
|
||||
|
||||
asset.onInitialize(function()
|
||||
openspace.action.registerAction(toggle_trail)
|
||||
openspace.action.registerAction(show_trail)
|
||||
openspace.action.registerAction(hide_trail)
|
||||
openspace.action.registerAction(ToggleTrail)
|
||||
openspace.action.registerAction(HideTrail)
|
||||
openspace.action.registerAction(ShowTrail)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function()
|
||||
openspace.action.removeAction(toggle_trail)
|
||||
openspace.action.removeAction(show_trail)
|
||||
openspace.action.removeAction(hide_trail)
|
||||
openspace.action.removeAction(ShowTrail)
|
||||
openspace.action.removeAction(HideTrail)
|
||||
openspace.action.removeAction(ToggleTrail)
|
||||
end)
|
||||
|
||||
asset.export("ToggleTrail", ToggleTrail.Identifier)
|
||||
asset.export("HideTrail", HideTrail.Identifier)
|
||||
asset.export("ShowTrail", ShowTrail.Identifier)
|
||||
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Actions - Toggle current Trails",
|
||||
Version = "1.0",
|
||||
Description = [[ Asset providing actions to toggle trails]],
|
||||
Description = "Asset providing actions to toggle trails",
|
||||
Author = "OpenSpace Team",
|
||||
URL = "http://openspaceproject.com",
|
||||
License = "MIT license"
|
||||
|
||||
@@ -1,67 +1,69 @@
|
||||
local fade_up_trails = {
|
||||
Identifier = "os.fade_up_trails_planets_moon",
|
||||
Name = "Show Planet and Moon Trails",
|
||||
local FadeUpTrails = {
|
||||
Identifier = "os.planetsmoons.FadeUpTrails",
|
||||
Name = "Show planet and moon trails",
|
||||
Command = [[
|
||||
openspace.setPropertyValue("{planetTrail_solarSystem}.Renderable.Fade", 1, 2);
|
||||
openspace.setPropertyValue("{moonTrail_solarSystem}.Renderable.Fade", 1, 2);
|
||||
openspace.setPropertyValue("{planetTrail_solarSystem}.Renderable.Fade", 1, 2)
|
||||
openspace.setPropertyValue("{moonTrail_solarSystem}.Renderable.Fade", 1, 2)
|
||||
]],
|
||||
Documentation = "Fade up all planet and moon trails in the Scene",
|
||||
GuiPath = "/Trails",
|
||||
IsLocal = true
|
||||
}
|
||||
asset.export("fade_up_trails", fade_up_trails.Identifier)
|
||||
|
||||
local fade_down_trails = {
|
||||
Identifier = "os.fade_down_trails_planets_moon",
|
||||
Name = "Hide Planet and Moon Trails",
|
||||
local FadeDownTrails = {
|
||||
Identifier = "os.planetsmoons.FadeDownTrails",
|
||||
Name = "Hide planet and moon trails",
|
||||
Command = [[
|
||||
openspace.setPropertyValue("{planetTrail_solarSystem}.Renderable.Fade", 0, 2);
|
||||
openspace.setPropertyValue("{moonTrail_solarSystem}.Renderable.Fade", 0, 2);
|
||||
openspace.setPropertyValue("{planetTrail_solarSystem}.Renderable.Fade", 0, 2)
|
||||
openspace.setPropertyValue("{moonTrail_solarSystem}.Renderable.Fade", 0, 2)
|
||||
]],
|
||||
Documentation = "Fade down all planet and moon trails in the Scene",
|
||||
GuiPath = "/Trails",
|
||||
IsLocal = true
|
||||
}
|
||||
asset.export("fade_down_trails", fade_down_trails.Identifier)
|
||||
|
||||
local toggle_trails = {
|
||||
Identifier = "os.toggle_trails_planets_moon",
|
||||
Name = "Toggle Planet and Moon Trails",
|
||||
local ToggleTrails = {
|
||||
Identifier = "os.planetsmoons.ToggleTrails",
|
||||
Name = "Toggle planet and moon trails",
|
||||
Command = [[
|
||||
local capList = openspace.getProperty("{planetTrail_solarSystem}.Renderable.Fade");
|
||||
local list = openspace.getProperty("{moonTrail_solarSystem}.Renderable.Fade");
|
||||
local capList = openspace.getProperty("{planetTrail_solarSystem}.Renderable.Fade")
|
||||
local list = openspace.getProperty("{moonTrail_solarSystem}.Renderable.Fade")
|
||||
if (#capList == 0) and (#list == 0) then
|
||||
openspace.printWarning("No trails to toggle");
|
||||
openspace.printWarning("No trails to toggle")
|
||||
else
|
||||
local prop;
|
||||
local prop
|
||||
if (#capList > 0) then
|
||||
prop = capList[1];
|
||||
prop = capList[1]
|
||||
else
|
||||
prop = list[1];
|
||||
prop = list[1]
|
||||
end
|
||||
local currentFade = openspace.getPropertyValue(prop);
|
||||
local newFade = 0;
|
||||
local currentFade = openspace.getPropertyValue(prop)
|
||||
local newFade = 0
|
||||
if currentFade < 1 then
|
||||
newFade = 1;
|
||||
newFade = 1
|
||||
end
|
||||
openspace.setPropertyValue("{planetTrail_solarSystem}.Renderable.Fade", newFade, 2);
|
||||
openspace.setPropertyValue("{moonTrail_solarSystem}.Renderable.Fade", newFade, 2);
|
||||
openspace.setPropertyValue("{planetTrail_solarSystem}.Renderable.Fade", newFade, 2)
|
||||
openspace.setPropertyValue("{moonTrail_solarSystem}.Renderable.Fade", newFade, 2)
|
||||
end
|
||||
]],
|
||||
Documentation = "Toggle fade for planet and moon trails in the Scene",
|
||||
GuiPath = "/Trails",
|
||||
IsLocal = true
|
||||
}
|
||||
asset.export("toggle_trails", toggle_trails)
|
||||
|
||||
|
||||
asset.onInitialize(function()
|
||||
openspace.action.registerAction(fade_up_trails)
|
||||
openspace.action.registerAction(fade_down_trails)
|
||||
openspace.action.registerAction(toggle_trails)
|
||||
openspace.action.registerAction(FadeUpTrails)
|
||||
openspace.action.registerAction(FadeDownTrails)
|
||||
openspace.action.registerAction(ToggleTrails)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function()
|
||||
openspace.action.removeAction(toggle_trails)
|
||||
openspace.action.removeAction(fade_down_trails)
|
||||
openspace.action.removeAction(fade_up_trails)
|
||||
openspace.action.removeAction(ToggleTrails)
|
||||
openspace.action.removeAction(FadeDownTrails)
|
||||
openspace.action.removeAction(FadeUpTrails)
|
||||
end)
|
||||
|
||||
asset.export("FadeUpTrails", FadeUpTrails.Identifier)
|
||||
asset.export("FadeDownTrails", FadeDownTrails.Identifier)
|
||||
asset.export("ToggleTrails", ToggleTrails.Identifier)
|
||||
|
||||
@@ -1,163 +1,161 @@
|
||||
local enable_trail_fading = {
|
||||
Identifier = "os.enable_trail_fading",
|
||||
Name = "Enable Trail Fading",
|
||||
Command = [[
|
||||
openspace.setPropertyValue("Scene.*Trail.Renderable.Appearance.EnableFade", true);
|
||||
openspace.setPropertyValue("Scene.*trail.Renderable.Appearance.EnableFade", true);
|
||||
]],
|
||||
Documentation = "Set orbits to fade out towards the end",
|
||||
GuiPath = "/Trails/Appearance",
|
||||
IsLocal = true
|
||||
}
|
||||
asset.export("enable_trail_fading", enable_trail_fading.Identifier)
|
||||
|
||||
local disable_trail_fading = {
|
||||
Identifier = "os.disable_trail_fading",
|
||||
Name = "Disable Trail Fading",
|
||||
Command = [[
|
||||
openspace.setPropertyValue("Scene.*Trail.Renderable.Appearance.EnableFade", false);
|
||||
openspace.setPropertyValue("Scene.*trail.Renderable.Appearance.EnableFade", false);
|
||||
]],
|
||||
Documentation = "Sets trails not to fade out torwards end",
|
||||
GuiPath = "/Trails/Appearance",
|
||||
IsLocal = true
|
||||
}
|
||||
asset.export("disable_trail_fading", disable_trail_fading.Identifier)
|
||||
|
||||
local toggle_trail_fading = {
|
||||
Identifier = "os.toggle_trail_fading",
|
||||
Name = "Toggle Trail Fading",
|
||||
Command = [[
|
||||
local capList = openspace.getProperty("*Trail.Renderable.Appearance.EnableFade")
|
||||
local list = openspace.getProperty("*trail.Renderable.Appearance.EnableFade")
|
||||
if (#capList == 0) and (#list == 0) then
|
||||
openspace.printWarning("No trails to toggle");
|
||||
else
|
||||
local prop;
|
||||
if #capList > 0 then
|
||||
prop = capList[1];
|
||||
else
|
||||
prop = list[1];
|
||||
end
|
||||
local currentFade = openspace.getPropertyValue(prop);
|
||||
local newFade = not currentFade;
|
||||
openspace.setPropertyValue("Scene.*Trail.Renderable.Appearance.EnableFade", newFade);
|
||||
openspace.setPropertyValue("Scene.*trail.Renderable.Appearance.EnableFade", newFade);
|
||||
end
|
||||
]],
|
||||
Documentation = "Toggle trails to fade out towards the end for all trails in the Scene",
|
||||
GuiPath = "/Trails/Appearance",
|
||||
IsLocal = true
|
||||
}
|
||||
asset.export("toggle_trail_fading", toggle_trail_fading.Identifier)
|
||||
|
||||
local function getHightlightCommand(identifierString, value)
|
||||
local function highlightCommand(identifierString, value)
|
||||
local easeFunction = "QuinticEaseOut"
|
||||
if value > 1 then
|
||||
easeFunction = "QuinticEaseIn"
|
||||
end
|
||||
local command = 'openspace.setPropertyValue("'
|
||||
command = command .. identifierString .. '.Renderable.Appearance.Fade", '
|
||||
command = command .. value .. ', 2, "' .. easeFunction .. '")'
|
||||
return command;
|
||||
local command = [[openspace.setPropertyValue("]]
|
||||
command = command .. identifierString .. [[.Renderable.Appearance.Fade", ]]
|
||||
command = command .. value .. [[, 2, "]] .. easeFunction .. [[")]]
|
||||
return command
|
||||
end
|
||||
|
||||
local function getHighlightAction(identifierString, value, nameString)
|
||||
local actionString = 'Dehighlight'
|
||||
local function highlightAction(identifierString, value, nameString)
|
||||
local actionString = "Dehighlight"
|
||||
if value > 1 then
|
||||
actionString = 'Highlight'
|
||||
actionString = "Highlight"
|
||||
end
|
||||
local action = {
|
||||
return {
|
||||
Identifier = "os." .. actionString .. identifierString .. "_trail",
|
||||
Name = actionString .. " " .. nameString .. " Trail",
|
||||
Command = getHightlightCommand(identifierString, value),
|
||||
Name = actionString .. " " .. nameString .. " trail",
|
||||
Command = highlightCommand(identifierString, value),
|
||||
Documentation = "Animates the trail fade of " .. nameString .. "'s Trail",
|
||||
GuiPath = "/Trails/Appearance",
|
||||
IsLocal = true
|
||||
}
|
||||
return action
|
||||
end
|
||||
|
||||
local function getToggleHighlightAction(identifierString, value, nameString)
|
||||
local action = {
|
||||
local function toggleHighlightAction(identifierString, value, nameString)
|
||||
return {
|
||||
Identifier = "os.toggle_" .. identifierString .. "_trail_highlight",
|
||||
Name = "Toggle " .. nameString .. " Trail Highlight",
|
||||
Name = "Toggle " .. nameString .. " trail highlight",
|
||||
Command = [[
|
||||
local list = openspace.getProperty("]] .. identifierString .. [[.Renderable.Appearance.Fade");
|
||||
local list = openspace.getProperty("]] .. identifierString .. [[.Renderable.Appearance.Fade")
|
||||
if #list == 0 then
|
||||
openspace.printWarning("No planets to resize");
|
||||
openspace.printWarning("No planets to resize")
|
||||
else
|
||||
local prop = list[1];
|
||||
local prop = list[1]
|
||||
local fadeValue = openspace.getPropertyValue(prop)
|
||||
if fadeValue > 1 then
|
||||
]] .. getHightlightCommand(identifierString, 1, nameString) .. "\n" .. [[
|
||||
]] .. highlightCommand(identifierString, 1, nameString) .. "\n" .. [[
|
||||
else
|
||||
]] .. getHightlightCommand(identifierString, value, nameString) .. "\n" .. [[
|
||||
]] .. highlightCommand(identifierString, value, nameString) .. "\n" .. [[
|
||||
end
|
||||
end]],
|
||||
Documentation = "Animates the trail fade of " .. nameString .. "'s trail",
|
||||
GuiPath = "/Trails/Appearance",
|
||||
IsLocal = true
|
||||
}
|
||||
return action
|
||||
end
|
||||
|
||||
local earthTrailIdentifer = "Scene.EarthTrail"
|
||||
|
||||
local highlight_earth_trail = getHighlightAction(earthTrailIdentifer, 10, "Earth")
|
||||
asset.export("highlight_earth_trail", highlight_earth_trail.Identifier)
|
||||
local dehighlight_earth_trail = getHighlightAction(earthTrailIdentifer, 1, "Earth")
|
||||
asset.export("dehighlight_earth_trail", dehighlight_earth_trail.Identifier)
|
||||
local toggle_earth_trail_highlight = getToggleHighlightAction(earthTrailIdentifer, 10, "Earth")
|
||||
asset.export("toggle_earth_trail_highlight", toggle_earth_trail_highlight.Identifier)
|
||||
local EnableTrailFading = {
|
||||
Identifier = "os.EnableTrailFading",
|
||||
Name = "Enable trail fading",
|
||||
Command = [[
|
||||
openspace.setPropertyValue("Scene.*Trail.Renderable.Appearance.EnableFade", true)
|
||||
openspace.setPropertyValue("Scene.*trail.Renderable.Appearance.EnableFade", true)
|
||||
]],
|
||||
Documentation = "Set orbits to fade out towards the end",
|
||||
GuiPath = "/Trails/Appearance",
|
||||
IsLocal = true
|
||||
}
|
||||
|
||||
local highlight_inner_trails = getHighlightAction("{planetTrail_terrestrial}", 50, "Inner Planet")
|
||||
asset.export("highlight_inner_trails", highlight_inner_trails.Identifier)
|
||||
local dehighlight_inner_trails = getHighlightAction("{planetTrail_terrestrial}", 1, "Inner Planet")
|
||||
asset.export("dehighlight_inner_trails", dehighlight_inner_trails.Identifier)
|
||||
local toggle_inner_trail_highlight = getToggleHighlightAction("{planetTrail_terrestrial}", 50, "Inner Planet")
|
||||
asset.export("toggle_inner_trail_highlight", toggle_inner_trail_highlight.Identifier)
|
||||
local DisableTrailFading = {
|
||||
Identifier = "os.DisableTrailFading",
|
||||
Name = "Disable trail fading",
|
||||
Command = [[
|
||||
openspace.setPropertyValue("Scene.*Trail.Renderable.Appearance.EnableFade", false)
|
||||
openspace.setPropertyValue("Scene.*trail.Renderable.Appearance.EnableFade", false)
|
||||
]],
|
||||
Documentation = "Sets trails not to fade out torwards end",
|
||||
GuiPath = "/Trails/Appearance",
|
||||
IsLocal = true
|
||||
}
|
||||
|
||||
local highlight_outter_trails = getHighlightAction("{planetTrail_giants}", 100, "Outter Planet")
|
||||
asset.export("highlight_outter_trails", highlight_outter_trails.Identifier)
|
||||
local dehighlight_outter_trails = getHighlightAction("{planetTrail_giants}", 1, "Outter Planet")
|
||||
asset.export("dehighlight_outter_trails", dehighlight_outter_trails.Identifier)
|
||||
local toggle_outter_trail_highlight = getToggleHighlightAction("{planetTrail_giants}", 100, "Outter Planet")
|
||||
asset.export("toggle_outter_trail_highlight", toggle_outter_trail_highlight.Identifier)
|
||||
local ToggleTrailFading = {
|
||||
Identifier = "os.ToggleTrailFading",
|
||||
Name = "Toggle trail fading",
|
||||
Command = [[
|
||||
local capList = openspace.getProperty("*Trail.Renderable.Appearance.EnableFade")
|
||||
local list = openspace.getProperty("*trail.Renderable.Appearance.EnableFade")
|
||||
if (#capList == 0) and (#list == 0) then
|
||||
openspace.printWarning("No trails to toggle")
|
||||
else
|
||||
local prop
|
||||
if #capList > 0 then
|
||||
prop = capList[1]
|
||||
else
|
||||
prop = list[1]
|
||||
end
|
||||
local currentFade = openspace.getPropertyValue(prop)
|
||||
local newFade = not currentFade
|
||||
openspace.setPropertyValue("Scene.*Trail.Renderable.Appearance.EnableFade", newFade)
|
||||
openspace.setPropertyValue("Scene.*trail.Renderable.Appearance.EnableFade", newFade)
|
||||
end
|
||||
]],
|
||||
Documentation = "Toggle trails to fade out towards the end for all trails in the Scene",
|
||||
GuiPath = "/Trails/Appearance",
|
||||
IsLocal = true
|
||||
}
|
||||
|
||||
local HighlightEarthTrail = highlightAction("Scene.EarthTrail", 10, "Earth")
|
||||
local DehighlightEarthTrail = highlightAction("Scene.EarthTrail", 1, "Earth")
|
||||
local ToggleEarthTrailHighlight = toggleHighlightAction("Scene.EarthTrail", 10, "Earth")
|
||||
|
||||
local HighlightInnerTrails = highlightAction("{planetTrail_terrestrial}", 50, "Inner Planet")
|
||||
local DehighlightInnerTrails = highlightAction("{planetTrail_terrestrial}", 1, "Inner Planet")
|
||||
local ToggleInnerTrailHighlight = toggleHighlightAction("{planetTrail_terrestrial}", 50, "Inner Planet")
|
||||
|
||||
local HighlightOuterTrails = highlightAction("{planetTrail_giants}", 100, "Outer Planet")
|
||||
local DehighlightOuterTrails = highlightAction("{planetTrail_giants}", 1, "Outer Planet")
|
||||
local ToggleOuterTrailHighlight = toggleHighlightAction("{planetTrail_giants}", 100, "Outer Planet")
|
||||
|
||||
|
||||
asset.onInitialize(function()
|
||||
openspace.action.registerAction(enable_trail_fading)
|
||||
openspace.action.registerAction(disable_trail_fading)
|
||||
openspace.action.registerAction(toggle_trail_fading)
|
||||
openspace.action.registerAction(EnableTrailFading)
|
||||
openspace.action.registerAction(DisableTrailFading)
|
||||
openspace.action.registerAction(ToggleTrailFading)
|
||||
|
||||
openspace.action.registerAction(highlight_earth_trail)
|
||||
openspace.action.registerAction(dehighlight_earth_trail)
|
||||
openspace.action.registerAction(toggle_earth_trail_highlight)
|
||||
openspace.action.registerAction(HighlightEarthTrail)
|
||||
openspace.action.registerAction(DehighlightEarthTrail)
|
||||
openspace.action.registerAction(ToggleEarthTrailHighlight)
|
||||
|
||||
openspace.action.registerAction(highlight_inner_trails)
|
||||
openspace.action.registerAction(dehighlight_inner_trails)
|
||||
openspace.action.registerAction(toggle_inner_trail_highlight)
|
||||
openspace.action.registerAction(HighlightInnerTrails)
|
||||
openspace.action.registerAction(DehighlightInnerTrails)
|
||||
openspace.action.registerAction(ToggleInnerTrailHighlight)
|
||||
|
||||
openspace.action.registerAction(highlight_outter_trails)
|
||||
openspace.action.registerAction(dehighlight_outter_trails)
|
||||
openspace.action.registerAction(toggle_outter_trail_highlight)
|
||||
openspace.action.registerAction(HighlightOuterTrails)
|
||||
openspace.action.registerAction(DehighlightOuterTrails)
|
||||
openspace.action.registerAction(ToggleOuterTrailHighlight)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function()
|
||||
openspace.action.removeAction(toggle_outter_trail_highlight)
|
||||
openspace.action.removeAction(dehighlight_outter_trails)
|
||||
openspace.action.removeAction(highlight_outter_trails)
|
||||
openspace.action.removeAction(ToggleOuterTrailHighlight)
|
||||
openspace.action.removeAction(DehighlightOuterTrails)
|
||||
openspace.action.removeAction(HighlightOuterTrails)
|
||||
|
||||
openspace.action.removeAction(highlight_inner_trails)
|
||||
openspace.action.removeAction(dehighlight_inner_trails)
|
||||
openspace.action.removeAction(toggle_inner_trail_highlight)
|
||||
openspace.action.removeAction(ToggleInnerTrailHighlight)
|
||||
openspace.action.removeAction(DehighlightInnerTrails)
|
||||
openspace.action.removeAction(HighlightInnerTrails)
|
||||
|
||||
openspace.action.removeAction(highlight_earth_trail)
|
||||
openspace.action.removeAction(dehighlight_earth_trail)
|
||||
openspace.action.removeAction(toggle_earth_trail_highlight)
|
||||
openspace.action.removeAction(ToggleEarthTrailHighlight)
|
||||
openspace.action.removeAction(DehighlightEarthTrail)
|
||||
openspace.action.removeAction(HighlightEarthTrail)
|
||||
|
||||
openspace.action.removeAction(toggle_trail_fading)
|
||||
openspace.action.removeAction(disable_trail_fading)
|
||||
openspace.action.removeAction(enable_trail_fading)
|
||||
openspace.action.removeAction(ToggleTrailFading)
|
||||
openspace.action.removeAction(DisableTrailFading)
|
||||
openspace.action.removeAction(EnableTrailFading)
|
||||
end)
|
||||
|
||||
asset.export("EnableTrailFading", EnableTrailFading.Identifier)
|
||||
asset.export("DisableTrailFading", DisableTrailFading.Identifier)
|
||||
asset.export("ToggleTrailFading", ToggleTrailFading.Identifier)
|
||||
asset.export("HighlightEarthTrail", HighlightEarthTrail.Identifier)
|
||||
asset.export("DehighlightEarthTrail", DehighlightEarthTrail.Identifier)
|
||||
asset.export("ToggleEarthTrailHighlight", ToggleEarthTrailHighlight.Identifier)
|
||||
asset.export("HighlightInnerTrails", HighlightInnerTrails.Identifier)
|
||||
asset.export("DehighlightInnerTrails", DehighlightInnerTrails.Identifier)
|
||||
asset.export("ToggleInnerTrailHighlight", ToggleInnerTrailHighlight.Identifier)
|
||||
asset.export("HighlightOuterTrails", HighlightOuterTrails.Identifier)
|
||||
asset.export("DehighlightOuterTrails", DehighlightOuterTrails.Identifier)
|
||||
asset.export("ToggleOuterTrailHighlight", ToggleOuterTrailHighlight.Identifier)
|
||||
|
||||
@@ -4,10 +4,6 @@
|
||||
|
||||
asset.require("./base_blank")
|
||||
|
||||
-- Modules and component settings
|
||||
asset.require("modules/exoplanets/exoplanets")
|
||||
asset.require("modules/skybrowser/skybrowser")
|
||||
|
||||
-- Specifying which other assets should be loaded in this scene
|
||||
asset.require("scene/solarsystem/sun/sun")
|
||||
asset.require("scene/solarsystem/sun/glare")
|
||||
@@ -34,11 +30,11 @@ asset.require("scene/digitaluniverse/constellations")
|
||||
asset.require("scene/digitaluniverse/deepsky")
|
||||
asset.require("scene/digitaluniverse/dwarfs")
|
||||
asset.require("scene/digitaluniverse/exoplanets")
|
||||
asset.require("scene/digitaluniverse/exoplanets_candidates")
|
||||
asset.require("scene/digitaluniverse/globularclusters")
|
||||
asset.require("scene/digitaluniverse/grids")
|
||||
asset.require("scene/digitaluniverse/groups")
|
||||
asset.require("scene/digitaluniverse/h2regions")
|
||||
asset.require("scene/digitaluniverse/kepler")
|
||||
asset.require("scene/digitaluniverse/localdwarfs")
|
||||
asset.require("scene/digitaluniverse/milkyway")
|
||||
asset.require("scene/digitaluniverse/milkyway_arm_labels")
|
||||
@@ -57,57 +53,16 @@ asset.require("scene/digitaluniverse/superclusters")
|
||||
asset.require("scene/digitaluniverse/supernovaremnants")
|
||||
asset.require("scene/digitaluniverse/tully")
|
||||
asset.require("scene/digitaluniverse/voids")
|
||||
asset.require("nightsky/nightsky")
|
||||
|
||||
asset.require("customization/globebrowsing")
|
||||
asset.require("util/default_actions")
|
||||
asset.require("actions/default_actions")
|
||||
|
||||
local toggle_trails = {
|
||||
Identifier = "os_default.toggle_trails",
|
||||
Name = "Toggle Trails",
|
||||
Command = [[
|
||||
local list = openspace.getProperty("{planetTrail_solarSystem}.Renderable.Enabled");
|
||||
for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end
|
||||
|
||||
local moonlist = openspace.getProperty("{moonTrail_solarSystem}.Renderable.Enabled");
|
||||
for _,v in pairs(moonlist) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end
|
||||
]],
|
||||
Documentation = "Toggles the visibility of planet and moon trails",
|
||||
GuiPath = "/Rendering",
|
||||
IsLocal = false,
|
||||
|
||||
Key = "h"
|
||||
}
|
||||
|
||||
local toggle_planet_labels = {
|
||||
Identifier = "os_default.toggle_planet_labels",
|
||||
Name = "Toggle planet labels",
|
||||
Command = [[
|
||||
local list = openspace.getProperty("{solarsystem_labels}.Renderable.Enabled");
|
||||
for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end
|
||||
]],
|
||||
Documentation = "Turns on visibility for all solar system labels",
|
||||
GuiPath = "/Rendering",
|
||||
IsLocal = false,
|
||||
|
||||
Key = "l"
|
||||
}
|
||||
|
||||
local trailAction = asset.require("actions/trails/toggle_trails_planets_moons").toggle_trails
|
||||
|
||||
asset.onInitialize(function ()
|
||||
openspace.bindKey("h", trailAction.Identifier)
|
||||
|
||||
openspace.action.registerAction(toggle_planet_labels)
|
||||
openspace.bindKey(toggle_planet_labels.Key, toggle_planet_labels.Identifier)
|
||||
asset.require("modules/exoplanets/exoplanets")
|
||||
asset.require("modules/skybrowser/skybrowser")
|
||||
|
||||
asset.onInitialize(function()
|
||||
openspace.globebrowsing.loadWMSServersFromFile(
|
||||
openspace.absPath("${DATA}/globebrowsing_servers.lua")
|
||||
)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
openspace.clearKey(toggle_trails.Key)
|
||||
|
||||
openspace.action.removeAction(toggle_planet_labels)
|
||||
openspace.clearKey(toggle_planet_labels.Key)
|
||||
end)
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
-- This is a blank scene that that just sets up the default menus/dasboard/keys, etc.
|
||||
|
||||
local propertyHelper = asset.require("util/property_helper")
|
||||
|
||||
-- Specifying which other assets should be loaded in this scene
|
||||
asset.require("spice/base")
|
||||
|
||||
asset.require("dashboard/default_dashboard")
|
||||
-- Load default key bindings applicable to most scenes
|
||||
asset.require("util/default_keybindings")
|
||||
asset.require("./default_keybindings")
|
||||
|
||||
-- Load web gui
|
||||
local webGui = asset.require("util/webgui")
|
||||
@@ -18,7 +16,11 @@ asset.require("util/dpiscaling")
|
||||
-- Load the images required for the launcher to show up
|
||||
asset.require("util/launcher_images")
|
||||
|
||||
asset.onInitialize(function ()
|
||||
-- Modules and component settings
|
||||
asset.require("modules/touch/default_settings")
|
||||
|
||||
|
||||
asset.onInitialize(function()
|
||||
webGui.setCefRoute("onscreen")
|
||||
openspace.setDefaultGuiSorting()
|
||||
openspace.setPropertyValueSingle("RenderEngine.VerticalLogOffset", 0.100000)
|
||||
|
||||
35
data/assets/base_keybindings.asset
Normal file
35
data/assets/base_keybindings.asset
Normal file
@@ -0,0 +1,35 @@
|
||||
asset.require("./base")
|
||||
local trailAction = asset.require("actions/trails/toggle_trails_planets_moons").ToggleTrails
|
||||
|
||||
|
||||
|
||||
local TogglePlanetLabels = {
|
||||
Identifier = "os_default.TogglePlanetLabels",
|
||||
Name = "Toggle planet labels",
|
||||
Command = [[
|
||||
local list = openspace.getProperty("{solarsystem_labels}.Renderable.Enabled")
|
||||
for _,v in pairs(list) do
|
||||
openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v))
|
||||
end
|
||||
]],
|
||||
Documentation = "Turns on visibility for all solar system labels",
|
||||
GuiPath = "/Solar System",
|
||||
IsLocal = false,
|
||||
Key = "l"
|
||||
}
|
||||
|
||||
asset.onInitialize(function()
|
||||
openspace.action.registerAction(TogglePlanetLabels)
|
||||
openspace.bindKey(TogglePlanetLabels.Key, TogglePlanetLabels.Identifier)
|
||||
|
||||
openspace.bindKey("h", trailAction)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function()
|
||||
openspace.clearKey("h")
|
||||
|
||||
openspace.action.removeAction(TogglePlanetLabels)
|
||||
openspace.clearKey(TogglePlanetLabels.Key)
|
||||
end)
|
||||
|
||||
asset.export("TogglePlanetLabels", TogglePlanetLabels.Identifier)
|
||||
@@ -23,7 +23,7 @@ local vrt_folders = {
|
||||
-- if areas overlap (for example CTX and HiRISE) and CTX is specified *after* HiRISE,
|
||||
-- CTX will stomp over the HiRISE.
|
||||
|
||||
-- tl;dr: Specify CTX folders first, then HiRISE
|
||||
-- tl;dr: Specify CTX folders first, then HiRISE
|
||||
-- example: "C:/OpenSpace/GlobeBrowsingData/Mars/CTX"
|
||||
|
||||
-- We recommend using this folder for CTX
|
||||
@@ -88,7 +88,7 @@ else
|
||||
vrt_folders["Earth"] = nil
|
||||
end
|
||||
|
||||
asset.onInitialize(function ()
|
||||
asset.onInitialize(function()
|
||||
-- Add local patches described at the top of this file
|
||||
for obj, list in pairs(vrt_folders) do
|
||||
for _, dir in pairs(list) do
|
||||
@@ -107,7 +107,7 @@ end)
|
||||
asset.meta = {
|
||||
Name = "Customization - GlobeBrowsing",
|
||||
Version = "1.0",
|
||||
Description = [[ This asset adds planetary images that can be downloaded separately
|
||||
Description = [[This asset adds planetary images that can be downloaded separately
|
||||
and placed in the OpenSpaceData folder]],
|
||||
Author = "OpenSpace Team",
|
||||
URL = "http://openspaceproject.com",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user