mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-01-06 03:29:44 -06:00
merging master, conflicts
This commit is contained in:
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -26,3 +26,6 @@
|
||||
[submodule "apps/OpenSpace-MinVR/ext/glfw"]
|
||||
path = apps/OpenSpace-MinVR/ext/glfw
|
||||
url = https://github.com/opensgct/glfw
|
||||
[submodule "ext/date"]
|
||||
path = ext/date
|
||||
url = https://github.com/HowardHinnant/date
|
||||
|
||||
@@ -27,10 +27,9 @@ cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
|
||||
project(OpenSpace)
|
||||
|
||||
set(OPENSPACE_VERSION_MAJOR 0)
|
||||
set(OPENSPACE_VERSION_MINOR 15)
|
||||
set(OPENSPACE_VERSION_PATCH 2)
|
||||
set(OPENSPACE_VERSION_STRING "Beta-7")
|
||||
|
||||
set(OPENSPACE_VERSION_MINOR 16)
|
||||
set(OPENSPACE_VERSION_PATCH 0)
|
||||
set(OPENSPACE_VERSION_STRING "Beta-8 RC1")
|
||||
|
||||
set(OPENSPACE_BASE_DIR "${PROJECT_SOURCE_DIR}")
|
||||
set(OPENSPACE_CMAKE_EXT_DIR "${OPENSPACE_BASE_DIR}/support/cmake")
|
||||
@@ -134,6 +133,11 @@ if (MSVC)
|
||||
set(GHOUL_OPTIMIZATION_ENABLE_OTHER_OPTIMIZATIONS ${OPENSPACE_OPTIMIZATION_ENABLE_OTHER_OPTIMIZATIONS} CACHE BOOL "" FORCE)
|
||||
endif ()
|
||||
|
||||
if (UNIX AND 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")
|
||||
endif ()
|
||||
|
||||
include(src/CMakeLists.txt)
|
||||
|
||||
##########################################################################################
|
||||
@@ -148,14 +152,14 @@ if (APPLE)
|
||||
find_library(COCOA_LIBRARY Carbon)
|
||||
find_library(APP_SERVICES_LIBRARY ApplicationServices)
|
||||
mark_as_advanced(CARBON_LIBRARY COCOA_LIBRARY APP_SERVICES_LIBRARY)
|
||||
target_link_libraries(openspace-core ${CARBON_LIBRARY} ${COREFOUNDATION_LIBRARY}
|
||||
target_link_libraries(openspace-core PUBLIC ${CARBON_LIBRARY} ${COREFOUNDATION_LIBRARY}
|
||||
${COCOA_LIBRARY} ${APP_SERVICES_LIBRARY})
|
||||
end_dependency()
|
||||
endif ()
|
||||
|
||||
# Ghoul
|
||||
add_subdirectory(${OPENSPACE_EXT_DIR}/ghoul)
|
||||
target_link_libraries(openspace-core Ghoul)
|
||||
target_link_libraries(openspace-core PUBLIC Ghoul)
|
||||
set_openspace_compile_settings(Ghoul)
|
||||
set_folder_location(Lua "External")
|
||||
set_folder_location(lz4 "External")
|
||||
@@ -165,7 +169,7 @@ link_directories("${GHOUL_LIBRARY_DIRS}")
|
||||
# Spice
|
||||
begin_dependency("Spice")
|
||||
add_subdirectory(${OPENSPACE_EXT_DIR}/spice)
|
||||
target_link_libraries(openspace-core Spice)
|
||||
target_link_libraries(openspace-core PUBLIC Spice)
|
||||
set_folder_location(Spice "External")
|
||||
end_dependency()
|
||||
|
||||
@@ -174,13 +178,13 @@ begin_dependency("CURL")
|
||||
if (WIN32)
|
||||
set(CURL_ROOT_DIR "${OPENSPACE_EXT_DIR}/curl")
|
||||
target_include_directories(openspace-core SYSTEM PUBLIC ${CURL_ROOT_DIR}/include)
|
||||
target_link_libraries(openspace-core ${CURL_ROOT_DIR}/lib/libcurl.lib)
|
||||
target_link_libraries(openspace-core PUBLIC ${CURL_ROOT_DIR}/lib/libcurl.lib)
|
||||
target_compile_definitions(openspace-core PUBLIC "OPENSPACE_CURL_ENABLED" "CURL_STATICLIB")
|
||||
else ()
|
||||
find_package(CURL)
|
||||
if (CURL_FOUND)
|
||||
target_include_directories(openspace-core SYSTEM PUBLIC ${CURL_INCLUDE_DIRS})
|
||||
target_link_libraries(openspace-core ${CURL_LIBRARIES})
|
||||
target_link_libraries(openspace-core PUBLIC ${CURL_LIBRARIES})
|
||||
target_compile_definitions(openspace-core PUBLIC "OPENSPACE_CURL_ENABLED")
|
||||
endif ()
|
||||
endif ()
|
||||
@@ -202,25 +206,6 @@ if (APPLE)
|
||||
endif ()
|
||||
|
||||
if (MSVC)
|
||||
option(OPENSPACE_ENABLE_VLD "Enable the Visual Leak Detector" OFF)
|
||||
if (OPENSPACE_ENABLE_VLD)
|
||||
begin_dependency("Visual Leak Detector")
|
||||
target_compile_definitions(openspace-core PUBLIC "OPENSPACE_ENABLE_VLD")
|
||||
target_link_libraries(openspace-core ${OPENSPACE_EXT_DIR}/vld/lib/vld.lib)
|
||||
target_include_directories(openspace-core PUBLIC ${OPENSPACE_EXT_DIR}/vld)
|
||||
end_dependency()
|
||||
endif ()
|
||||
|
||||
option(OPENSPACE_VTUNE_ENABLED "Include VTune support" OFF)
|
||||
set(OPENSPACE_VTUNE_PATH "C:/Program Files (x86)/IntelSWTools/VTune Amplifier 2019" CACHE STRING "Path to VTune installation")
|
||||
if (OPENSPACE_VTUNE_ENABLED)
|
||||
begin_dependency("Intel VTune")
|
||||
target_compile_definitions(openspace-core PUBLIC "OPENSPACE_HAS_VTUNE")
|
||||
target_include_directories(openspace-core PUBLIC "${OPENSPACE_VTUNE_PATH}/include")
|
||||
target_link_libraries(openspace-core "${OPENSPACE_VTUNE_PATH}/lib64/libittnotify.lib")
|
||||
end_dependency()
|
||||
endif ()
|
||||
|
||||
option(OPENSPACE_NVTOOLS_ENABLED "Include support for Nvidia Tools Extensions" OFF)
|
||||
set(OPENSPACE_NVTOOLS_PATH "C:/Program Files/NVIDIA Corporation/NvToolsExt")
|
||||
if (OPENSPACE_NVTOOLS_ENABLED)
|
||||
|
||||
123
Jenkinsfile
vendored
123
Jenkinsfile
vendored
@@ -67,7 +67,7 @@ def moduleCMakeFlags() {
|
||||
|
||||
def flags = '';
|
||||
for (module in modules) {
|
||||
flags += "-D OPENSPACE_MODULE_${module.toUpperCase()}=ON "
|
||||
flags += "-DOPENSPACE_MODULE_${module.toUpperCase()}=ON "
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
@@ -78,37 +78,74 @@ def moduleCMakeFlags() {
|
||||
// Pipeline start
|
||||
//
|
||||
|
||||
parallel master: {
|
||||
node('master') {
|
||||
stage('master/scm') {
|
||||
parallel tools: {
|
||||
node('tools') {
|
||||
stage('tools/scm') {
|
||||
deleteDir();
|
||||
gitHelper.checkoutGit(url, branch);
|
||||
gitHelper.checkoutGit(url, branch, false);
|
||||
helper.createDirectory('build');
|
||||
}
|
||||
stage('master/cppcheck/create') {
|
||||
sh 'cppcheck --enable=all --xml --xml-version=2 -i ext --suppressions-list=support/cppcheck/suppressions.txt include modules src tests 2> build/cppcheck.xml';
|
||||
}
|
||||
stage('master/cloc/create') {
|
||||
sh 'cloc --by-file --exclude-dir=build,data,ext --xml --out=build/cloc.xml --force-lang-def=support/cloc/langDef --quiet .';
|
||||
}
|
||||
}
|
||||
stage('tools/cppcheck') {
|
||||
sh(
|
||||
script: 'cppcheck --enable=all --xml --xml-version=2 -i ext --suppressions-list=support/cppcheck/suppressions.txt include modules src tests 2> build/cppcheck.xml',
|
||||
label: 'CPPCheck'
|
||||
)
|
||||
recordIssues(
|
||||
id: 'tools-cppcheck',
|
||||
tool: cppCheck()
|
||||
)
|
||||
}
|
||||
cleanWs()
|
||||
} // node('tools')
|
||||
},
|
||||
linux: {
|
||||
node('linux') {
|
||||
stage('linux/scm') {
|
||||
linux_gcc: {
|
||||
node('linux' && 'gcc') {
|
||||
stage('linux-gcc/scm') {
|
||||
deleteDir();
|
||||
gitHelper.checkoutGit(url, branch);
|
||||
}
|
||||
stage('linux-gcc/build(make)') {
|
||||
def cmakeCompileOptions = moduleCMakeFlags();
|
||||
cmakeCompileOptions += ' -DMAKE_BUILD_TYPE=Release';
|
||||
// Not sure why the linking of OpenSpaceTest takes so long
|
||||
compileHelper.build(compileHelper.Make(), compileHelper.Gcc(), cmakeCompileOptions, 'OpenSpace', 'build-make');
|
||||
compileHelper.recordCompileIssues(compileHelper.Gcc());
|
||||
}
|
||||
stage('linux-gcc/build(ninja)') {
|
||||
def cmakeCompileOptions = moduleCMakeFlags();
|
||||
cmakeCompileOptions += '-DMAKE_BUILD_TYPE=Release';
|
||||
// Not sure why the linking of OpenSpaceTest takes so long
|
||||
compileHelper.build(compileHelper.Ninja(), compileHelper.Gcc(), cmakeCompileOptions, 'OpenSpace', 'build-ninja');
|
||||
}
|
||||
stage('linux-gcc/test') {
|
||||
// testHelper.runUnitTests('build/OpenSpaceTest');
|
||||
}
|
||||
cleanWs()
|
||||
} // node('linux')
|
||||
},
|
||||
linux_clang: {
|
||||
node('linux' && 'clang') {
|
||||
stage('linux-clang/scm') {
|
||||
deleteDir()
|
||||
gitHelper.checkoutGit(url, branch);
|
||||
}
|
||||
stage('linux/build') {
|
||||
stage('linux-clang/build(make)') {
|
||||
def cmakeCompileOptions = moduleCMakeFlags()
|
||||
cmakeCompileOptions += ' -DMAKE_BUILD_TYPE=Release'
|
||||
// Not sure why the linking of OpenSpaceTest takes so long
|
||||
compileHelper.build(compileHelper.Make(), compileHelper.Gcc(), moduleCMakeFlags(), 'OpenSpace', 'build-all');
|
||||
compileHelper.build(compileHelper.Make(), compileHelper.Clang(), cmakeCompileOptions, 'OpenSpace', 'build-make');
|
||||
compileHelper.recordCompileIssues(compileHelper.Clang());
|
||||
}
|
||||
stage('linux/warnings') {
|
||||
// compileHelper.recordCompileIssues(compileHelper.Gcc());
|
||||
stage('linux-clang/build(ninja)') {
|
||||
def cmakeCompileOptions = moduleCMakeFlags()
|
||||
cmakeCompileOptions += '-DMAKE_BUILD_TYPE=Release'
|
||||
// Not sure why the linking of OpenSpaceTest takes so long
|
||||
compileHelper.build(compileHelper.Ninja(), compileHelper.Clang(), cmakeCompileOptions, 'OpenSpace', 'build-ninja');
|
||||
}
|
||||
stage('linux/test') {
|
||||
stage('linux-clang/test') {
|
||||
// testHelper.runUnitTests('build/OpenSpaceTest');
|
||||
}
|
||||
cleanWs()
|
||||
} // node('linux')
|
||||
},
|
||||
windows: {
|
||||
@@ -118,49 +155,37 @@ windows: {
|
||||
deleteDir();
|
||||
gitHelper.checkoutGit(url, branch);
|
||||
}
|
||||
stage('windows/build') {
|
||||
compileHelper.build(compileHelper.VisualStudio(), compileHelper.VisualStudio(), moduleCMakeFlags(), '', 'build-all');
|
||||
stage('windows/build(msvc)') {
|
||||
compileHelper.build(compileHelper.VisualStudio(), compileHelper.VisualStudio(), moduleCMakeFlags(), '', 'build-msvc');
|
||||
compileHelper.recordCompileIssues(compileHelper.VisualStudio());
|
||||
}
|
||||
stage('windows/warnings') {
|
||||
// compileHelper.recordCompileIssues(compileHelper.VisualStudio());
|
||||
stage('windows/build(ninja)') {
|
||||
compileHelper.build(compileHelper.Ninja(), compileHelper.VisualStudio(), moduleCMakeFlags(), '', 'build-ninja');
|
||||
}
|
||||
stage('windows/test') {
|
||||
// Currently, the unit tests are failing on Windows
|
||||
// testHelper.runUnitTests('bin\\Debug\\OpenSpaceTest')
|
||||
}
|
||||
} // node('windows')
|
||||
}
|
||||
cleanWs()
|
||||
} // node('windows')
|
||||
},
|
||||
osx: {
|
||||
node('osx') {
|
||||
stage('osx/scm') {
|
||||
macos: {
|
||||
node('macos') {
|
||||
stage('macos/scm') {
|
||||
deleteDir();
|
||||
gitHelper.checkoutGit(url, branch);
|
||||
}
|
||||
stage('osx/build') {
|
||||
compileHelper.build(compileHelper.Xcode(), compileHelper.Clang(), moduleCMakeFlags(), '', 'build-all');
|
||||
stage('macos/build(make)') {
|
||||
compileHelper.build(compileHelper.Make(), compileHelper.Clang(), moduleCMakeFlags(), '', 'build-make');
|
||||
}
|
||||
stage('osx/warnings') {
|
||||
// compileHelper.recordCompileIssues(compileHelper.Clang());
|
||||
stage('macos/build(xcode)') {
|
||||
compileHelper.build(compileHelper.Xcode(), compileHelper.Xcode(), moduleCMakeFlags(), '', 'build-xcode');
|
||||
}
|
||||
stage('osx/test') {
|
||||
stage('macos/test') {
|
||||
// Currently, the unit tests are crashing on OS X
|
||||
// testHelper.runUnitTests('build/Debug/OpenSpaceTest')
|
||||
}
|
||||
} // node('osx')
|
||||
}
|
||||
|
||||
//
|
||||
// Post-build actions
|
||||
//
|
||||
node('master') {
|
||||
stage('master/cppcheck/publish') {
|
||||
// publishCppcheck(pattern: 'build/cppcheck.xml');
|
||||
}
|
||||
stage('master/cloc/publish') {
|
||||
sloccountPublish(encoding: '', pattern: 'build/cloc.xml');
|
||||
}
|
||||
stage('master/notifications') {
|
||||
slackHelper.sendChangeSetSlackMessage(currentBuild);
|
||||
}
|
||||
cleanWs()
|
||||
} // node('macos')
|
||||
}
|
||||
|
||||
@@ -10,4 +10,4 @@ OpenSpace requires graphics support for [OpenGL](https://www.opengl.org/) versio
|
||||
|
||||
This repository contains the source code and example scenes for OpenSpace, but does not contain any data. To build and install the client, we refer to the [OpenSpace Wiki](http://wiki.openspaceproject.com/), specifically [building](http://wiki.openspaceproject.com/docs/developers/compiling/general) for [Windows](http://wiki.openspaceproject.com/docs/developers/compiling/windows), [Linux (Ubuntu)](http://wiki.openspaceproject.com/docs/developers/compiling/ubuntu), and [MacOS](http://wiki.openspaceproject.com/docs/developers/compiling/macos). Required preexisting dependencies are: [Boost](http://www.boost.org/) and [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:alexander.bock@me.com?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/enQtMjUxNzUyMTQ1ODQxLTI4YjNmMTY3ZDI1N2Q1NWM1ZjQ1NTQyNzAxM2YyMGQ5Y2NmYWJiNjI1NjU4YTkyNTc5ZDE5NzdhNGM2YmUzYTk).
|
||||
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).
|
||||
|
||||
@@ -74,7 +74,7 @@ endif ()
|
||||
|
||||
|
||||
#####
|
||||
# macos
|
||||
# MacOS
|
||||
#####
|
||||
if (APPLE)
|
||||
set(MACOSX_BUNDLE_ICON_FILE openspace.icns)
|
||||
@@ -101,7 +101,7 @@ target_include_directories(
|
||||
${SPOUT_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_link_libraries(OpenSpace openspace-core ${OPENVR_LIBRARY} ${SPOUT_LIBRARY})
|
||||
target_link_libraries(OpenSpace PUBLIC openspace-core ${OPENVR_LIBRARY} ${SPOUT_LIBRARY})
|
||||
|
||||
target_compile_definitions(OpenSpace PRIVATE
|
||||
${SGCT_OPENVR_DEFINITIONS}
|
||||
@@ -112,10 +112,11 @@ 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)
|
||||
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/ext/sgct)
|
||||
target_include_directories(OpenSpace SYSTEM PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/ext/sgct/include)
|
||||
target_link_libraries(OpenSpace sgct)
|
||||
target_link_libraries(OpenSpace PUBLIC sgct)
|
||||
|
||||
set_folder_location(sgct "External")
|
||||
set_folder_location(glfw "External/SGCT")
|
||||
@@ -127,11 +128,17 @@ set_folder_location(vrpn "External/SGCT")
|
||||
set_folder_location(zlibstatic "External/SGCT")
|
||||
|
||||
if (UNIX AND (NOT APPLE))
|
||||
target_link_libraries(OpenSpace Xcursor Xinerama X11)
|
||||
target_link_libraries(OpenSpace PUBLIC Xcursor Xinerama X11)
|
||||
endif ()
|
||||
|
||||
end_header("Dependency: SGCT")
|
||||
|
||||
begin_header("Dependency: Profile Editor")
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/ext/launcher)
|
||||
# target_include_directories(OpenSpace SYSTEM PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/ext/launcher/include)
|
||||
target_link_libraries(OpenSpace PUBLIC openspace-ui-launcher)
|
||||
end_header("Dependency: Profile Editor")
|
||||
|
||||
|
||||
# Web Browser and Web gui
|
||||
# Why not put these in the module's path? Because they do not have access to the
|
||||
@@ -158,7 +165,7 @@ endif ()
|
||||
if (MSVC)
|
||||
begin_header("Dependency: Dbghelp")
|
||||
# This library is used for being able to output the callstack if an exception escapes
|
||||
target_link_libraries(OpenSpace Dbghelp.lib)
|
||||
target_link_libraries(OpenSpace PUBLIC Dbghelp.lib)
|
||||
end_header()
|
||||
endif ()
|
||||
|
||||
|
||||
92
apps/OpenSpace/ext/launcher/CMakeLists.txt
Normal file
92
apps/OpenSpace/ext/launcher/CMakeLists.txt
Normal file
@@ -0,0 +1,92 @@
|
||||
##########################################################################################
|
||||
# #
|
||||
# OpenSpace #
|
||||
# #
|
||||
# Copyright (c) 2014-2020 #
|
||||
# #
|
||||
# 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 #
|
||||
# without restriction, including without limitation the rights to use, copy, modify, #
|
||||
# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to #
|
||||
# permit persons to whom the Software is furnished to do so, subject to the following #
|
||||
# conditions: #
|
||||
# #
|
||||
# The above copyright notice and this permission notice shall be included in all copies #
|
||||
# or substantial portions of the Software. #
|
||||
# #
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, #
|
||||
# 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. #
|
||||
##########################################################################################
|
||||
|
||||
include(${OPENSPACE_CMAKE_EXT_DIR}/set_openspace_compile_settings.cmake)
|
||||
|
||||
set(HEADER_FILES
|
||||
include/filesystemaccess.h
|
||||
include/launcherwindow.h
|
||||
include/profile/additionalscriptsdialog.h
|
||||
include/profile/assetsdialog.h
|
||||
include/profile/assettreeitem.h
|
||||
include/profile/assettreemodel.h
|
||||
include/profile/cameradialog.h
|
||||
include/profile/deltatimesdialog.h
|
||||
include/profile/keybindingsdialog.h
|
||||
include/profile/line.h
|
||||
include/profile/marknodesdialog.h
|
||||
include/profile/metadialog.h
|
||||
include/profile/modulesdialog.h
|
||||
include/profile/timedialog.h
|
||||
include/profile/profileedit.h
|
||||
include/profile/propertiesdialog.h
|
||||
)
|
||||
|
||||
set(SOURCE_FILES
|
||||
src/launcherwindow.cpp
|
||||
src/filesystemaccess.cpp
|
||||
src/profile/additionalscriptsdialog.cpp
|
||||
src/profile/assetsdialog.cpp
|
||||
src/profile/assettreeitem.cpp
|
||||
src/profile/assettreemodel.cpp
|
||||
src/profile/cameradialog.cpp
|
||||
src/profile/deltatimesdialog.cpp
|
||||
src/profile/keybindingsdialog.cpp
|
||||
src/profile/line.cpp
|
||||
src/profile/marknodesdialog.cpp
|
||||
src/profile/metadialog.cpp
|
||||
src/profile/modulesdialog.cpp
|
||||
src/profile/timedialog.cpp
|
||||
src/profile/profileedit.cpp
|
||||
src/profile/propertiesdialog.cpp
|
||||
)
|
||||
|
||||
find_package(Qt5 COMPONENTS Widgets REQUIRED)
|
||||
|
||||
set(MOC_FILES "")
|
||||
qt5_wrap_cpp(
|
||||
MOC_FILES
|
||||
include/launcherwindow.h
|
||||
include/profile/additionalscriptsdialog.h
|
||||
include/profile/assetsdialog.h
|
||||
include/profile/assettreemodel.h
|
||||
include/profile/cameradialog.h
|
||||
include/profile/deltatimesdialog.h
|
||||
include/profile/keybindingsdialog.h
|
||||
include/profile/marknodesdialog.h
|
||||
include/profile/metadialog.h
|
||||
include/profile/modulesdialog.h
|
||||
include/profile/timedialog.h
|
||||
include/profile/profileedit.h
|
||||
include/profile/propertiesdialog.h
|
||||
)
|
||||
|
||||
set(RESOURCE_FILES "")
|
||||
qt5_add_resources(RESOURCE_FILES resources/resources.qrc)
|
||||
|
||||
add_library(openspace-ui-launcher STATIC ${HEADER_FILES} ${SOURCE_FILES} ${MOC_FILES} ${RESOURCE_FILES})
|
||||
set_openspace_compile_settings(openspace-ui-launcher)
|
||||
target_include_directories(openspace-ui-launcher PUBLIC include)
|
||||
target_link_libraries(openspace-ui-launcher PUBLIC Qt5::Core Qt5::Gui Qt5::Widgets openspace-core)
|
||||
|
||||
74
apps/OpenSpace/ext/launcher/include/filesystemaccess.h
Normal file
74
apps/OpenSpace/ext/launcher/include/filesystemaccess.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2020 *
|
||||
* *
|
||||
* 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 *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_UI_LAUNCHER___FILESYSTEMACCESS___H__
|
||||
#define __OPENSPACE_UI_LAUNCHER___FILESYSTEMACCESS___H__
|
||||
|
||||
#include <QFileSystemModel>
|
||||
|
||||
class FileSystemAccess {
|
||||
public:
|
||||
/**
|
||||
* Constructor for filesystemAccess class
|
||||
*
|
||||
* \param fileExtension string that defines the filter used to find files. Only
|
||||
* files with this extension will be recognized (e.g. '.xml')
|
||||
* \param approvedPaths vector or strings containing directory names to be included
|
||||
* in the search. These are directories at the base level of
|
||||
* the starting point of the search. Any sub-directories within
|
||||
* these directories will be included.
|
||||
* \param hideFileExtensions if true then file extensions will be removed from the
|
||||
* listed files in the output
|
||||
* \param useCheckboxes if true then the text output format will contain a '0' as
|
||||
* the first character in the line (this first character is
|
||||
* used to represent checked ('1'), uncheck ('0') or doesn't
|
||||
* exist in filesystem ('x') states.
|
||||
*/
|
||||
FileSystemAccess(std::string fileExtension,
|
||||
std::vector<std::string> approvedPaths, bool hideFileExtensions,
|
||||
bool useCheckboxes);
|
||||
|
||||
/**
|
||||
* Function that uses the #QtFileSystemModel class to search the given directory
|
||||
*
|
||||
* \param dir The directory from which to start the search from
|
||||
*/
|
||||
std::string useQtFileSystemModelToTraverseDir(std::string dir);
|
||||
|
||||
private:
|
||||
void parseChildDirElements(QFileInfo item, std::string space, int level,
|
||||
std::vector<std::string>& dirNames, std::vector<std::string>& output);
|
||||
void parseChildFile(std::string res, bool& hasDirHeaderBeenAdded,
|
||||
std::vector<std::string>& dirNames, std::vector<std::string>& output);
|
||||
bool isApprovedPath(std::string path);
|
||||
|
||||
QFileSystemModel _filesystemModel;
|
||||
QDir::Filters _fileFilterOptions = QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot;
|
||||
std::string _fileExtension;
|
||||
std::vector<std::string> _approvedPaths;
|
||||
bool _hideFileExtensions = true;
|
||||
bool _useCheckboxes = false;
|
||||
};
|
||||
|
||||
#endif // __OPENSPACE_UI_LAUNCHER___FILESYSTEMACCESS___H__
|
||||
99
apps/OpenSpace/ext/launcher/include/launcherwindow.h
Normal file
99
apps/OpenSpace/ext/launcher/include/launcherwindow.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2020 *
|
||||
* *
|
||||
* 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 *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_UI_LAUNCHER___LAUNCHERWINDOW___H__
|
||||
#define __OPENSPACE_UI_LAUNCHER___LAUNCHERWINDOW___H__
|
||||
|
||||
#include <QMainWindow>
|
||||
|
||||
#include <openspace/scene/profile.h>
|
||||
#include <optional>
|
||||
|
||||
namespace openspace::configuration { struct Configuration; }
|
||||
|
||||
class QComboBox;
|
||||
class QLabel;
|
||||
|
||||
class LauncherWindow : public QMainWindow {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Constructor for LauncherWindow class
|
||||
*
|
||||
* \param profileEnabled true if profile selection combo box will be enabled
|
||||
* \param globalConfig reference to global configuration for OpenSpace settings
|
||||
* \param sgctConfigEnabled true if window selection combo box will be enabled
|
||||
* \param sgctConfigName the name of the sgct configuration function used to
|
||||
* generate window config (blank if file is used)
|
||||
* \param parentItem The parent that contains this (and possibly other) children
|
||||
* in the tree structure.
|
||||
*/
|
||||
LauncherWindow(bool profileEnabled,
|
||||
const openspace::configuration::Configuration& globalConfig,
|
||||
bool sgctConfigEnabled, std::string sgctConfigName, QWidget* parent);
|
||||
|
||||
/**
|
||||
* Returns bool for whether "start OpenSpace" was chosen when this window closed.
|
||||
* OpenSpace will not start if false
|
||||
*
|
||||
* \return true if the "start OpenSpace" button was clicked
|
||||
*/
|
||||
bool wasLaunchSelected() const;
|
||||
|
||||
/**
|
||||
* Returns the selected profile name when launcher window closed
|
||||
*
|
||||
* \return name of selected profile (this is only the name without file extension
|
||||
* and without path)
|
||||
*/
|
||||
std::string selectedProfile() const;
|
||||
|
||||
/**
|
||||
* Returns the selected sgct window configuration when launcher window closed
|
||||
*
|
||||
* \return name of selected profile (this is only the name without file extension
|
||||
* and without path)
|
||||
*/
|
||||
std::string selectedWindowConfig() const;
|
||||
|
||||
private:
|
||||
QWidget* createCentralWidget();
|
||||
void setBackgroundImage(const std::string& syncPath);
|
||||
|
||||
void openProfileEditor(const std::string& profile);
|
||||
|
||||
void populateProfilesList(std::string preset);
|
||||
void populateWindowConfigsList(std::string preset);
|
||||
|
||||
const std::string _assetPath;
|
||||
const std::string _configPath;
|
||||
const std::string _profilePath;
|
||||
const std::vector<std::string>& _readOnlyProfiles;
|
||||
bool _shouldLaunch = false;
|
||||
|
||||
QComboBox* _profileBox = nullptr;
|
||||
QComboBox* _windowConfigBox = nullptr;
|
||||
QLabel* _backgroundImage = nullptr;
|
||||
};
|
||||
#endif // __OPENSPACE_UI_LAUNCHER___LAUNCHERWINDOW___H__
|
||||
@@ -22,32 +22,35 @@
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <openspace/performance/performancemeasurement.h>
|
||||
#ifndef __OPENSPACE_UI_LAUNCHER___ADDITIONALSCRIPTS___H__
|
||||
#define __OPENSPACE_UI_LAUNCHER___ADDITIONALSCRIPTS___H__
|
||||
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/performance/performancemanager.h>
|
||||
#include <ghoul/opengl/ghoul_gl.h>
|
||||
#include <QDialog>
|
||||
|
||||
namespace openspace::performance {
|
||||
namespace openspace { class Profile; }
|
||||
|
||||
PerformanceMeasurement::PerformanceMeasurement(std::string identifier)
|
||||
: _identifier(std::move(identifier))
|
||||
{
|
||||
glFinish();
|
||||
_startTime = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
class QTextEdit;
|
||||
|
||||
PerformanceMeasurement::~PerformanceMeasurement() {
|
||||
glFinish();
|
||||
auto endTime = std::chrono::high_resolution_clock::now();
|
||||
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(
|
||||
endTime - _startTime
|
||||
).count();
|
||||
class AdditionalScriptsDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Constructor for addedScripts class
|
||||
*
|
||||
* \param profile The #openspace::Profile object containing all data of the
|
||||
* new or imported profile.
|
||||
* \param parent Pointer to parent Qt widget
|
||||
*/
|
||||
AdditionalScriptsDialog(openspace::Profile& profile, QWidget* parent);
|
||||
|
||||
global::performanceManager.storeIndividualPerformanceMeasurement(
|
||||
std::move(_identifier),
|
||||
duration
|
||||
);
|
||||
}
|
||||
private slots:
|
||||
void parseScript();
|
||||
|
||||
} // namespace openspace::performance
|
||||
private:
|
||||
void createWidgets();
|
||||
|
||||
openspace::Profile& _profile;
|
||||
QTextEdit* _textScripts = nullptr;
|
||||
};
|
||||
|
||||
#endif // __OPENSPACE_UI_LAUNCHER___ADDITIONALSCRIPTS___H__
|
||||
70
apps/OpenSpace/ext/launcher/include/profile/assetsdialog.h
Normal file
70
apps/OpenSpace/ext/launcher/include/profile/assetsdialog.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2020 *
|
||||
* *
|
||||
* 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 *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_UI_LAUNCHER___ASSETS___H__
|
||||
#define __OPENSPACE_UI_LAUNCHER___ASSETS___H__
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include "assettreemodel.h"
|
||||
|
||||
namespace openspace { class Profile; }
|
||||
|
||||
class QTextEdit;
|
||||
class QTreeView;
|
||||
|
||||
class AssetsDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Constructor for assets class
|
||||
*
|
||||
* \param profile The #openspace::Profile object containing all data of the
|
||||
* new or imported profile.
|
||||
* \param assetBasePath The path to the folder in which all of the assets are living
|
||||
* \param parent Pointer to parent Qt widget
|
||||
*/
|
||||
AssetsDialog(openspace::Profile& profile, const std::string& assetBasePath,
|
||||
QWidget* parent);
|
||||
|
||||
private slots:
|
||||
void parseSelections();
|
||||
void selected(const QModelIndex&);
|
||||
|
||||
private:
|
||||
void createWidgets();
|
||||
/**
|
||||
* Creates a text summary of all assets and their paths
|
||||
*
|
||||
* \return the #std::string summary
|
||||
*/
|
||||
QString createTextSummary();
|
||||
|
||||
openspace::Profile& _profile;
|
||||
AssetTreeModel _assetTreeModel;
|
||||
QTreeView* _assetTree = nullptr;
|
||||
QTextEdit* _summary = nullptr;
|
||||
};
|
||||
|
||||
#endif // __OPENSPACE_UI_LAUNCHER___ASSETS___H__
|
||||
197
apps/OpenSpace/ext/launcher/include/profile/assettreeitem.h
Normal file
197
apps/OpenSpace/ext/launcher/include/profile/assettreeitem.h
Normal file
@@ -0,0 +1,197 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2020 *
|
||||
* *
|
||||
* 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 *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_UI_LAUNCHER___ASSETTREEITEM___H__
|
||||
#define __OPENSPACE_UI_LAUNCHER___ASSETTREEITEM___H__
|
||||
|
||||
#include <QVariant>
|
||||
#include <vector>
|
||||
|
||||
class AssetTreeItem {
|
||||
public:
|
||||
static constexpr const int CheckboxColumn = 1;
|
||||
|
||||
/**
|
||||
* Constructor for assetTreeItem class
|
||||
*
|
||||
* \param data QVector containing the data contained in this tree view item
|
||||
* \param parentItem The parent that contains this (and possibly other) children
|
||||
* in the tree structure (optional).
|
||||
*/
|
||||
explicit AssetTreeItem(const std::vector<QVariant>& data,
|
||||
AssetTreeItem* parentItem = nullptr);
|
||||
|
||||
/**
|
||||
* Destructor for assetTreeItem class
|
||||
*/
|
||||
~AssetTreeItem();
|
||||
|
||||
/**
|
||||
* Returns pointer to this tree item's child at position \p row.
|
||||
*
|
||||
* \param row int of the row number of the child to get pointer
|
||||
* \param parentItem The parent that contains this (and possibly other) children
|
||||
* in the tree structure (optional).
|
||||
* \return pointer to the child #assetTreeItem
|
||||
*/
|
||||
AssetTreeItem* child(int row);
|
||||
|
||||
/**
|
||||
* Returns the number of children this item has
|
||||
*
|
||||
* \return The number of children
|
||||
*/
|
||||
int childCount() const;
|
||||
|
||||
/**
|
||||
* Returns the number of data columns of this item
|
||||
*
|
||||
* \return The number of data columns
|
||||
*/
|
||||
int columnCount() const;
|
||||
|
||||
/**
|
||||
* Returns the data at column \p column of this item
|
||||
*
|
||||
* \param column Column number from which to retrieve data
|
||||
* \return The data contained in the column
|
||||
*/
|
||||
QVariant data(int column) const;
|
||||
|
||||
/**
|
||||
* Inserts children item(s) to the current item
|
||||
*
|
||||
* \param position where in this item's children to insert new children
|
||||
* \param count number of children to insert
|
||||
* \param columns number of data columns in each child
|
||||
*
|
||||
* \return true if new children were successfully inserted
|
||||
*/
|
||||
bool insertChildren(int position, int count, int columns);
|
||||
|
||||
/**
|
||||
* Inserts data column(s) in the current item
|
||||
*
|
||||
* \param position column number at which to insert column(s)
|
||||
* \param columns number of columns to insert
|
||||
* \return true if columns were successfully inserted
|
||||
*/
|
||||
bool insertColumns(int position, int columns);
|
||||
|
||||
/**
|
||||
* Returns a pointer to the current item's parent
|
||||
*
|
||||
* \return pointer to the \p assetTreeItem parent
|
||||
*/
|
||||
AssetTreeItem* parent();
|
||||
|
||||
/**
|
||||
* Returns the row number / child number of this item's parent
|
||||
*
|
||||
* \return The row number of this item's parent
|
||||
*/
|
||||
int row() const;
|
||||
|
||||
/**
|
||||
* Returns the data at column \p column of this item
|
||||
*
|
||||
* \param position The position of the child(ren) to remove from the current
|
||||
* item (which is parent)
|
||||
* \param count The number of children to remove
|
||||
* \return true if child item(s) successfully removed
|
||||
*/
|
||||
bool removeChildren(int position, int count);
|
||||
|
||||
/**
|
||||
* Set data at column \p column
|
||||
*
|
||||
* \param column The data column number to set
|
||||
* \param value The #QVariant data element to store at column \p column
|
||||
* \return true if the data set was successful
|
||||
*/
|
||||
bool setData(int column, const QVariant &value);
|
||||
|
||||
/**
|
||||
* Returns the checked state of this item. If an asset is selected to be included
|
||||
* in a profile, then it is checked.
|
||||
*
|
||||
* \return true if this item is checked
|
||||
*/
|
||||
bool isChecked() const;
|
||||
|
||||
/**
|
||||
* Sets the checked state of this item (whether or not it is selected for a profile)
|
||||
*
|
||||
* \param set bool for whether or not this is checked
|
||||
*/
|
||||
void setChecked(bool set);
|
||||
|
||||
/**
|
||||
* Returns a bool for whether or not this is an asset. If it is a file
|
||||
* (has no children in the filesystem tree), then it is an asset.
|
||||
*
|
||||
* \return true if this is an asset file and not a directory containing asset(s)
|
||||
*/
|
||||
bool isAsset() const;
|
||||
|
||||
/**
|
||||
* Returns a bool for whether or not this is a category. If it is a directory
|
||||
* and not an asset (file), then it is a category.
|
||||
*
|
||||
* \return true if this is a category
|
||||
*/
|
||||
bool isCategory() const;
|
||||
|
||||
/**
|
||||
* Sets status of whether or not the asset exists in the current filesystem.
|
||||
* It is possible that an imported profile lists an asset from another system
|
||||
* that is not included on the current filesystem.
|
||||
*
|
||||
* \param set to true if the asset file exists in the current filesystem
|
||||
*/
|
||||
void setExistsInFilesystem(bool fileExists);
|
||||
|
||||
/**
|
||||
* Returns bool for whether or not the asset exists in the current filesystem
|
||||
*
|
||||
* \return true if the asset exists in the current filesystem
|
||||
*/
|
||||
bool doesExistInFilesystem() const;
|
||||
|
||||
/**
|
||||
* Returns the asset name of the current item
|
||||
*
|
||||
* \return The asset name
|
||||
*/
|
||||
QString name() const;
|
||||
|
||||
private:
|
||||
std::vector<AssetTreeItem*> _childItems;
|
||||
std::vector<QVariant> _itemData;
|
||||
AssetTreeItem* _parentItem;
|
||||
bool _isChecked = false;
|
||||
bool _fileExists = true;
|
||||
};
|
||||
|
||||
#endif // __OPENSPACE_UI_LAUNCHER___ASSETTREEITEM___H__
|
||||
232
apps/OpenSpace/ext/launcher/include/profile/assettreemodel.h
Normal file
232
apps/OpenSpace/ext/launcher/include/profile/assettreemodel.h
Normal file
@@ -0,0 +1,232 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2020 *
|
||||
* *
|
||||
* 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 *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_UI_LAUNCHER___ASSETTREEMODEL___H__
|
||||
#define __OPENSPACE_UI_LAUNCHER___ASSETTREEMODEL___H__
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
|
||||
#include "assettreeitem.h"
|
||||
#include "openspace/scene/profile.h"
|
||||
#include <memory>
|
||||
|
||||
class AssetTreeModel : public QAbstractItemModel {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AssetTreeModel(QObject* parent = nullptr);
|
||||
|
||||
/**
|
||||
* Returns the data contained at an index
|
||||
*
|
||||
* \param index that defines where the item is located in the tree model
|
||||
* \param role Qt-defined role that describes the reason Qt is calling the
|
||||
* function (can be multiple times)
|
||||
* \return QVariant data object
|
||||
*/
|
||||
QVariant data(const QModelIndex& index, int role) const override;
|
||||
|
||||
/**
|
||||
* Returns the header data of the tree view
|
||||
*
|
||||
* \param section of data to be obtained from header
|
||||
* \param orientation of the query (e.g. Qt::horizontal)
|
||||
* \param role Qt-defined role that describes the reason Qt is calling the
|
||||
* function (can be multiple times)
|
||||
* \return QVariant data object in the header
|
||||
*/
|
||||
QVariant headerData(int section, Qt::Orientation orientation,
|
||||
int role = Qt::DisplayRole) const override;
|
||||
|
||||
/**
|
||||
* Returns the index of item in #QModelIndex object form
|
||||
*
|
||||
* \param row the row number
|
||||
* \param column the column number
|
||||
* \param parent index of parent
|
||||
* \return #QModelIndex index of the item at specified position
|
||||
*/
|
||||
QModelIndex index(int row, int column,
|
||||
const QModelIndex& parent = QModelIndex()) const override;
|
||||
|
||||
/**
|
||||
* Returns the index of the parent of the item specified by input param
|
||||
*
|
||||
* \param index of item that is a child of the parent
|
||||
* \return #QModelIndex index of the parent
|
||||
*/
|
||||
QModelIndex parent(const QModelIndex& index) const override;
|
||||
|
||||
/**
|
||||
* Returns the index of the parent of the item specified by the input params
|
||||
*
|
||||
* \param row the row number
|
||||
* \param column the column number
|
||||
* \param parent index of parent
|
||||
* \return #QModelIndex index of the parent
|
||||
*/
|
||||
QModelIndex parent(int row, int column,
|
||||
const QModelIndex& parent = QModelIndex()) const;
|
||||
|
||||
/**
|
||||
* Returns asset item at specified index
|
||||
*
|
||||
* \param index of item that is a child of the parent
|
||||
* \return #assetTreeItem pointer to the item at the provided index
|
||||
*/
|
||||
AssetTreeItem* assetItem(const QModelIndex& index);
|
||||
|
||||
/**
|
||||
* Returns number of children/rows of the parent
|
||||
*
|
||||
* \param parent #QModelIndex of the parent item
|
||||
* \return number of children/rows of this parent
|
||||
*/
|
||||
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
|
||||
/**
|
||||
* Returns the number of columns of data in each item of the tree
|
||||
*
|
||||
* \param parent specified by the #QModelIndex index
|
||||
* \return the number of data columns
|
||||
*/
|
||||
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
|
||||
/**
|
||||
* Return the Qt flags of the item specified by index, which can include
|
||||
* Qt::ItemIsEnabled, Qt::ItemIsSelectable
|
||||
*
|
||||
* \param index specified by the #QModelIndex index
|
||||
* \return the Qt flags
|
||||
*/
|
||||
Qt::ItemFlags flags(const QModelIndex& index) const override;
|
||||
|
||||
/**
|
||||
* Set data at index \p index
|
||||
*
|
||||
* \param index location of the item to set
|
||||
* \param value The #QVariant data element to store at column \p column
|
||||
* \param role Qt-specific role to define context of the call
|
||||
* \return true if the data set was successful
|
||||
*/
|
||||
bool setData(const QModelIndex& index, const QVariant& value,
|
||||
int role = Qt::EditRole) override;
|
||||
|
||||
/**
|
||||
* Returns a vector of all #Assets selected in the tree view
|
||||
*
|
||||
* \param outputPaths vector of #openspace::Profile::Asset objects,
|
||||
* each of which are selected
|
||||
* \param outputItems vector of #assetTreeItem * objects,
|
||||
* each of which are selected
|
||||
*/
|
||||
void getSelectedAssets(std::vector<std::string>& outputPaths,
|
||||
std::vector<AssetTreeItem*>& outputItems);
|
||||
|
||||
/**
|
||||
* Imports asset tree data for this model by recursively traversing the folder
|
||||
* structure.
|
||||
* \param assetBasePath The base path where to find all assets
|
||||
*/
|
||||
void importModelData(const std::string& assetBasePath);
|
||||
|
||||
/**
|
||||
* Returns bool for if item is checked/selected
|
||||
*
|
||||
* \param index location of the item to set
|
||||
* \return true if the item is checked
|
||||
*/
|
||||
bool isChecked(QModelIndex& index) const;
|
||||
|
||||
/**
|
||||
* Answers query about whether or not item is an asset
|
||||
*
|
||||
* \param index location of the item to query
|
||||
* \return true if the item is an asset (and not a directory)
|
||||
*/
|
||||
bool isAsset(QModelIndex& index) const;
|
||||
|
||||
/**
|
||||
* Answers query about whether or not item is in the current filesystem
|
||||
*
|
||||
* \param index location of the item to query
|
||||
* \return true if the data is in the filesystem
|
||||
*/
|
||||
bool inFilesystem(QModelIndex& index) const;
|
||||
|
||||
/**
|
||||
* Returns number of child items of referenced item
|
||||
*
|
||||
* \param index location of the item to query
|
||||
* \return number of child items
|
||||
*/
|
||||
int childCount(QModelIndex& index) const;
|
||||
|
||||
/**
|
||||
* Returns a pointer to a child item of the current item
|
||||
*
|
||||
* \param row the child number of the current item
|
||||
* \return assetTreeItem pointer to the child
|
||||
*/
|
||||
AssetTreeItem* child(int row) const;
|
||||
|
||||
/**
|
||||
* Returns the asset name of the specified item
|
||||
*
|
||||
* \param index location of the item to query
|
||||
* \return the asset name of the item
|
||||
*/
|
||||
QString name(QModelIndex& index) const;
|
||||
|
||||
/**
|
||||
* Set asset name at specified index
|
||||
*
|
||||
* \param index location of the item to set
|
||||
* \param name the asset name to set
|
||||
*/
|
||||
void setName(QModelIndex& index, QString name);
|
||||
|
||||
/**
|
||||
* Set state of checked/selected of an item
|
||||
*
|
||||
* \param index location of the item to set
|
||||
* \param checked true if item is checked/selected
|
||||
*/
|
||||
void setChecked(QModelIndex& index, bool checked);
|
||||
|
||||
/**
|
||||
* Set state of whether or not asset exists in filesystem
|
||||
*
|
||||
* \param index location of the item to set
|
||||
* \param fileExists true if asset exists in filesystem
|
||||
*/
|
||||
void setExistenceInFilesystem(QModelIndex& index, bool fileExists);
|
||||
|
||||
private:
|
||||
AssetTreeItem* getItem(const QModelIndex& index) const;
|
||||
|
||||
std::unique_ptr<AssetTreeItem> _rootItem;
|
||||
};
|
||||
|
||||
#endif // __OPENSPACE_UI_LAUNCHER___ASSETTREEMODEL___H__
|
||||
86
apps/OpenSpace/ext/launcher/include/profile/cameradialog.h
Normal file
86
apps/OpenSpace/ext/launcher/include/profile/cameradialog.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2020 *
|
||||
* *
|
||||
* 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 *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_UI_LAUNCHER___CAMERA___H__
|
||||
#define __OPENSPACE_UI_LAUNCHER___CAMERA___H__
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace openspace { class Profile; }
|
||||
|
||||
class QLabel;
|
||||
class QLineEdit;
|
||||
class QTabWidget;
|
||||
|
||||
class CameraDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Constructor for camera gui class
|
||||
*
|
||||
* \param profile The #openspace::Profile object containing all data of the
|
||||
* new or imported profile.
|
||||
* \param parent Pointer to parent Qt widget (optional)
|
||||
*/
|
||||
CameraDialog(openspace::Profile& profile, QWidget* parent);
|
||||
|
||||
private slots:
|
||||
void approved();
|
||||
void tabSelect(int);
|
||||
|
||||
private:
|
||||
void createWidgets();
|
||||
QWidget* createNavStateWidget();
|
||||
QWidget* createGeoWidget();
|
||||
|
||||
void addErrorMsg(QString errorDescription);
|
||||
bool areRequiredFormsFilledAndValid();
|
||||
|
||||
openspace::Profile& _profile;
|
||||
QTabWidget* _tabWidget = nullptr;
|
||||
struct {
|
||||
QLineEdit* anchor = nullptr;
|
||||
QLineEdit* aim = nullptr;
|
||||
QLineEdit* refFrame = nullptr;
|
||||
QLineEdit* positionX = nullptr;
|
||||
QLineEdit* positionY = nullptr;
|
||||
QLineEdit* positionZ = nullptr;
|
||||
QLineEdit* upX = nullptr;
|
||||
QLineEdit* upY = nullptr;
|
||||
QLineEdit* upZ = nullptr;
|
||||
QLineEdit* yaw = nullptr;
|
||||
QLineEdit* pitch = nullptr;
|
||||
} _navState;
|
||||
|
||||
struct {
|
||||
QLineEdit* anchor = nullptr;
|
||||
QLineEdit* latitude = nullptr;
|
||||
QLineEdit* longitude = nullptr;
|
||||
QLineEdit* altitude = nullptr;
|
||||
} _geoState;
|
||||
|
||||
QLabel* _errorMsg = nullptr;
|
||||
};
|
||||
|
||||
#endif // __OPENSPACE_UI_LAUNCHER___CAMERA___H__
|
||||
108
apps/OpenSpace/ext/launcher/include/profile/deltatimesdialog.h
Normal file
108
apps/OpenSpace/ext/launcher/include/profile/deltatimesdialog.h
Normal file
@@ -0,0 +1,108 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2020 *
|
||||
* *
|
||||
* 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 *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_UI_LAUNCHER___DELTATIMES___H__
|
||||
#define __OPENSPACE_UI_LAUNCHER___DELTATIMES___H__
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace openspace { class Profile; }
|
||||
|
||||
class QDialogButtonBox;
|
||||
class QLabel;
|
||||
class QListWidget;
|
||||
class QLineEdit;
|
||||
class QPushButton;
|
||||
|
||||
class DeltaTimesDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Constructor for deltaTimes class
|
||||
*
|
||||
* \param profile The #openspace::Profile object containing all data of the
|
||||
* new or imported profile.
|
||||
* \param parent Pointer to parent Qt widget
|
||||
*/
|
||||
DeltaTimesDialog(openspace::Profile& profile, QWidget* parent);
|
||||
|
||||
/**
|
||||
* Returns a text summary of the delta time list for display purposes
|
||||
*
|
||||
* \param idx index in dt list
|
||||
* \param forListView true if this summary is for the Qt list view, false if
|
||||
* it is used for a different display mode
|
||||
*/
|
||||
std::string createSummaryForDeltaTime(size_t idx, bool forListView);
|
||||
|
||||
/**
|
||||
* Handles keypress while the Qt dialog window is open
|
||||
*
|
||||
* \param evt #QKeyEvent object for the key press event
|
||||
*/
|
||||
void keyPressEvent(QKeyEvent* evt);
|
||||
|
||||
|
||||
private slots:
|
||||
void listItemSelected();
|
||||
void valueChanged(const QString& text);
|
||||
void saveDeltaTimeValue();
|
||||
void discardDeltaTimeValue();
|
||||
void addDeltaTimeValue();
|
||||
void removeDeltaTimeValue();
|
||||
void parseSelections();
|
||||
|
||||
private:
|
||||
void createWidgets();
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
void transitionEditMode(int index, bool state);
|
||||
|
||||
void setLabelForKey(int index, bool editMode, std::string color);
|
||||
bool isLineEmpty(int index);
|
||||
|
||||
openspace::Profile& _profile;
|
||||
std::vector<double> _data;
|
||||
bool _editModeNewItem = false;
|
||||
|
||||
QListWidget* _listWidget = nullptr;
|
||||
QLabel* _adjustLabel = nullptr;
|
||||
QLineEdit* _seconds = nullptr;
|
||||
QLabel* _value = nullptr;
|
||||
|
||||
QPushButton* _addButton = nullptr;
|
||||
QPushButton* _removeButton = nullptr;
|
||||
QPushButton* _saveButton = nullptr;
|
||||
QPushButton* _discardButton = nullptr;
|
||||
QDialogButtonBox* _buttonBox = nullptr;
|
||||
|
||||
QLabel* _errorMsg = nullptr;
|
||||
};
|
||||
|
||||
#endif // __OPENSPACE_UI_LAUNCHER___DELTATIMES___H__
|
||||
109
apps/OpenSpace/ext/launcher/include/profile/keybindingsdialog.h
Normal file
109
apps/OpenSpace/ext/launcher/include/profile/keybindingsdialog.h
Normal file
@@ -0,0 +1,109 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2020 *
|
||||
* *
|
||||
* 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 *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_UI_LAUNCHER___KEYBINDINGS___H__
|
||||
#define __OPENSPACE_UI_LAUNCHER___KEYBINDINGS___H__
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include <openspace/scene/profile.h>
|
||||
#include <QWidget>
|
||||
#include <QListWidgetItem>
|
||||
|
||||
class QComboBox;
|
||||
class QCheckBox;
|
||||
class QTextEdit;
|
||||
class QDialogButtonBox;
|
||||
class QListWidget;
|
||||
class QLabel;
|
||||
class QPushButton;
|
||||
|
||||
class KeybindingsDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Constructor for keybindings class
|
||||
*
|
||||
* \param profile The #openspace::Profile object containing all data of the
|
||||
* new or imported profile.
|
||||
* \param parent Pointer to parent Qt widget (optional)
|
||||
*/
|
||||
KeybindingsDialog(openspace::Profile& profile, QWidget* parent);
|
||||
|
||||
/**
|
||||
* Handles keypress while the Qt dialog window is open
|
||||
*
|
||||
* \param evt #QKeyEvent object for the key press event
|
||||
*/
|
||||
void keyPressEvent(QKeyEvent* evt);
|
||||
|
||||
private slots:
|
||||
void listItemSelected();
|
||||
void listItemAdded();
|
||||
void listItemRemove();
|
||||
void listItemSave();
|
||||
void listItemCancelSave();
|
||||
void transitionToEditMode();
|
||||
void parseSelections();
|
||||
void keySelected(int index);
|
||||
|
||||
private:
|
||||
void createWidgets();
|
||||
void transitionFromEditMode();
|
||||
void editBoxDisabled(bool disabled);
|
||||
int indexInKeyMapping(std::vector<int>& mapVector, int keyInt);
|
||||
bool areRequiredFormsFilled();
|
||||
bool isLineEmpty(int index);
|
||||
|
||||
openspace::Profile& _profile;
|
||||
std::vector<openspace::Profile::Keybinding> _data;
|
||||
std::vector<int> _mapModKeyComboBoxIndexToKeyValue;
|
||||
std::vector<int> _mapKeyComboBoxIndexToKeyValue;
|
||||
bool _editModeNewItem = false;
|
||||
|
||||
QListWidget* _list = nullptr;
|
||||
QLabel* _keyModLabel = nullptr;
|
||||
QComboBox* _keyModCombo = nullptr;
|
||||
QLabel* _keyLabel = nullptr;
|
||||
QComboBox* _keyCombo = nullptr;
|
||||
QLabel* _nameLabel = nullptr;
|
||||
QLineEdit* _nameEdit = nullptr;
|
||||
QLabel* _guiPathLabel = nullptr;
|
||||
QLineEdit* _guiPathEdit = nullptr;
|
||||
QLabel* _documentationLabel = nullptr;
|
||||
QLineEdit* _documentationEdit = nullptr;
|
||||
QCheckBox* _localCheck = nullptr;
|
||||
QLabel* _scriptLabel = nullptr;
|
||||
QTextEdit* _scriptEdit = nullptr;
|
||||
|
||||
QPushButton* _addButton = nullptr;
|
||||
QPushButton* _removeButton = nullptr;
|
||||
QPushButton* _saveButton = nullptr;
|
||||
QPushButton* _cancelButton = nullptr;
|
||||
QDialogButtonBox* _buttonBox = nullptr;
|
||||
|
||||
QLabel* _errorMsg = nullptr;
|
||||
};
|
||||
|
||||
#endif // __OPENSPACE_UI_LAUNCHER___KEYBINDINGS___H__
|
||||
35
apps/OpenSpace/ext/launcher/include/profile/line.h
Normal file
35
apps/OpenSpace/ext/launcher/include/profile/line.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2020 *
|
||||
* *
|
||||
* 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 *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_UI_LAUNCHER___LINE___H__
|
||||
#define __OPENSPACE_UI_LAUNCHER___LINE___H__
|
||||
|
||||
#include <QFrame>
|
||||
|
||||
class Line : public QFrame {
|
||||
public:
|
||||
Line();
|
||||
};
|
||||
|
||||
#endif // __OPENSPACE_UI_LAUNCHER___LINE___H__
|
||||
@@ -0,0 +1,75 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2020 *
|
||||
* *
|
||||
* 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 *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_UI_LAUNCHER___MARKNODES___H__
|
||||
#define __OPENSPACE_UI_LAUNCHER___MARKNODES___H__
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace openspace { class Profile; }
|
||||
|
||||
class QLineEdit;
|
||||
class QListWidget;
|
||||
class QListWidgetItem;
|
||||
class QPushButton;
|
||||
|
||||
class MarkNodesDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Constructor for markNodes class
|
||||
*
|
||||
* \param profile The #openspace::Profile object containing all data of the
|
||||
* new or imported profile.
|
||||
* \param parent Pointer to parent Qt widget
|
||||
*/
|
||||
MarkNodesDialog(openspace::Profile& profile, QWidget* parent);
|
||||
|
||||
/**
|
||||
* Handles keypress while the Qt dialog window is open
|
||||
*
|
||||
* \param evt #QKeyEvent object for the key press event
|
||||
*/
|
||||
void keyPressEvent(QKeyEvent* evt);
|
||||
|
||||
private slots:
|
||||
void listItemSelected();
|
||||
void listItemAdded();
|
||||
void listItemRemove();
|
||||
void parseSelections();
|
||||
|
||||
private:
|
||||
void createWidgets();
|
||||
|
||||
std::vector<QListWidgetItem*> _markedNodesListItems;
|
||||
openspace::Profile& _profile;
|
||||
std::vector<std::string> _data;
|
||||
|
||||
QListWidget* _list = nullptr;
|
||||
QPushButton* _removeButton = nullptr;
|
||||
QLineEdit* _newNode = nullptr;
|
||||
|
||||
};
|
||||
|
||||
#endif // __OPENSPACE_UI_LAUNCHER___MARKNODES___H__
|
||||
@@ -22,34 +22,42 @@
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_CORE___PERFORMANCEMEASUREMENT___H__
|
||||
#define __OPENSPACE_CORE___PERFORMANCEMEASUREMENT___H__
|
||||
#ifndef __OPENSPACE_UI_LAUNCHER___META___H__
|
||||
#define __OPENSPACE_UI_LAUNCHER___META___H__
|
||||
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <QDialog>
|
||||
|
||||
namespace openspace::performance {
|
||||
namespace openspace { class Profile; }
|
||||
|
||||
class PerformanceManager;
|
||||
class QLineEdit;
|
||||
class QTextEdit;
|
||||
|
||||
class PerformanceMeasurement {
|
||||
class MetaDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
PerformanceMeasurement(std::string identifier);
|
||||
~PerformanceMeasurement();
|
||||
/**
|
||||
* Constructor for meta class
|
||||
*
|
||||
* \param profile The #openspace::Profile object containing all data of the
|
||||
* new or imported profile.
|
||||
* \param parent Pointer to parent Qt widget
|
||||
*/
|
||||
MetaDialog(openspace::Profile& profile, QWidget* parent);
|
||||
|
||||
private slots:
|
||||
void save();
|
||||
|
||||
private:
|
||||
std::string _identifier;
|
||||
std::chrono::high_resolution_clock::time_point _startTime;
|
||||
void createWidgets();
|
||||
|
||||
openspace::Profile& _profile;
|
||||
|
||||
QLineEdit* _nameEdit = nullptr;
|
||||
QLineEdit* _versionEdit = nullptr;
|
||||
QTextEdit* _descriptionEdit = nullptr;
|
||||
QLineEdit* _authorEdit = nullptr;
|
||||
QLineEdit* _urlEdit = nullptr;
|
||||
QLineEdit* _licenseEdit = nullptr;
|
||||
};
|
||||
|
||||
#define __MERGE_PerfMeasure(a,b) a##b
|
||||
#define __LABEL_PerfMeasure(a) __MERGE_PerfMeasure(unique_name_, a)
|
||||
|
||||
/// Declare a new variable for measuring the performance of the current block
|
||||
#define PerfMeasure(name) \
|
||||
auto __LABEL_PerfMeasure(__LINE__) = \
|
||||
openspace::performance::PerformanceMeasurement((name))
|
||||
|
||||
} // namespace openspace::performance
|
||||
|
||||
#endif // __OPENSPACE_CORE___PERFORMANCEMEASUREMENT___H__
|
||||
#endif // __OPENSPACE_UI_LAUNCHER___META___H__
|
||||
95
apps/OpenSpace/ext/launcher/include/profile/modulesdialog.h
Normal file
95
apps/OpenSpace/ext/launcher/include/profile/modulesdialog.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2020 *
|
||||
* *
|
||||
* 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 *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_UI_LAUNCHER___MODULES___H__
|
||||
#define __OPENSPACE_UI_LAUNCHER___MODULES___H__
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include <openspace/scene/profile.h>
|
||||
|
||||
class QDialogButtonBox;
|
||||
class QLabel;
|
||||
class QLineEdit;
|
||||
class QListWidget;
|
||||
class QPushButton;
|
||||
|
||||
class ModulesDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Constructor for osmodules class
|
||||
*
|
||||
* \param profile The #openspace::Profile object containing all data of the
|
||||
* new or imported profile.
|
||||
* \param parent Pointer to parent Qt widget
|
||||
*/
|
||||
ModulesDialog(openspace::Profile& profile, QWidget* parent);
|
||||
|
||||
/**
|
||||
* Handles keypress while the Qt dialog window is open
|
||||
*
|
||||
* \param evt #QKeyEvent object for the key press event
|
||||
*/
|
||||
void keyPressEvent(QKeyEvent* evt);
|
||||
|
||||
private slots:
|
||||
void listItemSelected();
|
||||
void listItemAdded();
|
||||
void listItemRemove();
|
||||
void listItemSave();
|
||||
void listItemCancelSave();
|
||||
void transitionToEditMode();
|
||||
void parseSelections();
|
||||
|
||||
private:
|
||||
void createWidgets();
|
||||
|
||||
QString createOneLineSummary(openspace::Profile::Module m);
|
||||
void transitionFromEditMode();
|
||||
void editBoxDisabled(bool disabled);
|
||||
bool isLineEmpty(int index) const;
|
||||
|
||||
openspace::Profile& _profile;
|
||||
std::vector<openspace::Profile::Module> _data;
|
||||
bool _editModeNewItem = false;
|
||||
|
||||
QListWidget* _list = nullptr;
|
||||
QLabel* _moduleLabel = nullptr;
|
||||
QLineEdit* _moduleEdit = nullptr;
|
||||
QLabel* _loadedLabel = nullptr;
|
||||
QLineEdit* _loadedEdit = nullptr;
|
||||
QLabel* _notLoadedLabel = nullptr;
|
||||
QLineEdit* _notLoadedEdit = nullptr;
|
||||
|
||||
QPushButton* _buttonAdd = nullptr;
|
||||
QPushButton* _buttonRemove = nullptr;
|
||||
QPushButton* _buttonSave = nullptr;
|
||||
QPushButton* _buttonCancel = nullptr;
|
||||
QDialogButtonBox* _buttonBox = nullptr;
|
||||
|
||||
QLabel* _errorMsg = nullptr;
|
||||
};
|
||||
|
||||
#endif // __OPENSPACE_UI_LAUNCHER___MODULES___H__
|
||||
123
apps/OpenSpace/ext/launcher/include/profile/profileedit.h
Normal file
123
apps/OpenSpace/ext/launcher/include/profile/profileedit.h
Normal file
@@ -0,0 +1,123 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2020 *
|
||||
* *
|
||||
* 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 *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_UI_LAUNCHER___PROFILEEDIT___H__
|
||||
#define __OPENSPACE_UI_LAUNCHER___PROFILEEDIT___H__
|
||||
|
||||
#include <QDialog>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace openspace { class Profile; }
|
||||
|
||||
class QWidget;
|
||||
class QLabel;
|
||||
class QLineEdit;
|
||||
class QTextEdit;
|
||||
|
||||
class ProfileEdit : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Constructor for ProfileEdit class
|
||||
*
|
||||
* \param profile The #openspace::Profile object containing all data of the
|
||||
* new or imported profile.
|
||||
* \param profileName The name of the profile to create
|
||||
* \param assetBasePath The path to the folder where the 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 parent Pointer to parent Qt widget
|
||||
*/
|
||||
ProfileEdit(openspace::Profile& profile, const std::string& profileName,
|
||||
std::string assetBasePath, std::string profileBasePath,
|
||||
const std::vector<std::string>& profilesReadOnly, QWidget* parent);
|
||||
|
||||
/**
|
||||
* Gets the status of the save when the window is closed; was the file saved?
|
||||
*
|
||||
* \return true if the file was saved (false if cancel)
|
||||
*/
|
||||
bool wasSaved() const;
|
||||
|
||||
/**
|
||||
* Gets the profile name from the top save/edit window. This can be changed by user in
|
||||
* order to save to a different file.
|
||||
*
|
||||
* \return the profile name
|
||||
*/
|
||||
std::string specifiedFilename() const;
|
||||
|
||||
/**
|
||||
* Handles keypress while the Qt dialog window is open
|
||||
*
|
||||
* \param evt #QKeyEvent object for the key press event
|
||||
*/
|
||||
void keyPressEvent(QKeyEvent* evt);
|
||||
|
||||
private slots:
|
||||
void duplicateProfile();
|
||||
void openMeta();
|
||||
void openProperties();
|
||||
void openModules();
|
||||
void openKeybindings();
|
||||
void openAssets();
|
||||
void openTime();
|
||||
void openAddedScripts();
|
||||
void openDeltaTimes();
|
||||
void openCamera();
|
||||
void openMarkNodes();
|
||||
void cancel();
|
||||
void approved();
|
||||
|
||||
private:
|
||||
void createWidgets(const std::string& profileName);
|
||||
void initSummaryTextForEachCategory();
|
||||
|
||||
openspace::Profile& _profile;
|
||||
const std::string _assetBasePath;
|
||||
const std::string _profileBasePath;
|
||||
bool _saveSelected = false;
|
||||
const std::vector<std::string>& _readOnlyProfiles;
|
||||
|
||||
QLineEdit* _profileEdit = nullptr;
|
||||
QLabel* _modulesLabel = nullptr;
|
||||
QLabel* _assetsLabel = nullptr;
|
||||
QTextEdit* _assetsEdit = nullptr;
|
||||
QLabel* _propertiesLabel = nullptr;
|
||||
QTextEdit* _propertiesEdit = nullptr;
|
||||
QLabel* _keybindingsLabel = nullptr;
|
||||
QTextEdit* _keybindingsEdit = nullptr;
|
||||
QLabel* _deltaTimesLabel = nullptr;
|
||||
QLabel* _interestingNodesLabel = nullptr;
|
||||
QLabel* _cameraLabel = nullptr;
|
||||
QLabel* _timeLabel = nullptr;
|
||||
QLabel* _metaLabel = nullptr;
|
||||
QLabel* _additionalScriptsLabel = nullptr;
|
||||
|
||||
QLabel* _errorMsg = nullptr;
|
||||
};
|
||||
|
||||
#endif // __OPENSPACE_UI_LAUNCHER___PROFILEEDIT___H__
|
||||
@@ -0,0 +1,96 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2020 *
|
||||
* *
|
||||
* 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 *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_UI_LAUNCHER___PROPERTIES___H__
|
||||
#define __OPENSPACE_UI_LAUNCHER___PROPERTIES___H__
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include <openspace/scene/profile.h>
|
||||
|
||||
class QComboBox;
|
||||
class QDialogButtonBox;
|
||||
class QLabel;
|
||||
class QLineEdit;
|
||||
class QListWidget;
|
||||
class QPushButton;
|
||||
|
||||
class PropertiesDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Constructor for properties class
|
||||
*
|
||||
* \param profile The #openspace::Profile object containing all data of the
|
||||
* new or imported profile.
|
||||
* \param parent Pointer to parent Qt widget
|
||||
*/
|
||||
PropertiesDialog(openspace::Profile& profile, QWidget* parent);
|
||||
|
||||
/**
|
||||
* Handles keypress while the Qt dialog window is open
|
||||
*
|
||||
* \param evt #QKeyEvent object for the key press event
|
||||
*/
|
||||
void keyPressEvent(QKeyEvent* evt);
|
||||
|
||||
private slots:
|
||||
void listItemSelected();
|
||||
void listItemAdded();
|
||||
void listItemRemove();
|
||||
void listItemSave();
|
||||
void listItemCancelSave();
|
||||
void transitionToEditMode();
|
||||
void parseSelections();
|
||||
|
||||
private:
|
||||
void createWidgets();
|
||||
|
||||
QString createOneLineSummary(openspace::Profile::Property p);
|
||||
void transitionFromEditMode();
|
||||
void editBoxDisabled(bool disabled);
|
||||
bool areRequiredFormsFilled();
|
||||
bool isLineEmpty(int index);
|
||||
|
||||
openspace::Profile& _profile;
|
||||
std::vector<openspace::Profile::Property> _data;
|
||||
bool _editModeNewItem = false;
|
||||
|
||||
QListWidget* _list = nullptr;
|
||||
QPushButton* _addButton = nullptr;
|
||||
QPushButton* _removeButton = nullptr;
|
||||
QLabel* _commandLabel = nullptr;
|
||||
QComboBox* _commandCombo = nullptr;
|
||||
QLabel* _propertyLabel = nullptr;
|
||||
QLineEdit* _propertyEdit = nullptr;
|
||||
QLabel* _valueLabel = nullptr;
|
||||
QLineEdit* _valueEdit = nullptr;
|
||||
QPushButton* _saveButton = nullptr;
|
||||
QPushButton* _cancelButton = nullptr;
|
||||
QDialogButtonBox* _buttonBox = nullptr;
|
||||
|
||||
QLabel* _errorMsg = nullptr;
|
||||
};
|
||||
|
||||
#endif // __OPENSPACE_UI_LAUNCHER___PROPERTIES___H__
|
||||
68
apps/OpenSpace/ext/launcher/include/profile/timedialog.h
Normal file
68
apps/OpenSpace/ext/launcher/include/profile/timedialog.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2020 *
|
||||
* *
|
||||
* 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 *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_UI_LAUNCHER___OSTIME___H__
|
||||
#define __OPENSPACE_UI_LAUNCHER___OSTIME___H__
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include <openspace/scene/profile.h>
|
||||
|
||||
class QComboBox;
|
||||
class QDateTimeEdit;
|
||||
class QLabel;
|
||||
class QLineEdit;
|
||||
|
||||
class TimeDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Constructor for ostime class
|
||||
*
|
||||
* \param profile The #openspace::Profile object containing all data of the
|
||||
* new or imported profile.
|
||||
* \param parent Pointer to parent Qt widget
|
||||
*/
|
||||
TimeDialog(openspace::Profile& profile, QWidget* parent);
|
||||
|
||||
private slots:
|
||||
void enableAccordingToType(int);
|
||||
void approved();
|
||||
|
||||
private:
|
||||
void createWidgets();
|
||||
void enableFormatForAbsolute(bool enableAbs);
|
||||
|
||||
openspace::Profile& _profile;
|
||||
openspace::Profile::Time _data;
|
||||
bool _initializedAsAbsolute = true;
|
||||
|
||||
QComboBox* _typeCombo = nullptr;
|
||||
QLabel* _absoluteLabel = nullptr;
|
||||
QDateTimeEdit* _absoluteEdit = nullptr;
|
||||
QLabel* _relativeLabel = nullptr;
|
||||
QLineEdit* _relativeEdit = nullptr;
|
||||
};
|
||||
|
||||
#endif // __OPENSPACE_UI_LAUNCHER___OSTIME___H__
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 145 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 8.6 KiB |
139
apps/OpenSpace/ext/launcher/resources/qss/launcher.qss
Normal file
139
apps/OpenSpace/ext/launcher/resources/qss/launcher.qss
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* General settings
|
||||
*/
|
||||
* {
|
||||
font-family: Segoe UI;
|
||||
}
|
||||
|
||||
QLabel#heading {
|
||||
font-size: 12pt;
|
||||
}
|
||||
|
||||
QLabel#error-message {
|
||||
color: rgb(221, 17, 17);
|
||||
}
|
||||
|
||||
/*
|
||||
* LauncherWindow
|
||||
*/
|
||||
LauncherWindow QLabel {
|
||||
font-family: Segoe UI;
|
||||
font-weight:600;
|
||||
}
|
||||
|
||||
LauncherWindow QLabel#label_choose, QLabel#label_options {
|
||||
color: #ddd;
|
||||
font-size:10pt;
|
||||
}
|
||||
|
||||
LauncherWindow QLabel#clear {
|
||||
background-color: rgba(0, 0, 0, 0%);
|
||||
}
|
||||
|
||||
LauncherWindow QComboBox#config {
|
||||
background: rgb(96, 96, 96);
|
||||
border: 1px solid rgb(128, 128, 128);
|
||||
border-radius: 3px;
|
||||
border-color: rgb(225, 225, 225);
|
||||
padding: 1px 18px 1px 3px;
|
||||
min-width: 6em;
|
||||
font-size: 10pt;
|
||||
font-family: Segoe UI;
|
||||
font-weight: bold;
|
||||
color: rgb(255, 255, 255);
|
||||
}
|
||||
|
||||
LauncherWindow QComboBox#config:hover {
|
||||
background: rgb(120, 120, 120);
|
||||
}
|
||||
|
||||
LauncherWindow QComboBox#config:disabled {
|
||||
background: rgb(175, 175, 175);
|
||||
color: rgb(225, 225, 225);
|
||||
}
|
||||
|
||||
LauncherWindow QPushButton#large {
|
||||
background: rgb(128, 128, 128);
|
||||
border-radius: 2px;
|
||||
border-style: outset;
|
||||
border-width: 2px;
|
||||
border-color: rgb(225, 225, 225);
|
||||
font-size: 16pt;
|
||||
font-weight: bold;
|
||||
color: rgb(239, 239, 239);
|
||||
}
|
||||
LauncherWindow QPushButton#large:hover {
|
||||
background: rgb(150, 150, 150);
|
||||
}
|
||||
|
||||
LauncherWindow QPushButton#small {
|
||||
background: rgb(96, 96, 96);
|
||||
border-radius: 2px;
|
||||
border-style: outset;
|
||||
border-width: 1px;
|
||||
border-color: rgb(225, 225, 225);
|
||||
min-height: 1em;
|
||||
font-size: 10pt;
|
||||
font-weight: bold;
|
||||
color: rgb(255, 255, 255);
|
||||
}
|
||||
|
||||
LauncherWindow QPushButton#small:hover {
|
||||
background: rgb(120, 120, 120);
|
||||
}
|
||||
|
||||
/*
|
||||
* ProfileEdit
|
||||
*/
|
||||
ProfileEdit QTextEdit {
|
||||
min-width: 30em;
|
||||
}
|
||||
|
||||
ProfileEdit QLabel#profile {
|
||||
font-size: 10pt;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
ProfileEdit QLabel#heading {
|
||||
font-size: 10pt;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
ProfileEdit QLabel#error-message {
|
||||
min-width: 10em;
|
||||
}
|
||||
|
||||
/*
|
||||
* Properties
|
||||
*/
|
||||
PropertiesDialog QListWidget {
|
||||
min-width: 40em;
|
||||
}
|
||||
|
||||
/*
|
||||
* Assets
|
||||
*/
|
||||
AssetsDialog QTreeView {
|
||||
min-width: 40em;
|
||||
}
|
||||
|
||||
/*
|
||||
* Keybindings
|
||||
*/
|
||||
KeybindingsDialog QListWidget {
|
||||
min-width: 40em;
|
||||
}
|
||||
|
||||
/*
|
||||
* DeltaTimes
|
||||
*/
|
||||
DeltaTimesDialog QListWidget {
|
||||
min-width: 40em;
|
||||
}
|
||||
|
||||
/*
|
||||
* Camera
|
||||
*/
|
||||
CameraDialog QLabel#error-message {
|
||||
min-width: 10em;
|
||||
}
|
||||
7
apps/OpenSpace/ext/launcher/resources/resources.qrc
Normal file
7
apps/OpenSpace/ext/launcher/resources/resources.qrc
Normal file
@@ -0,0 +1,7 @@
|
||||
<!DOCTYPE RCC><RCC version="1.0">
|
||||
<qresource>
|
||||
<file>qss/launcher.qss</file>
|
||||
<file>images/openspace-horiz-logo-small.png</file>
|
||||
<file>images/launcher-background.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
121
apps/OpenSpace/ext/launcher/src/filesystemaccess.cpp
Normal file
121
apps/OpenSpace/ext/launcher/src/filesystemaccess.cpp
Normal file
@@ -0,0 +1,121 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2020 *
|
||||
* *
|
||||
* 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 *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include "filesystemaccess.h"
|
||||
|
||||
FileSystemAccess::FileSystemAccess(std::string fileExtension,
|
||||
std::vector<std::string> approvedPaths,
|
||||
bool hideFileExtensions, bool useCheckboxes)
|
||||
: _fileExtension(std::move(fileExtension))
|
||||
, _approvedPaths(std::move(approvedPaths))
|
||||
, _hideFileExtensions(hideFileExtensions)
|
||||
, _useCheckboxes(useCheckboxes)
|
||||
{}
|
||||
|
||||
std::string FileSystemAccess::useQtFileSystemModelToTraverseDir(std::string dir) {
|
||||
_filesystemModel.setRootPath(QString::fromStdString(dir));
|
||||
QModelIndex index = _filesystemModel.index(_filesystemModel.rootPath());
|
||||
QFileInfo fileInfo = _filesystemModel.fileInfo(index);
|
||||
std::vector<std::string> dirsNested;
|
||||
std::vector<std::string> out;
|
||||
parseChildDirElements(fileInfo, "", 0, dirsNested, out);
|
||||
std::string combined;
|
||||
for (const std::string& o : out) {
|
||||
combined += o + "\n";
|
||||
}
|
||||
return combined;
|
||||
}
|
||||
|
||||
void FileSystemAccess::parseChildDirElements(QFileInfo fileInfo, std::string space,
|
||||
int level, std::vector<std::string>& dirNames,
|
||||
std::vector<std::string>& output)
|
||||
{
|
||||
QDir dir(fileInfo.filePath());
|
||||
bool hasDirHeaderBeenAdded = false;
|
||||
|
||||
QFileInfoList fileList = dir.entryInfoList(_fileFilterOptions);
|
||||
for (int i = 0; i < fileList.size(); i++) {
|
||||
QFileInfo fileInfo = fileList[i];
|
||||
std::string res = space + fileInfo.fileName().toStdString();
|
||||
|
||||
if (fileInfo.isDir()) {
|
||||
if (level != 0 || (level == 0 && isApprovedPath(res))) {
|
||||
dirNames.push_back(res);
|
||||
parseChildDirElements(fileInfo, (space + " "), level + 1, dirNames,
|
||||
output);
|
||||
}
|
||||
}
|
||||
else {
|
||||
parseChildFile(res, hasDirHeaderBeenAdded, dirNames, output);
|
||||
}
|
||||
}
|
||||
bool isThisDirAnEmptyDeadEnd = !hasDirHeaderBeenAdded;
|
||||
if (isThisDirAnEmptyDeadEnd && (dirNames.size() != 0)) {
|
||||
dirNames.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
bool FileSystemAccess::isApprovedPath(std::string path) {
|
||||
bool approvedMatch = false;
|
||||
path.erase(0, path.find_first_not_of(" "));
|
||||
|
||||
for (const std::string& p : _approvedPaths) {
|
||||
if (path.substr(0, p.length()).compare(p) == 0) {
|
||||
approvedMatch = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return approvedMatch;
|
||||
}
|
||||
|
||||
void FileSystemAccess::parseChildFile(std::string filename, bool& hasDirHeaderBeenAdded,
|
||||
std::vector<std::string>& dirNames,
|
||||
std::vector<std::string>& output)
|
||||
{
|
||||
std::string cbox = (_useCheckboxes) ? "0" : "";
|
||||
if (filename.length() <= _fileExtension.length()) {
|
||||
return;
|
||||
}
|
||||
else {
|
||||
std::string extension = filename.substr(filename.length()
|
||||
- _fileExtension.length());
|
||||
if (extension.compare(_fileExtension) != 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasDirHeaderBeenAdded) {
|
||||
for (const std::string& d : dirNames) {
|
||||
if (d.length() > 0) {
|
||||
output.push_back(cbox + d);
|
||||
}
|
||||
}
|
||||
dirNames.clear();
|
||||
hasDirHeaderBeenAdded = true;
|
||||
}
|
||||
if (_hideFileExtensions) {
|
||||
filename = filename.substr(0, filename.length() - _fileExtension.length());
|
||||
}
|
||||
output.push_back(cbox + filename);
|
||||
}
|
||||
386
apps/OpenSpace/ext/launcher/src/launcherwindow.cpp
Normal file
386
apps/OpenSpace/ext/launcher/src/launcherwindow.cpp
Normal file
@@ -0,0 +1,386 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2020 *
|
||||
* *
|
||||
* 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 *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include "launcherwindow.h"
|
||||
|
||||
#include "profile/profileedit.h"
|
||||
|
||||
#include <openspace/engine/configuration.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <QComboBox>
|
||||
#include <QFile>
|
||||
#include <QLabel>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
|
||||
using namespace openspace;
|
||||
|
||||
namespace {
|
||||
constexpr const int ScreenWidth = 480;
|
||||
constexpr const 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;
|
||||
|
||||
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 const QRect OptionsLabel(LeftRuler, TopRuler + 180, 151, 24);
|
||||
constexpr const QRect WindowConfigBox(
|
||||
LeftRuler, TopRuler + 210, ItemWidth, ItemHeight
|
||||
);
|
||||
constexpr const QRect StartButton(
|
||||
LeftRuler, TopRuler + 290, ItemWidth, ItemHeight
|
||||
);
|
||||
constexpr const QRect NewButton(
|
||||
LeftRuler + 140, TopRuler + 380, SmallItemWidth, SmallItemHeight
|
||||
);
|
||||
constexpr const QRect EditButton(
|
||||
LeftRuler, TopRuler + 380, SmallItemWidth, SmallItemHeight
|
||||
);
|
||||
} // geometry
|
||||
|
||||
std::optional<Profile> loadProfileFromFile(QWidget* parent, std::string filename) {
|
||||
std::ifstream inFile;
|
||||
try {
|
||||
inFile.open(filename, std::ifstream::in);
|
||||
}
|
||||
catch (const std::ifstream::failure& e) {
|
||||
throw ghoul::RuntimeError(fmt::format(
|
||||
"Exception opening {} profile for read: {}", filename, e.what()
|
||||
));
|
||||
}
|
||||
std::string content;
|
||||
std::string line;
|
||||
while (std::getline(inFile, line)) {
|
||||
content += line;
|
||||
}
|
||||
try {
|
||||
return Profile(content);
|
||||
}
|
||||
catch (const Profile::ParsingError& e) {
|
||||
QMessageBox::critical(
|
||||
parent,
|
||||
"Exception",
|
||||
QString::fromStdString(fmt::format(
|
||||
"ParsingError exception in {}: {}, {}",
|
||||
filename, e.component, e.message
|
||||
))
|
||||
);
|
||||
return std::nullopt;
|
||||
}
|
||||
catch (const ghoul::RuntimeError& e) {
|
||||
QMessageBox::critical(
|
||||
parent,
|
||||
"Exception",
|
||||
QString::fromStdString(fmt::format(
|
||||
"RuntimeError exception in {}, component {}: {}",
|
||||
filename, e.component, e.message
|
||||
))
|
||||
);
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
void saveProfile(QWidget* parent, const std::string& path, const Profile& p) {
|
||||
std::ofstream outFile;
|
||||
try {
|
||||
outFile.open(path, std::ofstream::out);
|
||||
outFile << p.serialize();
|
||||
}
|
||||
catch (const std::ofstream::failure& e) {
|
||||
QMessageBox::critical(
|
||||
parent,
|
||||
"Exception",
|
||||
QString::fromStdString(fmt::format(
|
||||
"Error writing data to file: {} ({})", path, e.what()
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
using namespace openspace;
|
||||
|
||||
LauncherWindow::LauncherWindow(bool profileEnabled,
|
||||
const configuration::Configuration& globalConfig,
|
||||
bool sgctConfigEnabled, std::string sgctConfigName,
|
||||
QWidget* parent)
|
||||
: QMainWindow(parent)
|
||||
, _assetPath(absPath(globalConfig.pathTokens.at("ASSETS")) + '/')
|
||||
, _configPath(absPath(globalConfig.pathTokens.at("CONFIG")) + '/')
|
||||
, _profilePath(absPath(globalConfig.pathTokens.at("PROFILES")) + '/')
|
||||
, _readOnlyProfiles(globalConfig.readOnlyProfiles)
|
||||
{
|
||||
Q_INIT_RESOURCE(resources);
|
||||
|
||||
qInstallMessageHandler(
|
||||
[](QtMsgType type, const QMessageLogContext&, const QString& msg) {
|
||||
if (type == QtCriticalMsg || type == QtFatalMsg || type == QtSystemMsg) {
|
||||
std::cerr << msg.toStdString() << std::endl;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
setWindowTitle("OpenSpace Launcher");
|
||||
setFixedSize(ScreenWidth, ScreenHeight);
|
||||
setAutoFillBackground(false);
|
||||
|
||||
{
|
||||
QFile file(":/qss/launcher.qss");
|
||||
file.open(QFile::ReadOnly);
|
||||
QString styleSheet = QLatin1String(file.readAll());
|
||||
setStyleSheet(styleSheet);
|
||||
}
|
||||
|
||||
setCentralWidget(createCentralWidget());
|
||||
|
||||
|
||||
populateProfilesList(globalConfig.profile);
|
||||
_profileBox->setEnabled(profileEnabled);
|
||||
|
||||
populateWindowConfigsList(sgctConfigName);
|
||||
_windowConfigBox->setEnabled(sgctConfigEnabled);
|
||||
|
||||
|
||||
std::string p = absPath(globalConfig.pathTokens.at("SYNC") + "/http/launcher_images");
|
||||
if (std::filesystem::exists(p)) {
|
||||
try {
|
||||
setBackgroundImage(p);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
std::cerr << "Error occurrred while reading background images: " << e.what();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QWidget* LauncherWindow::createCentralWidget() {
|
||||
QWidget* centralWidget = new QWidget;
|
||||
|
||||
_backgroundImage = new QLabel(centralWidget);
|
||||
_backgroundImage->setGeometry(geometry::BackgroundImage);
|
||||
_backgroundImage->setPixmap(QPixmap(":/images/launcher-background.png"));
|
||||
|
||||
QLabel* logoImage = new QLabel(centralWidget);
|
||||
logoImage->setObjectName("clear");
|
||||
logoImage->setGeometry(geometry::LogoImage);
|
||||
logoImage->setPixmap(QPixmap(":/images/openspace-horiz-logo-small.png"));
|
||||
|
||||
QLabel* labelChoose = new QLabel("Choose Profile", centralWidget);
|
||||
labelChoose->setObjectName("clear");
|
||||
labelChoose->setGeometry(geometry::ChooseLabel);
|
||||
labelChoose->setObjectName("label_choose");
|
||||
|
||||
_profileBox = new QComboBox(centralWidget);
|
||||
_profileBox->setObjectName("config");
|
||||
_profileBox->setGeometry(geometry::ProfileBox);
|
||||
|
||||
QLabel* optionsLabel = new QLabel("Window Options", centralWidget);
|
||||
optionsLabel->setObjectName("clear");
|
||||
optionsLabel->setGeometry(geometry::OptionsLabel);
|
||||
optionsLabel->setObjectName("label_options");
|
||||
|
||||
_windowConfigBox = new QComboBox(centralWidget);
|
||||
_windowConfigBox->setObjectName("config");
|
||||
_windowConfigBox->setGeometry(geometry::WindowConfigBox);
|
||||
|
||||
QPushButton* startButton = new QPushButton("START", centralWidget);
|
||||
connect(
|
||||
startButton, &QPushButton::released,
|
||||
[this]() {
|
||||
_shouldLaunch = true;
|
||||
close();
|
||||
}
|
||||
);
|
||||
startButton->setObjectName("large");
|
||||
startButton->setGeometry(geometry::StartButton);
|
||||
startButton->setCursor(Qt::PointingHandCursor);
|
||||
|
||||
QPushButton* newButton = new QPushButton("New", centralWidget);
|
||||
connect(
|
||||
newButton, &QPushButton::released,
|
||||
[this]() {
|
||||
openProfileEditor("");
|
||||
}
|
||||
);
|
||||
newButton->setObjectName("small");
|
||||
newButton->setGeometry(geometry::NewButton);
|
||||
newButton->setCursor(Qt::PointingHandCursor);
|
||||
|
||||
QPushButton* editButton = new QPushButton("Edit", centralWidget);
|
||||
connect(
|
||||
editButton, &QPushButton::released,
|
||||
[this]() {
|
||||
const std::string selection = _profileBox->currentText().toStdString();
|
||||
openProfileEditor(selection);
|
||||
}
|
||||
);
|
||||
editButton->setObjectName("small");
|
||||
editButton->setGeometry(geometry::EditButton);
|
||||
editButton->setCursor(Qt::PointingHandCursor);
|
||||
|
||||
return centralWidget;
|
||||
}
|
||||
|
||||
void LauncherWindow::setBackgroundImage(const std::string& syncPath) {
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
// First, we iterate through all folders in the launcher_images sync folder and we get
|
||||
// the folder with the highest number
|
||||
struct {
|
||||
fs::directory_entry path;
|
||||
int version = -1;
|
||||
} latest;
|
||||
for (const fs::directory_entry& p : fs::directory_iterator(syncPath)) {
|
||||
if (!p.is_directory()) {
|
||||
continue;
|
||||
}
|
||||
const std::string versionStr = p.path().stem().string();
|
||||
// All folder names in the sync folder should only be a digit, so we should be
|
||||
// find to just convert it here
|
||||
const int version = std::stoi(versionStr);
|
||||
|
||||
if (version > latest.version) {
|
||||
latest.version = version;
|
||||
latest.path = p;
|
||||
}
|
||||
}
|
||||
|
||||
if (latest.version == -1) {
|
||||
// The sync folder existed, but nothing was in there. Kinda weird, but still
|
||||
return;
|
||||
}
|
||||
|
||||
// Now we know which folder to use, we will pick an image at random
|
||||
std::vector<std::string> files;
|
||||
for (const fs::directory_entry& p : fs::directory_iterator(latest.path)) {
|
||||
files.push_back(p.path().string());
|
||||
}
|
||||
std::random_device rd;
|
||||
std::mt19937 g(rd());
|
||||
std::shuffle(files.begin(), files.end(), g);
|
||||
// We know there has to be at least one folder, so it's fine to just pick the first
|
||||
std::string image = files.front();
|
||||
_backgroundImage->setPixmap(QPixmap(QString::fromStdString(image)));
|
||||
}
|
||||
|
||||
void LauncherWindow::populateProfilesList(std::string preset) {
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
_profileBox->clear();
|
||||
|
||||
// Add all the files with the .profile extension to the dropdown
|
||||
for (const fs::directory_entry& p : fs::directory_iterator(_profilePath)) {
|
||||
if (p.path().extension() != ".profile") {
|
||||
continue;
|
||||
}
|
||||
_profileBox->addItem(QString::fromStdString(p.path().stem().string()));
|
||||
}
|
||||
|
||||
// Try to find the requested profile and set it as the current one
|
||||
const int idx = _profileBox->findText(QString::fromStdString(std::move(preset)));
|
||||
if (idx != -1) {
|
||||
_profileBox->setCurrentIndex(idx);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void LauncherWindow::populateWindowConfigsList(std::string preset) {
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
_windowConfigBox->clear();
|
||||
// Add all the files with the .xml extension to the dropdown
|
||||
for (const fs::directory_entry& p : fs::directory_iterator(_configPath)) {
|
||||
if (p.path().extension() != ".xml") {
|
||||
continue;
|
||||
}
|
||||
_windowConfigBox->addItem(QString::fromStdString(p.path().stem().string()));
|
||||
}
|
||||
|
||||
// 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
|
||||
const int idx = _windowConfigBox->findText(QString::fromStdString(std::move(preset)));
|
||||
if (idx != -1) {
|
||||
_windowConfigBox->setCurrentIndex(idx);
|
||||
}
|
||||
else {
|
||||
// Add the requested preset at the top
|
||||
_windowConfigBox->insertItem(0, QString::fromStdString(preset));
|
||||
_windowConfigBox->setCurrentIndex(0);
|
||||
}
|
||||
}
|
||||
|
||||
void LauncherWindow::openProfileEditor(const std::string& profile) {
|
||||
std::optional<Profile> p;
|
||||
if (profile.empty()) {
|
||||
// If the requested profile is the empty string, then we want to create a new one
|
||||
|
||||
p = Profile();
|
||||
}
|
||||
else {
|
||||
// Otherwise, we want to load that profile
|
||||
|
||||
std::string fullProfilePath = _profilePath + profile + ".profile";
|
||||
p = loadProfileFromFile(this, fullProfilePath);
|
||||
if (!p.has_value()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ProfileEdit editor(*p, profile, _assetPath, _profilePath, _readOnlyProfiles, this);
|
||||
editor.exec();
|
||||
if (editor.wasSaved()) {
|
||||
const std::string path = _profilePath + editor.specifiedFilename() + ".profile";
|
||||
saveProfile(this, path, *p);
|
||||
populateProfilesList(editor.specifiedFilename());
|
||||
}
|
||||
else {
|
||||
const std::string current = _profileBox->currentText().toStdString();
|
||||
populateProfilesList(current);
|
||||
}
|
||||
}
|
||||
|
||||
bool LauncherWindow::wasLaunchSelected() const {
|
||||
return _shouldLaunch;
|
||||
}
|
||||
|
||||
std::string LauncherWindow::selectedProfile() const {
|
||||
return _profileBox->currentText().toStdString();
|
||||
}
|
||||
|
||||
std::string LauncherWindow::selectedWindowConfig() const {
|
||||
return _windowConfigBox->currentText().toStdString();
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2020 *
|
||||
* *
|
||||
* 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 *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include "profile/additionalscriptsdialog.h"
|
||||
|
||||
#include "profile/line.h"
|
||||
#include <openspace/scene/profile.h>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QTextEdit>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
AdditionalScriptsDialog::AdditionalScriptsDialog(openspace::Profile& profile,
|
||||
QWidget* parent)
|
||||
: QDialog(parent)
|
||||
, _profile(profile)
|
||||
{
|
||||
setWindowTitle("Additional Scripts");
|
||||
createWidgets();
|
||||
|
||||
std::vector<std::string> scripts = _profile.additionalScripts();
|
||||
std::string scriptText = std::accumulate(
|
||||
scripts.begin(), scripts.end(),
|
||||
std::string(), [](std::string lhs, std::string rhs) { return lhs + rhs + '\n'; }
|
||||
);
|
||||
_textScripts->setText(QString::fromStdString(std::move(scriptText)));
|
||||
_textScripts->moveCursor(QTextCursor::MoveOperation::End);
|
||||
}
|
||||
|
||||
void AdditionalScriptsDialog::createWidgets() {
|
||||
QBoxLayout* layout = new QVBoxLayout(this);
|
||||
{
|
||||
QLabel* heading = new QLabel("Additional Lua Scripts for Configuration");
|
||||
heading->setObjectName("heading");
|
||||
layout->addWidget(heading);
|
||||
}
|
||||
|
||||
_textScripts = new QTextEdit;
|
||||
_textScripts->setAcceptRichText(false);
|
||||
layout->addWidget(_textScripts, 1);
|
||||
|
||||
layout->addWidget(new Line);
|
||||
|
||||
{
|
||||
QDialogButtonBox* buttons = new QDialogButtonBox;
|
||||
buttons->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel);
|
||||
connect(
|
||||
buttons, &QDialogButtonBox::accepted,
|
||||
this, &AdditionalScriptsDialog::parseScript
|
||||
);
|
||||
connect(
|
||||
buttons, &QDialogButtonBox::rejected,
|
||||
this, &AdditionalScriptsDialog::reject
|
||||
);
|
||||
layout->addWidget(buttons);
|
||||
}
|
||||
}
|
||||
|
||||
void AdditionalScriptsDialog::parseScript() {
|
||||
std::vector<std::string> additionalScripts;
|
||||
std::istringstream iss(_textScripts->toPlainText().toStdString());
|
||||
while (!iss.eof()) {
|
||||
std::string s;
|
||||
std::getline(iss, s);
|
||||
additionalScripts.push_back(std::move(s));
|
||||
}
|
||||
_profile.setAdditionalScripts(additionalScripts);
|
||||
accept();
|
||||
}
|
||||
238
apps/OpenSpace/ext/launcher/src/profile/assetsdialog.cpp
Normal file
238
apps/OpenSpace/ext/launcher/src/profile/assetsdialog.cpp
Normal file
@@ -0,0 +1,238 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2020 *
|
||||
* *
|
||||
* 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 *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include "profile/assetsdialog.h"
|
||||
|
||||
#include "profile/line.h"
|
||||
#include <openspace/scene/profile.h>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QHeaderView>
|
||||
#include <QLabel>
|
||||
#include <QVBoxLayout>
|
||||
#include <QTextEdit>
|
||||
#include <QTreeView>
|
||||
|
||||
namespace {
|
||||
bool traverseToExpandSelectedItems(QTreeView& tree, AssetTreeModel& model,
|
||||
int rows, QModelIndex parent)
|
||||
{
|
||||
bool isExpanded = false;
|
||||
|
||||
for (int r = 0; r < rows; r++) {
|
||||
QModelIndex idx = model.index(r, 0, parent);
|
||||
|
||||
if (!model.isAsset(idx)) {
|
||||
int nChildRows = model.childCount(idx);
|
||||
if (traverseToExpandSelectedItems(tree, model, nChildRows, idx)) {
|
||||
tree.setExpanded(idx, true);
|
||||
isExpanded = true;
|
||||
}
|
||||
}
|
||||
else if (model.isChecked(idx) || !model.inFilesystem(idx)) {
|
||||
isExpanded = true;
|
||||
}
|
||||
}
|
||||
return isExpanded;
|
||||
}
|
||||
|
||||
void traverseToFindFilesystemMatch(AssetTreeModel& model, QModelIndex parent,
|
||||
int nRows, const std::string& path)
|
||||
{
|
||||
const size_t slash = path.find_first_of('/', 0);
|
||||
const bool endOfPath = (slash == std::string::npos);
|
||||
std::string firstDir = endOfPath ? "" : path.substr(0, slash);
|
||||
|
||||
if (!endOfPath) {
|
||||
std::string nextPath = (slash == std::string::npos) ?
|
||||
path :
|
||||
path.substr(slash + 1);
|
||||
bool foundDirMatch = false;
|
||||
for (int r = 0; r < nRows; r++) {
|
||||
QModelIndex idx = model.index(r, 0, parent);
|
||||
std::string assetName = model.name(idx).toStdString();
|
||||
if (!model.isAsset(idx)) {
|
||||
if (firstDir == assetName) {
|
||||
int nChildRows = model.childCount(idx);
|
||||
foundDirMatch = true;
|
||||
traverseToFindFilesystemMatch(model, idx, nChildRows, nextPath);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!foundDirMatch) {
|
||||
// Insert missing directory here with name and exists=false condition
|
||||
model.assetItem(parent)->insertChildren(nRows, 1, 3);
|
||||
QModelIndex idx = model.index(nRows, 0, parent);
|
||||
model.setName(idx, QString::fromStdString(firstDir));
|
||||
model.setExistenceInFilesystem(idx, false);
|
||||
traverseToFindFilesystemMatch(model, idx, 0, nextPath);
|
||||
}
|
||||
}
|
||||
else {
|
||||
bool foundFileMatch = false;
|
||||
for (int r = 0; r < nRows; r++) {
|
||||
QModelIndex idx = model.index(r, 0, parent);
|
||||
std::string assetName = model.name(idx).toStdString();
|
||||
|
||||
if (path == assetName) {
|
||||
foundFileMatch = true;
|
||||
model.setChecked(idx, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundFileMatch) {
|
||||
// Insert missing file here with name and exists=false condition
|
||||
model.assetItem(parent)->insertChildren(nRows, 1, 3);
|
||||
QModelIndex idx = model.index(nRows, 0, parent);
|
||||
model.setName(idx, QString::fromStdString(path));
|
||||
model.setChecked(idx, true);
|
||||
model.setExistenceInFilesystem(idx, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
AssetsDialog::AssetsDialog(openspace::Profile& profile, const std::string& assetBasePath,
|
||||
QWidget* parent)
|
||||
: QDialog(parent)
|
||||
, _profile(profile)
|
||||
{
|
||||
setWindowTitle("Assets");
|
||||
_assetTreeModel.importModelData(assetBasePath);
|
||||
createWidgets();
|
||||
}
|
||||
|
||||
void AssetsDialog::createWidgets() {
|
||||
QBoxLayout* layout = new QVBoxLayout(this);
|
||||
{
|
||||
QLabel* heading = new QLabel("Select assets from /data/assets");
|
||||
heading->setObjectName("heading");
|
||||
layout->addWidget(heading);
|
||||
}
|
||||
{
|
||||
_assetTree = new QTreeView;
|
||||
_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."
|
||||
);
|
||||
_assetTree->setAlternatingRowColors(true);
|
||||
_assetTree->setModel(&_assetTreeModel);
|
||||
_assetTree->setRootIndex(_assetTreeModel.index(-1, 0));
|
||||
_assetTree->setColumnWidth(1, 60);
|
||||
_assetTree->setColumnWidth(0, _assetTree->width() - 60);
|
||||
_assetTree->header()->setSectionResizeMode(0, QHeaderView::Stretch);
|
||||
_assetTree->header()->setSectionResizeMode(1, QHeaderView::Fixed);
|
||||
_assetTree->header()->setStretchLastSection(false);
|
||||
_assetTree->setAnimated(true);
|
||||
_assetTree->setSortingEnabled(false);
|
||||
_assetTree->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
connect(_assetTree, &QTreeView::clicked, this, &AssetsDialog::selected);
|
||||
|
||||
|
||||
for (const std::string& a : _profile.assets()) {
|
||||
QModelIndex parent = _assetTreeModel.index(-1, 0);
|
||||
int nRows = _assetTreeModel.rowCount(parent);
|
||||
traverseToFindFilesystemMatch(_assetTreeModel, parent, nRows, a);
|
||||
}
|
||||
|
||||
int nRows = _assetTreeModel.rowCount(_assetTreeModel.index(-1, 0));
|
||||
traverseToExpandSelectedItems(
|
||||
*_assetTree,
|
||||
_assetTreeModel,
|
||||
nRows,
|
||||
_assetTreeModel.index(-1, 0)
|
||||
);
|
||||
layout->addWidget(_assetTree);
|
||||
}
|
||||
{
|
||||
QLabel* summaryHeading = new QLabel("Selection summary");
|
||||
summaryHeading->setObjectName("heading");
|
||||
layout->addWidget(summaryHeading);
|
||||
}
|
||||
{
|
||||
_summary = new QTextEdit;
|
||||
_summary->setReadOnly(true);
|
||||
_summary->setText(createTextSummary());
|
||||
layout->addWidget(_summary);
|
||||
}
|
||||
|
||||
layout->addWidget(new Line);
|
||||
|
||||
{
|
||||
QDialogButtonBox* buttons = new QDialogButtonBox;
|
||||
buttons->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel);
|
||||
connect(
|
||||
buttons, &QDialogButtonBox::accepted,
|
||||
this, &AssetsDialog::parseSelections
|
||||
);
|
||||
connect(
|
||||
buttons, &QDialogButtonBox::rejected,
|
||||
this, &AssetsDialog::reject
|
||||
);
|
||||
layout->addWidget(buttons);
|
||||
}
|
||||
}
|
||||
|
||||
QString AssetsDialog::createTextSummary() {
|
||||
std::vector<std::string> summaryPaths;
|
||||
std::vector<AssetTreeItem*> summaryItems;
|
||||
_assetTreeModel.getSelectedAssets(summaryPaths, summaryItems);
|
||||
|
||||
if (summaryPaths.size() != summaryItems.size()) {
|
||||
return "";
|
||||
}
|
||||
QString summary;
|
||||
for (int i = 0; i < summaryItems.size(); ++i) {
|
||||
bool existsInFilesystem = summaryItems.at(i)->doesExistInFilesystem();
|
||||
|
||||
constexpr const char* ExistsFormat = "{}<br>";
|
||||
constexpr const char* NotExistsFormat = "<font color='{}'>{}</font><br>";
|
||||
|
||||
std::string s = existsInFilesystem ?
|
||||
fmt::format("{}<br>", summaryPaths.at(i)) :
|
||||
fmt::format("<font color='red'>{}</font><br>", summaryPaths.at(i));
|
||||
summary += QString::fromStdString(s);
|
||||
}
|
||||
return summary;
|
||||
}
|
||||
|
||||
void AssetsDialog::parseSelections() {
|
||||
_profile.clearAssets();
|
||||
std::vector<std::string> summaryPaths;
|
||||
std::vector<AssetTreeItem*> summaryItems;
|
||||
_assetTreeModel.getSelectedAssets(summaryPaths, summaryItems);
|
||||
|
||||
for (const std::string& sel : summaryPaths) {
|
||||
_profile.addAsset(sel);
|
||||
}
|
||||
accept();
|
||||
}
|
||||
|
||||
void AssetsDialog::selected(const QModelIndex& sel) {
|
||||
_summary->setText(createTextSummary());
|
||||
}
|
||||
163
apps/OpenSpace/ext/launcher/src/profile/assettreeitem.cpp
Normal file
163
apps/OpenSpace/ext/launcher/src/profile/assettreeitem.cpp
Normal file
@@ -0,0 +1,163 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2020 *
|
||||
* *
|
||||
* 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 *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include "profile/assettreeitem.h"
|
||||
|
||||
AssetTreeItem::AssetTreeItem(const std::vector<QVariant>& data, AssetTreeItem* parentItem)
|
||||
: _itemData(data)
|
||||
, _parentItem(parentItem)
|
||||
{}
|
||||
|
||||
AssetTreeItem::~AssetTreeItem() {
|
||||
for (AssetTreeItem* item : _childItems) {
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
|
||||
AssetTreeItem* AssetTreeItem::child(int row) {
|
||||
if (row < 0 || row >= static_cast<int>(_childItems.size())) {
|
||||
return nullptr;
|
||||
}
|
||||
else {
|
||||
return _childItems.at(row);
|
||||
}
|
||||
}
|
||||
|
||||
int AssetTreeItem::childCount() const {
|
||||
return static_cast<int>(_childItems.size());
|
||||
}
|
||||
|
||||
int AssetTreeItem::row() const {
|
||||
if (_parentItem) {
|
||||
const auto it = std::find(
|
||||
_parentItem->_childItems.cbegin(),
|
||||
_parentItem->_childItems.cend(),
|
||||
this
|
||||
);
|
||||
return std::distance(_parentItem->_childItems.cbegin(), it);
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int AssetTreeItem::columnCount() const {
|
||||
return _itemData.size();
|
||||
}
|
||||
|
||||
QVariant AssetTreeItem::data(int column) const {
|
||||
if (column < 0 || column >= _itemData.size()) {
|
||||
return QVariant();
|
||||
}
|
||||
else {
|
||||
return _itemData.at(column);
|
||||
}
|
||||
}
|
||||
|
||||
bool AssetTreeItem::setData(int column, const QVariant& value) {
|
||||
if (column < 0 || column >= _itemData.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_itemData[column] = value;
|
||||
if (column == CheckboxColumn) {
|
||||
_isChecked = value.toBool();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AssetTreeItem::isChecked() const {
|
||||
return _isChecked;
|
||||
}
|
||||
|
||||
void AssetTreeItem::setChecked(bool set) {
|
||||
_isChecked = set;
|
||||
}
|
||||
|
||||
bool AssetTreeItem::isAsset() const {
|
||||
return (childCount() == 0);
|
||||
}
|
||||
|
||||
bool AssetTreeItem::isCategory() const {
|
||||
return (childCount() > 0);
|
||||
}
|
||||
|
||||
void AssetTreeItem::setExistsInFilesystem(bool fileExists) {
|
||||
_fileExists = fileExists;
|
||||
}
|
||||
|
||||
bool AssetTreeItem::doesExistInFilesystem() const {
|
||||
return _fileExists;
|
||||
}
|
||||
|
||||
QString AssetTreeItem::name() const {
|
||||
return QString(data(0).toString());
|
||||
}
|
||||
|
||||
bool AssetTreeItem::insertChildren(int position, int count, int columns) {
|
||||
if (position < 0 || position > _childItems.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int row = 0; row < count; ++row) {
|
||||
std::vector<QVariant> data(columns);
|
||||
AssetTreeItem*item = new AssetTreeItem(data, this);
|
||||
_childItems.insert(_childItems.begin() + position, item);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AssetTreeItem::removeChildren(int position, int count) {
|
||||
if (position < 0 || position + count > _childItems.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int row = 0; row < count; ++row) {
|
||||
delete _childItems[position];
|
||||
_childItems.erase(_childItems.begin() + position);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AssetTreeItem::insertColumns(int position, int columns) {
|
||||
if (position < 0 || position > _itemData.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int column = 0; column < columns; ++column) {
|
||||
_itemData.insert(_itemData.begin() + position, QVariant());
|
||||
}
|
||||
|
||||
for (AssetTreeItem* child : qAsConst(_childItems)) {
|
||||
child->insertColumns(position, columns);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
AssetTreeItem* AssetTreeItem::parent() {
|
||||
return _parentItem;
|
||||
}
|
||||
351
apps/OpenSpace/ext/launcher/src/profile/assettreemodel.cpp
Normal file
351
apps/OpenSpace/ext/launcher/src/profile/assettreemodel.cpp
Normal file
@@ -0,0 +1,351 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2020 *
|
||||
* *
|
||||
* 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 *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include "profile/assettreeitem.h"
|
||||
#include "profile/assettreemodel.h"
|
||||
#include "filesystemaccess.h"
|
||||
#include <sstream>
|
||||
#include <QColor>
|
||||
|
||||
namespace {
|
||||
constexpr const char* Header1 = "Asset";
|
||||
constexpr const char* Header2 = "Enabled";
|
||||
|
||||
struct ImportElement {
|
||||
std::string line;
|
||||
int level = -1;
|
||||
bool checked = false;
|
||||
bool existsInFilesystem = true;
|
||||
};
|
||||
|
||||
int getLevelFromLine(std::string line) {
|
||||
int level = 0;
|
||||
for (unsigned int i = 0; i < line.length(); ++i) {
|
||||
if (line.substr(i, 1) == " ") {
|
||||
level++;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return level;
|
||||
}
|
||||
|
||||
void trimWhitespaceFromLine(std::string& line) {
|
||||
line.erase(0, line.find_first_not_of(" \t\n"));
|
||||
line.erase(line.find_last_not_of(" \t\n") + 1);
|
||||
}
|
||||
|
||||
bool importGetNextLine(ImportElement& elem, std::istringstream& iss) {
|
||||
std::getline(iss, elem.line);
|
||||
const bool ok = iss.good();
|
||||
if (!ok) {
|
||||
elem.line = "";
|
||||
elem.level = -1;
|
||||
}
|
||||
else {
|
||||
elem.checked = elem.line.substr(0, 1) != "0";
|
||||
elem.existsInFilesystem = elem.line.substr(0, 1) != "x";
|
||||
elem.line = elem.line.substr(1);
|
||||
elem.level = getLevelFromLine(elem.line);
|
||||
trimWhitespaceFromLine(elem.line);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
void importInsertItem(std::istringstream& iss, AssetTreeItem* parent,
|
||||
ImportElement& elem, int level)
|
||||
{
|
||||
int nChildInsert = -1;
|
||||
bool continueToNextLine = true;
|
||||
|
||||
while (continueToNextLine && elem.line.length() != 0) {
|
||||
int levelChange = elem.level - level;
|
||||
|
||||
if (levelChange == 0) {
|
||||
parent->insertChildren(++nChildInsert, 1, 3);
|
||||
parent->child(nChildInsert)->setData(0, QString::fromStdString(elem.line));
|
||||
bool shouldMakeElemChecked = (elem.checked || !elem.existsInFilesystem);
|
||||
Qt::CheckState check = (shouldMakeElemChecked) ? Qt::Checked : Qt::Unchecked;
|
||||
parent->child(nChildInsert)->setData(1, check);
|
||||
parent->child(nChildInsert)->setExistsInFilesystem(elem.existsInFilesystem);
|
||||
continueToNextLine = importGetNextLine(elem, iss);
|
||||
}
|
||||
else if (levelChange == 1) {
|
||||
importInsertItem(iss, parent->child(nChildInsert), elem, level + 1);
|
||||
}
|
||||
else if (levelChange < 0) {
|
||||
continueToNextLine = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void parseChildrenForSelected(AssetTreeItem* item,
|
||||
std::vector<std::string>& outputPaths,
|
||||
std::vector<AssetTreeItem*>& outputItems,
|
||||
std::string pathPrefix)
|
||||
{
|
||||
std::string itemName = item->data(0).toString().toStdString();
|
||||
bool isPathPrefix = ((pathPrefix.length()) == 0 && (itemName == Header1));
|
||||
|
||||
if (item->isAsset()) {
|
||||
if (item->isChecked()) {
|
||||
std::string path = pathPrefix + itemName;
|
||||
outputItems.push_back(item);
|
||||
outputPaths.push_back(path);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!isPathPrefix) {
|
||||
pathPrefix += itemName;
|
||||
pathPrefix += "/";
|
||||
}
|
||||
for (int i = 0; i < item->childCount(); ++i) {
|
||||
parseChildrenForSelected(
|
||||
item->child(i),
|
||||
outputPaths,
|
||||
outputItems,
|
||||
pathPrefix
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
AssetTreeModel::AssetTreeModel(QObject* parent)
|
||||
: QAbstractItemModel(parent)
|
||||
{
|
||||
_rootItem = std::make_unique<AssetTreeItem>(
|
||||
std::vector<QVariant>{
|
||||
QString::fromStdString(Header1), QString::fromStdString(Header2)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void AssetTreeModel::importModelData(const std::string& assetBasePath) {
|
||||
FileSystemAccess assets(
|
||||
".asset",
|
||||
{ "scene", "global", "customization", "examples", "util" },
|
||||
true,
|
||||
true
|
||||
);
|
||||
std::string assetList = assets.useQtFileSystemModelToTraverseDir(assetBasePath);
|
||||
|
||||
std::istringstream iss(assetList);
|
||||
ImportElement rootElem = { "", 0, false };
|
||||
|
||||
if (importGetNextLine(rootElem, iss)) {
|
||||
importInsertItem(iss, _rootItem.get(), rootElem, 0);
|
||||
}
|
||||
}
|
||||
|
||||
AssetTreeItem* AssetTreeModel::getItem(const QModelIndex& index) const {
|
||||
if (index.isValid()) {
|
||||
AssetTreeItem* item = static_cast<AssetTreeItem*>(index.internalPointer());
|
||||
if (item) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return _rootItem.get();
|
||||
}
|
||||
|
||||
bool AssetTreeModel::isChecked(QModelIndex& index) const {
|
||||
AssetTreeItem* item = getItem(index);
|
||||
const int isChecked = item->data(1).toInt();
|
||||
return isChecked == Qt::Checked;
|
||||
}
|
||||
|
||||
bool AssetTreeModel::isAsset(QModelIndex& index) const {
|
||||
AssetTreeItem* item = getItem(index);
|
||||
return item->isAsset();
|
||||
}
|
||||
|
||||
bool AssetTreeModel::inFilesystem(QModelIndex& index) const {
|
||||
AssetTreeItem* item = getItem(index);
|
||||
return item->doesExistInFilesystem();
|
||||
}
|
||||
|
||||
int AssetTreeModel::childCount(QModelIndex& index) const {
|
||||
return getItem(index)->childCount();
|
||||
}
|
||||
|
||||
QString AssetTreeModel::name(QModelIndex& index) const {
|
||||
return getItem(index)->name();
|
||||
}
|
||||
|
||||
void AssetTreeModel::setName(QModelIndex& index, QString name) {
|
||||
getItem(index)->setData(0, name);
|
||||
}
|
||||
|
||||
void AssetTreeModel::setChecked(QModelIndex& index, bool checked) {
|
||||
getItem(index)->setData(1, checked ? Qt::Checked : Qt::Unchecked);
|
||||
}
|
||||
|
||||
void AssetTreeModel::setExistenceInFilesystem(QModelIndex& index, bool fileExists) {
|
||||
getItem(index)->setExistsInFilesystem(fileExists);
|
||||
}
|
||||
|
||||
AssetTreeItem* AssetTreeModel::child(int row) const {
|
||||
QModelIndex i = index(row, 0);
|
||||
int nKids = childCount(i);
|
||||
if (row < nKids) {
|
||||
return getItem(i)->child(row);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QModelIndex AssetTreeModel::index(int row, int column, const QModelIndex& parent) const {
|
||||
if (parent.isValid() && parent.column() != 0) {
|
||||
return QModelIndex();
|
||||
}
|
||||
if (!hasIndex(row, column, parent)) {
|
||||
return QModelIndex();
|
||||
}
|
||||
AssetTreeItem* parentItem = getItem(parent);
|
||||
if (!parentItem) {
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
if (!parent.isValid()) {
|
||||
parentItem = _rootItem.get();
|
||||
}
|
||||
|
||||
AssetTreeItem* childItem = parentItem->child(row);
|
||||
if (childItem) {
|
||||
return createIndex(row, column, childItem);
|
||||
}
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
QModelIndex AssetTreeModel::parent(int row, int column, const QModelIndex& parent) const {
|
||||
QModelIndex idx = index(row, column, parent);
|
||||
return AssetTreeModel::parent(idx);
|
||||
}
|
||||
|
||||
QModelIndex AssetTreeModel::parent(const QModelIndex& index) const {
|
||||
if (!index.isValid()) {
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
AssetTreeItem* childItem = getItem(index);
|
||||
AssetTreeItem* parentItem = childItem ? childItem->parent() : nullptr;
|
||||
if (parentItem == _rootItem.get() || !parentItem) {
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
return createIndex(parentItem->row(), 0, parentItem);
|
||||
}
|
||||
|
||||
AssetTreeItem* AssetTreeModel::assetItem(const QModelIndex& index) {
|
||||
return getItem(index);
|
||||
}
|
||||
|
||||
int AssetTreeModel::rowCount(const QModelIndex& parent) const {
|
||||
const AssetTreeItem* parentItem = getItem(parent);
|
||||
return parentItem ? parentItem->childCount() : 0;
|
||||
}
|
||||
|
||||
int AssetTreeModel::columnCount(const QModelIndex&) const {
|
||||
return _rootItem->columnCount();
|
||||
}
|
||||
|
||||
QVariant AssetTreeModel::data(const QModelIndex& index, int role) const {
|
||||
if (!index.isValid()) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
AssetTreeItem* item = static_cast<AssetTreeItem*>(index.internalPointer());
|
||||
|
||||
if (index.column() == AssetTreeItem::CheckboxColumn) {
|
||||
if (item->isAsset() && (role == Qt::CheckStateRole)) {
|
||||
return static_cast<int>(item->isChecked() ? Qt::Checked : Qt::Unchecked);
|
||||
}
|
||||
else {
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
if (role == Qt::ForegroundRole) {
|
||||
if (item->doesExistInFilesystem()) {
|
||||
return QVariant(QColor(Qt::black));
|
||||
}
|
||||
else {
|
||||
return QVariant(QColor(Qt::red));
|
||||
}
|
||||
}
|
||||
else if (role == Qt::DisplayRole) {
|
||||
return item->data(index.column());
|
||||
}
|
||||
else {
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
bool AssetTreeModel::setData(const QModelIndex& index, const QVariant& value, int role) {
|
||||
bool setSuccess = false;
|
||||
|
||||
if (!index.isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AssetTreeItem* item = static_cast<AssetTreeItem*>(index.internalPointer());
|
||||
|
||||
if (role == Qt::CheckStateRole && index.column() == AssetTreeItem::CheckboxColumn) {
|
||||
setSuccess = item->setData(index.column(), value);
|
||||
}
|
||||
return setSuccess;
|
||||
}
|
||||
|
||||
Qt::ItemFlags AssetTreeModel::flags(const QModelIndex& index) const {
|
||||
if (!index.isValid()) {
|
||||
return Qt::NoItemFlags;
|
||||
}
|
||||
|
||||
Qt::ItemFlags flags = Qt::ItemIsEnabled;
|
||||
|
||||
if (index.column() == AssetTreeItem::CheckboxColumn) {
|
||||
flags |= Qt::ItemIsUserCheckable;
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
QVariant AssetTreeModel::headerData(int section, Qt::Orientation orientation,
|
||||
int role) const
|
||||
{
|
||||
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
|
||||
return _rootItem->data(section);
|
||||
}
|
||||
else {
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
void AssetTreeModel::getSelectedAssets(std::vector<std::string>& outputPaths,
|
||||
std::vector<AssetTreeItem*>& outputItems)
|
||||
{
|
||||
parseChildrenForSelected(_rootItem.get(), outputPaths, outputItems, "");
|
||||
}
|
||||
437
apps/OpenSpace/ext/launcher/src/profile/cameradialog.cpp
Normal file
437
apps/OpenSpace/ext/launcher/src/profile/cameradialog.cpp
Normal file
@@ -0,0 +1,437 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2020 *
|
||||
* *
|
||||
* 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 *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include "profile/cameradialog.h"
|
||||
|
||||
#include "profile/line.h"
|
||||
#include <openspace/scene/profile.h>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QDoubleValidator>
|
||||
#include <QFrame>
|
||||
#include <QGridLayout>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QKeyEvent>
|
||||
#include <QTabWidget>
|
||||
|
||||
namespace {
|
||||
constexpr const int CameraTypeNav = 0;
|
||||
constexpr const int CameraTypeGeo = 1;
|
||||
|
||||
template <class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
|
||||
template <class... Ts> overloaded(Ts...)->overloaded<Ts...>;
|
||||
|
||||
bool inNumericalRange(QLineEdit* le, float min, float max) {
|
||||
QString s = le->text();
|
||||
bool validConversion = false;
|
||||
float value = s.toFloat(&validConversion);
|
||||
if (!validConversion) {
|
||||
return false;
|
||||
}
|
||||
if (value < min || value > max) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
CameraDialog::CameraDialog(openspace::Profile& profile, QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, _profile(profile)
|
||||
{
|
||||
setWindowTitle("Set Camera Position");
|
||||
createWidgets();
|
||||
|
||||
if (_profile.camera().has_value()) {
|
||||
openspace::Profile::CameraType type = *_profile.camera();
|
||||
std::visit(overloaded {
|
||||
[this](const openspace::Profile::CameraNavState& nav) {
|
||||
_tabWidget->setCurrentIndex(CameraTypeNav);
|
||||
_navState.anchor->setText(QString::fromStdString(nav.anchor));
|
||||
_navState.aim->setText(QString::fromStdString(*nav.aim));
|
||||
_navState.refFrame->setText(QString::fromStdString(nav.referenceFrame));
|
||||
_navState.positionX->setText(QString::number(nav.position.x));
|
||||
_navState.positionY->setText(QString::number(nav.position.y));
|
||||
_navState.positionZ->setText(QString::number(nav.position.z));
|
||||
if (nav.up.has_value()) {
|
||||
_navState.upX->setText(QString::number(nav.up.value().x));
|
||||
_navState.upY->setText(QString::number(nav.up.value().y));
|
||||
_navState.upZ->setText(QString::number(nav.up.value().z));
|
||||
}
|
||||
else {
|
||||
_navState.upX->clear();
|
||||
_navState.upY->clear();
|
||||
_navState.upZ->clear();
|
||||
}
|
||||
if (nav.yaw.has_value()) {
|
||||
_navState.yaw->setText(QString::number(*nav.yaw));
|
||||
}
|
||||
else {
|
||||
_navState.yaw->clear();
|
||||
}
|
||||
if (nav.pitch.has_value()) {
|
||||
_navState.pitch->setText(QString::number(*nav.pitch));
|
||||
}
|
||||
else {
|
||||
_navState.pitch->clear();
|
||||
}
|
||||
tabSelect(CameraTypeNav);
|
||||
},
|
||||
[this](const openspace::Profile::CameraGoToGeo& geo) {
|
||||
_tabWidget->setCurrentIndex(CameraTypeGeo);
|
||||
_geoState.anchor->setText(QString::fromStdString(geo.anchor));
|
||||
_geoState.latitude->setText(QString::number(geo.latitude));
|
||||
_geoState.longitude->setText(QString::number(geo.longitude));
|
||||
if (geo.altitude.has_value()) {
|
||||
_geoState.altitude->setText(QString::number(*geo.altitude));
|
||||
}
|
||||
else {
|
||||
_geoState.altitude->clear();
|
||||
}
|
||||
tabSelect(CameraTypeGeo);
|
||||
}
|
||||
}, type);
|
||||
}
|
||||
else {
|
||||
_tabWidget->setCurrentIndex(CameraTypeNav);
|
||||
_navState.anchor->clear();
|
||||
_navState.aim->clear();
|
||||
_navState.refFrame->clear();
|
||||
_navState.positionX->clear();
|
||||
_navState.positionY->clear();
|
||||
_navState.positionZ->clear();
|
||||
_navState.upX->clear();
|
||||
_navState.upY->clear();
|
||||
_navState.upZ->clear();
|
||||
_navState.yaw->clear();
|
||||
_navState.pitch->clear();
|
||||
|
||||
_geoState.anchor->clear();
|
||||
_geoState.latitude->clear();
|
||||
_geoState.longitude->clear();
|
||||
_geoState.altitude->clear();
|
||||
}
|
||||
}
|
||||
|
||||
void CameraDialog::createWidgets() {
|
||||
QBoxLayout* layout = new QVBoxLayout(this);
|
||||
_tabWidget = new QTabWidget;
|
||||
connect(_tabWidget, &QTabWidget::tabBarClicked, this, &CameraDialog::tabSelect);
|
||||
_tabWidget->addTab(createNavStateWidget(), "Navigation State");
|
||||
_tabWidget->addTab(createGeoWidget(), "Geo State");
|
||||
layout->addWidget(_tabWidget);
|
||||
|
||||
layout->addWidget(new Line);
|
||||
|
||||
{
|
||||
QBoxLayout* footerLayout = new QHBoxLayout;
|
||||
|
||||
_errorMsg = new QLabel;
|
||||
_errorMsg->setObjectName("error-message");
|
||||
_errorMsg->setWordWrap(true);
|
||||
footerLayout->addWidget(_errorMsg);
|
||||
|
||||
QDialogButtonBox* buttons = new QDialogButtonBox;
|
||||
buttons->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel);
|
||||
connect(buttons, &QDialogButtonBox::accepted, this, &CameraDialog::approved);
|
||||
connect(buttons, &QDialogButtonBox::rejected, this, &CameraDialog::reject);
|
||||
footerLayout->addWidget(buttons);
|
||||
|
||||
layout->addLayout(footerLayout);
|
||||
}
|
||||
}
|
||||
|
||||
QWidget* CameraDialog::createNavStateWidget() {
|
||||
QWidget* box = new QWidget;
|
||||
QGridLayout* layout = new QGridLayout(box);
|
||||
|
||||
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"
|
||||
);
|
||||
_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"));
|
||||
_navState.positionX = new QLineEdit;
|
||||
_navState.positionX->setValidator(new QDoubleValidator);
|
||||
_navState.positionX->setToolTip("Camera position vector (x)");
|
||||
posLayout->addWidget(_navState.positionX);
|
||||
|
||||
posLayout->addWidget(new QLabel("Y"));
|
||||
_navState.positionY = new QLineEdit;
|
||||
_navState.positionY->setValidator(new QDoubleValidator);
|
||||
_navState.positionY->setToolTip("Camera position vector (y)");
|
||||
posLayout->addWidget(_navState.positionY);
|
||||
|
||||
posLayout->addWidget(new QLabel("Z"));
|
||||
_navState.positionZ = new QLineEdit;
|
||||
_navState.positionZ->setValidator(new QDoubleValidator);
|
||||
_navState.positionZ->setToolTip("Camera position vector (z)");
|
||||
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);
|
||||
|
||||
return box;
|
||||
}
|
||||
|
||||
QWidget* CameraDialog::createGeoWidget() {
|
||||
QWidget* box = new QWidget;
|
||||
QGridLayout* layout = new QGridLayout(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"), 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);
|
||||
|
||||
return box;
|
||||
}
|
||||
|
||||
bool CameraDialog::areRequiredFormsFilledAndValid() {
|
||||
bool allFormsOk = true;
|
||||
_errorMsg->clear();
|
||||
|
||||
if (_tabWidget->currentIndex() == CameraTypeNav) {
|
||||
if (_navState.anchor->text().isEmpty()) {
|
||||
allFormsOk = false;
|
||||
addErrorMsg("Anchor is empty");
|
||||
}
|
||||
if (_navState.positionX->text().isEmpty()) {
|
||||
allFormsOk = false;
|
||||
addErrorMsg("Position X is empty");
|
||||
}
|
||||
if (_navState.positionY->text().isEmpty()) {
|
||||
allFormsOk = false;
|
||||
addErrorMsg("Position Y is empty");
|
||||
}
|
||||
if (_navState.positionZ->text().isEmpty()) {
|
||||
allFormsOk = false;
|
||||
addErrorMsg("Position Z is empty");
|
||||
}
|
||||
int upVectorCount = 0;
|
||||
const bool hasUpX = !_navState.upX->text().isEmpty();
|
||||
const bool hasUpY = !_navState.upY->text().isEmpty();
|
||||
const bool hasUpZ = !_navState.upZ->text().isEmpty();
|
||||
|
||||
if (hasUpX || hasUpY || hasUpZ) {
|
||||
if (!hasUpX) {
|
||||
allFormsOk = false;
|
||||
addErrorMsg("Up X is empty");
|
||||
}
|
||||
if (!hasUpY) {
|
||||
allFormsOk = false;
|
||||
addErrorMsg("Up Y is empty");
|
||||
}
|
||||
if (!hasUpZ) {
|
||||
allFormsOk = false;
|
||||
addErrorMsg("Up Z is empty");
|
||||
}
|
||||
}
|
||||
if (!_navState.yaw->text().isEmpty()) {
|
||||
if (!inNumericalRange(_navState.yaw, -360.0, 360.0)) {
|
||||
allFormsOk = false;
|
||||
addErrorMsg("Yaw value is not in +/- 360.0 range");
|
||||
}
|
||||
}
|
||||
if (!_navState.pitch->text().isEmpty()) {
|
||||
if (!inNumericalRange(_navState.pitch, -360.0, 360.0)) {
|
||||
allFormsOk = false;
|
||||
addErrorMsg("Pitch value is not in +/- 360.0 range");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_tabWidget->currentIndex() == CameraTypeGeo) {
|
||||
if (_geoState.anchor->text().isEmpty()) {
|
||||
allFormsOk = false;
|
||||
addErrorMsg("Anchor is empty");
|
||||
}
|
||||
if (!inNumericalRange(_geoState.latitude, -90.0, 90.0)) {
|
||||
allFormsOk = false;
|
||||
addErrorMsg("Latitude value is not in +/- 90.0 range");
|
||||
}
|
||||
if (!inNumericalRange(_geoState.longitude, -180.0, 180.0)) {
|
||||
allFormsOk = false;
|
||||
addErrorMsg("Longitude value is not in +/- 180.0 range");
|
||||
}
|
||||
}
|
||||
return allFormsOk;
|
||||
}
|
||||
|
||||
void CameraDialog::addErrorMsg(QString errorDescription) {
|
||||
QString contents = _errorMsg->text();
|
||||
if (!contents.isEmpty()) {
|
||||
contents += ", ";
|
||||
}
|
||||
contents += errorDescription;
|
||||
_errorMsg->setText(contents);
|
||||
}
|
||||
|
||||
void CameraDialog::approved() {
|
||||
if (!areRequiredFormsFilledAndValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_tabWidget->currentIndex() == CameraTypeNav) {
|
||||
openspace::Profile::CameraNavState nav;
|
||||
nav.anchor = _navState.anchor->text().toStdString();
|
||||
nav.aim = _navState.aim->text().toStdString();
|
||||
nav.referenceFrame = _navState.refFrame->text().toStdString();
|
||||
nav.position.x = _navState.positionX->text().toDouble();
|
||||
nav.position.y = _navState.positionY->text().toDouble();
|
||||
nav.position.z = _navState.positionZ->text().toDouble();
|
||||
if (!_navState.upX->text().isEmpty() &&
|
||||
!_navState.upY->text().isEmpty() &&
|
||||
!_navState.upZ->text().isEmpty())
|
||||
{
|
||||
glm::dvec3 u = {
|
||||
_navState.upX->text().toDouble(),
|
||||
_navState.upY->text().toDouble(),
|
||||
_navState.upZ->text().toDouble()
|
||||
};
|
||||
nav.up = u;
|
||||
}
|
||||
else {
|
||||
nav.up = std::nullopt;
|
||||
}
|
||||
if (!_navState.yaw->text().isEmpty()) {
|
||||
nav.yaw = _navState.yaw->text().toDouble();
|
||||
}
|
||||
else {
|
||||
nav.yaw = std::nullopt;
|
||||
}
|
||||
if (!_navState.pitch->text().isEmpty()) {
|
||||
nav.pitch = _navState.pitch->text().toDouble();
|
||||
}
|
||||
else {
|
||||
nav.pitch = std::nullopt;
|
||||
}
|
||||
_profile.setCamera(nav);
|
||||
}
|
||||
else if (_tabWidget->currentIndex() == CameraTypeGeo) {
|
||||
openspace::Profile::CameraGoToGeo geo;
|
||||
geo.anchor = _geoState.anchor->text().toStdString();
|
||||
geo.latitude = _geoState.latitude->text().toDouble();
|
||||
geo.longitude = _geoState.longitude->text().toDouble();
|
||||
if (!_geoState.altitude->text().isEmpty()) {
|
||||
geo.altitude = _geoState.altitude->text().toDouble();
|
||||
}
|
||||
_profile.setCamera(geo);
|
||||
}
|
||||
|
||||
accept();
|
||||
}
|
||||
|
||||
void CameraDialog::tabSelect(int tabIndex) {
|
||||
_errorMsg->clear();
|
||||
|
||||
if (tabIndex == 0) {
|
||||
_navState.anchor->setFocus(Qt::OtherFocusReason);
|
||||
}
|
||||
else if (tabIndex == 1) {
|
||||
_geoState.anchor->setFocus(Qt::OtherFocusReason);
|
||||
}
|
||||
else {
|
||||
throw std::logic_error("Unknown tab index");
|
||||
}
|
||||
}
|
||||
392
apps/OpenSpace/ext/launcher/src/profile/deltatimesdialog.cpp
Normal file
392
apps/OpenSpace/ext/launcher/src/profile/deltatimesdialog.cpp
Normal file
@@ -0,0 +1,392 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2020 *
|
||||
* *
|
||||
* 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 *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include "profile/deltatimesdialog.h"
|
||||
|
||||
#include "profile/line.h"
|
||||
#include <openspace/scene/profile.h>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QDoubleValidator>
|
||||
#include <QEvent>
|
||||
#include <QKeyEvent>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QListWidget>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
|
||||
namespace {
|
||||
constexpr const int MaxNumberOfKeys = 30;
|
||||
|
||||
struct TimeInterval {
|
||||
uint64_t secondsPerInterval;
|
||||
std::string intervalName;
|
||||
};
|
||||
|
||||
std::array<TimeInterval, 7> TimeIntervals = {
|
||||
TimeInterval{ 31536000, "year" },
|
||||
TimeInterval{ 18144000, "month" },
|
||||
TimeInterval{ 604800, "week" },
|
||||
TimeInterval{ 86400, "day" },
|
||||
TimeInterval{ 3600, "hour" },
|
||||
TimeInterval{ 60, "minute" },
|
||||
TimeInterval{ 1, "second" }
|
||||
};
|
||||
|
||||
std::string checkForTimeDescription(int intervalIndex, double value) {
|
||||
double amount = value / TimeIntervals[intervalIndex].secondsPerInterval;
|
||||
std::string description = fmt::format("{}", amount);
|
||||
description += " " + TimeIntervals[intervalIndex].intervalName + "/sec";
|
||||
return description;
|
||||
}
|
||||
|
||||
std::string timeDescription(double value) {
|
||||
if (value == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
size_t i;
|
||||
for (i = 0; i < (TimeIntervals.size() - 1); ++i) {
|
||||
if (abs(value) >= TimeIntervals[i].secondsPerInterval) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return checkForTimeDescription(i, value);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
DeltaTimesDialog::DeltaTimesDialog(openspace::Profile& profile, QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, _profile(profile)
|
||||
{
|
||||
setWindowTitle("Simulation Time Increments");
|
||||
createWidgets();
|
||||
|
||||
_data = _profile.deltaTimes();
|
||||
|
||||
for (size_t d = 0; d < _data.size(); ++d) {
|
||||
std::string summary = createSummaryForDeltaTime(d, true);
|
||||
_listWidget->addItem(new QListWidgetItem(QString::fromStdString(summary)));
|
||||
}
|
||||
|
||||
transitionEditMode(_listWidget->count() - 1, false);
|
||||
}
|
||||
|
||||
void DeltaTimesDialog::createWidgets() {
|
||||
QBoxLayout* layout = new QVBoxLayout(this);
|
||||
{
|
||||
_listWidget = new QListWidget;
|
||||
connect(
|
||||
_listWidget, &QListWidget::itemSelectionChanged,
|
||||
this, &DeltaTimesDialog::listItemSelected
|
||||
);
|
||||
_listWidget->setAutoScroll(true);
|
||||
_listWidget->setLayoutMode(QListView::SinglePass);
|
||||
layout->addWidget(_listWidget);
|
||||
}
|
||||
|
||||
{
|
||||
QBoxLayout* buttonLayout = new QHBoxLayout;
|
||||
_addButton = new QPushButton("Add Entry");
|
||||
connect(
|
||||
_addButton, &QPushButton::clicked,
|
||||
this, &DeltaTimesDialog::addDeltaTimeValue
|
||||
);
|
||||
buttonLayout->addWidget(_addButton);
|
||||
|
||||
_removeButton = new QPushButton("Remove Last Entry");
|
||||
connect(
|
||||
_removeButton, &QPushButton::clicked,
|
||||
this, &DeltaTimesDialog::removeDeltaTimeValue
|
||||
);
|
||||
buttonLayout->addWidget(_removeButton);
|
||||
|
||||
buttonLayout->addStretch();
|
||||
layout->addLayout(buttonLayout);
|
||||
}
|
||||
{
|
||||
_adjustLabel = new QLabel("Set Simulation Time Increment for key");
|
||||
layout->addWidget(_adjustLabel);
|
||||
}
|
||||
{
|
||||
QBoxLayout* box = new QHBoxLayout;
|
||||
_seconds = new QLineEdit;
|
||||
_seconds->setValidator(new QDoubleValidator);
|
||||
connect(_seconds, &QLineEdit::textChanged, this, &DeltaTimesDialog::valueChanged);
|
||||
box->addWidget(_seconds);
|
||||
|
||||
_value = new QLabel;
|
||||
box->addWidget(_value);
|
||||
layout->addLayout(box);
|
||||
}
|
||||
|
||||
{
|
||||
QBoxLayout* box = new QHBoxLayout;
|
||||
_saveButton = new QPushButton("Save");
|
||||
connect(
|
||||
_saveButton, &QPushButton::clicked,
|
||||
this, &DeltaTimesDialog::saveDeltaTimeValue
|
||||
);
|
||||
box->addWidget(_saveButton);
|
||||
|
||||
_discardButton = new QPushButton("Discard");
|
||||
connect(
|
||||
_discardButton, &QPushButton::clicked,
|
||||
this, &DeltaTimesDialog::discardDeltaTimeValue
|
||||
);
|
||||
box->addWidget(_discardButton);
|
||||
|
||||
box->addStretch();
|
||||
layout->addLayout(box);
|
||||
}
|
||||
layout->addWidget(new Line);
|
||||
{
|
||||
QBoxLayout* footer = new QHBoxLayout;
|
||||
_errorMsg = new QLabel;
|
||||
_errorMsg->setObjectName("error-message");
|
||||
_errorMsg->setWordWrap(true);
|
||||
footer->addWidget(_errorMsg);
|
||||
|
||||
_buttonBox = new QDialogButtonBox;
|
||||
_buttonBox->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel);
|
||||
connect(
|
||||
_buttonBox, &QDialogButtonBox::accepted,
|
||||
this, &DeltaTimesDialog::parseSelections
|
||||
);
|
||||
connect(_buttonBox, &QDialogButtonBox::rejected, this, &DeltaTimesDialog::reject);
|
||||
footer->addWidget(_buttonBox);
|
||||
layout->addLayout(footer);
|
||||
}
|
||||
}
|
||||
|
||||
std::string DeltaTimesDialog::createSummaryForDeltaTime(size_t idx, bool forListView) {
|
||||
int k = (idx%10 == 9) ? 0 : idx%10 + 1;
|
||||
k = (idx == 0) ? 1 : k;
|
||||
std::string key = std::to_string(k);
|
||||
|
||||
std::string s;
|
||||
if (idx >= 20) {
|
||||
s = "CTRL + " + key;
|
||||
}
|
||||
else if (idx >= 10) {
|
||||
s = "SHIFT + " + key;
|
||||
}
|
||||
else {
|
||||
s = key;
|
||||
if (forListView) {
|
||||
s += " ";
|
||||
}
|
||||
}
|
||||
|
||||
if (forListView) {
|
||||
s += '\t' + std::to_string(_data.at(idx)) + '\t' + timeDescription(_data.at(idx));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void DeltaTimesDialog::listItemSelected() {
|
||||
QListWidgetItem *item = _listWidget->currentItem();
|
||||
int index = _listWidget->row(item);
|
||||
|
||||
if (index < (static_cast<int>(_data.size()) - 1)) {
|
||||
_listWidget->setCurrentRow(index);
|
||||
}
|
||||
|
||||
if (!_data.empty()) {
|
||||
if (_data.at(index) == 0) {
|
||||
_seconds->clear();
|
||||
}
|
||||
else {
|
||||
_seconds->setText(QString::number(_data.at(index)));
|
||||
}
|
||||
}
|
||||
_editModeNewItem = true;
|
||||
transitionEditMode(index, true);
|
||||
}
|
||||
|
||||
void DeltaTimesDialog::setLabelForKey(int index, bool editMode, std::string color) {
|
||||
std::string labelS = "Set Simulation Time Increment for key";
|
||||
if (index >= _data.size()) {
|
||||
index = _data.size() - 1;
|
||||
}
|
||||
if (editMode) {
|
||||
labelS += " '" + createSummaryForDeltaTime(index, false) + "':";
|
||||
}
|
||||
_adjustLabel->setText(QString::fromStdString(
|
||||
"<font color='" + color + "'>" + labelS + "</font>"
|
||||
));
|
||||
}
|
||||
|
||||
void DeltaTimesDialog::valueChanged(const QString& text) {
|
||||
if (_seconds->text().isEmpty()) {
|
||||
_errorMsg->setText("");
|
||||
}
|
||||
else {
|
||||
int value = _seconds->text().toDouble();
|
||||
if (value != 0) {
|
||||
_value->setText(QString::fromStdString(
|
||||
timeDescription(_seconds->text().toDouble()))
|
||||
);
|
||||
_errorMsg->setText("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool DeltaTimesDialog::isLineEmpty(int index) {
|
||||
bool isEmpty = true;
|
||||
if (!_listWidget->item(index)->text().isEmpty()) {
|
||||
isEmpty = false;
|
||||
}
|
||||
if (!_data.empty() && (_data.at(0) != 0)) {
|
||||
isEmpty = false;
|
||||
}
|
||||
return isEmpty;
|
||||
}
|
||||
|
||||
void DeltaTimesDialog::addDeltaTimeValue() {
|
||||
int currentListSize = _listWidget->count();
|
||||
const QString messageAddValue = " (Enter integer value below & click 'Save')";
|
||||
|
||||
if ((currentListSize == 1) && (isLineEmpty(0))) {
|
||||
// Special case where list is "empty" but really has one line that is blank.
|
||||
// This is done because QListWidget does not seem to like having its sole
|
||||
// remaining item being removed.
|
||||
_data.at(0) = 0;
|
||||
_listWidget->item(0)->setText(messageAddValue);
|
||||
}
|
||||
else if (_data.size() < MaxNumberOfKeys) {
|
||||
_data.push_back(0);
|
||||
_listWidget->addItem(new QListWidgetItem(messageAddValue));
|
||||
}
|
||||
else {
|
||||
_errorMsg->setText("Exceeded maximum amount of simulation time increments");
|
||||
}
|
||||
_listWidget->setCurrentRow(_listWidget->count() - 1);
|
||||
_seconds->setFocus(Qt::OtherFocusReason);
|
||||
_editModeNewItem = true;
|
||||
}
|
||||
|
||||
void DeltaTimesDialog::saveDeltaTimeValue() {
|
||||
QListWidgetItem* item = _listWidget->currentItem();
|
||||
if (item != nullptr) {
|
||||
int index = _listWidget->row(item);
|
||||
if (_data.size() > 0) {
|
||||
_data.at(index) = _seconds->text().toDouble();
|
||||
std::string summary = createSummaryForDeltaTime(index, true);
|
||||
_listWidget->item(index)->setText(QString::fromStdString(summary));
|
||||
transitionEditMode(index, false);
|
||||
_editModeNewItem = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DeltaTimesDialog::discardDeltaTimeValue() {
|
||||
listItemSelected();
|
||||
transitionEditMode(_listWidget->count() - 1, false);
|
||||
if (_editModeNewItem && !_data.empty() && _data.back() == 0) {
|
||||
removeDeltaTimeValue();
|
||||
}
|
||||
_editModeNewItem = false;
|
||||
}
|
||||
|
||||
void DeltaTimesDialog::removeDeltaTimeValue() {
|
||||
if (_listWidget->count() > 0) {
|
||||
if (_listWidget->count() == 1) {
|
||||
_data.at(0) = 0;
|
||||
_listWidget->item(0)->setText("");
|
||||
}
|
||||
else {
|
||||
delete _listWidget->takeItem(_listWidget->count() - 1);
|
||||
if (!_data.empty()) {
|
||||
_data.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
_listWidget->clearSelection();
|
||||
transitionEditMode(_listWidget->count() - 1, false);
|
||||
}
|
||||
|
||||
void DeltaTimesDialog::transitionEditMode(int index, bool state) {
|
||||
_listWidget->setEnabled(!state);
|
||||
_addButton->setEnabled(!state);
|
||||
_removeButton->setEnabled(!state);
|
||||
_buttonBox->setEnabled(!state);
|
||||
|
||||
_saveButton->setEnabled(state);
|
||||
_discardButton->setEnabled(state);
|
||||
_adjustLabel->setEnabled(state);
|
||||
_seconds->setEnabled(state);
|
||||
_errorMsg->clear();
|
||||
|
||||
if (state) {
|
||||
_seconds->setFocus(Qt::OtherFocusReason);
|
||||
setLabelForKey(index, true, "black");
|
||||
}
|
||||
else {
|
||||
_addButton->setFocus(Qt::OtherFocusReason);
|
||||
setLabelForKey(index, false, "light gray");
|
||||
_value->clear();
|
||||
}
|
||||
_errorMsg->clear();
|
||||
}
|
||||
|
||||
void DeltaTimesDialog::parseSelections() {
|
||||
if ((_data.size() == 1) && (_data.at(0) == 0)) {
|
||||
_data.clear();
|
||||
}
|
||||
int finalNonzeroIndex = _data.size() - 1;
|
||||
for (; finalNonzeroIndex >= 0; --finalNonzeroIndex) {
|
||||
if (_data.at(finalNonzeroIndex) != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::vector<double> tempDt;
|
||||
for (size_t i = 0; i < (finalNonzeroIndex + 1); ++i) {
|
||||
tempDt.push_back(_data[i]);
|
||||
}
|
||||
_profile.setDeltaTimes(tempDt);
|
||||
accept();
|
||||
}
|
||||
|
||||
void DeltaTimesDialog::keyPressEvent(QKeyEvent* evt) {
|
||||
if (evt->key() == Qt::Key_Enter || evt->key() == Qt::Key_Return) {
|
||||
if (_editModeNewItem) {
|
||||
saveDeltaTimeValue();
|
||||
}
|
||||
else {
|
||||
addDeltaTimeValue();
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (evt->key() == Qt::Key_Escape) {
|
||||
if (_editModeNewItem) {
|
||||
discardDeltaTimeValue();
|
||||
return;
|
||||
}
|
||||
}
|
||||
QDialog::keyPressEvent(evt);
|
||||
}
|
||||
525
apps/OpenSpace/ext/launcher/src/profile/keybindingsdialog.cpp
Normal file
525
apps/OpenSpace/ext/launcher/src/profile/keybindingsdialog.cpp
Normal file
@@ -0,0 +1,525 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2020 *
|
||||
* *
|
||||
* 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 *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include "profile/keybindingsdialog.h"
|
||||
|
||||
#include "profile/line.h"
|
||||
#include <openspace/scene/profile.h>
|
||||
#include <openspace/util/keys.h>
|
||||
#include <qevent.h>
|
||||
#include <algorithm>
|
||||
#include <QKeyEvent>
|
||||
#include <QCheckBox>
|
||||
#include <QVBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <QLabel>
|
||||
#include <QComboBox>
|
||||
#include <QLineEdit>
|
||||
#include <QTextEdit>
|
||||
#include <QDialogButtonBox>
|
||||
|
||||
using namespace openspace;
|
||||
|
||||
namespace {
|
||||
const Profile::Keybinding BlankKey= {
|
||||
{ Key::Unknown, KeyModifier::NoModifier },
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
true,
|
||||
""
|
||||
};
|
||||
|
||||
void replaceChars(std::string& src, const std::string& from, const std::string& to) {
|
||||
std::string newString;
|
||||
std::string::size_type found, last = 0;
|
||||
|
||||
while ((found = src.find(from, last)) != std::string::npos) {
|
||||
newString.append(src, last, (found - last));
|
||||
newString += to;
|
||||
last = found + from.length();
|
||||
}
|
||||
newString += src.substr(last);
|
||||
src.swap(newString);
|
||||
}
|
||||
|
||||
std::string truncateString(std::string& s) {
|
||||
const size_t maxLength = 50;
|
||||
replaceChars(s, "\n", ";");
|
||||
if (s.length() > maxLength) {
|
||||
s.resize(maxLength);
|
||||
s += "...";
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string createOneLineSummary(Profile::Keybinding k) {
|
||||
std::string summary;
|
||||
|
||||
int keymod = static_cast<int>(k.key.modifier);
|
||||
if (keymod != static_cast<int>(KeyModifier::NoModifier)) {
|
||||
summary += KeyModifierNames.at(keymod) + " ";
|
||||
}
|
||||
int keyname = static_cast<int>(k.key.key);
|
||||
|
||||
summary += KeyNames.at(keyname) + " ";
|
||||
summary += truncateString(k.name) + " (";
|
||||
summary += truncateString(k.documentation) + ") @ ";
|
||||
summary += truncateString(k.guiPath) + " ";
|
||||
summary += (k.isLocal) ? "local" : "remote";
|
||||
summary += " `" + truncateString(k.script) + "`";
|
||||
|
||||
return summary;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
KeybindingsDialog::KeybindingsDialog(Profile& profile, QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, _profile(profile)
|
||||
, _data(_profile.keybindings())
|
||||
{
|
||||
setWindowTitle("Assign Keybindings");
|
||||
createWidgets();
|
||||
|
||||
transitionFromEditMode();
|
||||
}
|
||||
|
||||
void KeybindingsDialog::createWidgets() {
|
||||
QBoxLayout* layout = new QVBoxLayout(this);
|
||||
{
|
||||
_list = new QListWidget;
|
||||
connect(
|
||||
_list, &QListWidget::itemSelectionChanged,
|
||||
this, &KeybindingsDialog::listItemSelected
|
||||
);
|
||||
_list->setAlternatingRowColors(true);
|
||||
_list->setMovement(QListView::Free);
|
||||
_list->setResizeMode(QListView::Adjust);
|
||||
|
||||
for (size_t i = 0; i < _data.size(); ++i) {
|
||||
std::string summary = createOneLineSummary(_data[i]);
|
||||
_list->addItem(new QListWidgetItem(QString::fromStdString(summary)));
|
||||
}
|
||||
|
||||
layout->addWidget(_list);
|
||||
}
|
||||
{
|
||||
QBoxLayout* box = new QHBoxLayout;
|
||||
_addButton = new QPushButton("Add new");
|
||||
connect(
|
||||
_addButton, &QPushButton::clicked,
|
||||
this, &KeybindingsDialog::listItemAdded
|
||||
);
|
||||
box->addWidget(_addButton);
|
||||
|
||||
_removeButton = new QPushButton("Remove");
|
||||
connect(
|
||||
_removeButton, &QPushButton::clicked,
|
||||
this, &KeybindingsDialog::listItemRemove
|
||||
);
|
||||
box->addWidget(_removeButton);
|
||||
box->addStretch();
|
||||
layout->addLayout(box);
|
||||
}
|
||||
layout->addWidget(new Line);
|
||||
{
|
||||
QGridLayout* box = new QGridLayout;
|
||||
|
||||
_keyModLabel = new QLabel("Key Modifier");
|
||||
box->addWidget(_keyModLabel, 0, 0);
|
||||
_keyModCombo = new QComboBox;
|
||||
_keyModCombo->setToolTip(
|
||||
"Modifier keys to hold while key is pressed (blank means none)"
|
||||
);
|
||||
|
||||
QStringList comboModKeysStringList;
|
||||
int modIdx = 0;
|
||||
for (const std::pair<const int, std::string>& m : KeyModifierNames) {
|
||||
comboModKeysStringList += QString::fromStdString(m.second);
|
||||
_mapModKeyComboBoxIndexToKeyValue.push_back(modIdx++);
|
||||
}
|
||||
_keyModCombo->addItems(comboModKeysStringList);
|
||||
box->addWidget(_keyModCombo, 0, 1);
|
||||
|
||||
|
||||
_keyLabel = new QLabel("Key");
|
||||
box->addWidget(_keyLabel, 1, 0);
|
||||
_keyCombo = new QComboBox;
|
||||
_keyCombo->setToolTip("Key to press for this keybinding");
|
||||
|
||||
QStringList comboKeysStringList;
|
||||
for (int i = 0; i < static_cast<int>(Key::Last); ++i) {
|
||||
if (KeyNames.find(i) != KeyNames.end()) {
|
||||
comboKeysStringList += QString::fromStdString(KeyNames.at(i));
|
||||
// Create map to relate key combo box to integer value defined in Key
|
||||
_mapKeyComboBoxIndexToKeyValue.push_back(i);
|
||||
}
|
||||
}
|
||||
_keyCombo->addItems(comboKeysStringList);
|
||||
connect(
|
||||
_keyCombo, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
this, &KeybindingsDialog::keySelected
|
||||
);
|
||||
box->addWidget(_keyCombo, 1, 1);
|
||||
|
||||
|
||||
_nameLabel = new QLabel("Name:");
|
||||
box->addWidget(_nameLabel, 2, 0);
|
||||
_nameEdit = new QLineEdit;
|
||||
_nameEdit->setToolTip("Name assigned to this keybinding");
|
||||
box->addWidget(_nameEdit, 2, 1);
|
||||
|
||||
|
||||
_guiPathLabel = new QLabel("GUI Path:");
|
||||
box->addWidget(_guiPathLabel, 3, 0);
|
||||
_guiPathEdit = new QLineEdit;
|
||||
_guiPathEdit->setToolTip(
|
||||
"[OPTIONAL] Path for where this keybinding appears in GUI menu"
|
||||
);
|
||||
box->addWidget(_guiPathEdit, 3, 1);
|
||||
|
||||
|
||||
_documentationLabel = new QLabel("Documentation:");
|
||||
box->addWidget(_documentationLabel, 4, 0);
|
||||
_documentationEdit = new QLineEdit;
|
||||
_documentationEdit->setToolTip(
|
||||
"[OPTIONAL] Documentation entry for keybinding"
|
||||
);
|
||||
box->addWidget(_documentationEdit, 4, 1);
|
||||
|
||||
|
||||
_localCheck = new QCheckBox("Local");
|
||||
_localCheck->setToolTip(
|
||||
"Determines whether the command, when executed, should be shared with "
|
||||
"connected instances or only executed locally"
|
||||
);
|
||||
box->addWidget(_localCheck, 5, 0, 1, 2);
|
||||
|
||||
|
||||
_scriptLabel = new QLabel("Script");
|
||||
box->addWidget(_scriptLabel, 6, 0, 1, 2);
|
||||
_scriptEdit = new QTextEdit;
|
||||
_scriptEdit->setAcceptRichText(false);
|
||||
_scriptEdit->setToolTip("Command(s) to execute at keypress event");
|
||||
_scriptEdit->setTabChangesFocus(true);
|
||||
box->addWidget(_scriptEdit, 7, 0, 1, 2);
|
||||
box->setRowStretch(7, 1);
|
||||
|
||||
QBoxLayout* buttonBox = new QHBoxLayout;
|
||||
_saveButton = new QPushButton("Save");
|
||||
connect(
|
||||
_saveButton, &QPushButton::clicked,
|
||||
this, &KeybindingsDialog::listItemSave
|
||||
);
|
||||
buttonBox->addWidget(_saveButton);
|
||||
|
||||
_cancelButton = new QPushButton("Cancel");
|
||||
connect(
|
||||
_cancelButton, &QPushButton::clicked,
|
||||
this, &KeybindingsDialog::listItemCancelSave
|
||||
);
|
||||
buttonBox->addWidget(_cancelButton);
|
||||
buttonBox->addStretch();
|
||||
box->addLayout(buttonBox, 8, 1, 1, 2);
|
||||
layout->addLayout(box);
|
||||
}
|
||||
layout->addWidget(new Line);
|
||||
{
|
||||
QBoxLayout* footerLayout = new QHBoxLayout;
|
||||
|
||||
_errorMsg = new QLabel;
|
||||
_errorMsg->setObjectName("error-message");
|
||||
_errorMsg->setWordWrap(true);
|
||||
footerLayout->addWidget(_errorMsg);
|
||||
|
||||
_buttonBox = new QDialogButtonBox;
|
||||
_buttonBox->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel);
|
||||
QObject::connect(
|
||||
_buttonBox, &QDialogButtonBox::accepted,
|
||||
this, &KeybindingsDialog::parseSelections
|
||||
);
|
||||
QObject::connect(
|
||||
_buttonBox, &QDialogButtonBox::rejected,
|
||||
this, &KeybindingsDialog::reject
|
||||
);
|
||||
footerLayout->addWidget(_buttonBox);
|
||||
layout->addLayout(footerLayout);
|
||||
}
|
||||
}
|
||||
|
||||
void KeybindingsDialog::listItemSelected() {
|
||||
QListWidgetItem *item = _list->currentItem();
|
||||
int index = _list->row(item);
|
||||
|
||||
if (_data.size() > 0) {
|
||||
Profile::Keybinding& k = _data[index];
|
||||
const int modifierKey = indexInKeyMapping(
|
||||
_mapModKeyComboBoxIndexToKeyValue,
|
||||
static_cast<int>(k.key.modifier)
|
||||
);
|
||||
_keyModCombo->setCurrentIndex(modifierKey);
|
||||
|
||||
if (k.key.key == Key::Unknown) {
|
||||
_keyCombo->setCurrentIndex(0);
|
||||
}
|
||||
else {
|
||||
const int key = indexInKeyMapping(
|
||||
_mapKeyComboBoxIndexToKeyValue,
|
||||
static_cast<int>(k.key.key)
|
||||
);
|
||||
_keyCombo->setCurrentIndex(key);
|
||||
}
|
||||
|
||||
// Do key here
|
||||
_nameEdit->setText(QString::fromStdString(k.name));
|
||||
_guiPathEdit->setText(QString::fromStdString(k.guiPath));
|
||||
_documentationEdit->setText(QString::fromStdString(k.documentation));
|
||||
_localCheck->setChecked(k.isLocal);
|
||||
_scriptEdit->setText(QString::fromStdString(k.script));
|
||||
}
|
||||
transitionToEditMode();
|
||||
}
|
||||
|
||||
void KeybindingsDialog::keySelected(int index) {
|
||||
const QString numKeyWarning = "Warning: Using a number key may conflict with the "
|
||||
"keybindings for simulation time increments.";
|
||||
QString errorContents = _errorMsg->text();
|
||||
bool alreadyContainsWarning = (errorContents.length() >= numKeyWarning.length() &&
|
||||
errorContents.left(numKeyWarning.length()) == numKeyWarning);
|
||||
if (_mapKeyComboBoxIndexToKeyValue[index] >= static_cast<int>(Key::Num0)
|
||||
&& _mapKeyComboBoxIndexToKeyValue[index] <= static_cast<int>(Key::Num9))
|
||||
{
|
||||
if (!alreadyContainsWarning) {
|
||||
errorContents = numKeyWarning + errorContents;
|
||||
_errorMsg->setText(errorContents);
|
||||
}
|
||||
}
|
||||
else if (alreadyContainsWarning) {
|
||||
_errorMsg->setText(errorContents.mid(numKeyWarning.length()));
|
||||
}
|
||||
}
|
||||
|
||||
int KeybindingsDialog::indexInKeyMapping(std::vector<int>& mapVector, int keyInt) {
|
||||
const auto it = std::find(mapVector.cbegin(), mapVector.cend(), keyInt);
|
||||
return std::distance(mapVector.cbegin(), it);
|
||||
}
|
||||
|
||||
bool KeybindingsDialog::isLineEmpty(int index) {
|
||||
bool isEmpty = true;
|
||||
if (!_list->item(index)->text().isEmpty()) {
|
||||
isEmpty = false;
|
||||
}
|
||||
if (!_data.empty() && !_data.at(0).name.empty()) {
|
||||
isEmpty = false;
|
||||
}
|
||||
return isEmpty;
|
||||
}
|
||||
|
||||
void KeybindingsDialog::listItemAdded() {
|
||||
int currentListSize = _list->count();
|
||||
|
||||
_data.push_back(BlankKey);
|
||||
_list->addItem(new QListWidgetItem(" (Enter details below & click 'Save')"));
|
||||
// Scroll down to that blank line highlighted
|
||||
_list->setCurrentRow(_list->count() - 1);
|
||||
|
||||
// Blank-out the 2 text fields, set combo box to index 0
|
||||
_keyModCombo->setCurrentIndex(static_cast<int>(_data.back().key.modifier));
|
||||
if (_data.back().key.key == Key::Unknown) {
|
||||
_keyCombo->setCurrentIndex(0);
|
||||
}
|
||||
else {
|
||||
_keyCombo->setCurrentIndex(static_cast<int>(_data.back().key.key));
|
||||
}
|
||||
_keyModCombo->setFocus(Qt::OtherFocusReason);
|
||||
_nameEdit->setText(QString::fromStdString(_data.back().name));
|
||||
_guiPathEdit->setText("/");
|
||||
_documentationEdit->setText(QString::fromStdString(_data.back().documentation));
|
||||
_localCheck->setChecked(false);
|
||||
_scriptEdit->setText(QString::fromStdString(_data.back().script));
|
||||
|
||||
_editModeNewItem = true;
|
||||
}
|
||||
|
||||
void KeybindingsDialog::listItemSave() {
|
||||
if (!areRequiredFormsFilled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QListWidgetItem* item = _list->currentItem();
|
||||
int index = _list->row(item);
|
||||
|
||||
if (!_data.empty()) {
|
||||
int keyModIdx = _mapModKeyComboBoxIndexToKeyValue.at(
|
||||
_keyModCombo->currentIndex());
|
||||
_data[index].key.modifier = static_cast<KeyModifier>(keyModIdx);
|
||||
int keyIdx = _mapKeyComboBoxIndexToKeyValue.at(_keyCombo->currentIndex());
|
||||
_data[index].key.key = static_cast<Key>(keyIdx);
|
||||
_data[index].name = _nameEdit->text().toStdString();
|
||||
_data[index].guiPath = _guiPathEdit->text().toStdString();
|
||||
_data[index].documentation = _documentationEdit->text().toStdString();
|
||||
_data[index].script = _scriptEdit->toPlainText().toStdString();
|
||||
_data[index].isLocal = (_localCheck->isChecked());
|
||||
std::string summary = createOneLineSummary(_data[index]);
|
||||
_list->item(index)->setText(QString::fromStdString(summary));
|
||||
}
|
||||
transitionFromEditMode();
|
||||
}
|
||||
|
||||
bool KeybindingsDialog::areRequiredFormsFilled() {
|
||||
bool requiredFormsFilled = true;
|
||||
std::string errors;
|
||||
if (_keyCombo->currentIndex() < 0) {
|
||||
errors += "Missing key";
|
||||
requiredFormsFilled = false;
|
||||
}
|
||||
if (_nameEdit->text().length() == 0) {
|
||||
if (!errors.empty()) {
|
||||
errors += ", ";
|
||||
}
|
||||
errors += "Missing keybinding name";
|
||||
requiredFormsFilled = false;
|
||||
}
|
||||
if (_scriptEdit->toPlainText().isEmpty()) {
|
||||
if (!errors.empty()) {
|
||||
errors += ", ";
|
||||
}
|
||||
errors += "Missing script";
|
||||
requiredFormsFilled = false;
|
||||
}
|
||||
_errorMsg->setText(QString::fromStdString(errors));
|
||||
return requiredFormsFilled;
|
||||
}
|
||||
|
||||
void KeybindingsDialog::listItemCancelSave() {
|
||||
listItemSelected();
|
||||
transitionFromEditMode();
|
||||
if (_editModeNewItem && !_data.empty() &&
|
||||
(_data.back().name.length() == 0 || _data.back().script.length() == 0 ||
|
||||
_data.back().key.key == Key::Unknown))
|
||||
{
|
||||
listItemRemove();
|
||||
}
|
||||
_editModeNewItem = false;
|
||||
}
|
||||
|
||||
void KeybindingsDialog::listItemRemove() {
|
||||
if (_list->count() > 0) {
|
||||
if (_list->count() == 1) {
|
||||
// Special case where last remaining item is being removed (QListWidget does
|
||||
// not like the final item being removed so instead clear it & leave it)
|
||||
_data.at(0) = BlankKey;
|
||||
_list->item(0)->setText("");
|
||||
}
|
||||
else {
|
||||
int index = _list->currentRow();
|
||||
if (index >= 0 && index < _list->count()) {
|
||||
_list->takeItem(index);
|
||||
if (!_data.empty()) {
|
||||
_data.erase(_data.begin() + index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_list->clearSelection();
|
||||
transitionFromEditMode();
|
||||
}
|
||||
|
||||
void KeybindingsDialog::transitionToEditMode() {
|
||||
_list->setDisabled(true);
|
||||
_addButton->setDisabled(true);
|
||||
_removeButton->setDisabled(true);
|
||||
_saveButton->setDisabled(true);
|
||||
_cancelButton->setDisabled(true);
|
||||
_buttonBox->setDisabled(true);
|
||||
_keyLabel->setText("<font color='black'>Key</font>");
|
||||
_keyModLabel->setText("<font color='black'>Key Modifier</font>");
|
||||
_nameLabel->setText("<font color='black'>Name</font>");
|
||||
_scriptLabel->setText("<font color='black'>Script</font>");
|
||||
_guiPathLabel->setText("<font color='black'>GUI Path</font>");
|
||||
_documentationLabel->setText("<font color='black'>Documentation</font>");
|
||||
|
||||
editBoxDisabled(false);
|
||||
_errorMsg->setText("");
|
||||
}
|
||||
|
||||
void KeybindingsDialog::transitionFromEditMode() {
|
||||
_list->setDisabled(false);
|
||||
_addButton->setDisabled(false);
|
||||
_removeButton->setDisabled(false);
|
||||
_saveButton->setDisabled(false);
|
||||
_cancelButton->setDisabled(false);
|
||||
_buttonBox->setDisabled(false);
|
||||
|
||||
_keyLabel->setText("<font color='light gray'>Key</font>");
|
||||
_keyModLabel->setText("<font color='light gray'>Key Modifier</font>");
|
||||
_nameLabel->setText("<font color='light gray'>Name</font>");
|
||||
_scriptLabel->setText("<font color='light gray'>Script</font>");
|
||||
_guiPathLabel->setText("<font color='light gray'>GUI Path</font>");
|
||||
_documentationLabel->setText("<font color='light gray'>Documentation</font>");
|
||||
editBoxDisabled(true);
|
||||
_errorMsg->setText("");
|
||||
}
|
||||
|
||||
void KeybindingsDialog::editBoxDisabled(bool disabled) {
|
||||
_keyLabel->setDisabled(disabled);
|
||||
_keyCombo->setDisabled(disabled);
|
||||
_keyModLabel->setDisabled(disabled);
|
||||
_keyModCombo->setDisabled(disabled);
|
||||
_nameLabel->setDisabled(disabled);
|
||||
_nameEdit->setDisabled(disabled);
|
||||
_guiPathLabel->setDisabled(disabled);
|
||||
_guiPathEdit->setDisabled(disabled);
|
||||
_documentationLabel->setDisabled(disabled);
|
||||
_documentationEdit->setDisabled(disabled);
|
||||
_localCheck->setDisabled(disabled);
|
||||
_scriptLabel->setDisabled(disabled);
|
||||
_scriptEdit->setDisabled(disabled);
|
||||
_cancelButton->setDisabled(disabled);
|
||||
_saveButton->setDisabled(disabled);
|
||||
}
|
||||
|
||||
void KeybindingsDialog::parseSelections() {
|
||||
// Handle case with only one remaining but empty line
|
||||
if ((_data.size() == 1) && (_data.at(0).name.empty())) {
|
||||
_data.clear();
|
||||
}
|
||||
_profile.setKeybindings(_data);
|
||||
accept();
|
||||
}
|
||||
|
||||
void KeybindingsDialog::keyPressEvent(QKeyEvent* evt) {
|
||||
if (evt->key() == Qt::Key_Enter || evt->key() == Qt::Key_Return) {
|
||||
return;
|
||||
}
|
||||
else if (evt->key() == Qt::Key_Escape) {
|
||||
if (_editModeNewItem) {
|
||||
listItemCancelSave();
|
||||
return;
|
||||
}
|
||||
}
|
||||
QDialog::keyPressEvent(evt);
|
||||
}
|
||||
|
||||
30
apps/OpenSpace/ext/launcher/src/profile/line.cpp
Normal file
30
apps/OpenSpace/ext/launcher/src/profile/line.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2020 *
|
||||
* *
|
||||
* 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 *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include "profile/line.h"
|
||||
|
||||
Line::Line() {
|
||||
setFrameShape(QFrame::HLine);
|
||||
setFrameShadow(QFrame::Sunken);
|
||||
}
|
||||
157
apps/OpenSpace/ext/launcher/src/profile/marknodesdialog.cpp
Normal file
157
apps/OpenSpace/ext/launcher/src/profile/marknodesdialog.cpp
Normal file
@@ -0,0 +1,157 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2020 *
|
||||
* *
|
||||
* 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 *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include "profile/marknodesdialog.h"
|
||||
|
||||
#include "profile/line.h"
|
||||
#include <openspace/scene/profile.h>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QEvent>
|
||||
#include <QKeyEvent>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QListWidget>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
MarkNodesDialog::MarkNodesDialog(openspace::Profile& profile, QWidget* parent)
|
||||
: QDialog(parent)
|
||||
, _profile(profile)
|
||||
, _data(_profile.markNodes())
|
||||
{
|
||||
setWindowTitle("Mark Interesting Nodes");
|
||||
createWidgets();
|
||||
}
|
||||
|
||||
void MarkNodesDialog::createWidgets() {
|
||||
QBoxLayout* layout = new QVBoxLayout(this);
|
||||
_list = new QListWidget;
|
||||
connect(
|
||||
_list, &QListWidget::itemSelectionChanged,
|
||||
this, &MarkNodesDialog::listItemSelected
|
||||
);
|
||||
_list->setAlternatingRowColors(true);
|
||||
_list->setMovement(QListView::Free);
|
||||
_list->setResizeMode(QListView::Adjust);
|
||||
|
||||
for (size_t i = 0; i < _data.size(); ++i) {
|
||||
_markedNodesListItems.push_back(
|
||||
new QListWidgetItem(QString::fromStdString(_data[i]))
|
||||
);
|
||||
_list->addItem(_markedNodesListItems[i]);
|
||||
}
|
||||
layout->addWidget(_list);
|
||||
|
||||
_removeButton = new QPushButton("Remove");
|
||||
connect(_removeButton, &QPushButton::clicked, this, &MarkNodesDialog::listItemRemove);
|
||||
layout->addWidget(_removeButton);
|
||||
|
||||
{
|
||||
QBoxLayout* box = new QHBoxLayout;
|
||||
box->addWidget(new QLabel("Node to add:"));
|
||||
_newNode = new QLineEdit;
|
||||
_newNode->setToolTip(
|
||||
"Name of scenegraph node to add to list of \"interesting\" nodes"
|
||||
);
|
||||
box->addWidget(_newNode);
|
||||
|
||||
QPushButton* addButton = new QPushButton("Add new");
|
||||
connect(
|
||||
addButton, &QPushButton::clicked,
|
||||
this, &MarkNodesDialog::listItemAdded
|
||||
);
|
||||
box->addWidget(addButton);
|
||||
layout->addLayout(box);
|
||||
}
|
||||
layout->addWidget(new Line);
|
||||
{
|
||||
QDialogButtonBox* buttons = new QDialogButtonBox;
|
||||
buttons->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel);
|
||||
QObject::connect(
|
||||
buttons, &QDialogButtonBox::accepted,
|
||||
this, &MarkNodesDialog::parseSelections
|
||||
);
|
||||
QObject::connect(
|
||||
buttons, &QDialogButtonBox::rejected,
|
||||
this, &MarkNodesDialog::reject
|
||||
);
|
||||
layout->addWidget(buttons);
|
||||
}
|
||||
}
|
||||
|
||||
void MarkNodesDialog::listItemSelected() {
|
||||
_removeButton->setEnabled(true);
|
||||
}
|
||||
|
||||
void MarkNodesDialog::listItemAdded() {
|
||||
if (_newNode->text().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string itemToAdd = _newNode->text().toStdString();
|
||||
const auto it = std::find(_data.cbegin(), _data.cend(), itemToAdd);
|
||||
if (it != _data.end()) {
|
||||
_list->setCurrentRow(std::distance(_data.cbegin(), it));
|
||||
}
|
||||
else {
|
||||
_data.push_back(itemToAdd);
|
||||
_markedNodesListItems.push_back(new QListWidgetItem(_newNode->text()));
|
||||
_list->addItem(_markedNodesListItems.back());
|
||||
|
||||
// Scroll down to that blank line highlighted
|
||||
_list->setCurrentItem(_markedNodesListItems.back());
|
||||
}
|
||||
|
||||
// Blank-out entry again
|
||||
_newNode->clear();
|
||||
}
|
||||
|
||||
void MarkNodesDialog::listItemRemove() {
|
||||
QListWidgetItem* item = _list->currentItem();
|
||||
int index = _list->row(item);
|
||||
|
||||
if (index < 0 || index >= _markedNodesListItems.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
_list->takeItem(index);
|
||||
_data.erase(_data.begin() + index);
|
||||
_markedNodesListItems.erase(_markedNodesListItems.begin() + index);
|
||||
}
|
||||
|
||||
void MarkNodesDialog::parseSelections() {
|
||||
_profile.setMarkNodes(_data);
|
||||
accept();
|
||||
}
|
||||
|
||||
void MarkNodesDialog::keyPressEvent(QKeyEvent* evt) {
|
||||
if (evt->key() == Qt::Key_Enter || evt->key() == Qt::Key_Return) {
|
||||
if (_newNode->text().length() > 0 && _newNode->hasFocus()) {
|
||||
listItemAdded();
|
||||
return;
|
||||
}
|
||||
}
|
||||
QDialog::keyPressEvent(evt);
|
||||
}
|
||||
|
||||
136
apps/OpenSpace/ext/launcher/src/profile/metadialog.cpp
Normal file
136
apps/OpenSpace/ext/launcher/src/profile/metadialog.cpp
Normal file
@@ -0,0 +1,136 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2020 *
|
||||
* *
|
||||
* 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 *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include "profile/metadialog.h"
|
||||
|
||||
#include "profile/line.h"
|
||||
#include <openspace/scene/profile.h>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QKeyEvent>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QTextEdit>
|
||||
#include <QVBoxLayout>
|
||||
#include <algorithm>
|
||||
|
||||
MetaDialog::MetaDialog(openspace::Profile& profile, QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, _profile(profile)
|
||||
{
|
||||
setWindowTitle("Meta");
|
||||
createWidgets();
|
||||
|
||||
if (_profile.meta().has_value()) {
|
||||
openspace::Profile::Meta meta = *_profile.meta();
|
||||
if (meta.name.has_value()) {
|
||||
_nameEdit->setText(QString::fromStdString(*meta.name));
|
||||
}
|
||||
if (meta.version.has_value()) {
|
||||
_versionEdit->setText(QString::fromStdString(*meta.version));
|
||||
}
|
||||
if (meta.description.has_value()) {
|
||||
_descriptionEdit->setText(QString::fromStdString(*meta.description));
|
||||
}
|
||||
if (meta.author.has_value()) {
|
||||
_authorEdit->setText(QString::fromStdString(*meta.author));
|
||||
}
|
||||
if (meta.url.has_value()) {
|
||||
_urlEdit->setText(QString::fromStdString(*meta.url));
|
||||
}
|
||||
if (meta.license.has_value()) {
|
||||
_licenseEdit->setText(QString::fromStdString(*meta.license));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MetaDialog::createWidgets() {
|
||||
QBoxLayout* layout = new QVBoxLayout(this);
|
||||
layout->addWidget(new QLabel("Name"));
|
||||
_nameEdit = new QLineEdit;
|
||||
layout->addWidget(_nameEdit);
|
||||
|
||||
layout->addWidget(new QLabel("Version"));
|
||||
_versionEdit = new QLineEdit;
|
||||
layout->addWidget(_versionEdit);
|
||||
|
||||
layout->addWidget(new QLabel("Description"));
|
||||
_descriptionEdit = new QTextEdit;
|
||||
_descriptionEdit->setAcceptRichText(false);
|
||||
_descriptionEdit->setTabChangesFocus(true);
|
||||
layout->addWidget(_descriptionEdit);
|
||||
|
||||
layout->addWidget(new QLabel("Author"));
|
||||
_authorEdit = new QLineEdit;
|
||||
layout->addWidget(_authorEdit);
|
||||
|
||||
layout->addWidget(new QLabel("URL"));
|
||||
_urlEdit = new QLineEdit;
|
||||
layout->addWidget(_urlEdit);
|
||||
|
||||
layout->addWidget(new QLabel("License"));
|
||||
_licenseEdit = new QLineEdit;
|
||||
layout->addWidget(_licenseEdit);
|
||||
|
||||
layout->addWidget(new Line);
|
||||
|
||||
QDialogButtonBox* buttons = new QDialogButtonBox;
|
||||
buttons->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel);
|
||||
QObject::connect(buttons, &QDialogButtonBox::accepted, this, &MetaDialog::save);
|
||||
QObject::connect(buttons, &QDialogButtonBox::rejected, this, &MetaDialog::reject);
|
||||
layout->addWidget(buttons);
|
||||
}
|
||||
|
||||
void MetaDialog::save() {
|
||||
const bool allEmpty =
|
||||
_nameEdit->text().isEmpty() && _versionEdit->text().isEmpty() &&
|
||||
_descriptionEdit->toPlainText().isEmpty() && _authorEdit->text().isEmpty() &&
|
||||
_urlEdit->text().isEmpty() && _licenseEdit->text().isEmpty();
|
||||
|
||||
if (!allEmpty) {
|
||||
openspace::Profile::Meta m;
|
||||
if (!_nameEdit->text().isEmpty()) {
|
||||
m.name = _nameEdit->text().toStdString();
|
||||
}
|
||||
if (!_versionEdit->text().isEmpty()) {
|
||||
m.version = _versionEdit->text().toStdString();
|
||||
}
|
||||
if (!_descriptionEdit->toPlainText().isEmpty()) {
|
||||
m.description = _descriptionEdit->toPlainText().toStdString();
|
||||
}
|
||||
if (!_authorEdit->text().isEmpty()) {
|
||||
m.author = _authorEdit->text().toStdString();
|
||||
}
|
||||
if (!_urlEdit->text().isEmpty()) {
|
||||
m.url = _urlEdit->text().toStdString();
|
||||
}
|
||||
if (!_licenseEdit->text().isEmpty()) {
|
||||
m.license = _licenseEdit->text().toStdString();
|
||||
}
|
||||
_profile.setMeta(m);
|
||||
}
|
||||
else {
|
||||
_profile.clearMeta();
|
||||
}
|
||||
accept();
|
||||
}
|
||||
364
apps/OpenSpace/ext/launcher/src/profile/modulesdialog.cpp
Normal file
364
apps/OpenSpace/ext/launcher/src/profile/modulesdialog.cpp
Normal file
@@ -0,0 +1,364 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2020 *
|
||||
* *
|
||||
* 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 *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include "profile/modulesdialog.h"
|
||||
|
||||
#include "profile/line.h"
|
||||
#include <QDialogButtonBox>
|
||||
#include <QEvent>
|
||||
#include <QKeyEvent>
|
||||
#include <QLabel>
|
||||
#include <QListWidget>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
using namespace openspace;
|
||||
|
||||
namespace {
|
||||
const Profile::Module Blank = { "", "", "" };
|
||||
} // namespace
|
||||
|
||||
ModulesDialog::ModulesDialog(Profile& profile, QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, _profile(profile)
|
||||
, _data(_profile.modules())
|
||||
{
|
||||
setWindowTitle("Modules");
|
||||
createWidgets();
|
||||
|
||||
transitionFromEditMode();
|
||||
}
|
||||
|
||||
void ModulesDialog::createWidgets() {
|
||||
QBoxLayout* layout = new QVBoxLayout(this);
|
||||
{
|
||||
_list = new QListWidget;
|
||||
connect(
|
||||
_list, &QListWidget::itemSelectionChanged,
|
||||
this, &ModulesDialog::listItemSelected
|
||||
);
|
||||
_list->setAlternatingRowColors(true);
|
||||
_list->setMovement(QListView::Free);
|
||||
_list->setResizeMode(QListView::Adjust);
|
||||
|
||||
for (const Profile::Module& m : _data) {
|
||||
_list->addItem(new QListWidgetItem(createOneLineSummary(m)));
|
||||
}
|
||||
layout->addWidget(_list);
|
||||
}
|
||||
{
|
||||
QBoxLayout* box = new QHBoxLayout;
|
||||
_buttonAdd = new QPushButton("Add new");
|
||||
connect(_buttonAdd, &QPushButton::clicked, this, &ModulesDialog::listItemAdded);
|
||||
box->addWidget(_buttonAdd);
|
||||
|
||||
_buttonRemove = new QPushButton("Remove");
|
||||
connect(
|
||||
_buttonRemove, &QPushButton::clicked,
|
||||
this, &ModulesDialog::listItemRemove
|
||||
);
|
||||
box->addWidget(_buttonRemove);
|
||||
|
||||
box->addStretch();
|
||||
|
||||
layout->addLayout(box);
|
||||
}
|
||||
{
|
||||
_moduleLabel = new QLabel("Module");
|
||||
layout->addWidget(_moduleLabel);
|
||||
_moduleEdit = new QLineEdit;
|
||||
_moduleEdit->setToolTip("Name of OpenSpace module related to this profile");
|
||||
layout->addWidget(_moduleEdit);
|
||||
|
||||
_loadedLabel = new QLabel("Command if Module is Loaded");
|
||||
layout->addWidget(_loadedLabel);
|
||||
_loadedEdit = new QLineEdit;
|
||||
_loadedEdit->setToolTip(
|
||||
"Lua command(s) to execute if OpenSpace has been compiled with the module"
|
||||
);
|
||||
layout->addWidget(_loadedEdit);
|
||||
|
||||
_notLoadedLabel = new QLabel("Command if Module is NOT Loaded");
|
||||
layout->addWidget(_notLoadedLabel);
|
||||
_notLoadedEdit = new QLineEdit;
|
||||
_notLoadedEdit->setToolTip(
|
||||
"Lua command(s) to execute if the module is not present in the OpenSpace "
|
||||
"application (for example steps to account for a missing module)"
|
||||
);
|
||||
layout->addWidget(_notLoadedEdit);
|
||||
}
|
||||
{
|
||||
QBoxLayout* box = new QHBoxLayout;
|
||||
_buttonSave = new QPushButton("Save");
|
||||
_buttonSave->setToolTip("Save module changes to the above list");
|
||||
connect(_buttonSave, &QPushButton::clicked, this, &ModulesDialog::listItemSave);
|
||||
box->addWidget(_buttonSave);
|
||||
|
||||
_buttonCancel = new QPushButton("Cancel");
|
||||
_buttonCancel->setToolTip("Cancel adding this module to the above list");
|
||||
connect(
|
||||
_buttonCancel, &QPushButton::clicked,
|
||||
this, &ModulesDialog::listItemCancelSave
|
||||
);
|
||||
box->addWidget(_buttonCancel);
|
||||
|
||||
box->addStretch();
|
||||
|
||||
layout->addLayout(box);
|
||||
}
|
||||
layout->addWidget(new Line);
|
||||
{
|
||||
QBoxLayout* footerLayout = new QHBoxLayout;
|
||||
|
||||
_errorMsg = new QLabel;
|
||||
_errorMsg->setObjectName("error-message");
|
||||
_errorMsg->setWordWrap(true);
|
||||
footerLayout->addWidget(_errorMsg);
|
||||
|
||||
_buttonBox = new QDialogButtonBox;
|
||||
_buttonBox->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel);
|
||||
QObject::connect(
|
||||
_buttonBox, &QDialogButtonBox::accepted,
|
||||
this, &ModulesDialog::parseSelections
|
||||
);
|
||||
QObject::connect(
|
||||
_buttonBox, &QDialogButtonBox::rejected,
|
||||
this, &ModulesDialog::reject
|
||||
);
|
||||
footerLayout->addWidget(_buttonBox);
|
||||
layout->addLayout(footerLayout);
|
||||
}
|
||||
}
|
||||
|
||||
QString ModulesDialog::createOneLineSummary(Profile::Module m) {
|
||||
QString summary = QString::fromStdString(m.name);
|
||||
bool hasCommandForLoaded = (m.loadedInstruction->length() > 0);
|
||||
bool hasCommandForNotLoaded = (m.notLoadedInstruction->length() > 0);
|
||||
|
||||
if (hasCommandForLoaded && hasCommandForNotLoaded) {
|
||||
summary += " (commands set for both loaded & not-loaded conditions)";
|
||||
}
|
||||
else if (hasCommandForLoaded) {
|
||||
summary += " (command set only for loaded condition)";
|
||||
}
|
||||
else if (hasCommandForNotLoaded) {
|
||||
summary += " (command set only for NOT loaded condition)";
|
||||
}
|
||||
else {
|
||||
summary += " (no commands set)";
|
||||
}
|
||||
return summary;
|
||||
}
|
||||
|
||||
void ModulesDialog::listItemSelected() {
|
||||
QListWidgetItem* item = _list->currentItem();
|
||||
int index = _list->row(item);
|
||||
|
||||
if (!_data.empty()) {
|
||||
const Profile::Module& m = _data[index];
|
||||
_moduleEdit->setText(QString::fromStdString(m.name));
|
||||
if (m.loadedInstruction.has_value()) {
|
||||
_loadedEdit->setText(QString::fromStdString(*m.loadedInstruction));
|
||||
}
|
||||
else {
|
||||
_loadedEdit->clear();
|
||||
}
|
||||
if (m.notLoadedInstruction.has_value()) {
|
||||
_notLoadedEdit->setText(QString::fromStdString(*m.notLoadedInstruction));
|
||||
}
|
||||
else {
|
||||
_notLoadedEdit->clear();
|
||||
}
|
||||
}
|
||||
transitionToEditMode();
|
||||
}
|
||||
|
||||
bool ModulesDialog::isLineEmpty(int index) const {
|
||||
bool isEmpty = true;
|
||||
if (!_list->item(index)->text().isEmpty()) {
|
||||
isEmpty = false;
|
||||
}
|
||||
if (!_data.empty() && !_data.at(0).name.empty()) {
|
||||
isEmpty = false;
|
||||
}
|
||||
return isEmpty;
|
||||
}
|
||||
|
||||
void ModulesDialog::listItemAdded() {
|
||||
int currentListSize = _list->count();
|
||||
|
||||
if ((currentListSize == 1) && (isLineEmpty(0))) {
|
||||
// Special case where list is "empty" but really has one line that is blank.
|
||||
// This is done because QListWidget does not seem to like having its sole
|
||||
// remaining item being removed.
|
||||
_data.at(0) = Blank;
|
||||
_list->item(0)->setText(" (Enter details below & click 'Save')");
|
||||
_list->setCurrentRow(0);
|
||||
transitionToEditMode();
|
||||
}
|
||||
else {
|
||||
_data.push_back(Blank);
|
||||
_list->addItem(new QListWidgetItem(" (Enter details below & click 'Save')"));
|
||||
//Scroll down to that blank line highlighted
|
||||
_list->setCurrentRow(_list->count() - 1);
|
||||
_errorMsg->clear();
|
||||
}
|
||||
|
||||
// Blank-out the 2 text fields, set combo box to index 0
|
||||
_moduleEdit->setText(QString::fromStdString(_data.back().name));
|
||||
if (_data.back().loadedInstruction.has_value()) {
|
||||
_loadedEdit->setText(QString::fromStdString(*_data.back().loadedInstruction));
|
||||
}
|
||||
else {
|
||||
_loadedEdit->clear();
|
||||
}
|
||||
if (_data.back().notLoadedInstruction.has_value()) {
|
||||
_notLoadedEdit->setText(
|
||||
QString::fromStdString(*_data.back().notLoadedInstruction)
|
||||
);
|
||||
}
|
||||
else {
|
||||
_notLoadedEdit->clear();
|
||||
}
|
||||
_moduleEdit->setFocus(Qt::OtherFocusReason);
|
||||
_editModeNewItem = true;
|
||||
}
|
||||
|
||||
void ModulesDialog::listItemSave() {
|
||||
if (_moduleEdit->text().isEmpty()) {
|
||||
_errorMsg->setText("Missing module name");
|
||||
return;
|
||||
}
|
||||
|
||||
QListWidgetItem* item = _list->currentItem();
|
||||
int index = _list->row(item);
|
||||
|
||||
if ( _data.size() > 0) {
|
||||
_data[index].name = _moduleEdit->text().toStdString();
|
||||
_data[index].loadedInstruction = _loadedEdit->text().toStdString();
|
||||
_data[index].notLoadedInstruction = _notLoadedEdit->text().toStdString();
|
||||
_list->item(index)->setText(createOneLineSummary(_data[index]));
|
||||
}
|
||||
transitionFromEditMode();
|
||||
_editModeNewItem = false;
|
||||
}
|
||||
|
||||
void ModulesDialog::listItemCancelSave() {
|
||||
transitionFromEditMode();
|
||||
if (_editModeNewItem && !_data.empty() && _data.back().name.empty()) {
|
||||
listItemRemove();
|
||||
}
|
||||
_editModeNewItem = false;
|
||||
}
|
||||
|
||||
void ModulesDialog::listItemRemove() {
|
||||
if (_list->count() > 0) {
|
||||
if (_list->currentRow() >= 0 && _list->currentRow() < _list->count()) {
|
||||
if (_list->count() == 1) {
|
||||
// Special case where last remaining item is being removed (QListWidget
|
||||
// doesn't like the final item being removed so instead clear it)
|
||||
_data.at(0) = Blank;
|
||||
_list->item(0)->setText("");
|
||||
}
|
||||
else {
|
||||
int index = _list->currentRow();
|
||||
if (index >= 0 && index < _list->count()) {
|
||||
delete _list->takeItem(index);
|
||||
if (!_data.empty()) {
|
||||
_data.erase(_data.begin() + index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
transitionFromEditMode();
|
||||
}
|
||||
|
||||
void ModulesDialog::transitionToEditMode() {
|
||||
_list->setDisabled(true);
|
||||
_buttonAdd->setDisabled(true);
|
||||
_buttonRemove->setDisabled(true);
|
||||
_buttonSave->setDisabled(true);
|
||||
_buttonCancel->setDisabled(true);
|
||||
_buttonBox->setDisabled(true);
|
||||
|
||||
_moduleLabel->setText("<font color='black'>Module</font>");
|
||||
_loadedLabel->setText("<font color='black'>Command if Module is Loaded</font>");
|
||||
_notLoadedLabel->setText("<font color='black'>Command if Module is NOT Loaded</font>");
|
||||
editBoxDisabled(false);
|
||||
_errorMsg->setText("");
|
||||
}
|
||||
|
||||
void ModulesDialog::transitionFromEditMode() {
|
||||
_list->setDisabled(false);
|
||||
_buttonAdd->setDisabled(false);
|
||||
_buttonRemove->setDisabled(false);
|
||||
_buttonSave->setDisabled(false);
|
||||
_buttonCancel->setDisabled(false);
|
||||
_buttonBox->setDisabled(false);
|
||||
|
||||
editBoxDisabled(true);
|
||||
_moduleLabel->setText("<font color='light gray'>Module</font>");
|
||||
_loadedLabel->setText("<font color='light gray'>Command if Module is Loaded</font>");
|
||||
_notLoadedLabel->setText("<font color='light gray'>Command if Module is NOT Loaded</font>");
|
||||
_errorMsg->setText("");
|
||||
}
|
||||
|
||||
void ModulesDialog::editBoxDisabled(bool disabled) {
|
||||
_moduleLabel->setDisabled(disabled);
|
||||
_moduleEdit->setDisabled(disabled);
|
||||
_loadedLabel->setDisabled(disabled);
|
||||
_loadedEdit->setDisabled(disabled);
|
||||
_notLoadedLabel->setDisabled(disabled);
|
||||
_notLoadedEdit->setDisabled(disabled);
|
||||
_buttonCancel->setDisabled(disabled);
|
||||
_buttonSave->setDisabled(disabled);
|
||||
}
|
||||
|
||||
void ModulesDialog::parseSelections() {
|
||||
// Handle case with only one remaining but empty line
|
||||
if ((_data.size() == 1) && (_data.at(0).name.empty())) {
|
||||
_data.clear();
|
||||
}
|
||||
_profile.setModules(_data);
|
||||
accept();
|
||||
}
|
||||
|
||||
void ModulesDialog::keyPressEvent(QKeyEvent* evt) {
|
||||
if (evt->key() == Qt::Key_Enter || evt->key() == Qt::Key_Return) {
|
||||
if (_editModeNewItem) {
|
||||
listItemSave();
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (evt->key() == Qt::Key_Escape) {
|
||||
if (_editModeNewItem) {
|
||||
listItemCancelSave();
|
||||
return;
|
||||
}
|
||||
}
|
||||
QDialog::keyPressEvent(evt);
|
||||
}
|
||||
|
||||
505
apps/OpenSpace/ext/launcher/src/profile/profileedit.cpp
Normal file
505
apps/OpenSpace/ext/launcher/src/profile/profileedit.cpp
Normal file
@@ -0,0 +1,505 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2020 *
|
||||
* *
|
||||
* 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 *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include "profile/profileedit.h"
|
||||
|
||||
#include "profile/additionalscriptsdialog.h"
|
||||
#include "profile/assetsdialog.h"
|
||||
#include "profile/cameradialog.h"
|
||||
#include "profile/deltatimesdialog.h"
|
||||
#include "profile/keybindingsdialog.h"
|
||||
#include "profile/line.h"
|
||||
#include "profile/marknodesdialog.h"
|
||||
#include "profile/metadialog.h"
|
||||
#include "profile/modulesdialog.h"
|
||||
#include "profile/propertiesdialog.h"
|
||||
#include "profile/timedialog.h"
|
||||
#include <openspace/scene/profile.h>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QKeyEvent>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QTextEdit>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
|
||||
using namespace openspace;
|
||||
|
||||
namespace {
|
||||
QString labelText(int size, QString title) {
|
||||
QString label;
|
||||
if (size > 0) {
|
||||
label = title + " (" + QString::number(size) + ")";
|
||||
}
|
||||
else {
|
||||
label = title;
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
std::string summarizeAssets(const std::vector<std::string>& assets) {
|
||||
std::string results;
|
||||
for (const std::string& a : assets) {
|
||||
results += a + '\n';
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
std::string summarizeKeybindings(const std::vector<Profile::Keybinding>& keybindings)
|
||||
{
|
||||
std::string results;
|
||||
for (Profile::Keybinding k : keybindings) {
|
||||
results += k.name + " (";
|
||||
int keymod = static_cast<int>(k.key.modifier);
|
||||
if (keymod != static_cast<int>(openspace::KeyModifier::NoModifier)) {
|
||||
results += openspace::KeyModifierNames.at(keymod) + "+";
|
||||
}
|
||||
results += openspace::KeyNames.at(static_cast<int>(k.key.key));
|
||||
results += ")\n";
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
std::string summarizeProperties(const std::vector<Profile::Property>& properties) {
|
||||
std::string results;
|
||||
for (openspace::Profile::Property p : properties) {
|
||||
results += p.name + " = " + p.value + '\n';
|
||||
}
|
||||
return results;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
ProfileEdit::ProfileEdit(Profile& profile, const std::string& profileName,
|
||||
std::string assetBasePath, std::string profileBasePath,
|
||||
const std::vector<std::string>& readOnlyProfiles,
|
||||
QWidget* parent)
|
||||
: QDialog(parent)
|
||||
, _assetBasePath(std::move(assetBasePath))
|
||||
, _profileBasePath(std::move(profileBasePath))
|
||||
, _profile(profile)
|
||||
, _readOnlyProfiles(readOnlyProfiles)
|
||||
{
|
||||
setWindowTitle("Profile Editor");
|
||||
createWidgets(profileName);
|
||||
|
||||
initSummaryTextForEachCategory();
|
||||
}
|
||||
|
||||
void ProfileEdit::createWidgets(const std::string& profileName) {
|
||||
QBoxLayout* layout = new QVBoxLayout(this);
|
||||
QBoxLayout* topLayout = new QHBoxLayout;
|
||||
QBoxLayout* leftLayout = new QVBoxLayout;
|
||||
{
|
||||
QBoxLayout* container = new QHBoxLayout;
|
||||
QLabel* profileLabel = new QLabel("Profile Name:");
|
||||
profileLabel->setObjectName("profile");
|
||||
container->addWidget(profileLabel);
|
||||
|
||||
_profileEdit = new QLineEdit(QString::fromStdString(profileName));
|
||||
container->addWidget(_profileEdit);
|
||||
|
||||
QPushButton* duplicateButton = new QPushButton("Duplicate Profile");
|
||||
connect(
|
||||
duplicateButton, &QPushButton::clicked,
|
||||
this, &ProfileEdit::duplicateProfile
|
||||
);
|
||||
container->addWidget(duplicateButton);
|
||||
|
||||
layout->addLayout(container);
|
||||
}
|
||||
layout->addWidget(new Line);
|
||||
{
|
||||
QGridLayout* container = new QGridLayout;
|
||||
container->setColumnStretch(1, 1);
|
||||
|
||||
_propertiesLabel = new QLabel("Properties");
|
||||
_propertiesLabel->setObjectName("heading");
|
||||
_propertiesLabel->setWordWrap(true);
|
||||
container->addWidget(_propertiesLabel, 0, 0);
|
||||
|
||||
QPushButton* editProperties = new QPushButton("Edit");
|
||||
connect(
|
||||
editProperties, &QPushButton::clicked,
|
||||
this, &ProfileEdit::openProperties
|
||||
);
|
||||
container->addWidget(editProperties, 0, 2);
|
||||
|
||||
_propertiesEdit = new QTextEdit;
|
||||
_propertiesEdit->setReadOnly(true);
|
||||
container->addWidget(_propertiesEdit, 1, 0, 1, 3);
|
||||
|
||||
leftLayout->addLayout(container);
|
||||
}
|
||||
leftLayout->addWidget(new Line);
|
||||
{
|
||||
QGridLayout* container = new QGridLayout;
|
||||
container->setColumnStretch(1, 1);
|
||||
|
||||
_assetsLabel = new QLabel("Assets");
|
||||
_assetsLabel->setObjectName("heading");
|
||||
_assetsLabel->setWordWrap(true);
|
||||
container->addWidget(_assetsLabel, 0, 0);
|
||||
|
||||
QPushButton* assetsProperties = new QPushButton("Edit");
|
||||
connect(assetsProperties, &QPushButton::clicked, this, &ProfileEdit::openAssets);
|
||||
container->addWidget(assetsProperties, 0, 2);
|
||||
|
||||
_assetsEdit = new QTextEdit;
|
||||
_assetsEdit->setReadOnly(true);
|
||||
container->addWidget(_assetsEdit, 1, 0, 1, 3);
|
||||
|
||||
leftLayout->addLayout(container);
|
||||
}
|
||||
leftLayout->addWidget(new Line);
|
||||
{
|
||||
QGridLayout* container = new QGridLayout;
|
||||
container->setColumnStretch(1, 1);
|
||||
|
||||
_keybindingsLabel = new QLabel("Keybindings");
|
||||
_keybindingsLabel->setObjectName("heading");
|
||||
_keybindingsLabel->setWordWrap(true);
|
||||
container->addWidget(_keybindingsLabel, 0, 0);
|
||||
|
||||
QPushButton* keybindingsProperties = new QPushButton("Edit");
|
||||
connect(
|
||||
keybindingsProperties, &QPushButton::clicked,
|
||||
this, &ProfileEdit::openKeybindings
|
||||
);
|
||||
container->addWidget(keybindingsProperties, 0, 2);
|
||||
|
||||
_keybindingsEdit = new QTextEdit;
|
||||
_keybindingsEdit->setReadOnly(true);
|
||||
container->addWidget(_keybindingsEdit, 1, 0, 1, 3);
|
||||
|
||||
leftLayout->addLayout(container);
|
||||
}
|
||||
topLayout->addLayout(leftLayout, 3);
|
||||
|
||||
topLayout->addWidget(new Line);
|
||||
|
||||
QBoxLayout* rightLayout = new QVBoxLayout;
|
||||
{
|
||||
QBoxLayout* container = new QVBoxLayout;
|
||||
_metaLabel = new QLabel("Meta");
|
||||
_metaLabel->setObjectName("heading");
|
||||
_metaLabel->setWordWrap(true);
|
||||
container->addWidget(_metaLabel);
|
||||
|
||||
QPushButton* metaEdit = new QPushButton("Edit");
|
||||
connect(metaEdit, &QPushButton::clicked, this, &ProfileEdit::openMeta);
|
||||
metaEdit->setLayoutDirection(Qt::RightToLeft);
|
||||
container->addWidget(metaEdit);
|
||||
rightLayout->addLayout(container);
|
||||
}
|
||||
rightLayout->addWidget(new Line);
|
||||
{
|
||||
QBoxLayout* container = new QVBoxLayout;
|
||||
_interestingNodesLabel = new QLabel("Mark Interesting Nodes");
|
||||
_interestingNodesLabel->setObjectName("heading");
|
||||
_interestingNodesLabel->setWordWrap(true);
|
||||
container->addWidget(_interestingNodesLabel);
|
||||
|
||||
QPushButton* interestingNodesEdit = new QPushButton("Edit");
|
||||
connect(
|
||||
interestingNodesEdit, &QPushButton::clicked,
|
||||
this, &ProfileEdit::openMarkNodes
|
||||
);
|
||||
interestingNodesEdit->setLayoutDirection(Qt::RightToLeft);
|
||||
container->addWidget(interestingNodesEdit);
|
||||
rightLayout->addLayout(container);
|
||||
}
|
||||
rightLayout->addWidget(new Line);
|
||||
{
|
||||
QBoxLayout* container = new QVBoxLayout;
|
||||
_deltaTimesLabel = new QLabel("Simulation Time Increments");
|
||||
_deltaTimesLabel->setObjectName("heading");
|
||||
_deltaTimesLabel->setWordWrap(true);
|
||||
container->addWidget(_deltaTimesLabel);
|
||||
|
||||
QPushButton* deltaTimesEdit = new QPushButton("Edit");
|
||||
connect(
|
||||
deltaTimesEdit, &QPushButton::clicked,
|
||||
this, &ProfileEdit::openDeltaTimes
|
||||
);
|
||||
deltaTimesEdit->setLayoutDirection(Qt::RightToLeft);
|
||||
container->addWidget(deltaTimesEdit);
|
||||
rightLayout->addLayout(container);
|
||||
}
|
||||
rightLayout->addWidget(new Line);
|
||||
{
|
||||
QBoxLayout* container = new QVBoxLayout;
|
||||
_cameraLabel = new QLabel("Camera");
|
||||
_cameraLabel->setObjectName("heading");
|
||||
_cameraLabel->setWordWrap(true);
|
||||
container->addWidget(_cameraLabel);
|
||||
|
||||
QPushButton* cameraEdit = new QPushButton("Edit");
|
||||
connect(cameraEdit, &QPushButton::clicked, this, &ProfileEdit::openCamera);
|
||||
cameraEdit->setLayoutDirection(Qt::RightToLeft);
|
||||
container->addWidget(cameraEdit);
|
||||
rightLayout->addLayout(container);
|
||||
}
|
||||
rightLayout->addWidget(new Line);
|
||||
{
|
||||
QBoxLayout* container = new QVBoxLayout;
|
||||
_timeLabel = new QLabel("Time");
|
||||
_timeLabel->setObjectName("heading");
|
||||
_timeLabel->setWordWrap(true);
|
||||
container->addWidget(_timeLabel);
|
||||
|
||||
QPushButton* timeEdit = new QPushButton("Edit");
|
||||
connect(timeEdit, &QPushButton::clicked, this, &ProfileEdit::openTime);
|
||||
timeEdit->setLayoutDirection(Qt::RightToLeft);
|
||||
container->addWidget(timeEdit);
|
||||
rightLayout->addLayout(container);
|
||||
}
|
||||
rightLayout->addWidget(new Line);
|
||||
{
|
||||
QBoxLayout* container = new QVBoxLayout;
|
||||
_modulesLabel = new QLabel("Modules");
|
||||
_modulesLabel->setObjectName("heading");
|
||||
_modulesLabel->setWordWrap(true);
|
||||
container->addWidget(_modulesLabel);
|
||||
|
||||
QPushButton* modulesEdit = new QPushButton("Edit");
|
||||
connect(modulesEdit, &QPushButton::clicked, this, &ProfileEdit::openModules);
|
||||
modulesEdit->setLayoutDirection(Qt::RightToLeft);
|
||||
container->addWidget(modulesEdit);
|
||||
rightLayout->addLayout(container);
|
||||
}
|
||||
rightLayout->addWidget(new Line);
|
||||
{
|
||||
QBoxLayout* container = new QVBoxLayout;
|
||||
_additionalScriptsLabel = new QLabel("Additional Scripts");
|
||||
_additionalScriptsLabel->setObjectName("heading");
|
||||
_additionalScriptsLabel->setWordWrap(true);
|
||||
container->addWidget(_additionalScriptsLabel);
|
||||
|
||||
QPushButton* additionalScriptsEdit = new QPushButton("Edit");
|
||||
connect(
|
||||
additionalScriptsEdit, &QPushButton::clicked,
|
||||
this, &ProfileEdit::openAddedScripts
|
||||
);
|
||||
additionalScriptsEdit->setLayoutDirection(Qt::RightToLeft);
|
||||
container->addWidget(additionalScriptsEdit);
|
||||
rightLayout->addLayout(container);
|
||||
}
|
||||
topLayout->addLayout(rightLayout);
|
||||
layout->addLayout(topLayout);
|
||||
|
||||
layout->addWidget(new Line);
|
||||
|
||||
{
|
||||
QBoxLayout* footer = new QHBoxLayout;
|
||||
_errorMsg = new QLabel;
|
||||
_errorMsg->setObjectName("error-message");
|
||||
_errorMsg->setWordWrap(true);
|
||||
footer->addWidget(_errorMsg);
|
||||
|
||||
QDialogButtonBox* buttons = new QDialogButtonBox;
|
||||
buttons->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel);
|
||||
connect(buttons, &QDialogButtonBox::accepted, this, &ProfileEdit::approved);
|
||||
connect(buttons, &QDialogButtonBox::rejected, this, &ProfileEdit::reject);
|
||||
footer->addWidget(buttons);
|
||||
layout->addLayout(footer);
|
||||
}
|
||||
}
|
||||
|
||||
void ProfileEdit::initSummaryTextForEachCategory() {
|
||||
_modulesLabel->setText(labelText(_profile.modules().size(), "Modules"));
|
||||
|
||||
_assetsLabel->setText(labelText(_profile.assets().size(), "Assets"));
|
||||
_assetsEdit->setText(QString::fromStdString(summarizeAssets(_profile.assets())));
|
||||
|
||||
_propertiesLabel->setText(labelText(_profile.properties().size(), "Properties"));
|
||||
_propertiesEdit->setText(
|
||||
QString::fromStdString(summarizeProperties(_profile.properties()))
|
||||
);
|
||||
|
||||
_keybindingsLabel->setText(labelText(_profile.keybindings().size(), "Keybindings"));
|
||||
_keybindingsEdit->setText(
|
||||
QString::fromStdString(summarizeKeybindings(_profile.keybindings()))
|
||||
);
|
||||
|
||||
_deltaTimesLabel->setText(
|
||||
labelText(_profile.deltaTimes().size(), "Simulation Time Increments")
|
||||
);
|
||||
_interestingNodesLabel->setText(
|
||||
labelText(_profile.markNodes().size(), "Mark Interesting Nodes")
|
||||
);
|
||||
}
|
||||
|
||||
void ProfileEdit::duplicateProfile() {
|
||||
_errorMsg->clear();
|
||||
std::string profile = _profileEdit->text().toStdString();
|
||||
if (profile.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr const 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
|
||||
// number attached to it
|
||||
std::string versionStr = profile.substr(it + 1);
|
||||
try {
|
||||
version = std::stoi(versionStr);
|
||||
|
||||
// We will re-add the separator with the new version string to the file, so we
|
||||
// will remove the suffix here first
|
||||
profile = profile.substr(0, it);
|
||||
}
|
||||
catch (const std::invalid_argument& e) {
|
||||
// If this exception is thrown, we did find a separator character but the
|
||||
// substring afterwards was not a number, so the user just added a separator
|
||||
// by themselves. In this case we don't do anything
|
||||
}
|
||||
}
|
||||
|
||||
// By this point we have our current profile (without any suffix) in 'profile' and the
|
||||
// currently active version in 'version'. Now we need to put both together again and
|
||||
// also make sure that we don't pick a version number that already exists
|
||||
while (true) {
|
||||
version++;
|
||||
|
||||
std::string candidate = profile + Separator + std::to_string(version);
|
||||
std::string candidatePath = _profileBasePath + candidate + ".profile";
|
||||
|
||||
if (!std::filesystem::exists(candidatePath)) {
|
||||
_profileEdit->setText(QString::fromStdString(std::move(candidate)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProfileEdit::openMeta() {
|
||||
_errorMsg->clear();
|
||||
MetaDialog(_profile, this).exec();
|
||||
}
|
||||
|
||||
void ProfileEdit::openModules() {
|
||||
_errorMsg->clear();
|
||||
ModulesDialog(_profile, this).exec();
|
||||
_modulesLabel->setText(labelText(_profile.modules().size(), "Modules"));
|
||||
}
|
||||
|
||||
void ProfileEdit::openProperties() {
|
||||
_errorMsg->clear();
|
||||
PropertiesDialog(_profile, this).exec();
|
||||
_propertiesLabel->setText(labelText(_profile.properties().size(), "Properties"));
|
||||
_propertiesEdit->setText(
|
||||
QString::fromStdString(summarizeProperties(_profile.properties()))
|
||||
);
|
||||
}
|
||||
|
||||
void ProfileEdit::openKeybindings() {
|
||||
_errorMsg->clear();
|
||||
KeybindingsDialog(_profile, this).exec();
|
||||
_keybindingsLabel->setText(labelText(_profile.keybindings().size(), "Keybindings"));
|
||||
_keybindingsEdit->setText(
|
||||
QString::fromStdString(summarizeKeybindings(_profile.keybindings()))
|
||||
);
|
||||
}
|
||||
|
||||
void ProfileEdit::openAssets() {
|
||||
_errorMsg->clear();
|
||||
AssetsDialog(_profile, _assetBasePath, this).exec();
|
||||
_assetsLabel->setText(labelText(_profile.assets().size(), "Assets"));
|
||||
_assetsEdit->setText(QString::fromStdString(summarizeAssets(_profile.assets())));
|
||||
}
|
||||
|
||||
void ProfileEdit::openTime() {
|
||||
_errorMsg->clear();
|
||||
TimeDialog(_profile, this).exec();
|
||||
}
|
||||
|
||||
void ProfileEdit::openDeltaTimes() {
|
||||
_errorMsg->clear();
|
||||
DeltaTimesDialog(_profile, this).exec();
|
||||
_deltaTimesLabel->setText(
|
||||
labelText(_profile.deltaTimes().size(), "Simulation Time Increments")
|
||||
);
|
||||
}
|
||||
|
||||
void ProfileEdit::openAddedScripts() {
|
||||
_errorMsg->clear();
|
||||
AdditionalScriptsDialog(_profile, this).exec();
|
||||
}
|
||||
|
||||
void ProfileEdit::openCamera() {
|
||||
_errorMsg->clear();
|
||||
CameraDialog(_profile, this).exec();
|
||||
}
|
||||
|
||||
void ProfileEdit::openMarkNodes() {
|
||||
_errorMsg->clear();
|
||||
MarkNodesDialog(_profile, this).exec();
|
||||
_interestingNodesLabel->setText(
|
||||
labelText(_profile.markNodes().size(), "Mark Interesting Nodes")
|
||||
);
|
||||
}
|
||||
|
||||
bool ProfileEdit::wasSaved() const {
|
||||
return _saveSelected;
|
||||
}
|
||||
|
||||
std::string ProfileEdit::specifiedFilename() const {
|
||||
return _profileEdit->text().toStdString();
|
||||
}
|
||||
|
||||
void ProfileEdit::cancel() {
|
||||
_saveSelected = false;
|
||||
reject();
|
||||
}
|
||||
|
||||
void ProfileEdit::approved() {
|
||||
std::string profileName = _profileEdit->text().toStdString();
|
||||
if (profileName.empty()) {
|
||||
_errorMsg->setText("Profile name must be specified");
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = std::find(_readOnlyProfiles.begin(), _readOnlyProfiles.end(), profileName);
|
||||
if (it == _readOnlyProfiles.end()) {
|
||||
_saveSelected = true;
|
||||
_errorMsg->setText("");
|
||||
accept();
|
||||
}
|
||||
else {
|
||||
_errorMsg->setText(
|
||||
"This is a read-only profile. Click 'Duplicate' or rename & save"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void ProfileEdit::keyPressEvent(QKeyEvent* evt) {
|
||||
if (evt->key() == Qt::Key_Enter || evt->key() == Qt::Key_Return) {
|
||||
return;
|
||||
}
|
||||
QDialog::keyPressEvent(evt);
|
||||
}
|
||||
|
||||
369
apps/OpenSpace/ext/launcher/src/profile/propertiesdialog.cpp
Normal file
369
apps/OpenSpace/ext/launcher/src/profile/propertiesdialog.cpp
Normal file
@@ -0,0 +1,369 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2020 *
|
||||
* *
|
||||
* 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 *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include "profile/propertiesdialog.h"
|
||||
|
||||
#include "profile/line.h"
|
||||
#include <QComboBox>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QEvent>
|
||||
#include <QKeyEvent>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QListWidget>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <iostream>
|
||||
|
||||
using namespace openspace;
|
||||
|
||||
namespace {
|
||||
const Profile::Property Blank {
|
||||
Profile::Property::SetType::SetPropertyValueSingle,
|
||||
"",
|
||||
""
|
||||
};
|
||||
} // namespace
|
||||
|
||||
PropertiesDialog::PropertiesDialog(Profile& profile, QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, _profile(profile)
|
||||
, _data(_profile.properties())
|
||||
{
|
||||
setWindowTitle("Set Property Values");
|
||||
createWidgets();
|
||||
|
||||
transitionFromEditMode();
|
||||
}
|
||||
|
||||
void PropertiesDialog::createWidgets() {
|
||||
QBoxLayout* layout = new QVBoxLayout(this);
|
||||
{
|
||||
_list = new QListWidget;
|
||||
connect(
|
||||
_list, &QListWidget::itemSelectionChanged,
|
||||
this, &PropertiesDialog::listItemSelected
|
||||
);
|
||||
for (size_t i = 0; i < _data.size(); ++i) {
|
||||
_list->addItem(new QListWidgetItem(createOneLineSummary(_data[i])));
|
||||
}
|
||||
layout->addWidget(_list);
|
||||
}
|
||||
{
|
||||
QBoxLayout* box = new QHBoxLayout;
|
||||
_addButton = new QPushButton("Add New");
|
||||
connect(
|
||||
_addButton, &QPushButton::clicked,
|
||||
this, &PropertiesDialog::listItemAdded
|
||||
);
|
||||
box->addWidget(_addButton);
|
||||
|
||||
_removeButton = new QPushButton("Remove");
|
||||
connect(
|
||||
_removeButton, &QPushButton::clicked,
|
||||
this, &PropertiesDialog::listItemRemove
|
||||
);
|
||||
box->addWidget(_removeButton);
|
||||
|
||||
box->addStretch();
|
||||
|
||||
layout->addLayout(box);
|
||||
}
|
||||
layout->addWidget(new Line);
|
||||
{
|
||||
_commandLabel = new QLabel("Property Set Command");
|
||||
layout->addWidget(_commandLabel);
|
||||
|
||||
_commandCombo = new QComboBox;
|
||||
_commandCombo->addItems({ "SetPropertyValueSingle", "SetPropertyValue" });
|
||||
layout->addWidget(_commandCombo);
|
||||
|
||||
_propertyLabel = new QLabel("Property");
|
||||
layout->addWidget(_propertyLabel);
|
||||
_propertyEdit = new QLineEdit;
|
||||
_propertyEdit->setToolTip("Exact string is required for the property to be set");
|
||||
layout->addWidget(_propertyEdit);
|
||||
|
||||
_valueLabel = new QLabel("Value to Set");
|
||||
layout->addWidget(_valueLabel);
|
||||
_valueEdit = new QLineEdit;
|
||||
layout->addWidget(_valueEdit);
|
||||
|
||||
{
|
||||
QBoxLayout* box = new QHBoxLayout;
|
||||
_saveButton = new QPushButton("Save");
|
||||
connect(
|
||||
_saveButton, &QPushButton::clicked,
|
||||
this, &PropertiesDialog::listItemSave
|
||||
);
|
||||
box->addWidget(_saveButton);
|
||||
|
||||
_cancelButton = new QPushButton("Cancel");
|
||||
connect(
|
||||
_cancelButton, &QPushButton::clicked,
|
||||
this, &PropertiesDialog::listItemCancelSave
|
||||
);
|
||||
box->addWidget(_cancelButton);
|
||||
|
||||
box->addStretch();
|
||||
|
||||
layout->addLayout(box);
|
||||
}
|
||||
}
|
||||
layout->addWidget(new Line);
|
||||
{
|
||||
QBoxLayout* footerLayout = new QHBoxLayout;
|
||||
|
||||
_errorMsg = new QLabel;
|
||||
_errorMsg->setObjectName("error-message");
|
||||
_errorMsg->setWordWrap(true);
|
||||
footerLayout->addWidget(_errorMsg);
|
||||
|
||||
_buttonBox = new QDialogButtonBox;
|
||||
_buttonBox->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel);
|
||||
|
||||
connect(
|
||||
_buttonBox, &QDialogButtonBox::accepted,
|
||||
this, &PropertiesDialog::parseSelections
|
||||
);
|
||||
connect(
|
||||
_buttonBox, &QDialogButtonBox::rejected,
|
||||
this, &PropertiesDialog::reject
|
||||
);
|
||||
footerLayout->addWidget(_buttonBox);
|
||||
layout->addLayout(footerLayout);
|
||||
}
|
||||
}
|
||||
|
||||
QString PropertiesDialog::createOneLineSummary(Profile::Property p) {
|
||||
QString summary = QString::fromStdString(p.name);
|
||||
summary += " = ";
|
||||
summary += QString::fromStdString(p.value);
|
||||
summary += " (SetPropertyValue";
|
||||
if (p.setType == Profile::Property::SetType::SetPropertyValueSingle) {
|
||||
summary += "Single";
|
||||
}
|
||||
summary += ")";
|
||||
return summary;
|
||||
}
|
||||
|
||||
void PropertiesDialog::listItemSelected() {
|
||||
QListWidgetItem* item = _list->currentItem();
|
||||
int index = _list->row(item);
|
||||
|
||||
if (_data.size() > 0) {
|
||||
Profile::Property& p = _data[index];
|
||||
if (p.setType == Profile::Property::SetType::SetPropertyValueSingle) {
|
||||
_commandCombo->setCurrentIndex(0);
|
||||
}
|
||||
else {
|
||||
_commandCombo->setCurrentIndex(1);
|
||||
}
|
||||
_propertyEdit->setText(QString::fromStdString(p.name));
|
||||
_valueEdit->setText(QString::fromStdString(p.value));
|
||||
}
|
||||
transitionToEditMode();
|
||||
}
|
||||
|
||||
bool PropertiesDialog::isLineEmpty(int index) {
|
||||
bool isEmpty = true;
|
||||
if (!_list->item(index)->text().isEmpty()) {
|
||||
isEmpty = false;
|
||||
}
|
||||
if (!_data.empty() && !_data.at(0).name.empty()) {
|
||||
isEmpty = false;
|
||||
}
|
||||
return isEmpty;
|
||||
}
|
||||
|
||||
void PropertiesDialog::listItemAdded() {
|
||||
int currentListSize = _list->count();
|
||||
|
||||
if ((currentListSize == 1) && (isLineEmpty(0))) {
|
||||
// Special case where list is "empty" but really has one line that is blank.
|
||||
// This is done because QListWidget does not seem to like having its sole
|
||||
// remaining item being removed.
|
||||
_data.at(0) = Blank;
|
||||
_list->item(0)->setText(" (Enter details below & click 'Save')");
|
||||
_list->setCurrentRow(0);
|
||||
transitionToEditMode();
|
||||
}
|
||||
else {
|
||||
_data.push_back(Blank);
|
||||
_list->addItem(new QListWidgetItem(" (Enter details below & click 'Save')"));
|
||||
//Scroll down to that blank line highlighted
|
||||
_list->setCurrentRow(_list->count() - 1);
|
||||
}
|
||||
|
||||
// Blank-out the 2 text fields, set combo box to index 0
|
||||
_commandCombo->setCurrentIndex(0);
|
||||
_propertyEdit->setText(QString::fromStdString(_data.back().name));
|
||||
_valueEdit->setText(QString::fromStdString(_data.back().value));
|
||||
_commandCombo->setFocus(Qt::OtherFocusReason);
|
||||
_editModeNewItem = true;
|
||||
}
|
||||
|
||||
void PropertiesDialog::listItemSave() {
|
||||
if (!areRequiredFormsFilled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QListWidgetItem* item = _list->currentItem();
|
||||
int index = _list->row(item);
|
||||
|
||||
if ( _data.size() > 0) {
|
||||
if (_commandCombo->currentIndex() == 0) {
|
||||
_data[index].setType = Profile::Property::SetType::SetPropertyValueSingle;
|
||||
}
|
||||
else {
|
||||
_data[index].setType = Profile::Property::SetType::SetPropertyValue;
|
||||
}
|
||||
_data[index].name = _propertyEdit->text().toStdString();
|
||||
_data[index].value = _valueEdit->text().toStdString();
|
||||
_list->item(index)->setText(createOneLineSummary(_data[index]));
|
||||
}
|
||||
transitionFromEditMode();
|
||||
_editModeNewItem = false;
|
||||
}
|
||||
|
||||
bool PropertiesDialog::areRequiredFormsFilled() {
|
||||
bool requiredFormsFilled = true;
|
||||
QString errors;
|
||||
if (_propertyEdit->text().length() == 0) {
|
||||
errors += "Missing property name";
|
||||
requiredFormsFilled = false;
|
||||
}
|
||||
if (_valueEdit->text().length() == 0) {
|
||||
if (errors.length() > 0) {
|
||||
errors += ", ";
|
||||
}
|
||||
errors += "Missing value";
|
||||
requiredFormsFilled = false;
|
||||
}
|
||||
_errorMsg->setText("<font color='red'>" + errors + "</font>");
|
||||
return requiredFormsFilled;
|
||||
}
|
||||
|
||||
void PropertiesDialog::listItemCancelSave() {
|
||||
listItemSelected();
|
||||
transitionFromEditMode();
|
||||
if (_editModeNewItem) {
|
||||
if (_data.size() > 0) {
|
||||
if (_data.back().name.length() == 0 || _data.back().value.length() == 0) {
|
||||
listItemRemove();
|
||||
}
|
||||
}
|
||||
}
|
||||
_editModeNewItem = false;
|
||||
}
|
||||
|
||||
void PropertiesDialog::listItemRemove() {
|
||||
if (_list->count() > 0) {
|
||||
if (_list->currentRow() >= 0 && _list->currentRow() < _list->count()) {
|
||||
if (_list->count() == 1) {
|
||||
//Special case where last remaining item is being removed (QListWidget
|
||||
// doesn't like the final item being removed so instead clear it)
|
||||
_data.at(0) = Blank;
|
||||
_list->item(0)->setText("");
|
||||
}
|
||||
else {
|
||||
int index = _list->currentRow();
|
||||
if (index >= 0 && index < _list->count()) {
|
||||
delete _list->takeItem(index);
|
||||
if (_data.size() > 0) {
|
||||
_data.erase(_data.begin() + index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
transitionFromEditMode();
|
||||
}
|
||||
|
||||
void PropertiesDialog::transitionToEditMode() {
|
||||
_list->setDisabled(true);
|
||||
_addButton->setDisabled(true);
|
||||
_removeButton->setDisabled(true);
|
||||
_saveButton->setDisabled(true);
|
||||
_cancelButton->setDisabled(true);
|
||||
_buttonBox->setDisabled(true);
|
||||
|
||||
_commandLabel->setText("<font color='black'>Property Set Command</font>");
|
||||
_propertyLabel->setText("<font color='black'>Property</font>");
|
||||
_valueLabel->setText("<font color='black'>Value to set</font>");
|
||||
editBoxDisabled(false);
|
||||
_errorMsg->setText("");
|
||||
}
|
||||
|
||||
void PropertiesDialog::transitionFromEditMode() {
|
||||
_list->setDisabled(false);
|
||||
_addButton->setDisabled(false);
|
||||
_removeButton->setDisabled(false);
|
||||
_saveButton->setDisabled(false);
|
||||
_cancelButton->setDisabled(false);
|
||||
_buttonBox->setDisabled(false);
|
||||
|
||||
_commandLabel->setText("<font color='light gray'>Property Set Command</font>");
|
||||
_propertyLabel->setText("<font color='light gray'>Property</font>");
|
||||
_valueLabel->setText("<font color='light gray'>Value to set</font>");
|
||||
editBoxDisabled(true);
|
||||
_errorMsg->setText("");
|
||||
}
|
||||
|
||||
void PropertiesDialog::editBoxDisabled(bool disabled) {
|
||||
_commandLabel->setDisabled(disabled);
|
||||
_commandCombo->setDisabled(disabled);
|
||||
_propertyLabel->setDisabled(disabled);
|
||||
_propertyEdit->setDisabled(disabled);
|
||||
_valueLabel->setDisabled(disabled);
|
||||
_valueEdit->setDisabled(disabled);
|
||||
_saveButton->setDisabled(disabled);
|
||||
_cancelButton->setDisabled(disabled);
|
||||
}
|
||||
|
||||
void PropertiesDialog::parseSelections() {
|
||||
// Handle case with only one remaining but empty line
|
||||
if ((_data.size() == 1) && (_data.at(0).name.compare("") == 0)) {
|
||||
_data.clear();
|
||||
}
|
||||
_profile.setProperties(_data);
|
||||
accept();
|
||||
}
|
||||
|
||||
void PropertiesDialog::keyPressEvent(QKeyEvent* evt) {
|
||||
if (evt->key() == Qt::Key_Enter || evt->key() == Qt::Key_Return) {
|
||||
if (_editModeNewItem) {
|
||||
listItemSave();
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (evt->key() == Qt::Key_Escape) {
|
||||
if (_editModeNewItem) {
|
||||
listItemCancelSave();
|
||||
return;
|
||||
}
|
||||
}
|
||||
QDialog::keyPressEvent(evt);
|
||||
}
|
||||
|
||||
167
apps/OpenSpace/ext/launcher/src/profile/timedialog.cpp
Normal file
167
apps/OpenSpace/ext/launcher/src/profile/timedialog.cpp
Normal file
@@ -0,0 +1,167 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2020 *
|
||||
* *
|
||||
* 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 *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include "profile/timedialog.h"
|
||||
|
||||
#include "profile/line.h"
|
||||
#include <QComboBox>
|
||||
#include <QDateTimeEdit>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QKeyEvent>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QVBoxLayout>
|
||||
#include <fmt/format.h>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace openspace;
|
||||
|
||||
TimeDialog::TimeDialog(openspace::Profile& profile, QWidget* parent)
|
||||
: QDialog(parent)
|
||||
, _profile(profile)
|
||||
{
|
||||
setWindowTitle("Time");
|
||||
createWidgets();
|
||||
|
||||
QStringList types = { "Absolute", "Relative" };
|
||||
_typeCombo->addItems(types);
|
||||
if (_profile.time().has_value()) {
|
||||
_data = *_profile.time();
|
||||
if (_data.type == Profile::Time::Type::Relative) {
|
||||
if (_data.value == "") {
|
||||
_data.value = "now";
|
||||
}
|
||||
_relativeEdit->setSelection(0, _relativeEdit->text().length());
|
||||
}
|
||||
else {
|
||||
_absoluteEdit->setSelectedSection(QDateTimeEdit::YearSection);
|
||||
}
|
||||
}
|
||||
else {
|
||||
_data.type = Profile::Time::Type::Relative;
|
||||
_data.value = "now";
|
||||
}
|
||||
_initializedAsAbsolute = (_data.type == Profile::Time::Type::Absolute);
|
||||
enableAccordingToType(static_cast<int>(_data.type));
|
||||
}
|
||||
|
||||
void TimeDialog::createWidgets() {
|
||||
QBoxLayout* layout = new QVBoxLayout(this);
|
||||
{
|
||||
layout->addWidget(new QLabel("Time Type"));
|
||||
_typeCombo = new QComboBox;
|
||||
_typeCombo->setToolTip("Types: Absolute defined time or Relative to actual time");
|
||||
connect(
|
||||
_typeCombo, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
this, &TimeDialog::enableAccordingToType
|
||||
);
|
||||
layout->addWidget(_typeCombo);
|
||||
}
|
||||
{
|
||||
_absoluteLabel = new QLabel("Absolute UTC:");
|
||||
layout->addWidget(_absoluteLabel);
|
||||
_absoluteEdit = new QDateTimeEdit;
|
||||
_absoluteEdit->setDisplayFormat("yyyy-MM-dd T hh:mm:ss");
|
||||
_absoluteEdit->setDateTime(QDateTime::currentDateTime());
|
||||
layout->addWidget(_absoluteEdit);
|
||||
}
|
||||
{
|
||||
_relativeLabel = new QLabel("Relative Time:");
|
||||
layout->addWidget(_relativeLabel);
|
||||
_relativeEdit = new QLineEdit;
|
||||
_relativeEdit->setToolTip(
|
||||
"String for relative time to actual (e.g. \"-1d\" for back 1 day)"
|
||||
);
|
||||
layout->addWidget(_relativeEdit);
|
||||
}
|
||||
layout->addWidget(new Line);
|
||||
{
|
||||
QDialogButtonBox* buttons = new QDialogButtonBox;
|
||||
buttons->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel);
|
||||
|
||||
connect(buttons, &QDialogButtonBox::accepted, this, &TimeDialog::approved);
|
||||
QObject::connect(buttons, &QDialogButtonBox::rejected, this, &TimeDialog::reject);
|
||||
layout->addWidget(buttons);
|
||||
}
|
||||
}
|
||||
|
||||
void TimeDialog::enableAccordingToType(int idx) {
|
||||
Profile::Time::Type comboIdx = static_cast<Profile::Time::Type>(idx);
|
||||
bool setFormatForAbsolute = (comboIdx == Profile::Time::Type::Absolute);
|
||||
enableFormatForAbsolute(setFormatForAbsolute);
|
||||
_typeCombo->setCurrentIndex(idx);
|
||||
if (comboIdx == Profile::Time::Type::Relative) {
|
||||
_relativeEdit->setText("<font color='black'>Relative Time:</font>");
|
||||
if (_initializedAsAbsolute) {
|
||||
_relativeEdit->setText("now");
|
||||
}
|
||||
else {
|
||||
_relativeEdit->setText(QString::fromStdString(_data.value));
|
||||
}
|
||||
_relativeEdit->setFocus(Qt::OtherFocusReason);
|
||||
}
|
||||
else {
|
||||
_relativeEdit->setText("<font color='gray'>Relative Time:</font>");
|
||||
size_t tIdx = _data.value.find_first_of('T', 0);
|
||||
QString importDate = QString::fromStdString(_data.value.substr(0, tIdx));
|
||||
QString importTime = QString::fromStdString(_data.value.substr(tIdx + 1));
|
||||
_absoluteEdit->setDate(QDate::fromString(importDate, Qt::DateFormat::ISODate));
|
||||
_absoluteEdit->setTime(QTime::fromString(importTime));
|
||||
_relativeEdit->clear();
|
||||
_absoluteEdit->setFocus(Qt::OtherFocusReason);
|
||||
}
|
||||
}
|
||||
|
||||
void TimeDialog::enableFormatForAbsolute(bool enableAbs) {
|
||||
_absoluteLabel->setEnabled(enableAbs);
|
||||
_absoluteEdit->setEnabled(enableAbs);
|
||||
_relativeLabel->setEnabled(!enableAbs);
|
||||
_relativeEdit->setEnabled(!enableAbs);
|
||||
}
|
||||
|
||||
void TimeDialog::approved() {
|
||||
constexpr const int Relative = static_cast<int>(Profile::Time::Type::Relative);
|
||||
if (_typeCombo->currentIndex() == Relative) {
|
||||
if (_relativeEdit->text().isEmpty()) {
|
||||
_profile.clearTime();
|
||||
}
|
||||
else {
|
||||
Profile::Time t;
|
||||
t.type = Profile::Time::Type::Relative;
|
||||
t.value = _relativeEdit->text().toStdString();
|
||||
_profile.setTime(t);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Profile::Time t;
|
||||
t.type = Profile::Time::Type::Absolute;
|
||||
t.value = fmt::format(
|
||||
"{}T{}",
|
||||
_absoluteEdit->date().toString("yyyy-MM-dd").toStdString(),
|
||||
_absoluteEdit->time().toString().toStdString()
|
||||
);
|
||||
_profile.setTime(t);
|
||||
}
|
||||
accept();
|
||||
}
|
||||
@@ -63,6 +63,7 @@
|
||||
#include <Tracy.hpp>
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include <memory>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <openspace/openspace.h>
|
||||
@@ -82,18 +83,13 @@
|
||||
#include "SpoutLibrary.h"
|
||||
#endif // OPENSPACE_HAS_SPOUT
|
||||
|
||||
#ifdef OPENSPACE_HAS_VTUNE
|
||||
#include <ittnotify.h>
|
||||
|
||||
// If this is set to 'true', it will disable all frame markers in this file and expect
|
||||
// you to place them in the code you actually want to inspect
|
||||
constexpr const bool EnableDetailedVtune = false;
|
||||
#endif // OPENSPACE_HAS_VTUNE
|
||||
|
||||
#ifdef OPENSPACE_HAS_NVTOOLS
|
||||
#include "nvToolsExt.h"
|
||||
#endif // OPENSPACE_HAS_NVTOOLS
|
||||
|
||||
#include <launcherwindow.h>
|
||||
#include <QApplication>
|
||||
|
||||
using namespace openspace;
|
||||
using namespace sgct;
|
||||
|
||||
@@ -114,26 +110,6 @@ glm::mat4 currentModelMatrix;
|
||||
Window* FirstOpenVRWindow = nullptr;
|
||||
#endif
|
||||
|
||||
#ifdef OPENSPACE_HAS_VTUNE
|
||||
|
||||
struct {
|
||||
__itt_domain* init;
|
||||
__itt_domain* preSync;
|
||||
__itt_domain* postSyncPreDraw;
|
||||
__itt_domain* render;
|
||||
__itt_domain* draw2D;
|
||||
__itt_domain* postDraw;
|
||||
__itt_domain* keyboard;
|
||||
__itt_domain* mouseButton;
|
||||
__itt_domain* mousePos;
|
||||
__itt_domain* mouseScroll;
|
||||
__itt_domain* character;
|
||||
__itt_domain* encode;
|
||||
__itt_domain* decode;
|
||||
} _vTune;
|
||||
|
||||
#endif // OPENSPACE_HAS_VTUNE
|
||||
|
||||
//
|
||||
// SPOUT-support
|
||||
//
|
||||
@@ -242,15 +218,10 @@ LONG WINAPI generateMiniDump(EXCEPTION_POINTERS* exceptionPointers) {
|
||||
void mainInitFunc(GLFWwindow*) {
|
||||
ZoneScoped
|
||||
|
||||
#ifdef OPENSPACE_HAS_VTUNE
|
||||
if (EnableDetailedVtune) {
|
||||
__itt_frame_begin_v3(_vTune.init, nullptr);
|
||||
}
|
||||
#endif // OPENSPACE_HAS_VTUNE
|
||||
LTRACE("main::mainInitFunc(begin)");
|
||||
|
||||
LDEBUG("Initializing OpenSpace Engine started");
|
||||
global::openSpaceEngine.initialize();
|
||||
global::openSpaceEngine->initialize();
|
||||
LDEBUG("Initializing OpenSpace Engine finished");
|
||||
|
||||
{
|
||||
@@ -276,7 +247,7 @@ void mainInitFunc(GLFWwindow*) {
|
||||
currentViewport = currentWindow->viewports().front().get();
|
||||
|
||||
LDEBUG("Initializing OpenGL in OpenSpace Engine started");
|
||||
global::openSpaceEngine.initializeGL();
|
||||
global::openSpaceEngine->initializeGL();
|
||||
LDEBUG("Initializing OpenGL in OpenSpace Engine finished");
|
||||
|
||||
|
||||
@@ -354,7 +325,7 @@ void mainInitFunc(GLFWwindow*) {
|
||||
// Screenshots
|
||||
//
|
||||
std::string screenshotPath = "${SCREENSHOTS}";
|
||||
if (global::configuration.shouldUseScreenshotDate) {
|
||||
if (global::configuration->shouldUseScreenshotDate) {
|
||||
std::time_t now = std::time(nullptr);
|
||||
std::tm* nowTime = std::localtime(&now);
|
||||
char mbstr[128];
|
||||
@@ -371,27 +342,16 @@ void mainInitFunc(GLFWwindow*) {
|
||||
|
||||
|
||||
LTRACE("main::mainInitFunc(end)");
|
||||
#ifdef OPENSPACE_HAS_VTUNE
|
||||
if (EnableDetailedVtune) {
|
||||
__itt_frame_end_v3(_vTune.init, nullptr);
|
||||
}
|
||||
#endif // OPENSPACE_HAS_VTUNE
|
||||
}
|
||||
|
||||
|
||||
|
||||
void mainPreSyncFunc() {
|
||||
ZoneScoped
|
||||
|
||||
#ifdef OPENSPACE_HAS_VTUNE
|
||||
if (EnableDetailedVtune) {
|
||||
__itt_frame_begin_v3(_vTune.preSync, nullptr);
|
||||
}
|
||||
#endif // OPENSPACE_HAS_VTUNE
|
||||
LTRACE("main::mainPreSyncFunc(begin)");
|
||||
|
||||
try {
|
||||
global::openSpaceEngine.preSynchronization();
|
||||
global::openSpaceEngine->preSynchronization();
|
||||
}
|
||||
catch (const ghoul::RuntimeError& e) {
|
||||
LFATALC(e.component, e.message);
|
||||
@@ -404,7 +364,7 @@ void mainPreSyncFunc() {
|
||||
for (int i = GLFW_JOYSTICK_1; i <= GLFW_JOYSTICK_LAST; ++i) {
|
||||
ZoneScopedN("Joystick state");
|
||||
|
||||
JoystickInputState& state = global::joystickInputStates[i];
|
||||
JoystickInputState& state = global::joystickInputStates->at(i);
|
||||
|
||||
int present = glfwJoystickPresent(i);
|
||||
if (present == GLFW_FALSE) {
|
||||
@@ -474,11 +434,6 @@ void mainPreSyncFunc() {
|
||||
}
|
||||
|
||||
LTRACE("main::mainPreSyncFunc(end)");
|
||||
#ifdef OPENSPACE_HAS_VTUNE
|
||||
if (EnableDetailedVtune) {
|
||||
__itt_frame_end_v3(_vTune.preSync, nullptr);
|
||||
}
|
||||
#endif // OPENSPACE_HAS_VTUNE
|
||||
}
|
||||
|
||||
|
||||
@@ -486,17 +441,12 @@ void mainPreSyncFunc() {
|
||||
void mainPostSyncPreDrawFunc() {
|
||||
ZoneScoped
|
||||
|
||||
#ifdef OPENSPACE_HAS_VTUNE
|
||||
if (EnableDetailedVtune) {
|
||||
__itt_frame_begin_v3(_vTune.postSyncPreDraw, nullptr);
|
||||
}
|
||||
#endif // OPENSPACE_HAS_VTUNE
|
||||
#ifdef OPENSPACE_HAS_NVTOOLS
|
||||
nvtxRangePush("postSyncPreDraw");
|
||||
#endif // OPENSPACE_HAS_NVTOOLS
|
||||
LTRACE("main::postSynchronizationPreDraw(begin)");
|
||||
|
||||
global::openSpaceEngine.postSynchronizationPreDraw();
|
||||
global::openSpaceEngine->postSynchronizationPreDraw();
|
||||
|
||||
#ifdef OPENVR_SUPPORT
|
||||
if (FirstOpenVRWindow) {
|
||||
@@ -510,11 +460,6 @@ void mainPostSyncPreDrawFunc() {
|
||||
#ifdef OPENSPACE_HAS_NVTOOLS
|
||||
nvtxRangePop();
|
||||
#endif // OPENSPACE_HAS_NVTOOLS
|
||||
#ifdef OPENSPACE_HAS_VTUNE
|
||||
if (EnableDetailedVtune) {
|
||||
__itt_frame_end_v3(_vTune.postSyncPreDraw, nullptr);
|
||||
}
|
||||
#endif // OPENSPACE_HAS_VTUNE
|
||||
}
|
||||
|
||||
|
||||
@@ -522,11 +467,6 @@ void mainPostSyncPreDrawFunc() {
|
||||
void mainRenderFunc(const sgct::RenderData& data) {
|
||||
ZoneScoped
|
||||
|
||||
#ifdef OPENSPACE_HAS_VTUNE
|
||||
if (EnableDetailedVtune) {
|
||||
__itt_frame_begin_v3(_vTune.render, nullptr);
|
||||
}
|
||||
#endif // OPENSPACE_HAS_VTUNE
|
||||
#ifdef OPENSPACE_HAS_NVTOOLS
|
||||
nvtxRangePush("render");
|
||||
#endif // OPENSPACE_HAS_NVTOOLS
|
||||
@@ -575,7 +515,7 @@ void mainRenderFunc(const sgct::RenderData& data) {
|
||||
);
|
||||
currentModelMatrix = modelMatrix;
|
||||
currentModelViewProjectionMatrix = modelMatrix * viewMatrix * projectionMatrix;
|
||||
global::openSpaceEngine.render(modelMatrix, viewMatrix, projectionMatrix);
|
||||
global::openSpaceEngine->render(modelMatrix, viewMatrix, projectionMatrix);
|
||||
}
|
||||
catch (const ghoul::RuntimeError& e) {
|
||||
LERRORC(e.component, e.message);
|
||||
@@ -585,23 +525,12 @@ void mainRenderFunc(const sgct::RenderData& data) {
|
||||
#ifdef OPENSPACE_HAS_NVTOOLS
|
||||
nvtxRangePop();
|
||||
#endif // OPENSPACE_HAS_NVTOOLS
|
||||
#ifdef OPENSPACE_HAS_VTUNE
|
||||
if (EnableDetailedVtune) {
|
||||
__itt_frame_end_v3(_vTune.render, nullptr);
|
||||
}
|
||||
#endif // OPENSPACE_HAS_VTUNE
|
||||
}
|
||||
|
||||
|
||||
|
||||
void mainDraw2DFunc(const sgct::RenderData& data) {
|
||||
ZoneScoped
|
||||
|
||||
#ifdef OPENSPACE_HAS_VTUNE
|
||||
if (EnableDetailedVtune) {
|
||||
__itt_frame_begin_v3(_vTune.draw2D, nullptr);
|
||||
}
|
||||
#endif // OPENSPACE_HAS_VTUNE
|
||||
LTRACE("main::mainDraw2DFunc(begin)");
|
||||
|
||||
currentWindow = &data.window;
|
||||
@@ -609,7 +538,7 @@ void mainDraw2DFunc(const sgct::RenderData& data) {
|
||||
currentFrustumMode = data.frustumMode;
|
||||
|
||||
try {
|
||||
global::openSpaceEngine.drawOverlays();
|
||||
global::openSpaceEngine->drawOverlays();
|
||||
}
|
||||
catch (const ghoul::RuntimeError& e) {
|
||||
LERRORC(e.component, e.message);
|
||||
@@ -621,23 +550,12 @@ void mainDraw2DFunc(const sgct::RenderData& data) {
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
LTRACE("main::mainDraw2DFunc(end)");
|
||||
#ifdef OPENSPACE_HAS_VTUNE
|
||||
if (EnableDetailedVtune) {
|
||||
__itt_frame_end_v3(_vTune.draw2D, nullptr);
|
||||
}
|
||||
#endif // OPENSPACE_HAS_VTUNE
|
||||
}
|
||||
|
||||
|
||||
|
||||
void mainPostDrawFunc() {
|
||||
ZoneScoped
|
||||
|
||||
#ifdef OPENSPACE_HAS_VTUNE
|
||||
if (EnableDetailedVtune) {
|
||||
__itt_frame_begin_v3(_vTune.postDraw, nullptr);
|
||||
}
|
||||
#endif // OPENSPACE_HAS_VTUNE
|
||||
LTRACE("main::mainPostDrawFunc(begin)");
|
||||
|
||||
#ifdef OPENVR_SUPPORT
|
||||
@@ -647,7 +565,7 @@ void mainPostDrawFunc() {
|
||||
}
|
||||
#endif // OPENVR_SUPPORT
|
||||
|
||||
global::openSpaceEngine.postDraw();
|
||||
global::openSpaceEngine->postDraw();
|
||||
|
||||
#ifdef OPENSPACE_HAS_SPOUT
|
||||
for (const SpoutWindow& w : SpoutWindows) {
|
||||
@@ -678,11 +596,6 @@ void mainPostDrawFunc() {
|
||||
#endif // OPENSPACE_HAS_SPOUT
|
||||
|
||||
LTRACE("main::mainPostDrawFunc(end)");
|
||||
#ifdef OPENSPACE_HAS_VTUNE
|
||||
if (EnableDetailedVtune) {
|
||||
__itt_frame_end_v3(_vTune.postDraw, nullptr);
|
||||
}
|
||||
#endif // OPENSPACE_HAS_VTUNE
|
||||
}
|
||||
|
||||
|
||||
@@ -691,25 +604,14 @@ void mainKeyboardCallback(sgct::Key key, sgct::Modifier modifiers, sgct::Action
|
||||
int)
|
||||
{
|
||||
ZoneScoped
|
||||
|
||||
#ifdef OPENSPACE_HAS_VTUNE
|
||||
if (EnableDetailedVtune) {
|
||||
__itt_frame_begin_v3(_vTune.keyboard, nullptr);
|
||||
}
|
||||
#endif // OPENSPACE_HAS_VTUNE
|
||||
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);
|
||||
global::openSpaceEngine->keyboardCallback(k, m, a);
|
||||
|
||||
LTRACE("main::mainKeyboardCallback(begin)");
|
||||
#ifdef OPENSPACE_HAS_VTUNE
|
||||
if (EnableDetailedVtune) {
|
||||
__itt_frame_end_v3(_vTune.keyboard, nullptr);
|
||||
}
|
||||
#endif // OPENSPACE_HAS_VTUNE
|
||||
}
|
||||
|
||||
|
||||
@@ -718,67 +620,32 @@ void mainMouseButtonCallback(sgct::MouseButton key, sgct::Modifier modifiers,
|
||||
sgct::Action action)
|
||||
{
|
||||
ZoneScoped
|
||||
|
||||
#ifdef OPENSPACE_HAS_VTUNE
|
||||
if (EnableDetailedVtune) {
|
||||
__itt_frame_begin_v3(_vTune.mouseButton, nullptr);
|
||||
}
|
||||
#endif // OPENSPACE_HAS_VTUNE
|
||||
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);
|
||||
global::openSpaceEngine->mouseButtonCallback(k, a, m);
|
||||
|
||||
LTRACE("main::mainMouseButtonCallback(end)");
|
||||
#ifdef OPENSPACE_HAS_VTUNE
|
||||
if (EnableDetailedVtune) {
|
||||
__itt_frame_end_v3(_vTune.mouseButton, nullptr);
|
||||
}
|
||||
#endif // OPENSPACE_HAS_VTUNE
|
||||
}
|
||||
|
||||
|
||||
|
||||
void mainMousePosCallback(double x, double y) {
|
||||
ZoneScoped
|
||||
|
||||
#ifdef OPENSPACE_HAS_VTUNE
|
||||
if (EnableDetailedVtune) {
|
||||
__itt_frame_begin_v3(_vTune.mousePos, nullptr);
|
||||
}
|
||||
#endif // OPENSPACE_HAS_VTUNE
|
||||
|
||||
global::openSpaceEngine.mousePositionCallback(x, y);
|
||||
|
||||
#ifdef OPENSPACE_HAS_VTUNE
|
||||
if (EnableDetailedVtune) {
|
||||
__itt_frame_end_v3(_vTune.mousePos, nullptr);
|
||||
}
|
||||
#endif // OPENSPACE_HAS_VTUNE
|
||||
global::openSpaceEngine->mousePositionCallback(x, y);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void mainMouseScrollCallback(double posX, double posY) {
|
||||
ZoneScoped
|
||||
|
||||
#ifdef OPENSPACE_HAS_VTUNE
|
||||
if (EnableDetailedVtune) {
|
||||
__itt_frame_begin_v3(_vTune.mouseScroll, nullptr);
|
||||
}
|
||||
#endif // OPENSPACE_HAS_VTUNE
|
||||
LTRACE("main::mainMouseScrollCallback(begin");
|
||||
|
||||
global::openSpaceEngine.mouseScrollWheelCallback(posX, posY);
|
||||
global::openSpaceEngine->mouseScrollWheelCallback(posX, posY);
|
||||
|
||||
LTRACE("main::mainMouseScrollCallback(end)");
|
||||
#ifdef OPENSPACE_HAS_VTUNE
|
||||
if (EnableDetailedVtune) {
|
||||
__itt_frame_end_v3(_vTune.mouseScroll, nullptr);
|
||||
}
|
||||
#endif // OPENSPACE_HAS_VTUNE
|
||||
}
|
||||
|
||||
|
||||
@@ -786,43 +653,19 @@ void mainMouseScrollCallback(double posX, double posY) {
|
||||
void mainCharCallback(unsigned int codepoint, int modifiers) {
|
||||
ZoneScoped
|
||||
|
||||
#ifdef OPENSPACE_HAS_VTUNE
|
||||
if (EnableDetailedVtune) {
|
||||
__itt_frame_begin_v3(_vTune.character, nullptr);
|
||||
}
|
||||
#endif // OPENSPACE_HAS_VTUNE
|
||||
|
||||
const KeyModifier m = KeyModifier(modifiers);
|
||||
global::openSpaceEngine.charCallback(codepoint, m);
|
||||
|
||||
#ifdef OPENSPACE_HAS_VTUNE
|
||||
if (EnableDetailedVtune) {
|
||||
__itt_frame_end_v3(_vTune.character, nullptr);
|
||||
}
|
||||
#endif // OPENSPACE_HAS_VTUNE
|
||||
global::openSpaceEngine->charCallback(codepoint, m);
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::vector<std::byte> mainEncodeFun() {
|
||||
ZoneScoped
|
||||
|
||||
#ifdef OPENSPACE_HAS_VTUNE
|
||||
if (EnableDetailedVtune) {
|
||||
__itt_frame_begin_v3(_vTune.encode, nullptr);
|
||||
}
|
||||
#endif // OPENSPACE_HAS_VTUNE
|
||||
LTRACE("main::mainEncodeFun(begin)");
|
||||
|
||||
std::vector<std::byte> data = global::openSpaceEngine.encode();
|
||||
std::vector<std::byte> data = global::openSpaceEngine->encode();
|
||||
|
||||
LTRACE("main::mainEncodeFun(end)");
|
||||
#ifdef OPENSPACE_HAS_VTUNE
|
||||
if (EnableDetailedVtune) {
|
||||
__itt_frame_end_v3(_vTune.encode, nullptr);
|
||||
}
|
||||
#endif // OPENSPACE_HAS_VTUNE
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -830,43 +673,30 @@ std::vector<std::byte> mainEncodeFun() {
|
||||
|
||||
void mainDecodeFun(const std::vector<std::byte>& data, unsigned int) {
|
||||
ZoneScoped
|
||||
|
||||
#ifdef OPENSPACE_HAS_VTUNE
|
||||
if (EnableDetailedVtune) {
|
||||
__itt_frame_begin_v3(_vTune.decode, nullptr);
|
||||
}
|
||||
#endif // OPENSPACE_HAS_VTUNE
|
||||
LTRACE("main::mainDecodeFun(begin)");
|
||||
|
||||
global::openSpaceEngine.decode(data);
|
||||
global::openSpaceEngine->decode(data);
|
||||
|
||||
LTRACE("main::mainDecodeFun(end)");
|
||||
#ifdef OPENSPACE_HAS_VTUNE
|
||||
if (EnableDetailedVtune) {
|
||||
__itt_frame_end_v3(_vTune.decode, nullptr);
|
||||
}
|
||||
#endif // OPENSPACE_HAS_VTUNE
|
||||
}
|
||||
|
||||
|
||||
|
||||
void mainLogCallback(Log::Level level, const char* message) {
|
||||
void mainLogCallback(Log::Level level, std::string_view message) {
|
||||
ZoneScoped
|
||||
|
||||
std::string msg = message;
|
||||
// Remove the trailing \n that is passed along
|
||||
switch (level) {
|
||||
case Log::Level::Debug:
|
||||
LDEBUGC("SGCT", msg);
|
||||
LDEBUGC("SGCT", message);
|
||||
break;
|
||||
case Log::Level::Info:
|
||||
LINFOC("SGCT", msg);
|
||||
LINFOC("SGCT", message);
|
||||
break;
|
||||
case Log::Level::Warning:
|
||||
LWARNINGC("SGCT", msg);
|
||||
LWARNINGC("SGCT", message);
|
||||
break;
|
||||
case Log::Level::Error:
|
||||
LERRORC("SGCT", msg);
|
||||
LERRORC("SGCT", message);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -874,7 +704,7 @@ void mainLogCallback(Log::Level level, const char* message) {
|
||||
|
||||
|
||||
void setSgctDelegateFunctions() {
|
||||
WindowDelegate& sgctDelegate = global::windowDelegate;
|
||||
WindowDelegate& sgctDelegate = *global::windowDelegate;
|
||||
sgctDelegate.terminate = []() { Engine::instance().terminate(); };
|
||||
sgctDelegate.setBarrier = [](bool enabled) {
|
||||
ZoneScoped
|
||||
@@ -1097,30 +927,94 @@ void setSgctDelegateFunctions() {
|
||||
};
|
||||
}
|
||||
|
||||
void checkCommandLineForSettings(int& argc, char** argv, bool& hasSGCT, bool& hasProfile,
|
||||
std::string& sgctFunctionName)
|
||||
{
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
const std::string arg = argv[i];
|
||||
if (arg == "-c" || arg == "--config") {
|
||||
std::string p = ((i + 1) < argc) ? argv[i + 1] : "";
|
||||
p.erase(std::remove_if(p.begin(), p.end(), ::isspace), p.end());
|
||||
|
||||
const std::string sgctAssignment = "SGCTConfig=";
|
||||
const size_t findSgct = p.find(sgctAssignment);
|
||||
const size_t findBracket = p.find("}");
|
||||
if (findSgct != std::string::npos) {
|
||||
if (findBracket != std::string::npos) {
|
||||
sgctFunctionName = arg.substr(
|
||||
findSgct + sgctAssignment.length(),
|
||||
findBracket - findSgct
|
||||
);
|
||||
}
|
||||
hasSGCT = true;
|
||||
}
|
||||
if (p.find("Profile=") != std::string::npos) {
|
||||
hasProfile = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string setWindowConfigPresetForGui(const std::string labelFromCfgFile,
|
||||
const std::string xmlExt, bool haveCliSGCTConfig,
|
||||
const std::string& sgctFunctionName)
|
||||
{
|
||||
configuration::Configuration& config = *global::configuration;
|
||||
|
||||
std::string preset;
|
||||
bool sgctConfigFileSpecifiedByLuaFunction = !config.sgctConfigNameInitialized.empty();
|
||||
if (haveCliSGCTConfig) {
|
||||
preset = sgctFunctionName.empty() ? config.windowConfiguration : sgctFunctionName;
|
||||
preset += " (from CLI)";
|
||||
}
|
||||
else if (sgctConfigFileSpecifiedByLuaFunction) {
|
||||
preset = config.sgctConfigNameInitialized + labelFromCfgFile;
|
||||
}
|
||||
else {
|
||||
preset = config.windowConfiguration;
|
||||
if (preset.find('/') != std::string::npos) {
|
||||
preset.erase(0, preset.find_last_of('/') + 1);
|
||||
}
|
||||
if (preset.length() >= xmlExt.length()) {
|
||||
if (preset.substr(preset.length() - xmlExt.length()) == xmlExt) {
|
||||
preset = preset.substr(0, preset.length() - xmlExt.length());
|
||||
}
|
||||
}
|
||||
}
|
||||
return preset;
|
||||
}
|
||||
|
||||
std::string selectedSgctProfileFromLauncher(LauncherWindow& lw, bool hasCliSGCTConfig,
|
||||
std::string windowConfiguration,
|
||||
const std::string& labelFromCfgFile,
|
||||
const std::string& xmlExt)
|
||||
{
|
||||
std::string config = windowConfiguration;
|
||||
if (!hasCliSGCTConfig) {
|
||||
config = lw.selectedWindowConfig();
|
||||
if (config.find(labelFromCfgFile) != std::string::npos) {
|
||||
if (config.find("sgct.config") == std::string::npos) {
|
||||
config = config.substr(0, config.length() - labelFromCfgFile.length());
|
||||
}
|
||||
else {
|
||||
config = windowConfiguration;
|
||||
}
|
||||
}
|
||||
else {
|
||||
config = "${CONFIG}/" + config + xmlExt;
|
||||
}
|
||||
global::configuration->windowConfiguration = config;
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
glfwInit();
|
||||
|
||||
#ifdef WIN32
|
||||
SetUnhandledExceptionFilter(generateMiniDump);
|
||||
#endif // WIN32
|
||||
|
||||
#ifdef OPENSPACE_HAS_VTUNE
|
||||
if (EnableDetailedVtune) {
|
||||
_vTune.init = __itt_domain_create("init");
|
||||
_vTune.preSync = __itt_domain_create("preSync");
|
||||
_vTune.postSyncPreDraw = __itt_domain_create("postSyncPreDraw");
|
||||
_vTune.render = __itt_domain_create("render");
|
||||
_vTune.draw2D = __itt_domain_create("draw2D");
|
||||
_vTune.postDraw = __itt_domain_create("postDraw");
|
||||
_vTune.keyboard = __itt_domain_create("keyboard");
|
||||
_vTune.mouseButton = __itt_domain_create("mouseButton");
|
||||
_vTune.mousePos = __itt_domain_create("mousePos");
|
||||
_vTune.mouseScroll = __itt_domain_create("mouseScroll");
|
||||
_vTune.character = __itt_domain_create("character");
|
||||
_vTune.encode = __itt_domain_create("encode");
|
||||
_vTune.decode = __itt_domain_create("decode");
|
||||
}
|
||||
#endif // OPENSPACE_HAS_VTUNE
|
||||
|
||||
|
||||
// Initialize the LogManager and add the console log as this will be used every time
|
||||
// and we need a fall back if something goes wrong between here and when we add the
|
||||
// logs from the configuration file. If the user requested as specific loglevel in the
|
||||
@@ -1139,6 +1033,7 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
ghoul::initialize();
|
||||
global::create();
|
||||
|
||||
// Register the path of the executable,
|
||||
// to make it possible to find other files in the same directory.
|
||||
@@ -1212,26 +1107,25 @@ int main(int argc, char** argv) {
|
||||
|
||||
// Loading configuration from disk
|
||||
LDEBUG("Loading configuration from disk");
|
||||
global::configuration = configuration::loadConfigurationFromFile(
|
||||
*global::configuration = configuration::loadConfigurationFromFile(
|
||||
configurationFilePath
|
||||
);
|
||||
|
||||
// If the user requested a commandline-based configuration script that should
|
||||
// overwrite some of the values, this is the time to do it
|
||||
if (!commandlineArguments.configurationOverride.empty()) {
|
||||
LDEBUG("Executing Lua script passed through the commandline:");
|
||||
LDEBUG(commandlineArguments.configurationOverride);
|
||||
ghoul::lua::runScript(
|
||||
global::configuration.state,
|
||||
global::configuration->state,
|
||||
commandlineArguments.configurationOverride
|
||||
);
|
||||
parseLuaState(global::configuration);
|
||||
parseLuaState(*global::configuration);
|
||||
}
|
||||
|
||||
// Determining SGCT configuration file
|
||||
LDEBUG("SGCT Configuration file: " + global::configuration.windowConfiguration);
|
||||
LDEBUG("SGCT Configuration file: " + global::configuration->windowConfiguration);
|
||||
|
||||
windowConfiguration = global::configuration.windowConfiguration;
|
||||
windowConfiguration = global::configuration->windowConfiguration;
|
||||
}
|
||||
catch (const documentation::SpecificationError& e) {
|
||||
LFATALC("main", "Loading of configuration file failed");
|
||||
@@ -1254,7 +1148,47 @@ int main(int argc, char** argv) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
global::openSpaceEngine.registerPathTokens();
|
||||
global::openSpaceEngine->registerPathTokens();
|
||||
|
||||
|
||||
bool hasSGCTConfig = false;
|
||||
bool hasProfile = false;
|
||||
std::string sgctFunctionName;
|
||||
checkCommandLineForSettings(argc, argv, hasSGCTConfig, hasProfile, sgctFunctionName);
|
||||
|
||||
// Call profile GUI
|
||||
const std::string labelFromCfgFile = " (from .cfg)";
|
||||
const std::string xmlExt = ".xml";
|
||||
std::string windowCfgPreset = setWindowConfigPresetForGui(
|
||||
labelFromCfgFile,
|
||||
xmlExt,
|
||||
hasSGCTConfig,
|
||||
sgctFunctionName
|
||||
);
|
||||
|
||||
bool skipLauncher =
|
||||
(hasProfile && hasSGCTConfig) || global::configuration->bypassLauncher;
|
||||
if (!skipLauncher) {
|
||||
int qac = 0;
|
||||
QApplication app(qac, nullptr);
|
||||
LauncherWindow win(!hasProfile,
|
||||
*global::configuration, !hasSGCTConfig, windowCfgPreset, nullptr);
|
||||
win.show();
|
||||
app.exec();
|
||||
|
||||
if (!win.wasLaunchSelected()) {
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
global::configuration->profile = win.selectedProfile();
|
||||
windowConfiguration = selectedSgctProfileFromLauncher(
|
||||
win,
|
||||
hasSGCTConfig,
|
||||
windowConfiguration,
|
||||
labelFromCfgFile,
|
||||
xmlExt
|
||||
);
|
||||
}
|
||||
|
||||
// Prepend the outgoing sgctArguments with the program name
|
||||
// as well as the configuration file that sgct is supposed to use
|
||||
@@ -1266,6 +1200,7 @@ int main(int argc, char** argv) {
|
||||
|
||||
Log::instance().setLogToConsole(false);
|
||||
Log::instance().setShowTime(false);
|
||||
Log::instance().setShowLogLevel(false);
|
||||
Log::instance().setLogCallback(mainLogCallback);
|
||||
|
||||
#ifdef __APPLE__
|
||||
@@ -1299,11 +1234,12 @@ int main(int argc, char** argv) {
|
||||
catch (const std::runtime_error& e) {
|
||||
LFATALC("main", e.what());
|
||||
Engine::destroy();
|
||||
global::openSpaceEngine.deinitialize();
|
||||
global::openSpaceEngine->deinitialize();
|
||||
ghoul::deinitialize();
|
||||
throw;
|
||||
}
|
||||
catch (...) {
|
||||
global::openSpaceEngine.deinitialize();
|
||||
global::openSpaceEngine->deinitialize();
|
||||
ghoul::deinitialize();
|
||||
Engine::destroy();
|
||||
throw;
|
||||
@@ -1342,8 +1278,9 @@ int main(int argc, char** argv) {
|
||||
Engine::instance().render();
|
||||
LINFO("Ending rendering loop");
|
||||
|
||||
global::openSpaceEngine.deinitializeGL();
|
||||
global::openSpaceEngine.deinitialize();
|
||||
global::openSpaceEngine->deinitializeGL();
|
||||
global::openSpaceEngine->deinitialize();
|
||||
global::destroy();
|
||||
|
||||
// Clear function bindings to avoid crash after destroying the OpenSpace Engine
|
||||
Log::instance().setLogCallback(nullptr);
|
||||
|
||||
@@ -37,7 +37,7 @@ create_new_application(Sync MACOSX_BUNDLE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/openspace.icns
|
||||
)
|
||||
|
||||
target_link_libraries(Sync openspace-core)
|
||||
target_link_libraries(Sync PUBLIC openspace-core)
|
||||
|
||||
# Web Browser and Web gui
|
||||
# Why not put these in the module's path? Because they do not have access to the
|
||||
|
||||
@@ -37,7 +37,7 @@ create_new_application(TaskRunner MACOSX_BUNDLE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/openspace.icns
|
||||
)
|
||||
|
||||
target_link_libraries(TaskRunner openspace-core)
|
||||
target_link_libraries(TaskRunner PUBLIC openspace-core)
|
||||
|
||||
# Web Browser and Web gui
|
||||
# Why not put these in the module's path? Because they do not have access to the
|
||||
|
||||
@@ -38,7 +38,7 @@ create_new_application(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/openspace.icns
|
||||
)
|
||||
|
||||
target_link_libraries(Wormhole openspace-core)
|
||||
target_link_libraries(Wormhole PUBLIC openspace-core)
|
||||
|
||||
# Web Browser and Web gui
|
||||
# Why not put these in the module's path? Because they do not have access to the
|
||||
|
||||
@@ -44,42 +44,33 @@ int main(int argc, char** argv) {
|
||||
CommandlineParser::AllowUnknownCommands::Yes
|
||||
);
|
||||
|
||||
std::stringstream defaultPassword;
|
||||
defaultPassword << std::hex << std::setfill('0') << std::setw(6) <<
|
||||
(std::hash<size_t>{}(
|
||||
std::chrono::system_clock::now().time_since_epoch().count()
|
||||
) % 0xffffff);
|
||||
struct {
|
||||
std::string port;
|
||||
std::string password;
|
||||
std::string changeHostPassword;
|
||||
} settings;
|
||||
|
||||
std::stringstream defaultChangeHostPassword;
|
||||
defaultChangeHostPassword << std::hex << std::setfill('0') << std::setw(6) <<
|
||||
(std::hash<size_t>{}(
|
||||
std::chrono::system_clock::now().time_since_epoch().count() + 1
|
||||
) % 0xffffff);
|
||||
|
||||
std::string portString;
|
||||
commandlineParser.addCommand(
|
||||
std::make_unique<ghoul::cmdparser::SingleCommand<std::string>>(
|
||||
portString,
|
||||
settings.port,
|
||||
"--port",
|
||||
"-p",
|
||||
"Sets the port to listen on"
|
||||
)
|
||||
);
|
||||
|
||||
std::string password;
|
||||
commandlineParser.addCommand(
|
||||
std::make_unique<ghoul::cmdparser::SingleCommand<std::string>>(
|
||||
password,
|
||||
settings.password,
|
||||
"--password",
|
||||
"-l",
|
||||
"Sets the password to use"
|
||||
)
|
||||
);
|
||||
|
||||
std::string changeHostPassword;
|
||||
commandlineParser.addCommand(
|
||||
std::make_unique<ghoul::cmdparser::SingleCommand<std::string>>(
|
||||
changeHostPassword,
|
||||
settings.changeHostPassword,
|
||||
"--hostpassword",
|
||||
"-h",
|
||||
"Sets the host password to use"
|
||||
@@ -89,29 +80,41 @@ int main(int argc, char** argv) {
|
||||
commandlineParser.setCommandLine(arguments);
|
||||
commandlineParser.execute();
|
||||
|
||||
if (password.empty()) {
|
||||
password = defaultPassword.str();
|
||||
if (settings.password.empty()) {
|
||||
std::stringstream defaultPassword;
|
||||
defaultPassword << std::hex << std::setfill('0') << std::setw(6) <<
|
||||
(std::hash<size_t>{}(
|
||||
std::chrono::system_clock::now().time_since_epoch().count()
|
||||
) % 0xffffff);
|
||||
|
||||
settings.password = defaultPassword.str();
|
||||
}
|
||||
if (changeHostPassword.empty()) {
|
||||
changeHostPassword = defaultChangeHostPassword.str();
|
||||
if (settings.changeHostPassword.empty()) {
|
||||
std::stringstream defaultChangeHostPassword;
|
||||
defaultChangeHostPassword << std::hex << std::setfill('0') << std::setw(6) <<
|
||||
(std::hash<size_t>{}(
|
||||
std::chrono::system_clock::now().time_since_epoch().count() + 1
|
||||
) % 0xffffff);
|
||||
|
||||
settings.changeHostPassword = defaultChangeHostPassword.str();
|
||||
}
|
||||
|
||||
LINFO(fmt::format("Connection password: {}", password));
|
||||
LINFO(fmt::format("Host password: {}", changeHostPassword));
|
||||
LINFO(fmt::format("Connection password: {}", settings.password));
|
||||
LINFO(fmt::format("Host password: {}", settings.changeHostPassword));
|
||||
|
||||
int port = 25001;
|
||||
|
||||
if (!portString.empty()) {
|
||||
if (!settings.port.empty()) {
|
||||
try {
|
||||
port = std::stoi(portString);
|
||||
port = std::stoi(settings.port);
|
||||
}
|
||||
catch (const std::invalid_argument&) {
|
||||
LERROR(fmt::format("Invalid port: {}", portString));
|
||||
LERROR(fmt::format("Invalid port: {}", settings.port));
|
||||
}
|
||||
}
|
||||
|
||||
ParallelServer server;
|
||||
server.start(port, password, changeHostPassword);
|
||||
server.start(port, settings.password, settings.changeHostPassword);
|
||||
server.setDefaultHostAddress("127.0.0.1");
|
||||
LINFO(fmt::format("Server listening to port {}", port));
|
||||
|
||||
|
||||
@@ -2,93 +2,32 @@
|
||||
-- loading this scene directly without any other elements added on top of it will
|
||||
-- probably not work
|
||||
|
||||
local assetHelper = asset.require('util/asset_helper')
|
||||
local sceneHelper = asset.require('util/scene_helper')
|
||||
local propertyHelper = asset.require('util/property_helper')
|
||||
asset.require('./base_blank')
|
||||
|
||||
-- Specifying which other assets should be loaded in this scene
|
||||
asset.require('spice/base')
|
||||
|
||||
asset.require('scene/solarsystem/sun/sun')
|
||||
asset.require('scene/solarsystem/sun/glare')
|
||||
asset.require('scene/solarsystem/planets')
|
||||
asset.require('scene/solarsystem/sun/default_layers')
|
||||
asset.require('scene/solarsystem/planets/planets')
|
||||
asset.require('scene/solarsystem/planets/default_layers')
|
||||
asset.require('scene/solarsystem/planets/mars/moons/phobos')
|
||||
asset.require('scene/solarsystem/planets/mars/moons/deimos')
|
||||
asset.require('scene/solarsystem/dwarf_planets/pluto/system')
|
||||
--asset.request('scene/milkyway/milkyway/volume')
|
||||
--asset.request('scene/milkyway/constellations/constellation_art')
|
||||
--asset.request('scene/milkyway/constellations/constellation_keybinds')
|
||||
asset.require('scene/solarsystem/dwarf_planets/pluto/default_layers')
|
||||
asset.require('scene/solarsystem/dwarf_planets/pluto/charon/default_layers')
|
||||
asset.require('scene/milkyway/milkyway/volume')
|
||||
asset.require('scene/milkyway/constellations/constellation_art')
|
||||
asset.require('scene/milkyway/constellations/constellation_keybinds')
|
||||
asset.require('util/launcher_images')
|
||||
|
||||
assetHelper.requestAll(asset, 'scene/digitaluniverse')
|
||||
--assetHelper.request('scene/digitaluniverse/stars')
|
||||
-- Load default key bindings applicable to most scenes
|
||||
asset.require('util/default_keybindings')
|
||||
asset.require('util/default_dashboard')
|
||||
asset.require('util/default_joystick')
|
||||
local assetHelper = asset.require('util/asset_helper')
|
||||
assetHelper.requireAll(asset, 'scene/milkyway/exoplanets')
|
||||
assetHelper.requireAll(asset, 'scene/digitaluniverse')
|
||||
|
||||
-- Load web gui
|
||||
local webGui = asset.require('util/webgui')
|
||||
|
||||
asset.request('customization/globebrowsing')
|
||||
|
||||
-- Keybindings that are specific for this scene
|
||||
local Keybindings = {
|
||||
{
|
||||
Key = "b",
|
||||
Name = "Toggle background",
|
||||
Command = propertyHelper.invert('Scene.MilkyWay.Renderable.Enabled') ..
|
||||
propertyHelper.invert('Scene.Stars.Renderable.Enabled'),
|
||||
Documentation = "Toggle background (Stars and Milkyway).",
|
||||
GuiPath = "/Rendering",
|
||||
Local = false
|
||||
},
|
||||
{
|
||||
Key = "g",
|
||||
Name = "Toggle background/shading",
|
||||
Command = propertyHelper.invert('Scene.MilkyWay.Renderable.Enabled') ..
|
||||
propertyHelper.invert('Scene.Stars.Renderable.Enabled') ..
|
||||
propertyHelper.invert('Scene.Earth.Renderable.Layers.NightLayers.Earth_at_Night_2012.Enabled') ..
|
||||
propertyHelper.invert('Scene.EarthAtmosphere.Renderable.Enabled') ..
|
||||
propertyHelper.invert('Scene.MarsAtmosphere.Renderable.Enabled') ..
|
||||
propertyHelper.invert('Scene.Earth.Renderable.Layers.WaterMasks.MODIS_Water_Mask.Enabled') ..
|
||||
propertyHelper.invert('Scene.Moon.Renderable.Enabled') ..
|
||||
propertyHelper.invert('Scene.Sun.Renderable.Enabled'),
|
||||
Documentation = "Toogles background and shading mode on the Earth and Mars alongside visibility of the Moon and the Sun",
|
||||
GuiPath = "/Rendering",
|
||||
Local = false
|
||||
},
|
||||
{
|
||||
Key = "h",
|
||||
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\n" ..
|
||||
"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",
|
||||
Local = false
|
||||
},
|
||||
{
|
||||
Key = "l",
|
||||
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",
|
||||
Local = false
|
||||
}
|
||||
}
|
||||
asset.require('customization/globebrowsing')
|
||||
|
||||
asset.onInitialize(function ()
|
||||
webGui.setCefRoute("onscreen")
|
||||
|
||||
sceneHelper.bindKeys(Keybindings)
|
||||
openspace.setDefaultGuiSorting()
|
||||
|
||||
openspace.setPropertyValueSingle("RenderEngine.VerticalLogOffset", 0.100000)
|
||||
|
||||
openspace.globebrowsing.loadWMSServersFromFile(
|
||||
openspace.absPath("${DATA}/globebrowsing_servers.lua")
|
||||
)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
sceneHelper.unbindKeys(Keybindings)
|
||||
end)
|
||||
end)
|
||||
50
data/assets/base_blank.asset
Normal file
50
data/assets/base_blank.asset
Normal file
@@ -0,0 +1,50 @@
|
||||
-- This is a blank scene that that just sets up the default menus/dasboard/keys, etc.
|
||||
|
||||
local assetHelper = asset.require('util/asset_helper')
|
||||
local sceneHelper = asset.require('util/scene_helper')
|
||||
local propertyHelper = asset.require('util/property_helper')
|
||||
|
||||
-- Specifying which other assets should be loaded in this scene
|
||||
asset.require('spice/base')
|
||||
|
||||
-- Load default key bindings applicable to most scenes
|
||||
asset.require('util/default_keybindings')
|
||||
asset.require('util/default_dashboard')
|
||||
asset.require('util/default_joystick')
|
||||
|
||||
-- Load web gui
|
||||
local webGui = asset.require('util/webgui')
|
||||
|
||||
-- Keybindings that are specific for this scene
|
||||
local Keybindings = {
|
||||
{
|
||||
Key = "h",
|
||||
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\n" ..
|
||||
"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",
|
||||
Local = false
|
||||
},
|
||||
{
|
||||
Key = "l",
|
||||
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",
|
||||
Local = false
|
||||
}
|
||||
}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
webGui.setCefRoute("onscreen")
|
||||
|
||||
sceneHelper.bindKeys(Keybindings)
|
||||
openspace.setDefaultGuiSorting()
|
||||
|
||||
openspace.setPropertyValueSingle("RenderEngine.VerticalLogOffset", 0.100000)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
sceneHelper.unbindKeys(Keybindings)
|
||||
end)
|
||||
@@ -25,13 +25,10 @@ local vrt_folders = {
|
||||
openspace.absPath('${BASE}/../OpenSpaceData/Mars/CTX'),
|
||||
-- if not and you have a custom path for CTX layers, enter it below
|
||||
'',
|
||||
|
||||
-- Our provided HiRISE layer
|
||||
openspace.absPath('${ASSETS}/scene/solarsystem/planets/mars/map_service_configs/ESRI/HiRISE'),
|
||||
-- We recommend using this folder for HiRISE
|
||||
openspace.absPath('${BASE}/../OpenSpaceData/Mars/HiRISE'),
|
||||
-- if not and you have a custom path for HiRISE layers, enter it below
|
||||
'',
|
||||
''
|
||||
},
|
||||
Moon = {
|
||||
-- Add folders here whose contents will be automatically added to the Moon globe
|
||||
@@ -58,10 +55,12 @@ 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
|
||||
openspace.globebrowsing.addBlendingLayersFromDirectory(dir, obj)
|
||||
if (dir ~= '') then
|
||||
openspace.globebrowsing.addBlendingLayersFromDirectory(dir, obj)
|
||||
|
||||
if CreateFocusNodes then
|
||||
openspace.globebrowsing.addFocusNodesFromDirectory(dir, obj)
|
||||
if CreateFocusNodes then
|
||||
openspace.globebrowsing.addFocusNodesFromDirectory(dir, obj)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -32,11 +32,11 @@ local Example_Fixed_Height = {
|
||||
Renderable = {
|
||||
Type = "RenderableModel",
|
||||
Body = "NEW HORIZONS",
|
||||
Geometry = {
|
||||
Geometry = {{
|
||||
Type = "MultiModelGeometry",
|
||||
GeometryFile = models .. "/NewHorizonsCleanModel.obj"
|
||||
},
|
||||
ColorTexture = textures .. "/NHTexture.jpg",
|
||||
GeometryFile = models .. "/NewHorizonsCleanModel.obj",
|
||||
ColorTexture = textures .. "/NHTexture.jpg"
|
||||
}}
|
||||
},
|
||||
GUI = {
|
||||
Path = "/Example"
|
||||
@@ -57,11 +57,11 @@ local Example_Adaptive_Height = {
|
||||
Renderable = {
|
||||
Type = "RenderableModel",
|
||||
Body = "NEW HORIZONS",
|
||||
Geometry = {
|
||||
Geometry = {{
|
||||
Type = "MultiModelGeometry",
|
||||
GeometryFile = models .. "/NewHorizonsCleanModel.obj"
|
||||
},
|
||||
ColorTexture = textures .. "/NHTexture.jpg",
|
||||
GeometryFile = models .. "/NewHorizonsCleanModel.obj",
|
||||
ColorTexture = textures .. "/NHTexture.jpg"
|
||||
}}
|
||||
},
|
||||
GUI = {
|
||||
Path = "/Example"
|
||||
|
||||
@@ -28,15 +28,16 @@ asset.onInitialize(function ()
|
||||
end
|
||||
|
||||
helper.setCurrentSlide(deck, 1)
|
||||
openspace.bindKey("RIGHT", "nextSlide()", "Next slide", "Next slide", "/Slides")
|
||||
openspace.bindKey("LEFT", "previousSlide()", "Previous slide", "Previous slide", "/Slides")
|
||||
openspace.bindKey("UP", "toggleSlides()", "Toggle slides", "Toggle slides", "/Slides")
|
||||
openspace.bindKey("KP_6", "nextSlide()", "Next slide", "Next slide", "/Slides")
|
||||
openspace.bindKey("KP_4", "previousSlide()", "Previous slide", "Previous slide", "/Slides")
|
||||
openspace.bindKey("KP_0", "toggleSlides()", "Toggle slides", "Toggle slides", "/Slides")
|
||||
|
||||
end)
|
||||
|
||||
|
||||
asset.onDeinitialize(function()
|
||||
openspace.clearKey("RIGHT")
|
||||
openspace.clearKey("LEFT")
|
||||
openspace.clearKey("KP_6")
|
||||
openspace.clearKey("KP_4")
|
||||
openspace.clearKey("KP_0")
|
||||
helper.removeDeck(deck)
|
||||
end)
|
||||
|
||||
@@ -35,10 +35,34 @@ local object = {
|
||||
},
|
||||
GUI = {
|
||||
Name = "2dF Galaxies",
|
||||
Path = "/Universe/Galaxies"
|
||||
Path = "/Universe/Galaxies",
|
||||
Description = [[Census 229,293 galaxies. DU Version 1.7. <br>
|
||||
The Two-degree Field (2dF) Survey was a project designed to map portions of the
|
||||
extragalactic universe. The 2dF instrument was mounted on the 3.9-meter
|
||||
(12.8-foot) Anglo-Australian Telescope (AAT), located 450 km (280 miles)
|
||||
northwest of Sydney. The telescope has a two-degree field of view on the sky,
|
||||
enabling large parts of the sky to be observed at one time. For each pointing of
|
||||
the telescope, the instrument can acquire up to 400 spectra simultaneously via
|
||||
optical fibers that feed into two spectrographs. Each spectrograph sees light
|
||||
that is between 350 nm and 800 nm, spanning the visible spectrum. <br><br> The
|
||||
2dF survey has three main components: the North Galactic Pole strip, the South
|
||||
Galactic Pole strip, and the random fields that surround the South Galactic Pole
|
||||
strip. The galaxy survey is composed of about 230,000 galaxies with brightness and
|
||||
redshift measurements. (Description from URL) <br><br> Data Reference: 2dF Galaxy
|
||||
Redshift Survey (2dFGRS Team, 1998-2003)]]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { object })
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "2dF Galaxies",
|
||||
Version = "2.0",
|
||||
Description = [[Digital Universe asset for the The Two-degree Field (2dF) Survey.]],
|
||||
Author = "Brian Abbott (AMNH), Eric Gawiser (Rutgers U)",
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"2dF"}
|
||||
}
|
||||
|
||||
@@ -37,10 +37,28 @@ local object = {
|
||||
},
|
||||
GUI = {
|
||||
Name = "2MASS Galaxies",
|
||||
Path = "/Universe/Galaxies"
|
||||
Path = "/Universe/Galaxies",
|
||||
Description = [[ The Two Micron All-Sky Survey (2MASS) is an infrared survey
|
||||
of the sky published in 2003. Because it is looking in the infrared, and
|
||||
this is a composite of the 2MASS point-source catalog, most of the light
|
||||
from this survey is starlight. In visible light, clouds of gas and dust
|
||||
obscure our view. However, in infrared, the longer wavelengths of light can
|
||||
penetrate these clouds without being scattered, thereby revealing stars
|
||||
that would normally be hidden to our eye. (Description from URL)]],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { object })
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "2MASS Galaxies",
|
||||
Version = "1.0",
|
||||
Description = [[ Digital Universe asset for the Two Micron All-Sky Survey (2MASS)
|
||||
survey]],
|
||||
Author = "Brian Abbott (AMNH)",
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"2MASS"}
|
||||
}
|
||||
|
||||
@@ -35,10 +35,31 @@ local object = {
|
||||
},
|
||||
GUI = {
|
||||
Name = "6dF Galaxies",
|
||||
Path = "/Universe/Galaxies"
|
||||
Path = "/Universe/Galaxies",
|
||||
Description = [[Census 109,569 galaxies. DU Version 1.4.<br> The Six-degree Field
|
||||
(6dF) Galaxy Survey mapped nearly half the sky from the Anglo-Australian
|
||||
Observatory. Unlike previous datasets, this one is not all-sky, meaning there
|
||||
are patches of sky that are not covered. In this case, the entire northern
|
||||
hemisphere has no coverage at all. This catalog overlaps with the Tully
|
||||
dataset, and there is a noticeable difference in the quality of these
|
||||
datasets. Tully is much tighter and the structure is more apparent, while the
|
||||
6dF data are more spread out. This is because of local motions within galaxy
|
||||
clusters have not been corrected in these data. (Description from URL)
|
||||
<br><br> Data Reference: The 6dF Galaxy Survey Redshift Catalogue
|
||||
(Jones+, 2009)]]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { object })
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "6dF Galaxies",
|
||||
Version = "2.0",
|
||||
Description = [[Digital Universe asset for The Six-degree Field (6dF) Galaxy Survey]],
|
||||
Author = "Brian Abbott (AMNH)",
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"6dF"}
|
||||
}
|
||||
|
||||
@@ -43,10 +43,32 @@ local object = {
|
||||
},
|
||||
GUI = {
|
||||
Name = "Abell Galaxy Clusters",
|
||||
Path = "/Universe/Galaxies"
|
||||
Path = "/Universe/Galaxies",
|
||||
Description = [[Census 2,246 galaxies. DU Version 1.4. <br> The Abell catalog
|
||||
includes all the nearby, and not so nearby, galaxy clusters. The northern
|
||||
hemisphere survey, published in 1958, was compiled by George Abell (1927–1983)
|
||||
from the Palomar Sky Survey plates. A subsequent southern hemisphere catalog
|
||||
was published posthumously in 1989. Further analysis by Brent Tully determined
|
||||
their distance and three-dimensional distribution. Each point in this data set
|
||||
represents a cluster of tens to hundreds (possibly even thousands) of
|
||||
galaxies, similar to the Virgo or Fornax Clusters. You will notice some points
|
||||
are assigned colors while most are gray. The data set also has an arbitrary
|
||||
cut-off for completeness, resulting in the rectangular shape of the data set.
|
||||
(Description from URL) <br><br> Data Reference: Abell Clusters of Rich
|
||||
Galaxies, Brent Tully (U Hawaii), Stuart Levy (NCSA/UIUC)]],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { object })
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Abell Galaxy Clusters",
|
||||
Version = "2.0",
|
||||
Description = [[Digital Universe asset for The Abell catalog]],
|
||||
Author = "Stuart Levy (NCSA/UIUC), Brian Abbott (AMNH)",
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"Abell"}
|
||||
}
|
||||
|
||||
@@ -25,10 +25,26 @@ local object = {
|
||||
},
|
||||
GUI = {
|
||||
Name = "Stars Labels - Alternate",
|
||||
Path = "/Milky Way/Stars"
|
||||
Path = "/Milky Way/Stars",
|
||||
Description = [[Census 3,550 star names. DU Version 1.7. <br>The main star data
|
||||
identify the accepted IAU star names for the brightest stars. However, astronomers
|
||||
have long cataloged thousands of stars beyond the brightest ones we see. Several
|
||||
attempts over thousands of years to name all the visible stars have led to two
|
||||
main catalogs: Johann Bayer's Catalog from 1603 and John Flamsteed's Catalog
|
||||
published in 1725. (Description from URL) <br><br> Data Reference: Various
|
||||
sources]],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Stars Labels - Alternate",
|
||||
Version = "1.0",
|
||||
Description = [[Digital Universe asset for alternate start labels]],
|
||||
Author = "Brian Abbott (AMNH)",
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"StarLabelsAlternate"}
|
||||
}
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { object })
|
||||
|
||||
@@ -89,6 +89,7 @@ local planck = {
|
||||
FadeInThreshold = 0.4
|
||||
},
|
||||
GUI = {
|
||||
Name = "Planck",
|
||||
Path = "/Universe/Cosmic Microwave Background"
|
||||
}
|
||||
}
|
||||
@@ -246,3 +247,19 @@ assetHelper.registerSceneGraphNodesAndExport(asset, {
|
||||
wmap, cbe, planck, multiverse_planck_1, multiverse_planck_2, multiverse_planck_3,
|
||||
multiverse_planck_4, Halpha
|
||||
})
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Background Radiation",
|
||||
Version = "2.0",
|
||||
Description = [[Various AllSky images for the Milky Way and observable Universe.
|
||||
Included: Wilkinson Microwave Anisotropy Probe (WMAP), Cosmic Background Explorer,
|
||||
Planck, Planck Multiverse 1-4, and H Alpha <br><br> Data Reference: Planck/ESA and
|
||||
the Planck Collaboration, Wilkinson Microwave Anisotropy Probe/NASA, Doug
|
||||
Finkbeiner (Princeton)]],
|
||||
Author = "Brian Abbott (AMNH), OpenSpace Team",
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"WMAP", "CBE", "Planck", "PlanckMultiverse1", "PlanckMultiverse2",
|
||||
"PlanckMultiverse3", "PlanckMultiverse4", "HAlpha"}
|
||||
}
|
||||
|
||||
@@ -31,10 +31,24 @@ local object = {
|
||||
},
|
||||
GUI = {
|
||||
Name = "Galaxy Cluster Labels",
|
||||
Path = "/Universe/Galaxies"
|
||||
Path = "/Universe/Galaxies",
|
||||
Description = [[Census 15 galaxy cluster labels. DU Version 1.2. <br>The Galaxy
|
||||
clusters dataset is a series of labels that mark where the large clusters of
|
||||
galaxies are in the nearby universe. These labels must be used in conjunction
|
||||
with the Tully galaxy group.(Description from URL) <br><br> Data Reference:
|
||||
Brian Abbott (AMNH)]],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { object })
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Galaxy Clusters Labels",
|
||||
Version = "1.0",
|
||||
Description = [[Digital Universe asset for Galaxy Clusters]],
|
||||
Author = "Brian Abbott (AMNH)",
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"GalaxyClusterLabels"}
|
||||
}
|
||||
|
||||
@@ -36,10 +36,22 @@ local object = {
|
||||
},
|
||||
GUI = {
|
||||
Name = "Constellation Bounds",
|
||||
Path = "/Milky Way/Constellations"
|
||||
Path = "/Milky Way/Constellations",
|
||||
Description = [[A Spherical mesh dividing the sky into regions that fit the
|
||||
constellations.]],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { object })
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Constellation Bounds",
|
||||
Version = "1.0",
|
||||
Description = [[DU asset providing a Spherical mesh dividing the sky into regions that
|
||||
fit the constellations.]],
|
||||
Author = "Brian Abbott (AMNH)",
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"ConstellationBounds"}
|
||||
}
|
||||
|
||||
@@ -48,10 +48,29 @@ local constellations = {
|
||||
Unit = "pc"
|
||||
},
|
||||
GUI = {
|
||||
Path = "/Milky Way/Constellations"
|
||||
Name = "Constellations",
|
||||
Path = "/Milky Way/Constellations",
|
||||
Description = [[Census 88 constellations and labels. DU Version 2.3. <br> These
|
||||
modern constellations are largely based on those of the Babylonians and
|
||||
Greeks; however, most cultures have their own figures and stories of the sky.
|
||||
More than half the official constellations adopted by scientists in 1930 were
|
||||
known to the ancients over 2,000 years ago. Each star falls into one of these
|
||||
88 regions. Of course, today we know the stars in any given constellation do
|
||||
not necessarily have any physical relationship with one another. One star may
|
||||
be nearby, while an adjacent star in the sky may be far away.(Description
|
||||
from URL) <br><br> Data Reference: various]],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { constellationsExtragalactic, constellations })
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Constellations",
|
||||
Version = "1.0",
|
||||
Description = [[Digital Universe asset for constellation lines]],
|
||||
Author = "Brian Abbott (AMNH)",
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"Constellations", "ConstellationsExtragalactic"}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,8 @@ local deepSkyPoints = {
|
||||
},
|
||||
GUI = {
|
||||
Name = "Deep Sky Objects Points",
|
||||
Path = "/Universe/Galaxies"
|
||||
Path = "/Universe/Galaxies",
|
||||
Description = [[Point cloud and labels for Deep Sky Objects]]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,8 +81,30 @@ local deepSkyImages = {
|
||||
},
|
||||
GUI = {
|
||||
Name = "Deep Sky Objects Images",
|
||||
Path = "/Universe/Galaxies"
|
||||
Path = "/Universe/Galaxies",
|
||||
Description = [[Census: 63 images and labels. DU Version 1.3. <br> These data are
|
||||
2-D images of Messier objects placed in 3-D space. Not only do we place these
|
||||
images at the proper location and give them the correct orientation, we also
|
||||
size them accurately so that you can fly to the globular cluster M13, for
|
||||
example, and see just how small the cluster of hundreds of thousands of stars
|
||||
is relative to the rest of the Galaxy. Included Messier Objects by number are:
|
||||
6, 7, 11, 16, 18, 21, 23-26, 29, 34-39, 41, 46-48, 50, 52, 67, 93, 103, 2-5,
|
||||
9, 10, 12-15, 19, 22, 28, 30, 53-56, 68-72, 75, 79, 80, 92, 107, 27, 57, 76,
|
||||
97, 8, 17, 20, 78, 1 (Description from URL) <br><br> Data Reference: Largely
|
||||
NOAO and various other sources (each image has a ref)]],
|
||||
}
|
||||
}
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { deepSkyPoints, deepSkyImages })
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Deep Sky Objects Images",
|
||||
Version = "1.0",
|
||||
Description = [[Digital Universe asset for Deep Sky Objects and their Images]],
|
||||
Author = "Nate Greenstein, Matt Everhart, Brian Abbott (AMNH)",
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"DeepSkyObjects", "DeepSkyObjectsImages"}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,10 +41,36 @@ local object = {
|
||||
},
|
||||
GUI = {
|
||||
Name = "Brown Dwarfs",
|
||||
Path = "/Milky Way"
|
||||
Path = "/Milky Way",
|
||||
Description = [[Census: 785 L dwarfs, 101 T dwarfs, 17 Y dwarfs. DU Version 6.4.
|
||||
<br> In astronomy, there are dwarf stars-red, white, and brown-dwarf novae,
|
||||
and even dwarf galaxies. As you might imagine, astronomers use the term dwarf
|
||||
when they refer to the smaller objects in any given class. For decades it was
|
||||
believed that M stars were the coolest stars in the Galaxy. Some M stars,
|
||||
called red dwarfs, make up 70% of the stars in the Galaxy, including our
|
||||
nearest known neighbor, Proxima Centauri. However, a new class of objects,
|
||||
even cooler than M stars, was recently discovered and given a spectral type
|
||||
of L. L-type objects straddle the boundary between red dwarfs and brown
|
||||
dwarfs, the latter of which are not massive enough to ignite the nuclear
|
||||
processes necessary for it to shine as a star. L-type objects are typically
|
||||
very dim stars or brown dwarfs. Even cooler than L-type objects are T-type
|
||||
objects. These are mostly brown dwarfs and resemble large, massive,
|
||||
Jupiter-like objects, too large to be planets and typically too small to be
|
||||
stars. Beyond the T dwarfs are the Y-type objects, which are even more
|
||||
dim.(Description from URL) <br><br> Data Reference: The Brown Dwarf Kinematics
|
||||
Project (Faherty+ 2019)]]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { object })
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Brown Dwarfs",
|
||||
Version = "2.0",
|
||||
Description = [[Digital Universe asset for Brown Dwarfs]],
|
||||
Author = "Brian Abbott (AMNH)",
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"Dwarfs"}
|
||||
}
|
||||
|
||||
@@ -39,10 +39,27 @@ local object = {
|
||||
EnablePixelSizeControl = true,
|
||||
},
|
||||
GUI = {
|
||||
Path = "/Milky Way/Exoplanets"
|
||||
Name = "Exoplanets",
|
||||
Path = "/Milky Way/Exoplanets",
|
||||
Description = [[Census: 4,055 planets in 3,023 systems. DU Version 20.11. <br>
|
||||
Extrasolar planets, or exoplanets, are a relatively new phenomenon in
|
||||
astronomy. While many astronomers believed in their existence, no
|
||||
observational evidence was available until 1995. Since that time, scientists
|
||||
have discovered thousands of systems consisting of one or more planets around
|
||||
a host star.(Description from URL) <br><br> Data Reference: NASA Exoplanet
|
||||
Archive (CalTech/NASA)]],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { object })
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Exoplanets",
|
||||
Version = "1.0",
|
||||
Description = [[Digital Universe asset for Exoplanets]],
|
||||
Author = "Brian Abbott (AMNH)",
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"Exoplanets"}
|
||||
}
|
||||
|
||||
@@ -38,10 +38,42 @@ local object = {
|
||||
},
|
||||
GUI = {
|
||||
Name = "Globular Clusters",
|
||||
Path = "/Milky Way"
|
||||
Path = "/Milky Way",
|
||||
Description = [[Census: 157 globular clusters. DU Version 2.6. <br>Globular star
|
||||
clusters are gravitationally bound groups of 100,000 to 1 million stars. They
|
||||
are compact, spherical “balls” of stars with very high stellar densities in
|
||||
their centers (stars near their center are within a light year of one
|
||||
another). These clusters are typically 30 to 100 light years in diameter. If
|
||||
Earth were located inside one of these clusters, our sky would be lit by an
|
||||
abundance of stars brighter than the Sun. The globular clusters form one of
|
||||
the most complete data sets in the Atlas. Data for the clusters represent
|
||||
almost all the clusters in our Galaxy—several on the opposite side of Galactic
|
||||
center may be invisible to us. The clusters orbit the Milky Way in random
|
||||
orientations, as comets orbit the Sun.(Description from URL) <br><br> Data
|
||||
Reference: Properties of Galactic Globular Clusters, C. Francis+
|
||||
(U Cambridge)]],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { object })
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Globular Clusters",
|
||||
Version = "2.0",
|
||||
Description = [[Census: 157 globular clusters. DU Version 2.6. Globular star clusters
|
||||
are gravitationally bound groups of 100,000 to 1 million stars. They are compact,
|
||||
spherical “balls” of stars with very high stellar densities in their centers (stars
|
||||
near their center are within a light year of one another). These clusters are
|
||||
typically 30 to 100 light years in diameter. If Earth were located inside one of these
|
||||
clusters, our sky would be lit by an abundance of stars brighter than the Sun. The
|
||||
globular clusters form one of the most complete data sets in the Atlas. Data for the
|
||||
clusters represent almost all the clusters in our Galaxy—several on the opposite side
|
||||
of Galactic center may be invisible to us. The clusters orbit the Milky Way in random
|
||||
orientations, as comets orbit the Sun.(Description from URL) <br><br> Data Reference:
|
||||
Properties of Galactic Globular Clusters, C. Francis+ (U Cambridge)]],
|
||||
Author = "Brian Abbott (AMNH)",
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"GlobularClusters"}
|
||||
}
|
||||
|
||||
@@ -533,3 +533,23 @@ assetHelper.registerSceneGraphNodesAndExport(asset, {
|
||||
galacticLabels, plane1ld, plane1lm, plane1ly, plane10ly, plane100ly, plane1kly,
|
||||
plane10kly, plane100kly, plane1Mly, plane10Mly, plane100Mly, plane20Gly
|
||||
})
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Grids",
|
||||
Version = "2.0",
|
||||
Description = [[Various grids for showing size reference. Included: 10,000 light year
|
||||
grid, 10 light year grid, 20 billion light year grid, 10 million light year grid,
|
||||
100 light year grid, 100 million light year grid, Ecliptic Coordinate Sphere
|
||||
(500-light-year radius), Galactic Coordinate Sphere (1000-light-year radius),
|
||||
Galaxy Coordinate Grid, Celestial Coordinates / Radio Sphere (dynamic radius), 1
|
||||
billion light year grid, Celestial Coordinate Sphere (1000000-light-year radius),
|
||||
1,000 light year grid, 1 million light year grid, 1 light year grid]],
|
||||
Author = "Brian Abbott (AMNH)",
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"RadioSphere", "OortSphere", "EclipticSphere", "EclipticSphereLabels",
|
||||
"Equatorial", "EquatorialSphereLabels", "GalacticSphere", "GalacticSphereLabels",
|
||||
"1ldGrid", "1lmGrid", "1lyGrid", "10lyGrid", "100lyGrid", "1klyGrid" "10klyGrid",
|
||||
"100klyGrid", "1MlyGrid", "10MlyGrid", "100MlyGrid", "20GlyGrid"}
|
||||
}
|
||||
|
||||
@@ -32,10 +32,23 @@ local object = {
|
||||
},
|
||||
GUI = {
|
||||
Name = "Galaxy Group Labels",
|
||||
Path = "/Universe/Galaxies"
|
||||
Path = "/Universe/Galaxies",
|
||||
Description = [[Census: 62 galaxy group labels. DU Version 1.2. <br> The Galaxy
|
||||
Groups data are a set of labels that mark the nearby galaxy groups. The Milky Way
|
||||
is in the Local Group, and we are surrounded by many other groups.(Description
|
||||
from URL) <br><br> Data Reference: Brian Abbott (AMNH)]]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { object })
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Galaxy Group Labels",
|
||||
Version = "1.0",
|
||||
Author = "Brian Abbott (AMNH)",
|
||||
Description = [[Digital Universe asset for Galaxy Groups]],
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"NearbyGalaxyGroups"}
|
||||
}
|
||||
|
||||
@@ -38,10 +38,30 @@ local object = {
|
||||
},
|
||||
GUI = {
|
||||
Name = "HII Regions",
|
||||
Path = "/Milky Way"
|
||||
Path = "/Milky Way",
|
||||
Description = [[Census: 1,271 nebulae. DU Version 4.6. <br> H ii (pronounced
|
||||
H-two) regions are stellar nurseries for newborn stars. Stars are born from
|
||||
condensing clouds of hydrogen gas. As these clouds condense, the densities
|
||||
become high enough to form stars. From Earth's perspective, you'll notice that
|
||||
the H ii regions all lie close to the Galactic plane. This is not an accident
|
||||
of nature. These star-forming regions lie in the plane of the Galaxy because
|
||||
that is where star formation occurs in spiral galaxies such as our Milky Way.
|
||||
Because of this, they are great tracers of the spiral arms of the Galaxy, and
|
||||
were instrumental in our understanding of the Galaxy's overall structure
|
||||
(Description from URL) <br><br> Data Reference: The WISE catalog of Galactic
|
||||
HII Regions (Anderson+, 2014)]],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { object })
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "HII Regions",
|
||||
Version = "1.0",
|
||||
Description = [[Digital Universe asset for HII Regions]],
|
||||
Author = "Carter Emmart, Brian Abbott (AMNH)",
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"HIIRegions"}
|
||||
}
|
||||
|
||||
@@ -34,10 +34,29 @@ local object = {
|
||||
},
|
||||
GUI = {
|
||||
Name = "Kepler Planetary Candidates",
|
||||
Path = "/Milky Way/Exoplanets"
|
||||
Path = "/Milky Way/Exoplanets",
|
||||
Description = [[Census: 3,254 stars. DU Version 9.3. <br> The exoplanet candidate
|
||||
stars are likely hosts for exoplanets. These are stars plucked from NASA's Kepler
|
||||
and TESS space telescopes. The Kepler mission was designed to stare at one spot,
|
||||
roughly twelve degrees across, in the constellation Cygnus. By staring at one
|
||||
spot, the spacecraft could monitor over 500,000 stars in that field for subtle
|
||||
variations in brightness.The data included here are the stars that are considered
|
||||
good candidates to host planets. Rather than represent them photo-realistically,
|
||||
with accurate colors, we choose to visualize them as generic, pure yellow stars.
|
||||
(Description from URL) <br><br> Data Reference: NASA Exoplanet Archive
|
||||
(CalTech/NASA)]],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { object })
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Kepler Planetary Candidates",
|
||||
Version = "2.0",
|
||||
Description = [[Digital Universe asset for Kepler Planetary Candidates]],
|
||||
Author = "Brian Abbott, Emily Rice, and Jason No (AMNH)",
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"KeplerPlanetaryCandidates"}
|
||||
}
|
||||
|
||||
@@ -39,10 +39,30 @@ local object = {
|
||||
},
|
||||
GUI = {
|
||||
Name = "Local Group",
|
||||
Path = "/Universe/Galaxies"
|
||||
Path = "/Universe/Galaxies",
|
||||
Description = [[Census: 102 galaxies. DU Version 6.4. <br> A group of galaxies is
|
||||
a small number of large galaxies that are typically surrounded by a large
|
||||
number of small galaxies. The Milky Way belongs to the Local Group, and is one
|
||||
of roughly 100 galaxies in that group. The Milky Way, the Andromeda Galaxy
|
||||
(also known as Messier 31, or M31), and the Triangulum Galaxy (M33) are three
|
||||
of the largest galaxies in the Local Group. Each is a spiral galaxy containing
|
||||
hundreds of billions of stars. Surrounding the Milky Way and Andromeda are a
|
||||
bevy of dwarf galaxies-smaller, often irregular galaxies, that contain
|
||||
hundreds of millions to a few billion stars. (Description from URL) <br><br>
|
||||
Data Reference: Properties of dwarf galaxies in the Local Group
|
||||
(McConnachie+, 2012)]],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { object })
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Local Group",
|
||||
Version = "2.0",
|
||||
Description = [[Digital Universe asset for the Local Goup]],
|
||||
Author = "Brian Abbott (AMNH)",
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"LocalDwarfGalaxies"}
|
||||
}
|
||||
|
||||
@@ -1,60 +1,6 @@
|
||||
local assetHelper = asset.require('util/asset_helper')
|
||||
|
||||
|
||||
|
||||
local sphereTextures = asset.syncedResource({
|
||||
Name = "Milky Way Sphere Textures",
|
||||
Type = "HttpSynchronization",
|
||||
Identifier = "milkyway_textures",
|
||||
Version = 2
|
||||
})
|
||||
|
||||
local planeTextures = asset.syncedResource({
|
||||
Name = "Milky Way Plane Textures",
|
||||
Type = "HttpSynchronization",
|
||||
Identifier = "digitaluniverse_milkyway_textures",
|
||||
Version = 2
|
||||
})
|
||||
|
||||
local planeSpeck = asset.syncedResource({
|
||||
Name = "Milky Way Plane Speck",
|
||||
Type = "HttpSynchronization",
|
||||
Identifier = "digitaluniverse_milkyway_speck",
|
||||
Version = 1
|
||||
})
|
||||
|
||||
local homespeck = asset.syncedResource({
|
||||
Name = "Home Speck File",
|
||||
Type = "HttpSynchronization",
|
||||
Identifier = "digitaluniverse_home_speck",
|
||||
Version = 1
|
||||
})
|
||||
|
||||
local sphere = {
|
||||
Identifier = "MilkyWay",
|
||||
Transform = {
|
||||
Rotation = {
|
||||
Type = "StaticRotation",
|
||||
Rotation = {0, 0, 3.14159265359}
|
||||
}
|
||||
},
|
||||
Renderable = {
|
||||
Type = "RenderableSphere",
|
||||
Size = 9.2E21,
|
||||
Segments = 40,
|
||||
Opacity = 0.35,
|
||||
Texture = sphereTextures .. "/DarkUniverse_mellinger_4k.jpg",
|
||||
Orientation = "Inside",
|
||||
UseAdditiveBlending = true,
|
||||
MirrorTexture = true,
|
||||
FadeOutThreshold = 0.0015,
|
||||
Background = true
|
||||
},
|
||||
GUI = {
|
||||
Name = "Milky Way Sphere",
|
||||
Path = "/Milky Way"
|
||||
}
|
||||
}
|
||||
local dataPaths = asset.require("scene/digitaluniverse/milkyway_data")
|
||||
|
||||
local plane = {
|
||||
Identifier = "MilkyWayGalaxyImage",
|
||||
@@ -65,58 +11,38 @@ local plane = {
|
||||
Color = { 1.0, 1.0, 1.0 },
|
||||
Opacity = 0.99,
|
||||
ScaleFactor = 2.8,
|
||||
File = planeSpeck .. "/galaxy.speck",
|
||||
TexturePath = planeTextures,
|
||||
File = dataPaths.SpeckPath .. "/galaxy.speck",
|
||||
TexturePath = dataPaths.TexturesPath,
|
||||
Luminosity = "size",
|
||||
ScaleLuminosity = 1.0,
|
||||
-- Fade in value in the same unit as "Unit"
|
||||
FadeInDistances = { 3000.0, 50000.0 },
|
||||
PlaneMinSize = 5.0,
|
||||
Unit = "pc"
|
||||
},
|
||||
GUI = {
|
||||
Name = "Milky Way Galaxy Image",
|
||||
Path = "/Universe/Galaxies"
|
||||
Path = "/Universe/Galaxies",
|
||||
Description = [[Census: 1 image. DU Version 2.2. <br> The exterior view of the
|
||||
Milky Way is simply a two-dimensional image. The image is that of NGC 1232, a
|
||||
galaxy thought to resemble our Milky Way. The image has been properly sized
|
||||
and approximately oriented to function as a placeholder, allowing one to see
|
||||
the context of the Galaxy relative to other data in the atlas. The features
|
||||
you see in the image, of course, do not represent our Galaxy, per se, but
|
||||
resemble similar features found in our Galaxy.(Description from URL)
|
||||
<br><br> Data Reference: European Southern Observatory]]
|
||||
}
|
||||
}
|
||||
|
||||
local homeLabel = {
|
||||
Identifier = "HomeLabel",
|
||||
Renderable = {
|
||||
Type = "RenderableBillboardsCloud",
|
||||
Enabled = false,
|
||||
Color = { 1.0, 0.4, 0.2 },
|
||||
Opacity = 0.99,
|
||||
ScaleFactor = 500.0,
|
||||
--File = homespeck .. "/home.speck",
|
||||
-- Texture = textures .. "/point3.png",
|
||||
DrawLabels = true,
|
||||
LabelFile = homespeck .. "/home.label",
|
||||
TextColor = { 0.8, 0.8, 0.8 },
|
||||
TextSize = 20.50,
|
||||
TextMinSize = 16.0,
|
||||
TransformationMatrix = {
|
||||
-0.7357425748, 0.67726129641, 0.0, 0.0,
|
||||
-0.074553778365, -0.080991471307, 0.9939225904, 0.0,
|
||||
0.67314530211, 0.73127116582, 0.11008126223, 0.0,
|
||||
0.0, 0.0, 0.0, 1.0
|
||||
},
|
||||
Unit = "Mpc",
|
||||
-- Fade in value in the same unit as "Unit"
|
||||
FadeInDistances = { 0.05, 1.0 },
|
||||
-- Max size in pixels
|
||||
BillboardMaxSize = 8.22,
|
||||
BillboardMinSize = 0.0,
|
||||
--CorrectionSizeEndDistance = 22.0,
|
||||
--CorrectionSizeFactor = 10.45
|
||||
EnablePixelSizeControl = true
|
||||
},
|
||||
GUI = {
|
||||
Name = "Home Label",
|
||||
Path = "/Universe/Galaxies"
|
||||
}
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { plane })
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "MilkyWay Galaxy",
|
||||
Version = "2.0",
|
||||
Description = [[Digital Universe asset containt 2D image of the MilkyWay. For
|
||||
extragalactic viewing]],
|
||||
Author = "Brian Abbott, Carter Emmart (AMNH)",
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"MilkyWayGalaxyImage"}
|
||||
}
|
||||
|
||||
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { sphere, plane, homeLabel })
|
||||
|
||||
63
data/assets/scene/digitaluniverse/milkyway_arm_labels.asset
Normal file
63
data/assets/scene/digitaluniverse/milkyway_arm_labels.asset
Normal file
@@ -0,0 +1,63 @@
|
||||
local assetHelper = asset.require('util/asset_helper')
|
||||
|
||||
local dataPaths = asset.require("scene/digitaluniverse/milkyway_data")
|
||||
|
||||
local plane = {
|
||||
Identifier = "MilkyWayGalaxyArmLabelsImage",
|
||||
Parent = "Root",
|
||||
Renderable = {
|
||||
Type = "RenderablePlanesCloud",
|
||||
Enabled = false,
|
||||
Color = { 1.0, 1.0, 1.0 },
|
||||
Opacity = 0.99,
|
||||
ScaleFactor = 2.8,
|
||||
File = dataPaths.SpeckPath .. "/galaxyArmLabels.speck",
|
||||
TexturePath = dataPaths.TexturesPath,
|
||||
Luminosity = "size",
|
||||
ScaleLuminosity = 1.0,
|
||||
FadeInDistances = { 3000.0, 50000.0 },
|
||||
PlaneMinSize = 5.0,
|
||||
Unit = "pc"
|
||||
},
|
||||
GUI = {
|
||||
Name = "Milky Way Arms Labels",
|
||||
Path = "/Universe/Galaxies",
|
||||
Description = [[ Census: 1 image. DU Version: 1.2. This image contains labels for
|
||||
the Milky Way's spiral arms. We label them in this manner ("hard coding" the
|
||||
labels into an image rather than having native labels) so that they can retain
|
||||
their size, shape, and location as they overlay the galaxy. (Description from
|
||||
Digital Universe Data Profiles)]],
|
||||
}
|
||||
}
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { plane })
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Milky Way Arms Labels",
|
||||
Version = "1.0",
|
||||
Description = [[ Image with arm labels for the Milky Way galaxy]],
|
||||
Author = "Brian Abbott (AMNH)",
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = [[ Copyright © American Museum of Natural History. All rights reserved.
|
||||
<br><br> Downloading the Atlas: AMNH offers the Atlas free of charge via our
|
||||
website, http://www.haydenplanetarium.org/. The User is free to download and/or
|
||||
duplicate verbatim copies of the Atlas provided this license and copyright
|
||||
information accompany the Atlas. <br><br> Modifying the Atlas: The user is free to
|
||||
modify the Atlas by either adding data or altering existing data, provided it is
|
||||
for personal use only. Once the user modifies the Atlas, it is no longer part of
|
||||
AMNH's Atlas and cannot be used publicly alongside or within the Atlas without
|
||||
written permission from AMNH. <br><br> Distributing the Atlas: The user is
|
||||
forbidden to distribute and use the Atlas for profit, as part of a software and/or
|
||||
production system that will subsequently be redistributed, or for public
|
||||
consumption (via print, electronic media, or broadcast/produced pieces) without
|
||||
written permission from AMNH. <br><br> Neither the names of American Museum of
|
||||
Natural History and Hayden Planetarium nor the names of their contributors may be
|
||||
used to endorse or promote products derived from this Atlas without specific,
|
||||
prior written permission. <br><br> The Atlas is free but is offered WITHOUT ANY
|
||||
WARRANTY of any kind. We provide the Atlas as is and take no responsibility for
|
||||
any damage resulting from the use of this Atlas. The entire risk as to the quality
|
||||
and performance of this product is with the user. <br><br> For more information,
|
||||
please visit http://www.haydenplanetarium.org/universe]],
|
||||
Identifiers = {"MilkyWayGalaxyArmLabelsImage"}
|
||||
}
|
||||
16
data/assets/scene/digitaluniverse/milkyway_data.asset
Normal file
16
data/assets/scene/digitaluniverse/milkyway_data.asset
Normal file
@@ -0,0 +1,16 @@
|
||||
local planeTextures = asset.syncedResource({
|
||||
Name = "Milky Way Plane Textures",
|
||||
Type = "HttpSynchronization",
|
||||
Identifier = "digitaluniverse_milkyway_textures",
|
||||
Version = 2
|
||||
})
|
||||
|
||||
local planeSpeck = asset.syncedResource({
|
||||
Name = "Milky Way Plane Speck",
|
||||
Type = "HttpSynchronization",
|
||||
Identifier = "digitaluniverse_milkyway_speck",
|
||||
Version = 1
|
||||
})
|
||||
|
||||
asset.export("TexturesPath", planeTextures)
|
||||
asset.export("SpeckPath", planeSpeck)
|
||||
57
data/assets/scene/digitaluniverse/milkyway_label.asset
Normal file
57
data/assets/scene/digitaluniverse/milkyway_label.asset
Normal file
@@ -0,0 +1,57 @@
|
||||
--milkyway_label.asset
|
||||
local assetHelper = asset.require('util/asset_helper')
|
||||
|
||||
|
||||
|
||||
local homespeck = asset.syncedResource({
|
||||
Name = "Home Speck File",
|
||||
Type = "HttpSynchronization",
|
||||
Identifier = "digitaluniverse_home_speck",
|
||||
Version = 1
|
||||
})
|
||||
|
||||
local homeLabel = {
|
||||
Identifier = "HomeLabel",
|
||||
Renderable = {
|
||||
Type = "RenderableBillboardsCloud",
|
||||
Enabled = false,
|
||||
Color = { 1.0, 0.4, 0.2 },
|
||||
Opacity = 0.99,
|
||||
ScaleFactor = 500.0,
|
||||
DrawLabels = true,
|
||||
LabelFile = homespeck .. "/home.label",
|
||||
TextColor = { 0.8, 0.8, 0.8 },
|
||||
TextSize = 20.50,
|
||||
TextMinSize = 16.0,
|
||||
TransformationMatrix = {
|
||||
-0.7357425748, 0.67726129641, 0.0, 0.0,
|
||||
-0.074553778365, -0.080991471307, 0.9939225904, 0.0,
|
||||
0.67314530211, 0.73127116582, 0.11008126223, 0.0,
|
||||
0.0, 0.0, 0.0, 1.0
|
||||
},
|
||||
Unit = "Mpc",
|
||||
FadeInDistances = { 0.05, 1.0 },
|
||||
BillboardMaxSize = 8.22,
|
||||
BillboardMinSize = 0.0,
|
||||
EnablePixelSizeControl = true
|
||||
},
|
||||
GUI = {
|
||||
Name = "Home Label",
|
||||
Path = "/Universe/Galaxies",
|
||||
Description = [[Label for the Milky Way titled "Home", sided for the galactic
|
||||
level]],
|
||||
}
|
||||
}
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { homeLabel })
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Home Label",
|
||||
Version = "1.0",
|
||||
Description = [[Label for the Milky Way titled "Home", sided for the galactic level]],
|
||||
Author = "OpenSpace Team",
|
||||
URL = "http://openspaceproject.com",
|
||||
License = "MIT license",
|
||||
Identifiers = {"HomeLabel"}
|
||||
}
|
||||
52
data/assets/scene/digitaluniverse/milkyway_sphere.asset
Normal file
52
data/assets/scene/digitaluniverse/milkyway_sphere.asset
Normal file
@@ -0,0 +1,52 @@
|
||||
local assetHelper = asset.require('util/asset_helper')
|
||||
|
||||
|
||||
|
||||
local sphereTextures = asset.syncedResource({
|
||||
Name = "Milky Way Sphere Textures",
|
||||
Type = "HttpSynchronization",
|
||||
Identifier = "milkyway_textures",
|
||||
Version = 2
|
||||
})
|
||||
|
||||
|
||||
local sphere = {
|
||||
Identifier = "MilkyWay",
|
||||
Transform = {
|
||||
Rotation = {
|
||||
Type = "StaticRotation",
|
||||
Rotation = {0, 0, 3.14159265359}
|
||||
}
|
||||
},
|
||||
Renderable = {
|
||||
Type = "RenderableSphere",
|
||||
Size = 9.2E21,
|
||||
Segments = 40,
|
||||
Opacity = 0.35,
|
||||
Texture = sphereTextures .. "/DarkUniverse_mellinger_4k.jpg",
|
||||
Orientation = "Inside",
|
||||
UseAdditiveBlending = true,
|
||||
MirrorTexture = true,
|
||||
FadeOutThreshold = 0.0015,
|
||||
Background = true
|
||||
},
|
||||
GUI = {
|
||||
Name = "Milky Way Sphere",
|
||||
Path = "/Milky Way",
|
||||
Description = [[All sky image of the Milky Way that is visible when inside. Fades
|
||||
out when zooming away from the Milky Way]],
|
||||
}
|
||||
}
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { sphere })
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Milky Way Galaxy Sphere",
|
||||
Version = "2.0",
|
||||
Description = [[All sky image of the Milky Way]],
|
||||
Author = "OpenSpace Team",
|
||||
URL = "http://openspaceproject.com",
|
||||
License = "MIT license",
|
||||
Identifiers = {"MilkyWay"}
|
||||
}
|
||||
@@ -42,10 +42,30 @@ local object = {
|
||||
},
|
||||
GUI = {
|
||||
Name = "OB Associations",
|
||||
Path = "/Milky Way"
|
||||
Path = "/Milky Way",
|
||||
Description = [[Census: 61 OB associations. DU Version 2.4. <br> OB associations
|
||||
are young groups of stars that were formed within a giant molecular cloud, but
|
||||
have dispersed after the original gas and dust from the cloud was blown away
|
||||
by the star's radiation pressure. Although an association's stars are no
|
||||
longer gravitationally bound to one another, they share a common motion in
|
||||
space because they were formed from the same cloud. This allows astronomers to
|
||||
easily determine OB association membership stars. These objects are color
|
||||
coded by their spiral arm membership. Blue associations trace the Sagittarius
|
||||
Arm. Purple associations are in the local Orion Spur. Orange associations are
|
||||
in the Perseus Arm (Description from URL) <br><br> Data Reference: New List of
|
||||
OB Associations (Melnik+)]],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { object })
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "OB Associations",
|
||||
Version = "2.0",
|
||||
Description = [[Digital Universe asset for OB Associations]],
|
||||
Author = "Brian Abbott (AMNH)",
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"OBAssociations"}
|
||||
}
|
||||
|
||||
@@ -38,10 +38,30 @@ local object = {
|
||||
},
|
||||
GUI = {
|
||||
Name = "Open Star Clusters",
|
||||
Path = "/Milky Way"
|
||||
Path = "/Milky Way",
|
||||
Description = [[Census: 2,040 clusters. DU Version 5.7. <br> OB associations are
|
||||
young groups of stars that were formed within a giant molecular cloud, but
|
||||
have dispersed after the original gas and dust from the cloud was blown away
|
||||
by the star's radiation pressure. Although an association's stars are no
|
||||
longer gravitationally bound to one another, they share a common motion in
|
||||
space because they were formed from the same cloud. This allows astronomers to
|
||||
easily determine OB association membership stars. These objects are color
|
||||
coded by their spiral arm membership. Blue associations trace the Sagittarius
|
||||
Arm. Purple associations are in the local Orion Spur. Orange associations are
|
||||
in the Perseus Arm (Description from URL) <br><br> Data Reference: Optically
|
||||
visible open clusters and Candidates (Dias+ 2002-2015)]],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { object })
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Open Star Clusters",
|
||||
Version = "2.0",
|
||||
Description = [[Digital Universe asset for Open Star Clusters]],
|
||||
Author = "Brian Abbott (AMNH)",
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"OpenStarClusters"}
|
||||
}
|
||||
|
||||
@@ -38,10 +38,27 @@ local object = {
|
||||
},
|
||||
GUI = {
|
||||
Name = "Planetary Nebulae",
|
||||
Path = "/Milky Way"
|
||||
Path = "/Milky Way",
|
||||
Description = [[Census: 283 nebulae. DU Version 2.8. <br> A planetary nebula is an
|
||||
expanding shell of gas ejected from a star late in its life cycle. Appearing
|
||||
like greenish disks to a telescopic observer, planetary nebulae received their
|
||||
name from their resemblance to the gaseous planets of our solar system. In no
|
||||
way are they related to planets, rather, they are products of dying stars.
|
||||
(Description from URL) <br><br> Data Reference: Planetary Nebulae distances
|
||||
in Gaia DR2 (Kimeswenger+, 2018), Strasbourg-ESO Catalog of Planetary Nebulae
|
||||
(Acker+ 1992)]],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { object })
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Planetary Nebulae",
|
||||
Version = "2.0",
|
||||
Description = [[Digital Universe asset for Planetary Nebulae]],
|
||||
Author = "Brian Abbott (AMNH)",
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"PlanetaryNebulae"}
|
||||
}
|
||||
|
||||
@@ -37,10 +37,32 @@ local object = {
|
||||
EnablePixelSizeControl = false
|
||||
},
|
||||
GUI = {
|
||||
Path = "/Milky Way"
|
||||
Name = "Pulsars",
|
||||
Path = "/Milky Way",
|
||||
Description = [[Census: 2,498 pulsars. DU Version 5.6. <br> Upon death, stars
|
||||
leave behind one of three possible remnants: a white dwarf, a neutron star, or
|
||||
a black hole. Stars that are more massive than the sun will often become
|
||||
neutron stars in a violent explosion called a supernova. During a supernova,
|
||||
the core of the star collapses under such high pressure that the electrons,
|
||||
which normally remain outside the atomic nucleus, are forced to combine with
|
||||
the protons in the nucleus. Atomic nuclei break apart, producing what is
|
||||
called a degenerate state of matter. The collapse is halted when the material
|
||||
cannot be packed any tighter. At this point, the star has a radius of about
|
||||
10-15 kilometers. The density of this material is so high that a teaspoonful
|
||||
would weigh about 100 million tons on Earth. (Description from URL) <br><br>
|
||||
Data Reference: ATNF Pulsar Catalogue, (Manchester+, 2005)]],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { object })
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Pulsars",
|
||||
Version = "2.0",
|
||||
Description = [[Digital Universe asset for Pulsars.]],
|
||||
Author = "Brian Abbott (AMNH)",
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"Pulsars"}
|
||||
}
|
||||
|
||||
@@ -35,10 +35,28 @@ local object = {
|
||||
EnablePixelSizeControl = true
|
||||
},
|
||||
GUI = {
|
||||
Path = "/Universe"
|
||||
Name = "Quasars",
|
||||
Path = "/Universe",
|
||||
Description = [[Census: 569,442 quasars. DU Version 2.2. <br>
|
||||
Quasars are the most distant objects we can see. They are extremely active
|
||||
galaxies that contain supermassive black holes which are gobbling up material
|
||||
at a furious rate. The Million Quasars Catalogue is an aggregate catalog of
|
||||
several surveys, including 2dF and Sloan. So, it should not be surprising that
|
||||
the shape of these data mimic the shape of the Sloan and 2dF galaxy surveys,
|
||||
with large parts of the sky unobserved.(Description from URL) <br><br> Data
|
||||
Reference: The Million Quasars catalog (Flesch, 2017)]]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { object })
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Quasars",
|
||||
Version = "2.0",
|
||||
Description = [[Digital Universe asset for Quasars.]],
|
||||
Author = "Brian Abbott (AMNH)",
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"Quasars"}
|
||||
}
|
||||
|
||||
@@ -44,10 +44,34 @@ local object = {
|
||||
},
|
||||
GUI = {
|
||||
Name = "Sloan Digital Sky Survey",
|
||||
Path = "/Universe/Galaxies"
|
||||
Path = "/Universe/Galaxies",
|
||||
Description = [[Census: 2,600,258 galaxies. DU Version 10.6.<br> The Sloan Digital
|
||||
Sky Survey (SDSS) is an ambitious project to image about 35% of the sky, deep
|
||||
into the universe. The survey measured the position and brightness of almost 1
|
||||
billion objects, and obtained spectra to more than 4 million objects. This is
|
||||
not an all-sky survey, so there are large parts of the sky that remain
|
||||
unobserved, which produces the bow tie distribution and the black areas where
|
||||
there surely are galaxies, but we have yet to observe them. These galaxies
|
||||
appear to extend beyond the 2dF survey to distances that exceed 5 billion
|
||||
light years. However, the weblike structure of clusters, filaments, and voids
|
||||
seems to fade by about 2 billion light years. Beyond this distance, the
|
||||
completeness of the survey drops so that only the intrinsically bright
|
||||
galaxies are visible. The weblike cosmic structure is echoed in these data,
|
||||
with orange clusters standing out among the less dense aqua-colored galaxies
|
||||
and the less dense regions of green-colored galaxies. (Description from URL)
|
||||
<br><br> Data Reference: Sloan Digital Sky Survey (http://www.sdss.org/)]]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { object })
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Sloan Digital Sky Survey",
|
||||
Version = "2.0",
|
||||
Description = [[Digital Universe asset for The Sloan Digital Sky Survey (SDSS).]],
|
||||
Author = "Brian Abbott (AMNH)",
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"SloanDigitalSkySurvey"}
|
||||
}
|
||||
|
||||
@@ -26,10 +26,21 @@ local object = {
|
||||
},
|
||||
GUI = {
|
||||
Name = "Stars Labels",
|
||||
Path = "/Milky Way/Stars"
|
||||
Path = "/Milky Way/Stars",
|
||||
Description = [[Labels for stars in the Milky Way. See 'Stars' for more
|
||||
info.]],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { object })
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Star Labels",
|
||||
Version = "2.0",
|
||||
Description = [[Digital Universe asset for labels of the stars.]],
|
||||
Author = "Brian Abbott (AMNH)",
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"StarsLabels"}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,8 @@ local sunOrbit = {
|
||||
},
|
||||
GUI = {
|
||||
Name = "Sun Orbit",
|
||||
Path = "/Milky Way/Stars/Stars Orbits"
|
||||
Path = "/Milky Way/Stars/Stars Orbits",
|
||||
Description = [["Orbits of the Sun around the Milky Way"]]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +51,8 @@ local barnardsOrbit = {
|
||||
},
|
||||
GUI = {
|
||||
Name = "Barnards Orbit",
|
||||
Path = "/Milky Way/Stars/Stars Orbits"
|
||||
Path = "/Milky Way/Stars/Stars Orbits",
|
||||
Description = [["Orbits of Barnard's Star around the Milky Way"]]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +74,8 @@ local kapteynsOrbit = {
|
||||
},
|
||||
GUI = {
|
||||
Name = "Kapteyns Orbit",
|
||||
Path = "/Milky Way/Stars/Stars Orbits"
|
||||
Path = "/Milky Way/Stars/Stars Orbits",
|
||||
Description = [["Orbits of Kapteyn's Star around the Milky Way"]]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +97,8 @@ local lacaille9352Orbit = {
|
||||
},
|
||||
GUI = {
|
||||
Name = "Lacaille 9352 Orbit",
|
||||
Path = "/Milky Way/Stars/Stars Orbits"
|
||||
Path = "/Milky Way/Stars/Stars Orbits",
|
||||
Description = [["Orbits of Lacaille9352 around the Milky Way"]]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,7 +120,8 @@ local lSR1826Orbit = {
|
||||
},
|
||||
GUI = {
|
||||
Name = "LSR1826+3014 Orbit",
|
||||
Path = "/Milky Way/Stars/Stars Orbits"
|
||||
Path = "/Milky Way/Stars/Stars Orbits",
|
||||
Description = [["Orbits of LSR1826+3014 around the Milky Way"]]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +143,8 @@ local lSRJ0822Orbit = {
|
||||
},
|
||||
GUI = {
|
||||
Name = "LSRJ0822+1700 Orbit",
|
||||
Path = "/Milky Way/Stars/Stars Orbits"
|
||||
Path = "/Milky Way/Stars/Stars Orbits",
|
||||
Description = [["Orbits of LSRJ0822+1700 around the Milky Way"]]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,7 +166,8 @@ local pM_J13420Orbit = {
|
||||
},
|
||||
GUI = {
|
||||
Name = "PM_J13420-3415 Orbit",
|
||||
Path = "/Milky Way/Stars/Stars Orbits"
|
||||
Path = "/Milky Way/Stars/Stars Orbits",
|
||||
Description = [["Orbits of PM_J13420-3415 around the Milky Way"]]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,3 +175,18 @@ assetHelper.registerSceneGraphNodesAndExport(asset, {
|
||||
sunOrbit, barnardsOrbit, pM_J13420Orbit, lSRJ0822Orbit, lSR1826Orbit,
|
||||
lacaille9352Orbit, kapteynsOrbit
|
||||
})
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Star Orbits",
|
||||
Version = "1.0",
|
||||
Description = [[Select Star Orbital paths that delineate their trajectory around the
|
||||
Milky Way over 1 billion years into the future. Included: Sun, Barnards, Kapteyns,
|
||||
Lacaille 9352, LSR1826+3014, LSRJ0822+1700, PM_J13420-3415. <br><br> Data
|
||||
Reference: Sebastien Lepine (AMNH)]],
|
||||
Author = "Brian Abbott (AMNH)",
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"SunOrbit", "BarnardsOrbit", "KapteynsOrbit", "pM_J13420Orbit",
|
||||
"LSR1826Orbit", "LSRJ0822Orbit", "lacaille9352Orbit"}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,15 @@ local stars = {
|
||||
RenderMethod = "Texture Based" -- or PSF
|
||||
},
|
||||
GUI = {
|
||||
Path = "/Milky Way/Stars"
|
||||
Name = "Stars",
|
||||
Path = "/Milky Way/Stars",
|
||||
Description = [[Census: 117,003 stars with 321 labels.<br> DU Version 7.8. This
|
||||
star catalog is a combination of all available star catalogs, wherein we
|
||||
choose the best distance available to place the stars around the Sun as
|
||||
accurately as is possible. (Description from URL) <br><br> Data Reference:
|
||||
XHIP: An Extended Hipparcos Compilation (Anderson E., Francis C. 2012);
|
||||
Hipparcos Catalog (European Space Agency 1997); Gliese Catalog (Gliese and
|
||||
Jahriess 1991)]],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,8 +70,21 @@ local sunstar = {
|
||||
},
|
||||
GUI = {
|
||||
Name = "Sun",
|
||||
Path = "/Milky Way/Stars"
|
||||
Path = "/Milky Way/Stars",
|
||||
Description = [[Individual star to represent the sun when outside of the solar
|
||||
system]]
|
||||
}
|
||||
}
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { stars, sunstar })
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Stars",
|
||||
Version = "2.0",
|
||||
Description = [[Digital Universe asset for the stars.]],
|
||||
Author = "Brian Abbott (AMNH)",
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"Stars"}
|
||||
}
|
||||
|
||||
@@ -38,10 +38,25 @@ local object = {
|
||||
},
|
||||
GUI = {
|
||||
Name = "Galaxy Superclusters",
|
||||
Path = "/Universe/Galaxies"
|
||||
Path = "/Universe/Galaxies",
|
||||
Description = [[Census: 33 labels. DU Version 1.3.<br> The superclusters dataset
|
||||
is a set of labels that mark the major galaxy superclusters in the local universe.
|
||||
They correspond to, and should be viewed with, the Abell clusters. Astronomers
|
||||
estimate there are 10 million superclusters in the observable universe.
|
||||
(Description from URL) <br><br> Data Reference: Superclusters of Abell and X-ray
|
||||
clusters (Einasto+, 2001)]]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { object })
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Galaxy Superclusters",
|
||||
Version = "2.0",
|
||||
Description = [[Digital Universe asset for Galaxy Superclusters.]],
|
||||
Author = "Brian Abbott (AMNH)",
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"GalaxySuperclusters"}
|
||||
}
|
||||
|
||||
@@ -40,10 +40,24 @@ local object = {
|
||||
},
|
||||
GUI = {
|
||||
Name = "Supernova Remnants",
|
||||
Path = "/Milky Way"
|
||||
Path = "/Milky Way",
|
||||
Description = [[Census: 112 supernova remnants.<br> DU Version 3.7. A supernova
|
||||
remnant is the ejected gas that results from a supernova. It glows for a
|
||||
cosmically short period of time before mixing with the interstellar medium.
|
||||
(Description from URL) <br><br> Data Reference: The First Fermi LAT SNR
|
||||
Catalog (Acero+, 2016)]],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { object })
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Supernova Remnants",
|
||||
Version = "2.0",
|
||||
Description = [[Digital Universe asset for Supernova Remnants.]],
|
||||
Author = "Brian Abbott (AMNH)",
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"SupernovaRemnants"}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ local tullyPoints = {
|
||||
ColorOption = { "prox5Mpc" },
|
||||
ColorRange = { { 1.0, 30.0 } },
|
||||
LabelFile = speck .. "/tully.label",
|
||||
DrawLabels = true,
|
||||
DrawLabels = false,
|
||||
TextColor = { 0.7, 0.7, 0.7 },
|
||||
TextSize = 19.36,
|
||||
TextMinSize = 8.2,
|
||||
@@ -54,7 +54,23 @@ local tullyPoints = {
|
||||
},
|
||||
GUI = {
|
||||
Name = "Tully Galaxies",
|
||||
Path = "/Universe/Galaxies"
|
||||
Path = "/Universe/Galaxies",
|
||||
Description = [[Census: 30,059 galaxies. DU Version 1.5.<br> The Tully Catalog is
|
||||
the most polished, accurate catalog of nearby galaxies. It includes over 30,000
|
||||
galaxies in the local universe that surround the Milky Way. This catalog
|
||||
demonstrates the large-scale structure of the universe exceptionally well. And,
|
||||
each galaxy has a representative image reflecting its morphological type, and is
|
||||
properly sized and inclined. Size and shape. The data form a cube, which is an
|
||||
arbitrary cutoff based on the completeness of these data. Beyond this, data from
|
||||
these sources are not as reliable, so effort is made to show a complete picture,
|
||||
albeit limited by observations (for example, we cannot see dwarf galaxies much
|
||||
beyond the Local Group). The size of the cube is roughly 1 billion light years on
|
||||
a diagonal (so the farthest galaxies in the dataset are about 1 billion light
|
||||
years from the Milky Way), or about 700 million light years per side.
|
||||
<br><br>Colors. Orange denotes more dense regions of the local universe, aqua is
|
||||
given to galaxies in an intermediate-density area, and green is given to lower
|
||||
density regions.(Description from URL) <br><br> Data Reference: Tully Galaxy
|
||||
Catalog: Brent Tully (U Hawaii), Stuart Levy (NCSA/UIUC)]]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,9 +99,30 @@ local tullyImages = {
|
||||
},
|
||||
GUI = {
|
||||
Name = "Tully Galaxies Images",
|
||||
Path = "/Universe/Galaxies"
|
||||
Path = "/Universe/Galaxies",
|
||||
Description = [[Each galaxy is represented by an image
|
||||
that represents its morphological type (spiral, elliptical, etc.). Most of these
|
||||
come from The Galaxy Catalog. A handful of nearby galaxies are represented by
|
||||
their actual images, which come mostly from the National Optical Astronomy
|
||||
Observatory (NOAO). Each of these images has been altered from its original state.
|
||||
These images were taken from Earth on some of the world’s largest telescopes, so
|
||||
foreground stars from our own Galaxy appear in each image. We are representing
|
||||
galaxies in extragalactic space, so we have removed the stars from each image.
|
||||
(Description from URL) <br><br> Data Reference: Tully Galaxy Catalog: Brent Tully
|
||||
(U Hawaii), Stuart Levy (NCSA/UIUC)]]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { tullyPoints, tullyImages })
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Tully Galaxies",
|
||||
Version = "3.0",
|
||||
Description = [[Digital Universe asset for Tully Galaxies, including point cloud and
|
||||
images.]],
|
||||
Author = "Stuart Levy (NCSA/UIUC), Brian Abbott (AMNH)",
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"TullyGalaxies" , "TullyGalaxiesImages"}
|
||||
}
|
||||
|
||||
@@ -25,10 +25,30 @@ local object = {
|
||||
Unit = "Mpc"
|
||||
},
|
||||
GUI = {
|
||||
Path = "/Universe/Galaxies"
|
||||
Name = "Voids",
|
||||
Path = "/Universe/Galaxies",
|
||||
Description = [[ Census: 24 cosmic voids. DU Version 1.2. <br>Cosmic voids are
|
||||
vast, empty spaces where there are either no galaxies, or very few galaxies.
|
||||
They are associated with cold spots in the cosmic microwave background (CMB)
|
||||
light, the earliest picture we have of the universe (see page 58). Those cold
|
||||
spots in the CMB evolved into large voids, some as much as 300 million light
|
||||
years in diameter. Labels roughly denote the location of cosmic voids in the
|
||||
Tully galaxies. Voids are only visible with motion cuing as you spin around
|
||||
these data. The labels help to guide the eye and provide sign posts for the
|
||||
largest voids in our cosmic neighborhood. (Description from URL) <br><br> Data
|
||||
Reference: various sources]]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { object })
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Voids",
|
||||
Version = "2.0",
|
||||
Author = "Brian Abbott (AMNH)",
|
||||
Description = [[Digital Universe asset for Cosmic voids.]],
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"Voids"}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,11 @@ local images = asset.syncedResource({
|
||||
Name = "Constellation Images",
|
||||
Type = "HttpSynchronization",
|
||||
Identifier = "constellation_images",
|
||||
Version = 1
|
||||
Version = 2
|
||||
})
|
||||
|
||||
--function that reads the file
|
||||
local createConstellations = function (guiPath, constellationfile)
|
||||
local createConstellations = function (baseIdentifier, guiPath, constellationfile)
|
||||
local genConstellations = {};
|
||||
--skip the first line
|
||||
local notFirstLine = false;
|
||||
@@ -33,7 +33,8 @@ local createConstellations = function (guiPath, constellationfile)
|
||||
group = (group == '' and globe or group)
|
||||
|
||||
local aconstellation = {
|
||||
Identifier = guiPath .. '-' .. name,
|
||||
-- Identifier = guiPath .. '-' .. name,
|
||||
Identifier = baseIdentifier .. '-' .. abbreviation,
|
||||
Parent = transforms.SolarSystemBarycenter.Identifier,
|
||||
Transform = {
|
||||
Translation = {
|
||||
@@ -83,7 +84,7 @@ local nodes = {}
|
||||
asset.onInitialize(function ()
|
||||
local constellationsCSV = images .. "/constellation_data.csv"
|
||||
|
||||
nodes = createConstellations('Constellation Art', constellationsCSV)
|
||||
nodes = createConstellations('ConstellationArt', 'Constellation Art', constellationsCSV)
|
||||
for _, n in ipairs(nodes) do
|
||||
openspace.addSceneGraphNode(n);
|
||||
end
|
||||
@@ -101,6 +102,6 @@ asset.meta = {
|
||||
Version = "1.0",
|
||||
Description = "Artistic images depicting the constellations",
|
||||
Author = "James Hedberg",
|
||||
URL = "jameshedberg.com",
|
||||
URL = "http://jameshedberg.com",
|
||||
License = "CC-BY"
|
||||
}
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
Data about Constellations columns are: group, name, x, y, z, scale, imageName, rotX, rotY, rotZ, centerStar
|
||||
normal,Ori,Orion,-550.8742,-259.3621,-188.9620,1.5,Ori.png,1.128407,1.058407,1.668407,HD37128
|
||||
zodiac,Tau,Taurus,-18.7277,-0.3175,-6.9092,1.2,Tau.png,1.198407,0.908407,1.378407,Aldebran
|
||||
zodiac,Ari,Aries,-13.2892,9.4519,-11.9378,0.8,Ari.png,0.668407,0.538407,0.518407,Hamal
|
||||
zodiac,Gem,Gemini,-362.5493,-102.2245,79.4030,0.85,Gem.png,-0.731593,2.268407,-0.451593,Mekbuda
|
||||
zodiac,Cnc,Cancer,-30.9209,-16.4584,22.6601,0.8,Cnc.png,-1.151593,1.888407,-1.041593,HD74442
|
||||
zodiac,Leo,Leo,-17.9030,-13.2719,31.4196,1.33,Leo.png,-0.131593,2.448407,0.418407,HD89484
|
||||
zodiac,Vir,Virgo,36.5809,-35.1877,62.3341,1.5,Vir.png,-0.371593,3.138407,0.518407,HD116658
|
||||
zodiac,Lib,Libra,17.5393,-6.2768,14.5916,1.0,Lib.png,-1.011593,3.138407,1.318407,HD130819
|
||||
zodiac,Sco,Scorpius,137.4378,-19.4456,37.3606,1.2,Sco.png,1.698407,-1.001593,-1.751593,HD148478
|
||||
zodiac,Sgr,Sagittarius,66.2304,11.1498,-14.8095,1.2,Sgr.png,1.728407,-1.321593,-1.751593,HD175191
|
||||
zodiac,Cap,Capricornus,32.9799,20.0621,-29.3945,1.3,Cap.png,1.158407,-0.881593,-0.561593,HD200761
|
||||
zodiac,Aqr,Aquarius,86.5090,149.4078,-155.8102,1.2,Aqr.png,-2.921593,-2.391593,-2.551593,-2.511593
|
||||
zodiac,Psc,Pisces,-28.0235,45.3150,-76.8893,1.6,Psc.png,0.458407,-0.001593,0.618407,HD4656
|
||||
northern,Uma,Ursa Major,-12.0503,7.1931,19.8974,1.6,UMa.png,0.748407,2.398407,0.658407,HD95418
|
||||
northern,Dra,Draco,-1.4340,20.6566,23.5098,1.9,Dra.png,0.658407,-2.541593,1.058407,HD137759
|
||||
southern,Ant,Antila,-0.2233,-103.8908,42.7940,1.3,Ant.png,1.848407,0.198407,-3.141593,HD90610
|
||||
southern,Crv,Corvus,8.0442,-16.8858,19.3984,1.1,Crv.png,2.198407,-0.041593,-2.221593,HD108767
|
||||
southern,Cet,Cetus,-28.7960,7.2425,-73.6693,1.5,Cet.png,0.238407,0.368407,0.688407,HD11353
|
||||
southern,Cha,Chameleon,53.5121,-108.3624,-38.1807,1.1,Cha.png,-1.801593,2.738407,0.448407,HD92305
|
||||
northern,Cam,Camelopardalis,-304.8155,179.0620,71.1454,1.7,Cam.png,2.128407,1.228407,1.478407,HD31910
|
||||
equatorial,Aql,Aquila,11.7741,9.7467,-1.6418,1.0,Aql.png,-2.601593,-2.511593,-3.141593,HD182640
|
||||
southern,Aps,Apus,31.6370,-32.5620,-16.5786,1.1,Aps.png,-1.691593,-2.281593,0.838407,HD149324
|
||||
northern,Lyn,Lynx,-98.3174,4.4830,67.2289,1.2,Lyn.png,1.688407,1.768407,1.668407,HD70272
|
||||
southern,Phe,Phoenix,5.0172,-4.2096,-22.8088,1.5,Phe.png,-3.141593,3.138407,-3.141593,HD6595
|
||||
northern,Cyg,Cygnus,78.7445,375.2440,12.4995,1.4,Cyg.png,1.668407,-0.931593,-0.261593,HD194093
|
||||
southern,Cen,Centaurus,20.1398,-33.1830,9.5915,2.7,Cen.png,-1.291593,3.088407,0.458407,HD110304
|
||||
northern,Aur,Auriga,-12.3062,3.8595,1.0302,1.5,Aur.png,1.378407,1.108407,1.178407,HD34029
|
||||
northern,Peg,Pegasus,0.9791,32.5947,-27.7339,2.42,Peg.png,0.918407,-0.221593,-0.191593,HD218045
|
||||
southern,Hya,Hydra,-2.9043,-33.5496,25.8962,3,Hya.png,-0.531593,2.838407,0.368407,HD93813
|
||||
southern,Oct,Octans,22.0434,-27.8601,-24.3108,1.0,Oct.png,-0.911593,0.398407,1.198407,HD214846
|
||||
southern,Nor,Norma,34.9251,-17.5643,0.0068,1.0,Nor.png,-1.631593,-2.421593,1.298407,HD146686
|
||||
southern,Mus,Musca,48.8888,-79.2952,-10.2828,1.25,Mus.png,-1.871593,3.138407,0.358407,HD109668
|
||||
southern,Hyi,Hydrus,3.2767,-4.7183,-4.7829,1.1,Hyi.png,2.438407,-3.141593,-2.381593,HD2151
|
||||
northern,Lac,Lacerta,-6.0878,30.5794,-3.6064,1.0,Lac.png,-1.521593,-2.391593,3.138407,HD213558
|
||||
equatorial,Lep,Lepus,-212.6297,-184.4909,-132.1156,1.0,Lep.png,-1.801593,-2.351593,-0.861593,HD36673
|
||||
southern,Lup,Lupus,129.1166,-102.2983,33.3251,1.2,Lup.png,-1.191593,-2.391593,0.798407,HD129056
|
||||
southern,Men,Mensa,2.4149,-8.5586,-4.8892,1.0,Men.png,-2.101593,-2.781593,0.828407,HD43834
|
||||
southern,Mic,Microscopium,51.0335,11.1671,-44.3692,1.0,Mic.png,0.728407,-0.831593,-0.561593,HD199951
|
||||
equatorial,Mon,Monoceros,-93.0725,-66.8909,8.6548,1.2,Mon.png,-1.331593,1.988407,-0.891593,HD55185
|
||||
southern,Pav,Pavo,4.4549,-2.5959,-3.2739,1.3,Pav.png,-2.391593,-2.171593,1.648407,HD190248
|
||||
southern,Ind,Indus,133.6149,-53.5569,-115.9552,1.5,Ind.png,-2.031593,-1.491593,1.758407,HD198700
|
||||
northern,LMi,Leo Minor,-23.3948,-2.5770,38.0756,1.1,LMi.png,-3.141593,0.478407,-2.201593,HD90537
|
||||
northern,Lyr,Lyra,2.8086,6.7630,2.5555,1.0,Lyr.png,-1.831593,-2.091593,3.141500,HD172167
|
||||
northern,Her,Hercules,14.0526,14.9773,12.5478,1.3,Her.png,-1.511593,-1.811593,2.288407,HD156164
|
||||
southern,Gru,Grus,18.6528,-3.2893,-24.6602,1.3,Gru.png,-3.141593,-2.511593,-2.901593,HD209952
|
||||
southern,Crt,Crater,1.5886,-43.9831,40.3390,1.3,Crt.png,-0.521593,3.140000,0.588407,HD98430
|
||||
northern,Del,Delphinus,14.8599,24.6150,-8.0550,1.2,Del.png,1.308407,-0.951593,-0.241593,HD196524
|
||||
southern,Dor,Dorado,-0.6460,-9.3172,-6.9654,1.2,Dor.png,2.118407,1.768407,-2.901593,HD33262
|
||||
northern,Equ,Equuleus,27.7363,41.7071,-27.4371,1.2,Equ.png,-1.801593,-2.511593,2.558407,HD202447
|
||||
southern,Eri,Eridanus,-37.5153,-23.5231,-65.6368,2.1,Eri.png,0.128407,0.698407,0.998407,HD20720
|
||||
southern,For,Fornax,-14.0351,-17.8282,-46.5514,1.4,For.png,3.138407,2.678407,-2.351593,HD17652
|
||||
southern,Hor,Horologium,2.1021,-27.1310,-40.5136,1.2,Hor.png,-3.141593,2.468407,-2.191593,HD16920
|
||||
southern,Pyx,Pyxis,-66.7424,-248.9639,26.0445,1.2,Pyx.png,1.838407,-1.651593,2.708407,HD74575
|
||||
southern,Ret,Reticulum,2.8130,-37.2904,-33.2644,1.5,Ret.png,1.998407,2.188407,-2.591593,HD27256
|
||||
northern,Sge,Sagitta,44.3886,70.9446,-7.6264,1.2,Sge.png,-0.741593,-2.231593,2.108407,HD189319
|
||||
southern,Scl,Sculptor,21.6545,-6.8861,-166.5240,1.3,Scl.png,-0.071593,-0.221593,0.638407,HD2429
|
||||
southern,Sct,Scutum,48.8939,21.5158,-0.1629,1.2,Sct.png,1.188407,-1.271593,-0.971593,HD171443
|
||||
southern,Tuc,Tucana,35.3950,-20.2535,-45.2324,1.1,Tuc.png,-0.351593,-0.161593,0.308407,HD211416
|
||||
northern,Tri,Triangulum,-26.6263,21.9119,-16.2254,1.2,Tri.png,1.168407,0.218407,0.558407,HD13161
|
||||
southern,TrA,Triangulum Australe,96.2283,-76.4459,-33.5257,1.2,TrA.png,-1.991593,-2.491593,1.128407,HD150798
|
||||
southern,Tel,Telescopium,72.3444,-14.5016,-20.0248,1.2,Tel.png,-0.461593,-1.731593,0.298407,HD169467
|
||||
southern,Ara,Ara,164.9273,-75.6246,-35.3100,1.1,Ara.png,-1.381593,-2.131593,1.048407,HD157244
|
||||
southern,Cae,Caelum,-6.0961,-13.7926,-13.3392,1.0,Cae.png,-0.661593,0.948407,0.418407,HD29875
|
||||
southern,CMa,Canis Major,-1.7693,-1.9125,-0.4074,1.3,CMa.png,1.128407,1.048407,1.878407,HD48915
|
||||
northern,CMi,Canis Minor,-2.8348,-1.8906,0.7881,1.2,CMi.png,2.538407,1.138407,-3.141593,HD61421
|
||||
southern,Vol,Volans,37.6000,-182.7856,-62.6559,1.2,Vol.png,-2.441593,1.988407,-0.351593,HD68520
|
||||
northern,UMi,Ursa Minor,-11.3527,27.2100,25.1835,1.3,UMi.png,-2.491593,-0.581593,-2.381593,HD131873
|
||||
northern,And,Andromdeda,-32.8276,43.3946,-27.8475,1.6,And.png,-2.021593,-3.141593,-2.521593,HD6860
|
||||
northern,Boo,Bootes,11.2468,14.9864,30.4945,2.0,Boo.png,-3.141593,-0.601593,-2.361593,HD135722
|
||||
northern,Vul,Vulpecula,46.7540,77.7780,5.3953,1.1,Vul.png,-2.301593,-2.061593,-3.141593,HD131873
|
||||
northern,CVn,Canes Venatici,-3.1198,5.7935,33.1368,1.3,CVn.png,0.148407,3.138407,0.428407,HD112413
|
||||
southern,Cir,Circinus,11.4255,-11.6937,-1.3129,1.0,Cir.png,1.448407,-0.391593,-2.211593,HD128898
|
||||
northern,Com,Coma Berenices,1.9257,-1.2062,12.2465,1.4,Com.png,3.138407,-0.051593,-2.711593,HD114378
|
||||
southern,CrA,Corona Australis,146.1322,-4.7492,-53.7124,1.0,CrA.png,-3.141593,-2.021593,-3.141593,HD178345
|
||||
northern,CrB,Corona Borealis,33.5737,32.0314,52.9729,1.3,CrB.png,-3.141593,-0.601593,-2.271593,HD143107
|
||||
northern,Cas,Cassiopeia,-36.3073,59.4424,-7.6926,1.4,Cas.png,-1.431593,3.128407,-2.331593,HD3712
|
||||
northern,Cep,Cepheus,-2.8178,14.4985,2.3848,1.7,Cep.png,-1.331593,-2.291593,-2.931593,HD203280
|
||||
southern,Car,Carina Vela Puppis,14.1325,-188.6018,-42.2785,2.0,Car.png,2.078407,1.048407,-3.111593,HD71129
|
||||
northern,Col,Columba,-11.2568,-20.5973,-11.9895,1.0,Col.png,2.518407,1.358407,-2.981593,HD39425
|
||||
northern,Per,Perseus,-139.8202,79.8063,-16.2631,1.3,Per.png,-1.751593,2.428407,-2.411593,HD22928
|
||||
northern,Oph,Ophiuchus,127.9419,14.0822,56.2015,3.2,Oph.png,2.178407,-0.781593,-1.681593,HD149757
|
||||
southern,PsA,Piscis Austrinus,99.9977,47.6679,-199.6345,1.0,PsA.png,3.138407,-2.541593,-2.881593,HD214748
|
||||
southern,Cru,Crux,49.3509,-85.0446,-0.6223,1.1,Cru.png,1.718407,0.048407,-2.741593,HD108248
|
||||
southern,Pic,Pictor,-4.5417,-45.5649,-27.1768,1.0,Pic.png,2.568407,2.138407,-2.081593,HD39523
|
||||
|
@@ -4,9 +4,9 @@ local Keybindings = {
|
||||
{
|
||||
Key = "c",
|
||||
Name = "Show Constellation Art",
|
||||
Command = "openspace.setPropertyValue('Scene.Constellation Art*.Renderable.Opacity', 0);" ..
|
||||
"openspace.setPropertyValue('Scene.Constellation Art*.Renderable.Enabled', true);" ..
|
||||
"openspace.setPropertyValue('Scene.Constellation Art*.Renderable.Opacity', 0.1, 2);",
|
||||
Command = "openspace.setPropertyValue('Scene.ConstellationArt*.Renderable.Opacity', 0);" ..
|
||||
"openspace.setPropertyValue('Scene.ConstellationArt*.Renderable.Enabled', true);" ..
|
||||
"openspace.setPropertyValue('Scene.ConstellationArt*.Renderable.Opacity', 0.1, 2);",
|
||||
Documentation = "Enables and fades up constellation art work",
|
||||
GuiPath = "/Rendering",
|
||||
Local = false
|
||||
@@ -14,7 +14,7 @@ local Keybindings = {
|
||||
{
|
||||
Key = "SHIFT+c",
|
||||
Name = "Hide Constellation Art",
|
||||
Command = "openspace.setPropertyValue('Scene.Constellation Art*.Renderable.Opacity', 0, 2);",
|
||||
Command = "openspace.setPropertyValue('Scene.ConstellationArt*.Renderable.Opacity', 0, 2);",
|
||||
Documentation = "Fades out constellation artwork",
|
||||
GuiPath = "/Rendering",
|
||||
Local = false
|
||||
@@ -22,7 +22,7 @@ local Keybindings = {
|
||||
{
|
||||
Key = "CTRL+c",
|
||||
Name = "Disable Constellation Art",
|
||||
Command = "openspace.setPropertyValue('Scene.Constellation Art*.Renderable.Enabled', false);",
|
||||
Command = "openspace.setPropertyValue('Scene.ConstellationArt*.Renderable.Enabled', false);",
|
||||
Documentation = "Disable constellation artwork",
|
||||
GuiPath = "/Rendering",
|
||||
Local = false
|
||||
@@ -36,3 +36,13 @@ end)
|
||||
asset.onDeinitialize(function ()
|
||||
scene_helper.unbindKeys(Keybindings)
|
||||
end)
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Constellation Image Keybinds",
|
||||
Version = "1.0",
|
||||
Description = "Keybinds for fading in and out the constellations",
|
||||
Author = "OpenSpace Team",
|
||||
URL = "http://openspaceproject.com",
|
||||
License = "MIT License"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
local DataPath = asset.syncedResource({
|
||||
Name = "Exoplanet Data Files",
|
||||
Type = "HttpSynchronization",
|
||||
Identifier = "exoplanets_data",
|
||||
Version = 1
|
||||
})
|
||||
asset.export("DataPath", DataPath)
|
||||
@@ -0,0 +1,7 @@
|
||||
local TexturesPath = asset.syncedResource({
|
||||
Name = "Exoplanet Textures",
|
||||
Type = "HttpSynchronization",
|
||||
Identifier = "exoplanets_textures",
|
||||
Version = 1
|
||||
})
|
||||
asset.export("TexturesPath", TexturesPath)
|
||||
@@ -35,6 +35,4 @@ local object = {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { object })
|
||||
|
||||
@@ -52,3 +52,15 @@ local MilkyWayVolumeGalaxy = {
|
||||
|
||||
local objects = { MilkyWayVolumeGalaxy }
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, objects)
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Milky Way Volume",
|
||||
Version = "1.0",
|
||||
Description = [[Volumetric rendering of Milky Way galaxy based on simulation from
|
||||
NAOJ.]],
|
||||
Author = "OpenSpace Team",
|
||||
URL = "http://openspaceproject.com",
|
||||
License = "MIT License",
|
||||
Identifiers = {"MilkyWayVolume"}
|
||||
}
|
||||
|
||||
53
data/assets/scene/milkyway/objects/orionnebula/cluster.asset
Normal file
53
data/assets/scene/milkyway/objects/orionnebula/cluster.asset
Normal file
@@ -0,0 +1,53 @@
|
||||
--orionnebula/cluster.asset
|
||||
local assetHelper = asset.require('util/asset_helper')
|
||||
local transforms = asset.require("./transforms")
|
||||
|
||||
local sync = asset.syncedResource({
|
||||
Name = "Orion Nebula Star Cluster",
|
||||
Type = "HttpSynchronization",
|
||||
Identifier = "orion_nebula_star_cluster",
|
||||
Version = 1
|
||||
})
|
||||
|
||||
local OrionClusterStars = {
|
||||
Identifier = "OrionClusterStars",
|
||||
Parent = transforms.NebulaPosition.Identifier,
|
||||
Renderable = {
|
||||
Type = "RenderableStars",
|
||||
File = sync .. "/oricluster.speck",
|
||||
Texture = sync .. "/halo.png",
|
||||
Texture = sync .. "/colorbv.cmap",
|
||||
MagnitudeExponent = 5.02,
|
||||
SizeComposition = "Distance Modulus",
|
||||
RenderMethod = "Texture Based"
|
||||
},
|
||||
GUI = {
|
||||
Name = "Orion Nebula Star Cluster",
|
||||
Path = "/Milky Way/Stars"
|
||||
}
|
||||
}
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { OrionClusterStars })
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Orion Nebula Star Cluster",
|
||||
Version = "1.0",
|
||||
Description = [[ In order to have an accurate depiction of the Orion nebula, we need
|
||||
to include the star cluster that was birthed from it. We turned to a study of the
|
||||
cluster's stellar population by Lynne Hillenbrand, who was working at the University of
|
||||
California, Berkeley at the time. The catalog from her paper contains more than 1500
|
||||
stars, about half the stars in the actual cluster. The cluster is very crowded, with a
|
||||
peak density of 10000 stars per cubic parsec over a wide range of masses from a tenth the
|
||||
sun's mass up to 50 times its mass. We were presented with one problem: there are no
|
||||
distances. For the stellar distances, we needed to deduce them by statistical methods.
|
||||
Knowing the size of the cluster and approximating the shape to be roughly spherical, we
|
||||
placed each star along a line of sight through this imaginary sphere centered on the
|
||||
cluster. In this sense, these data are observed data and the view from Earth is accurate.
|
||||
But the distance of each star has been derived from this educated-guess approach for the
|
||||
cluster distribution. ]],
|
||||
Author = "AMNH Digital Universe",
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"OrionClusterStars"}
|
||||
}
|
||||
160
data/assets/scene/milkyway/objects/orionnebula/nebula.asset
Normal file
160
data/assets/scene/milkyway/objects/orionnebula/nebula.asset
Normal file
@@ -0,0 +1,160 @@
|
||||
local assetHelper = asset.require('util/asset_helper')
|
||||
local sunTransforms = asset.require('scene/solarsystem/sun/transforms')
|
||||
local transforms = asset.require('./transforms')
|
||||
|
||||
local center = sunTransforms.SolarSystemBarycenter.Identifier;
|
||||
local LIGHTS = assetHelper.getDefaultLightSources(center);
|
||||
|
||||
local sync = asset.syncedResource({
|
||||
Name = "Orion Nebula Model",
|
||||
Type = "HttpSynchronization",
|
||||
Identifier = "orion_nebula_model",
|
||||
Version = 1
|
||||
})
|
||||
|
||||
local NebulaHolder = {
|
||||
Identifier = "OrionNebulaHolder",
|
||||
Parent = transforms.NebulaPosition.Identifier,
|
||||
Transform = {
|
||||
Scale = {
|
||||
Type = "StaticScale",
|
||||
Scale = 35999998699110400.000000
|
||||
},
|
||||
Rotation = {
|
||||
Type = "FixedRotation",
|
||||
Attached = "OrionNebulaHolder",
|
||||
XAxis = {1.000000,1.000000,0.510000},
|
||||
XAxisOrthogonal = true,
|
||||
YAxis = "Sun",
|
||||
YAxisInverted = false
|
||||
}
|
||||
},
|
||||
GUI = {
|
||||
Name = "Orion Nebula",
|
||||
Path = "/Milky Way/Objects",
|
||||
}
|
||||
}
|
||||
|
||||
local OrionNebulaModel = {
|
||||
Identifier = "OrionNebulaModel",
|
||||
Parent = NebulaHolder.Identifier,
|
||||
Transform = {
|
||||
Scale = {
|
||||
Type = "StaticScale",
|
||||
Scale = 0.67500000
|
||||
}
|
||||
},
|
||||
Renderable = {
|
||||
Type = "RenderableModel",
|
||||
Geometry = {{
|
||||
Type = "MultiModelGeometry",
|
||||
GeometryFile = sync .. "/orion_nebula.obj",
|
||||
ColorTexture = sync .. "/heic0601a_masked.png"
|
||||
}},
|
||||
Opacity = 1.0,
|
||||
DisableFaceCulling = false,
|
||||
SpecularIntensity = 0.0,
|
||||
AmbientIntensity = 0.45,
|
||||
DiffuseIntensity = 0.0,
|
||||
RotationVector = { 0.000000, 22.300000, 0.000000 },
|
||||
LightSources = LIGHTS;
|
||||
},
|
||||
GUI = {
|
||||
Name = "Orion Nebula Model",
|
||||
Path = "/Milky Way/Objects",
|
||||
Hidden = true
|
||||
}
|
||||
}
|
||||
|
||||
local OrionNebulaShocksModel = {
|
||||
Identifier = "OrionNebulaShocksModel",
|
||||
Parent = NebulaHolder.Identifier,
|
||||
Transform = {
|
||||
Scale = {
|
||||
Type = "StaticScale",
|
||||
Scale = 0.67500000
|
||||
}
|
||||
},
|
||||
Renderable = {
|
||||
Type = "RenderableModel",
|
||||
Geometry = {{
|
||||
Type = "MultiModelGeometry",
|
||||
GeometryFile = sync .. "/orishocks.obj",
|
||||
ColorTexture = "${DATA}/colors/pink.png"
|
||||
}},
|
||||
Opacity = 1.0,
|
||||
DisableFaceCulling = false,
|
||||
SpecularIntensity = 0.0,
|
||||
AmbientIntensity = 0.19,
|
||||
DiffuseIntensity = 0.4,
|
||||
RotationVector = { 0.000000, 22.300000, 0.000000 },
|
||||
LightSources = LIGHTS;
|
||||
},
|
||||
GUI = {
|
||||
Name = "Orion Nebula Shocks",
|
||||
Path = "/Milky Way/Objects",
|
||||
Hidden = false
|
||||
}
|
||||
}
|
||||
|
||||
local OrionNebulaProplydsModel = {
|
||||
Identifier = "OrionNebulaProplydsModel",
|
||||
Parent = NebulaHolder.Identifier,
|
||||
Transform = {
|
||||
Scale = {
|
||||
Type = "StaticScale",
|
||||
Scale = 0.67500000
|
||||
}
|
||||
},
|
||||
Renderable = {
|
||||
Type = "RenderableModel",
|
||||
Geometry = {{
|
||||
Type = "MultiModelGeometry",
|
||||
GeometryFile = sync .. "/proplyds.obj",
|
||||
ColorTexture = "${DATA}/colors/pink.png"
|
||||
}},
|
||||
Opacity = 1.0,
|
||||
DisableFaceCulling = false,
|
||||
SpecularIntensity = 0.0,
|
||||
AmbientIntensity = 1.0,
|
||||
DiffuseIntensity = 1.0,
|
||||
RotationVector = { 0.000000, 22.300000, 0.000000 },
|
||||
LightSources = LIGHTS;
|
||||
},
|
||||
GUI = {
|
||||
Name = "Orion Nebula Proplyds",
|
||||
Path = "/Milky Way/Objects",
|
||||
Hidden = false
|
||||
}
|
||||
}
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, {
|
||||
NebulaHolder,
|
||||
OrionNebulaModel,
|
||||
OrionNebulaShocksModel,
|
||||
OrionNebulaProplydsModel
|
||||
})
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Orion Nebula Model",
|
||||
Version = "1.0",
|
||||
Description = [[ In the Digital Universe model of the Orion Nebula, we depict the
|
||||
ionization front effectively as a terrain, with a flat Hubble image of the nebula mapped
|
||||
on the undulating surface. In reality, the ionization front has a slight thickness to
|
||||
it - about a third of a light year - but is quite thin compared to the overall size of
|
||||
the nebula, which stretches about ten light years from side to side.<br><br>Close into
|
||||
the center, we see small teardrop-shaped structures with their narrow ends pointing away
|
||||
from the bright star: these are protoplanetary disks, or proplyds, of dense gas and dust
|
||||
surrounding young stars. The larger formations that one sees farther away from the center
|
||||
of the nebula take on a cup-like shape, with the narrow end pointing away from the
|
||||
nebulas center. These enormous structures are bow shocks that delineate the region where
|
||||
highspeed winds from the central star slow from supersonic to subsonic speeds. You can
|
||||
think of an HII region as a sort of tremendous explosion, taking place over millennia,
|
||||
and the bow shocks are part of the outward rush of material. ]],
|
||||
Author = "AMNH Digital Universe",
|
||||
URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe",
|
||||
License = "AMNH Digital Universe",
|
||||
Identifiers = {"OrionNebulaModel", "OrionNebulaModel", "OrionNebulaProplydsModel",
|
||||
"OrionNebulaShocksModel"}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
asset.require('./cluster')
|
||||
asset.require('./nebula')
|
||||
@@ -0,0 +1,26 @@
|
||||
local assetHelper = asset.require('util/asset_helper')
|
||||
local sunTransforms = asset.require('scene/solarsystem/sun/transforms')
|
||||
|
||||
local PARSEC_CONSTANT = 3.0856776E16;
|
||||
|
||||
local NebulaPosition = {
|
||||
Identifier = "NebulaPosition",
|
||||
Parent = sunTransforms.SolarSystemBarycenter.Identifier,
|
||||
Transform = {
|
||||
Translation = {
|
||||
Type = "StaticTranslation",
|
||||
Position = {
|
||||
-329.915 * PARSEC_CONSTANT,
|
||||
-183.153 * PARSEC_CONSTANT,
|
||||
-132.706 * PARSEC_CONSTANT
|
||||
}
|
||||
},
|
||||
},
|
||||
GUI = {
|
||||
Name = "Orion Nebula Position",
|
||||
Path = "/Milky Way/Objects",
|
||||
Hidden = true
|
||||
}
|
||||
}
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { NebulaPosition })
|
||||
@@ -40,6 +40,15 @@ local object = {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, { object })
|
||||
|
||||
|
||||
asset.meta = {
|
||||
Name = "Stars Denver",
|
||||
Version = "1.0",
|
||||
Description = [[Alternative Milky Way Atlas: based on HIPPARCOS and Yale Bright
|
||||
Star catalogs]],
|
||||
Author = "Ka chun Yu",
|
||||
URL = "http://openspaceproject.com",
|
||||
License = "Creative Commons Attribution-Share Alike 3.0 Unported"
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user