merging master, conflicts

This commit is contained in:
elon
2021-02-10 11:33:01 -05:00
957 changed files with 109153 additions and 11129 deletions

3
.gitmodules vendored
View File

@@ -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

View File

@@ -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
View File

@@ -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')
}

View File

@@ -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).

View File

@@ -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 ()

View 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)

View 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__

View 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__

View File

@@ -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__

View 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__

View 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__

View 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__

View 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__

View 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__

View 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__

View 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__

View File

@@ -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__

View File

@@ -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__

View 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__

View 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__

View File

@@ -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__

View 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

View 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;
}

View 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>

View 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);
}

View 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();
}

View File

@@ -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();
}

View 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());
}

View 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;
}

View 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, "");
}

View 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");
}
}

View 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);
}

View 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);
}

View 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);
}

View 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);
}

View 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();
}

View 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);
}

View 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);
}

View 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);
}

View 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();
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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));

View File

@@ -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)

View 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)

View File

@@ -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

View File

@@ -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"

View File

@@ -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)

View File

@@ -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"}
}

View File

@@ -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"}
}

View File

@@ -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"}
}

View File

@@ -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 (19271983)
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"}
}

View File

@@ -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 })

View File

@@ -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"}
}

View File

@@ -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"}
}

View File

@@ -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"}
}

View File

@@ -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"}
}

View File

@@ -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"}
}

View File

@@ -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"}
}

View File

@@ -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"}
}

View File

@@ -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"}
}

View File

@@ -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"}
}

View File

@@ -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"}
}

View File

@@ -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"}
}

View File

@@ -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"}
}

View File

@@ -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"}
}

View File

@@ -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 })

View 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 &#169; 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"}
}

View 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)

View 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"}
}

View 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"}
}

View File

@@ -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"}
}

View File

@@ -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"}
}

View File

@@ -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"}
}

View File

@@ -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"}
}

View File

@@ -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"}
}

View File

@@ -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"}
}

View File

@@ -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"}
}

View File

@@ -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"}
}

View File

@@ -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"}
}

View File

@@ -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"}
}

View File

@@ -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"}
}

View File

@@ -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 worlds 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"}
}

View File

@@ -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"}
}

View File

@@ -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"
}

View File

@@ -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
1 Data about Constellations columns are: group, name, x, y, z, scale, imageName, rotX, rotY, rotZ, centerStar
2 normal,Ori,Orion,-550.8742,-259.3621,-188.9620,1.5,Ori.png,1.128407,1.058407,1.668407,HD37128
3 zodiac,Tau,Taurus,-18.7277,-0.3175,-6.9092,1.2,Tau.png,1.198407,0.908407,1.378407,Aldebran
4 zodiac,Ari,Aries,-13.2892,9.4519,-11.9378,0.8,Ari.png,0.668407,0.538407,0.518407,Hamal
5 zodiac,Gem,Gemini,-362.5493,-102.2245,79.4030,0.85,Gem.png,-0.731593,2.268407,-0.451593,Mekbuda
6 zodiac,Cnc,Cancer,-30.9209,-16.4584,22.6601,0.8,Cnc.png,-1.151593,1.888407,-1.041593,HD74442
7 zodiac,Leo,Leo,-17.9030,-13.2719,31.4196,1.33,Leo.png,-0.131593,2.448407,0.418407,HD89484
8 zodiac,Vir,Virgo,36.5809,-35.1877,62.3341,1.5,Vir.png,-0.371593,3.138407,0.518407,HD116658
9 zodiac,Lib,Libra,17.5393,-6.2768,14.5916,1.0,Lib.png,-1.011593,3.138407,1.318407,HD130819
10 zodiac,Sco,Scorpius,137.4378,-19.4456,37.3606,1.2,Sco.png,1.698407,-1.001593,-1.751593,HD148478
11 zodiac,Sgr,Sagittarius,66.2304,11.1498,-14.8095,1.2,Sgr.png,1.728407,-1.321593,-1.751593,HD175191
12 zodiac,Cap,Capricornus,32.9799,20.0621,-29.3945,1.3,Cap.png,1.158407,-0.881593,-0.561593,HD200761
13 zodiac,Aqr,Aquarius,86.5090,149.4078,-155.8102,1.2,Aqr.png,-2.921593,-2.391593,-2.551593,-2.511593
14 zodiac,Psc,Pisces,-28.0235,45.3150,-76.8893,1.6,Psc.png,0.458407,-0.001593,0.618407,HD4656
15 northern,Uma,Ursa Major,-12.0503,7.1931,19.8974,1.6,UMa.png,0.748407,2.398407,0.658407,HD95418
16 northern,Dra,Draco,-1.4340,20.6566,23.5098,1.9,Dra.png,0.658407,-2.541593,1.058407,HD137759
17 southern,Ant,Antila,-0.2233,-103.8908,42.7940,1.3,Ant.png,1.848407,0.198407,-3.141593,HD90610
18 southern,Crv,Corvus,8.0442,-16.8858,19.3984,1.1,Crv.png,2.198407,-0.041593,-2.221593,HD108767
19 southern,Cet,Cetus,-28.7960,7.2425,-73.6693,1.5,Cet.png,0.238407,0.368407,0.688407,HD11353
20 southern,Cha,Chameleon,53.5121,-108.3624,-38.1807,1.1,Cha.png,-1.801593,2.738407,0.448407,HD92305
21 northern,Cam,Camelopardalis,-304.8155,179.0620,71.1454,1.7,Cam.png,2.128407,1.228407,1.478407,HD31910
22 equatorial,Aql,Aquila,11.7741,9.7467,-1.6418,1.0,Aql.png,-2.601593,-2.511593,-3.141593,HD182640
23 southern,Aps,Apus,31.6370,-32.5620,-16.5786,1.1,Aps.png,-1.691593,-2.281593,0.838407,HD149324
24 northern,Lyn,Lynx,-98.3174,4.4830,67.2289,1.2,Lyn.png,1.688407,1.768407,1.668407,HD70272
25 southern,Phe,Phoenix,5.0172,-4.2096,-22.8088,1.5,Phe.png,-3.141593,3.138407,-3.141593,HD6595
26 northern,Cyg,Cygnus,78.7445,375.2440,12.4995,1.4,Cyg.png,1.668407,-0.931593,-0.261593,HD194093
27 southern,Cen,Centaurus,20.1398,-33.1830,9.5915,2.7,Cen.png,-1.291593,3.088407,0.458407,HD110304
28 northern,Aur,Auriga,-12.3062,3.8595,1.0302,1.5,Aur.png,1.378407,1.108407,1.178407,HD34029
29 northern,Peg,Pegasus,0.9791,32.5947,-27.7339,2.42,Peg.png,0.918407,-0.221593,-0.191593,HD218045
30 southern,Hya,Hydra,-2.9043,-33.5496,25.8962,3,Hya.png,-0.531593,2.838407,0.368407,HD93813
31 southern,Oct,Octans,22.0434,-27.8601,-24.3108,1.0,Oct.png,-0.911593,0.398407,1.198407,HD214846
32 southern,Nor,Norma,34.9251,-17.5643,0.0068,1.0,Nor.png,-1.631593,-2.421593,1.298407,HD146686
33 southern,Mus,Musca,48.8888,-79.2952,-10.2828,1.25,Mus.png,-1.871593,3.138407,0.358407,HD109668
34 southern,Hyi,Hydrus,3.2767,-4.7183,-4.7829,1.1,Hyi.png,2.438407,-3.141593,-2.381593,HD2151
35 northern,Lac,Lacerta,-6.0878,30.5794,-3.6064,1.0,Lac.png,-1.521593,-2.391593,3.138407,HD213558
36 equatorial,Lep,Lepus,-212.6297,-184.4909,-132.1156,1.0,Lep.png,-1.801593,-2.351593,-0.861593,HD36673
37 southern,Lup,Lupus,129.1166,-102.2983,33.3251,1.2,Lup.png,-1.191593,-2.391593,0.798407,HD129056
38 southern,Men,Mensa,2.4149,-8.5586,-4.8892,1.0,Men.png,-2.101593,-2.781593,0.828407,HD43834
39 southern,Mic,Microscopium,51.0335,11.1671,-44.3692,1.0,Mic.png,0.728407,-0.831593,-0.561593,HD199951
40 equatorial,Mon,Monoceros,-93.0725,-66.8909,8.6548,1.2,Mon.png,-1.331593,1.988407,-0.891593,HD55185
41 southern,Pav,Pavo,4.4549,-2.5959,-3.2739,1.3,Pav.png,-2.391593,-2.171593,1.648407,HD190248
42 southern,Ind,Indus,133.6149,-53.5569,-115.9552,1.5,Ind.png,-2.031593,-1.491593,1.758407,HD198700
43 northern,LMi,Leo Minor,-23.3948,-2.5770,38.0756,1.1,LMi.png,-3.141593,0.478407,-2.201593,HD90537
44 northern,Lyr,Lyra,2.8086,6.7630,2.5555,1.0,Lyr.png,-1.831593,-2.091593,3.141500,HD172167
45 northern,Her,Hercules,14.0526,14.9773,12.5478,1.3,Her.png,-1.511593,-1.811593,2.288407,HD156164
46 southern,Gru,Grus,18.6528,-3.2893,-24.6602,1.3,Gru.png,-3.141593,-2.511593,-2.901593,HD209952
47 southern,Crt,Crater,1.5886,-43.9831,40.3390,1.3,Crt.png,-0.521593,3.140000,0.588407,HD98430
48 northern,Del,Delphinus,14.8599,24.6150,-8.0550,1.2,Del.png,1.308407,-0.951593,-0.241593,HD196524
49 southern,Dor,Dorado,-0.6460,-9.3172,-6.9654,1.2,Dor.png,2.118407,1.768407,-2.901593,HD33262
50 northern,Equ,Equuleus,27.7363,41.7071,-27.4371,1.2,Equ.png,-1.801593,-2.511593,2.558407,HD202447
51 southern,Eri,Eridanus,-37.5153,-23.5231,-65.6368,2.1,Eri.png,0.128407,0.698407,0.998407,HD20720
52 southern,For,Fornax,-14.0351,-17.8282,-46.5514,1.4,For.png,3.138407,2.678407,-2.351593,HD17652
53 southern,Hor,Horologium,2.1021,-27.1310,-40.5136,1.2,Hor.png,-3.141593,2.468407,-2.191593,HD16920
54 southern,Pyx,Pyxis,-66.7424,-248.9639,26.0445,1.2,Pyx.png,1.838407,-1.651593,2.708407,HD74575
55 southern,Ret,Reticulum,2.8130,-37.2904,-33.2644,1.5,Ret.png,1.998407,2.188407,-2.591593,HD27256
56 northern,Sge,Sagitta,44.3886,70.9446,-7.6264,1.2,Sge.png,-0.741593,-2.231593,2.108407,HD189319
57 southern,Scl,Sculptor,21.6545,-6.8861,-166.5240,1.3,Scl.png,-0.071593,-0.221593,0.638407,HD2429
58 southern,Sct,Scutum,48.8939,21.5158,-0.1629,1.2,Sct.png,1.188407,-1.271593,-0.971593,HD171443
59 southern,Tuc,Tucana,35.3950,-20.2535,-45.2324,1.1,Tuc.png,-0.351593,-0.161593,0.308407,HD211416
60 northern,Tri,Triangulum,-26.6263,21.9119,-16.2254,1.2,Tri.png,1.168407,0.218407,0.558407,HD13161
61 southern,TrA,Triangulum Australe,96.2283,-76.4459,-33.5257,1.2,TrA.png,-1.991593,-2.491593,1.128407,HD150798
62 southern,Tel,Telescopium,72.3444,-14.5016,-20.0248,1.2,Tel.png,-0.461593,-1.731593,0.298407,HD169467
63 southern,Ara,Ara,164.9273,-75.6246,-35.3100,1.1,Ara.png,-1.381593,-2.131593,1.048407,HD157244
64 southern,Cae,Caelum,-6.0961,-13.7926,-13.3392,1.0,Cae.png,-0.661593,0.948407,0.418407,HD29875
65 southern,CMa,Canis Major,-1.7693,-1.9125,-0.4074,1.3,CMa.png,1.128407,1.048407,1.878407,HD48915
66 northern,CMi,Canis Minor,-2.8348,-1.8906,0.7881,1.2,CMi.png,2.538407,1.138407,-3.141593,HD61421
67 southern,Vol,Volans,37.6000,-182.7856,-62.6559,1.2,Vol.png,-2.441593,1.988407,-0.351593,HD68520
68 northern,UMi,Ursa Minor,-11.3527,27.2100,25.1835,1.3,UMi.png,-2.491593,-0.581593,-2.381593,HD131873
69 northern,And,Andromdeda,-32.8276,43.3946,-27.8475,1.6,And.png,-2.021593,-3.141593,-2.521593,HD6860
70 northern,Boo,Bootes,11.2468,14.9864,30.4945,2.0,Boo.png,-3.141593,-0.601593,-2.361593,HD135722
71 northern,Vul,Vulpecula,46.7540,77.7780,5.3953,1.1,Vul.png,-2.301593,-2.061593,-3.141593,HD131873
72 northern,CVn,Canes Venatici,-3.1198,5.7935,33.1368,1.3,CVn.png,0.148407,3.138407,0.428407,HD112413
73 southern,Cir,Circinus,11.4255,-11.6937,-1.3129,1.0,Cir.png,1.448407,-0.391593,-2.211593,HD128898
74 northern,Com,Coma Berenices,1.9257,-1.2062,12.2465,1.4,Com.png,3.138407,-0.051593,-2.711593,HD114378
75 southern,CrA,Corona Australis,146.1322,-4.7492,-53.7124,1.0,CrA.png,-3.141593,-2.021593,-3.141593,HD178345
76 northern,CrB,Corona Borealis,33.5737,32.0314,52.9729,1.3,CrB.png,-3.141593,-0.601593,-2.271593,HD143107
77 northern,Cas,Cassiopeia,-36.3073,59.4424,-7.6926,1.4,Cas.png,-1.431593,3.128407,-2.331593,HD3712
78 northern,Cep,Cepheus,-2.8178,14.4985,2.3848,1.7,Cep.png,-1.331593,-2.291593,-2.931593,HD203280
79 southern,Car,Carina Vela Puppis,14.1325,-188.6018,-42.2785,2.0,Car.png,2.078407,1.048407,-3.111593,HD71129
80 northern,Col,Columba,-11.2568,-20.5973,-11.9895,1.0,Col.png,2.518407,1.358407,-2.981593,HD39425
81 northern,Per,Perseus,-139.8202,79.8063,-16.2631,1.3,Per.png,-1.751593,2.428407,-2.411593,HD22928
82 northern,Oph,Ophiuchus,127.9419,14.0822,56.2015,3.2,Oph.png,2.178407,-0.781593,-1.681593,HD149757
83 southern,PsA,Piscis Austrinus,99.9977,47.6679,-199.6345,1.0,PsA.png,3.138407,-2.541593,-2.881593,HD214748
84 southern,Cru,Crux,49.3509,-85.0446,-0.6223,1.1,Cru.png,1.718407,0.048407,-2.741593,HD108248
85 southern,Pic,Pictor,-4.5417,-45.5649,-27.1768,1.0,Pic.png,2.568407,2.138407,-2.081593,HD39523

View File

@@ -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"
}

View File

@@ -0,0 +1,7 @@
local DataPath = asset.syncedResource({
Name = "Exoplanet Data Files",
Type = "HttpSynchronization",
Identifier = "exoplanets_data",
Version = 1
})
asset.export("DataPath", DataPath)

View File

@@ -0,0 +1,7 @@
local TexturesPath = asset.syncedResource({
Name = "Exoplanet Textures",
Type = "HttpSynchronization",
Identifier = "exoplanets_textures",
Version = 1
})
asset.export("TexturesPath", TexturesPath)

View File

@@ -35,6 +35,4 @@ local object = {
}
}
assetHelper.registerSceneGraphNodesAndExport(asset, { object })

View File

@@ -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"}
}

View 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"}
}

View 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"}
}

View File

@@ -0,0 +1,2 @@
asset.require('./cluster')
asset.require('./nebula')

View File

@@ -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 })

View File

@@ -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