Merge branch 'master' of https://github.com/OpenSpace/OpenSpace into thesis/2020/software-integration

This commit is contained in:
aniisaaden
2020-10-20 09:51:10 +02:00
72 changed files with 1553 additions and 1287 deletions

View File

@@ -27,9 +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")

11
Jenkinsfile vendored
View File

@@ -95,7 +95,8 @@ parallel tools: {
tool: cppCheck()
)
}
}
cleanWs()
} // node('tools')
},
linux_gcc: {
node('linux' && 'gcc') {
@@ -119,6 +120,7 @@ linux_gcc: {
stage('linux-gcc/test') {
// testHelper.runUnitTests('build/OpenSpaceTest');
}
cleanWs()
} // node('linux')
},
linux_clang: {
@@ -143,6 +145,7 @@ linux_clang: {
stage('linux-clang/test') {
// testHelper.runUnitTests('build/OpenSpaceTest');
}
cleanWs()
} // node('linux')
},
windows: {
@@ -164,7 +167,8 @@ windows: {
// testHelper.runUnitTests('bin\\Debug\\OpenSpaceTest')
}
} // node('windows')
}
cleanWs()
} // node('windows')
},
macos: {
node('macos') {
@@ -182,5 +186,6 @@ macos: {
// Currently, the unit tests are crashing on OS X
// testHelper.runUnitTests('build/Debug/OpenSpaceTest')
}
} // node('osx')
cleanWs()
} // node('macos')
}

View File

@@ -34,6 +34,7 @@ set(HEADER_FILES
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
@@ -52,6 +53,7 @@ set(SOURCE_FILES
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

View File

@@ -54,7 +54,7 @@ public:
*
* \param dir The directory from which to start the search from
*/
std::string useQtFileSystemModelToTraverseDir(QString dir);
std::string useQtFileSystemModelToTraverseDir(std::string dir);
private:
void parseChildDirElements(QFileInfo item, std::string space, int level,

View File

@@ -27,20 +27,20 @@
#include <QMainWindow>
#include <QString>
#include "profile/profileedit.h"
#include "filesystemaccess.h"
#include <openspace/scene/profile.h>
#include <openspace/engine/globals.h>
#include <optional>
namespace openspace::configuration { struct Configuration; }
class QComboBox;
class QLabel;
class LauncherWindow : public QMainWindow {
Q_OBJECT
public:
/**
* Constructor for LauncherWindow class
*
* \param basePath The base OpenSpace installation path
* \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
@@ -49,9 +49,9 @@ public:
* \param parentItem The parent that contains this (and possibly other) children
* in the tree structure.
*/
LauncherWindow(std::string basePath, bool profileEnabled,
openspace::configuration::Configuration& globalConfig, bool sgctConfigEnabled,
std::string sgctConfigName, QWidget* parent);
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.
@@ -61,14 +61,6 @@ public:
*/
bool wasLaunchSelected() const;
/**
* Returns true if both the profile and sgct window configuration were specified
* at the command line (and so the launcher will not run).
*
* \return true if both profile and sgct window config were specified at CLI
*/
bool isFullyConfiguredFromCliArgs() const;
/**
* Returns the selected profile name when launcher window closed
*
@@ -85,29 +77,23 @@ public:
*/
std::string selectedWindowConfig() const;
public slots:
void openWindowEdit();
void openWindowNew();
void startOpenSpace();
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);
std::optional<openspace::Profile> loadProfileFromFile(std::string filename);
void saveProfileToFile(const std::string& path, const openspace::Profile& p);
FileSystemAccess _fileAccessProfiles;
FileSystemAccess _fileAccessWinConfigs;
FileSystemAccess _filesystemAccess;
std::string _reportAssetsInFilesystem;
openspace::configuration::Configuration& _globalConfig;
QString _basePath;
bool _launch = false;
bool _fullyConfiguredViaCliArgs = false;
bool _profileChangeAllowed = true;
bool _sgctConfigChangeAllowed = true;
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

@@ -47,6 +47,8 @@ private slots:
void parseScript();
private:
void createWidgets();
openspace::Profile& _profile;
QTextEdit* _textScripts = nullptr;
};

View File

@@ -28,7 +28,6 @@
#include <QDialog>
#include "assettreemodel.h"
#include "filesystemaccess.h"
namespace openspace { class Profile; }
@@ -43,14 +42,18 @@ public:
*
* \param profile The #openspace::Profile object containing all data of the
* new or imported profile.
* \param reportAssets A full summary of all assets and their respective paths in
* a text format unique to this application (more details are
* in class #assetTreeModel)
* \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 reportAssets,
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
*
@@ -58,11 +61,6 @@ public:
*/
QString createTextSummary();
private slots:
void parseSelections();
void selected(const QModelIndex&);
private:
openspace::Profile& _profile;
AssetTreeModel _assetTreeModel;
QTreeView* _assetTree = nullptr;

View File

@@ -32,7 +32,7 @@
#include <memory>
class AssetTreeModel : public QAbstractItemModel {
Q_OBJECT
Q_OBJECT
public:
AssetTreeModel(QObject* parent = nullptr);
@@ -145,23 +145,11 @@ public:
std::vector<AssetTreeItem*>& outputItems);
/**
* Imports asset tree data for this model. The import text format is unique to
* this asset tree structure.
* Each line starts with an character (0, 1, or x) to represent its checked status
* or if it doesn't exist in the current filesystem.
* This is followed by the name of either an asset or directory, with a space for
* each level of sub-directory. Example:
* 0Base
* 0 Directory
* 0 Asset1
* 1 Asset2
* 0 Asset3
* 1Asset4
* This format is used internally to translate from code that reads the filesystem
*
* \param contents asset recursive listing of directory in format described above
* 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& contents);
void importModelData(const std::string& assetBasePath);
/**
* Returns bool for if item is checked/selected

View File

@@ -50,6 +50,7 @@ private slots:
void tabSelect(int);
private:
void createWidgets();
QWidget* createNavStateWidget();
QWidget* createGeoWidget();

View File

@@ -41,9 +41,9 @@ public:
/**
* Constructor for deltaTimes class
*
* \param imported The #openspace::Profile object containing all data of the
* \param profile The #openspace::Profile object containing all data of the
* new or imported profile.
* \param parent Pointer to parent Qt widget (optional)
* \param parent Pointer to parent Qt widget
*/
DeltaTimesDialog(openspace::Profile& profile, QWidget* parent);
@@ -61,10 +61,10 @@ public:
*
* \param evt #QKeyEvent object for the key press event
*/
void keyPressEvent(QKeyEvent *evt);
void keyPressEvent(QKeyEvent* evt);
public slots:
private slots:
void listItemSelected();
void valueChanged(const QString& text);
void saveDeltaTimeValue();
@@ -74,6 +74,8 @@ public slots:
void parseSelections();
private:
void createWidgets();
/**
* Called to transition to editing a particular dt value (gui settings)
*

View File

@@ -45,7 +45,7 @@ public:
/**
* Constructor for keybindings class
*
* \param imported The #openspace::Profile object containing all data of the
* \param profile The #openspace::Profile object containing all data of the
* new or imported profile.
* \param parent Pointer to parent Qt widget (optional)
*/
@@ -56,9 +56,9 @@ public:
*
* \param evt #QKeyEvent object for the key press event
*/
void keyPressEvent(QKeyEvent *evt);
void keyPressEvent(QKeyEvent* evt);
public slots:
private slots:
void listItemSelected();
void listItemAdded();
void listItemRemove();
@@ -69,13 +69,11 @@ public slots:
void keySelected(int index);
private:
void createWidgets();
void transitionFromEditMode();
void editBoxDisabled(bool disabled);
int indexInKeyMapping(std::vector<int>& mapVector, int keyInt);
bool areRequiredFormsFilled();
std::string truncateString(std::string& s);
void replaceChars(std::string& src, const std::string& from,
const std::string& to);
bool isLineEmpty(int index);
openspace::Profile& _profile;

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

@@ -40,8 +40,8 @@ public:
/**
* Constructor for markNodes class
*
* \param imported The #openspace::Profile object containing all data of the
* new or imported profile.
* \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);
@@ -53,13 +53,15 @@ public:
*/
void keyPressEvent(QKeyEvent* evt);
public slots:
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;

View File

@@ -35,20 +35,21 @@ class QTextEdit;
class MetaDialog : public QDialog {
Q_OBJECT
public:
/**
* Constructor for meta class
*
* \param imported The #openspace::Profile object containing all data of the
* new or imported profile.
* \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);
public slots:
private slots:
void save();
private:
void createWidgets();
openspace::Profile& _profile;
QLineEdit* _nameEdit = nullptr;

View File

@@ -41,20 +41,20 @@ public:
/**
* Constructor for osmodules class
*
* \param imported The #openspace::Profile object containing all data of the
* new or imported profile.
* \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& profiles, QWidget* parent);
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);
void keyPressEvent(QKeyEvent* evt);
public slots:
private slots:
void listItemSelected();
void listItemAdded();
void listItemRemove();
@@ -64,15 +64,16 @@ public slots:
void parseSelections();
private:
void createWidgets();
QString createOneLineSummary(openspace::Profile::Module m);
void transitionFromEditMode();
void editBoxDisabled(bool disabled);
bool isLineEmpty(int index);
bool isLineEmpty(int index) const;
openspace::Profile& _profile;
std::vector<openspace::Profile::Module> _data;
bool _editModeNewItem = false;
const openspace::Profile::Module kBlank = {"", "", ""};
QListWidget* _list = nullptr;
QLabel* _moduleLabel = nullptr;

View File

@@ -26,18 +26,15 @@
#define __OPENSPACE_UI_LAUNCHER___PROFILEEDIT___H__
#include <QDialog>
#include <QWidget>
#include "profile/metadialog.h"
#include "profile/propertiesdialog.h"
#include "profile/modulesdialog.h"
#include "profile/keybindingsdialog.h"
#include "profile/assetsdialog.h"
#include "profile/timedialog.h"
#include "profile/additionalscriptsdialog.h"
#include "profile/deltatimesdialog.h"
#include "profile/cameradialog.h"
#include "profile/marknodesdialog.h"
#include <openspace/scene/profile.h>
#include <string>
#include <vector>
namespace openspace { class Profile; }
class QWidget;
class QLabel;
class QLineEdit;
class QTextEdit;
class ProfileEdit : public QDialog {
Q_OBJECT
@@ -45,24 +42,18 @@ public:
/**
* Constructor for ProfileEdit class
*
* \param imported The #openspace::Profile object containing all data of the
* new or imported profile.
* \param reportedAssets string list of assets reported by filesystemAccess 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 (optional)
* \param parent Pointer to parent Qt widget
*/
ProfileEdit(openspace::Profile& profile, const std::string reportedAssets,
std::vector<std::string>& profilesReadOnly, QWidget* parent);
/**
* Sets the profile name in top save/edit window. This can be changed by user in
* order to save to a different file.
*
* \param profileToSet name of the profile to set to
*/
void setProfileName(QString profileToSet);
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?
@@ -86,7 +77,7 @@ public:
*/
void keyPressEvent(QKeyEvent* evt);
public slots:
private slots:
void duplicateProfile();
void openMeta();
void openProperties();
@@ -102,16 +93,14 @@ public slots:
void approved();
private:
void createWidgets(const std::string& profileName);
void initSummaryTextForEachCategory();
std::string summarizeAssets();
std::string summarizeProperties();
std::string summarizeKeybindings();
bool isReadOnly(std::string profileToSave);
openspace::Profile& _profile;
const std::string _reportedAssets;
const std::string _assetBasePath;
const std::string _profileBasePath;
bool _saveSelected = false;
std::vector<std::string> _readOnlyProfiles;
const std::vector<std::string>& _readOnlyProfiles;
QLineEdit* _profileEdit = nullptr;
QLabel* _modulesLabel = nullptr;

View File

@@ -42,9 +42,9 @@ public:
/**
* Constructor for properties class
*
* \param imported The #openspace::Profile object containing all data of the
* new or imported profile.
* \param parent Pointer to parent Qt widget (optional)
* \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);
@@ -53,9 +53,9 @@ public:
*
* \param evt #QKeyEvent object for the key press event
*/
void keyPressEvent(QKeyEvent *evt);
void keyPressEvent(QKeyEvent* evt);
public slots:
private slots:
void listItemSelected();
void listItemAdded();
void listItemRemove();
@@ -65,6 +65,8 @@ public slots:
void parseSelections();
private:
void createWidgets();
QString createOneLineSummary(openspace::Profile::Property p);
void transitionFromEditMode();
void editBoxDisabled(bool disabled);

View File

@@ -40,18 +40,20 @@ public:
/**
* Constructor for ostime class
*
* \param imported The #openspace::Profile object containing all data of the
* new or imported profile.
* \param parent Pointer to parent Qt widget (optional)
* \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);
public slots:
private slots:
void enableAccordingToType(int);
void approved();
private:
void createWidgets();
void enableFormatForAbsolute(bool enableAbs);
openspace::Profile& _profile;
openspace::Profile::Time _data;
bool _initializedAsAbsolute = true;

View File

@@ -33,8 +33,8 @@ FileSystemAccess::FileSystemAccess(std::string fileExtension,
, _useCheckboxes(useCheckboxes)
{}
std::string FileSystemAccess::useQtFileSystemModelToTraverseDir(QString dir) {
_filesystemModel.setRootPath(dir);
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;

View File

@@ -22,19 +22,22 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/scene/profile.h>
#include "launcherwindow.h"
#include <QPixmap>
#include <QKeyEvent>
#include "filesystemaccess.h"
#include "profile/profileedit.h"
#include <openspace/engine/configuration.h>
#include <sstream>
#include <iostream>
#include <QMessageBox>
#include <random>
#include <QLabel>
#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;
@@ -68,29 +71,82 @@ namespace {
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(std::string basePath, bool profileEnabled,
configuration::Configuration& globalConfig,
LauncherWindow::LauncherWindow(bool profileEnabled,
const configuration::Configuration& globalConfig,
bool sgctConfigEnabled, std::string sgctConfigName,
QWidget* parent)
: QMainWindow(parent)
, _fileAccessProfiles(".profile", { "./" }, true, false)
, _fileAccessWinConfigs(".xml", { "./" }, true, false)
, _filesystemAccess(
".asset", { "scene", "global", "customization", "examples", "util" }, true, true
)
, _basePath(QString::fromStdString(basePath))
, _profileChangeAllowed(profileEnabled)
, _sgctConfigChangeAllowed(sgctConfigEnabled)
, _globalConfig(globalConfig)
, _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(
// Now that the log is enabled and available, we can pipe all Qt messages to that
[](QtMsgType type, const QMessageLogContext&, const QString& msg) {
if (type == QtCriticalMsg || type == QtFatalMsg || type == QtSystemMsg) {
std::cerr << msg.toStdString() << std::endl;
@@ -109,11 +165,33 @@ LauncherWindow::LauncherWindow(std::string basePath, bool profileEnabled,
setStyleSheet(styleSheet);
}
setCentralWidget(createCentralWidget());
QWidget* centralWidget = new QWidget(this);
QLabel* backgroundImage = new QLabel(centralWidget);
backgroundImage->setGeometry(geometry::BackgroundImage);
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");
@@ -139,227 +217,164 @@ LauncherWindow::LauncherWindow(std::string basePath, bool profileEnabled,
_windowConfigBox->setGeometry(geometry::WindowConfigBox);
QPushButton* startButton = new QPushButton("START", centralWidget);
connect(startButton, &QPushButton::released, this, &LauncherWindow::startOpenSpace);
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, &LauncherWindow::openWindowNew);
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, &LauncherWindow::openWindowEdit);
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);
setCentralWidget(centralWidget);
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);
_reportAssetsInFilesystem = _filesystemAccess.useQtFileSystemModelToTraverseDir(
QString::fromStdString(basePath) + "/data/assets"
);
populateProfilesList(globalConfig.profile);
_profileBox->setEnabled(_profileChangeAllowed);
populateWindowConfigsList(sgctConfigName);
_windowConfigBox->setEnabled(_sgctConfigChangeAllowed);
_fullyConfiguredViaCliArgs = (!profileEnabled && !sgctConfigEnabled);
bool hasSyncFiles = false;
QString syncFilePath = QString::fromStdString(
globalConfig.pathTokens["SYNC"] + "/http/launcher_images/1/profile1.png"
);
QFileInfo check_file(syncFilePath);
// check if file exists and if yes: Is it really a file and no directory?
if (check_file.exists() && check_file.isFile()) {
hasSyncFiles = true;
if (version > latest.version) {
latest.version = version;
latest.path = p;
}
}
QString filename;
QString bgpath;
if (hasSyncFiles) {
std::random_device rd;
std::mt19937 rng(rd());
std::uniform_int_distribution<int> uni(0, 4);
int random_integer = uni(rng);
filename = QString::fromStdString(
"/http/launcher_images/1/profile" + std::to_string(random_integer) + ".png"
);
bgpath = QString::fromStdString(globalConfig.pathTokens["SYNC"]) + filename;
}
else {
bgpath = QString::fromStdString(":/images/launcher-background.png");
if (latest.version == -1) {
// The sync folder existed, but nothing was in there. Kinda weird, but still
return;
}
backgroundImage->setPixmap(QPixmap(bgpath));
// 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();
std::string reportProfiles = _fileAccessProfiles.useQtFileSystemModelToTraverseDir(
_basePath + "/data/profiles"
);
std::stringstream instream(reportProfiles);
std::string iline;
QStringList profilesListLine;
while (std::getline(instream, iline)) {
if (_profileBox->findText(QString::fromStdString(iline)) == -1) {
_profileBox->addItem(QString::fromStdString(iline));
// 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()));
}
if (preset.length() > 0) {
int presetMatchIdx = _profileBox->findText(QString::fromStdString(preset));
if (presetMatchIdx != -1) {
_profileBox->setCurrentIndex(presetMatchIdx);
}
// 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) {
std::string reportConfigs = _fileAccessWinConfigs.useQtFileSystemModelToTraverseDir(
_basePath + "/config"
);
std::stringstream instream(reportConfigs);
std::string iline;
QStringList windowConfigsListLine;
while (std::getline(instream, iline)) {
windowConfigsListLine << QString::fromStdString(iline);
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()));
}
_windowConfigBox->addItems(windowConfigsListLine);
if (preset.length() > 0) {
int presetMatchIdx = _windowConfigBox->findText(QString::fromStdString(preset));
if (presetMatchIdx != -1) {
_windowConfigBox->setCurrentIndex(presetMatchIdx);
}
else {
_windowConfigBox->addItem(QString::fromStdString(preset));
_windowConfigBox->setCurrentIndex(_windowConfigBox->count() - 1);
}
// 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::openWindowNew() {
std::string initialProfileSelection = _profileBox->currentText().toStdString();
Profile profile;
ProfileEdit editor(
profile,
_reportAssetsInFilesystem,
_globalConfig.readOnlyProfiles,
this
);
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()) {
std::string saveProfilePath = _basePath.toStdString();
saveProfilePath += "/data/profiles/";
saveProfilePath += editor.specifiedFilename() + ".profile";
saveProfileToFile(saveProfilePath, profile);
const std::string path = _profilePath + editor.specifiedFilename() + ".profile";
saveProfile(this, path, *p);
populateProfilesList(editor.specifiedFilename());
}
else {
populateProfilesList(initialProfileSelection);
}
}
void LauncherWindow::openWindowEdit() {
std::string initialProfileSelection = _profileBox->currentText().toStdString();
std::string profilePath = _basePath.toStdString() + "/data/profiles/";
int selectedProfileIdx = _profileBox->currentIndex();
QString profileToSet = _profileBox->itemText(selectedProfileIdx);
std::string editProfilePath = profilePath + profileToSet.toStdString() + ".profile";
std::optional<Profile> profile = loadProfileFromFile(editProfilePath);
if (profile.has_value()) {
ProfileEdit editor(
*profile,
_reportAssetsInFilesystem,
_globalConfig.readOnlyProfiles,
this
);
editor.setProfileName(profileToSet);
editor.exec();
if (editor.wasSaved()) {
profilePath += editor.specifiedFilename() + ".profile";
saveProfileToFile(profilePath, *profile);
populateProfilesList(editor.specifiedFilename());
}
else {
populateProfilesList(initialProfileSelection);
}
}
}
void LauncherWindow::saveProfileToFile(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(
this,
"Exception",
QString::fromStdString(fmt::format(
"Error writing data to file: {} ({})", path, e.what()
))
);
}
}
std::optional<Profile> LauncherWindow::loadProfileFromFile(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(
this,
"Exception",
QString::fromStdString(fmt::format(
"ParsingError exception in {}: {}, {}", filename, e.component, e.message
))
);
return std::nullopt;
}
catch (const ghoul::RuntimeError& e) {
QMessageBox::critical(
this,
"Exception",
QString::fromStdString(fmt::format(
"RuntimeError exception in {}, component {}: {}",
filename, e.component, e.message
))
);
return std::nullopt;
const std::string current = _profileBox->currentText().toStdString();
populateProfilesList(current);
}
}
bool LauncherWindow::wasLaunchSelected() const {
return _launch;
}
bool LauncherWindow::isFullyConfiguredFromCliArgs() const {
return _fullyConfiguredViaCliArgs;
return _shouldLaunch;
}
std::string LauncherWindow::selectedProfile() const {
@@ -369,8 +384,3 @@ std::string LauncherWindow::selectedProfile() const {
std::string LauncherWindow::selectedWindowConfig() const {
return _windowConfigBox->currentText().toStdString();
}
void LauncherWindow::startOpenSpace() {
_launch = true;
close();
}

View File

@@ -24,6 +24,7 @@
#include "profile/additionalscriptsdialog.h"
#include "profile/line.h"
#include <openspace/scene/profile.h>
#include <QDialogButtonBox>
#include <QHBoxLayout>
@@ -37,7 +38,18 @@ AdditionalScriptsDialog::AdditionalScriptsDialog(openspace::Profile& profile,
, _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");
@@ -49,12 +61,7 @@ AdditionalScriptsDialog::AdditionalScriptsDialog(openspace::Profile& profile,
_textScripts->setAcceptRichText(false);
layout->addWidget(_textScripts, 1);
{
QFrame* line = new QFrame;
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
layout->addWidget(line);
}
layout->addWidget(new Line);
{
QDialogButtonBox* buttons = new QDialogButtonBox;
@@ -69,24 +76,16 @@ AdditionalScriptsDialog::AdditionalScriptsDialog(openspace::Profile& profile,
);
layout->addWidget(buttons);
}
std::vector<std::string> scripts = _profile.additionalScripts();
std::string scpts = std::accumulate(
scripts.begin(), scripts.end(),
std::string(), [](std::string lhs, std::string rhs) { return lhs + rhs + '\n'; }
);
_textScripts->setText(QString::fromStdString(std::move(scpts)));
_textScripts->moveCursor(QTextCursor::MoveOperation::End);
}
void AdditionalScriptsDialog::parseScript() {
std::vector<std::string> tmpMultilineStringToVector;
std::vector<std::string> additionalScripts;
std::istringstream iss(_textScripts->toPlainText().toStdString());
while (!iss.eof()) {
std::string s;
getline(iss, s);
tmpMultilineStringToVector.push_back(s);
std::getline(iss, s);
additionalScripts.push_back(std::move(s));
}
_profile.setAdditionalScripts(tmpMultilineStringToVector);
_profile.setAdditionalScripts(additionalScripts);
accept();
}

View File

@@ -24,6 +24,7 @@
#include "profile/assetsdialog.h"
#include "profile/line.h"
#include <openspace/scene/profile.h>
#include <QDialogButtonBox>
#include <QHeaderView>
@@ -58,8 +59,8 @@ namespace {
void traverseToFindFilesystemMatch(AssetTreeModel& model, QModelIndex parent,
int nRows, const std::string& path)
{
size_t slash = path.find_first_of('/', 0);
bool endOfPath = (slash == std::string::npos);
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) {
@@ -71,7 +72,7 @@ namespace {
QModelIndex idx = model.index(r, 0, parent);
std::string assetName = model.name(idx).toStdString();
if (!model.isAsset(idx)) {
if (firstDir.compare(assetName) == 0) {
if (firstDir == assetName) {
int nChildRows = model.childCount(idx);
foundDirMatch = true;
traverseToFindFilesystemMatch(model, idx, nChildRows, nextPath);
@@ -83,7 +84,7 @@ namespace {
}
}
if (!foundDirMatch) {
//Insert missing directory here with name and exists=false condition
// 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));
@@ -97,14 +98,14 @@ namespace {
QModelIndex idx = model.index(r, 0, parent);
std::string assetName = model.name(idx).toStdString();
if (path.compare(assetName) == 0) {
if (path == assetName) {
foundFileMatch = true;
model.setChecked(idx, true);
break;
}
}
if (!foundFileMatch) {
//Insert missing file here with name and exists=false condition
// 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));
@@ -115,13 +116,17 @@ namespace {
}
} // namespace
AssetsDialog::AssetsDialog(openspace::Profile& profile, const std::string reportAssets,
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");
@@ -129,8 +134,6 @@ AssetsDialog::AssetsDialog(openspace::Profile& profile, const std::string report
layout->addWidget(heading);
}
{
_assetTreeModel.importModelData(reportAssets);
_assetTree = new QTreeView;
_assetTree->setToolTip(
"Expand arrow entries to browse assets in this OpenSpace installation. "
@@ -177,12 +180,8 @@ AssetsDialog::AssetsDialog(openspace::Profile& profile, const std::string report
_summary->setText(createTextSummary());
layout->addWidget(_summary);
}
{
QFrame* line = new QFrame;
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
layout->addWidget(line);
}
layout->addWidget(new Line);
{
QDialogButtonBox* buttons = new QDialogButtonBox;
@@ -210,10 +209,13 @@ QString AssetsDialog::createTextSummary() {
QString summary;
for (int i = 0; i < summaryItems.size(); ++i) {
bool existsInFilesystem = summaryItems.at(i)->doesExistInFilesystem();
std::string s = fmt::format("<font color='{}'>{}</font><br>",
(existsInFilesystem ? "black" : "red"),
summaryPaths.at(i)
);
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;

View File

@@ -30,7 +30,9 @@ AssetTreeItem::AssetTreeItem(const std::vector<QVariant>& data, AssetTreeItem* p
{}
AssetTreeItem::~AssetTreeItem() {
qDeleteAll(_childItems);
for (AssetTreeItem* item : _childItems) {
delete item;
}
}
AssetTreeItem* AssetTreeItem::child(int row) {
@@ -48,12 +50,12 @@ int AssetTreeItem::childCount() const {
int AssetTreeItem::row() const {
if (_parentItem) {
auto it = std::find(
_parentItem->_childItems.begin(),
_parentItem->_childItems.end(),
const auto it = std::find(
_parentItem->_childItems.cbegin(),
_parentItem->_childItems.cend(),
this
);
return std::distance(_parentItem->_childItems.begin(), it);
return std::distance(_parentItem->_childItems.cbegin(), it);
}
else {
return 0;

View File

@@ -24,6 +24,7 @@
#include "profile/assettreeitem.h"
#include "profile/assettreemodel.h"
#include "filesystemaccess.h"
#include <sstream>
#include <QColor>
@@ -57,7 +58,8 @@ namespace {
}
bool importGetNextLine(ImportElement& elem, std::istringstream& iss) {
bool ok = std::getline(iss, elem.line) ? true : false;
std::getline(iss, elem.line);
const bool ok = iss.good();
if (!ok) {
elem.line = "";
elem.level = -1;
@@ -143,8 +145,16 @@ AssetTreeModel::AssetTreeModel(QObject* parent)
);
}
void AssetTreeModel::importModelData(const std::string& contents) {
std::istringstream iss(contents);
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)) {
@@ -164,8 +174,8 @@ AssetTreeItem* AssetTreeModel::getItem(const QModelIndex& index) const {
bool AssetTreeModel::isChecked(QModelIndex& index) const {
AssetTreeItem* item = getItem(index);
int checked = item->data(1).toInt();
return checked == Qt::Checked;
const int isChecked = item->data(1).toInt();
return isChecked == Qt::Checked;
}
bool AssetTreeModel::isAsset(QModelIndex& index) const {

View File

@@ -24,6 +24,7 @@
#include "profile/cameradialog.h"
#include "profile/line.h"
#include <openspace/scene/profile.h>
#include <QDialogButtonBox>
#include <QDoubleValidator>
@@ -60,37 +61,7 @@ CameraDialog::CameraDialog(openspace::Profile& profile, QWidget *parent)
, _profile(profile)
{
setWindowTitle("Set Camera Position");
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);
{
QFrame* line = new QFrame;
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
layout->addWidget(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);
}
createWidgets();
if (_profile.camera().has_value()) {
openspace::Profile::CameraType type = *_profile.camera();
@@ -163,6 +134,34 @@ CameraDialog::CameraDialog(openspace::Profile& profile, QWidget *parent)
}
}
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);
@@ -175,14 +174,16 @@ QWidget* CameraDialog::createNavStateWidget() {
layout->addWidget(new QLabel("Aim:"), 1, 0);
_navState.aim = new QLineEdit;
_navState.aim->setToolTip(
"[OPTIONAL] If specified, camera will be aimed at this node while keeping the "
"anchor node in the same view location"
"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("[OPTIONAL] Camera location in reference to this frame");
_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);
@@ -218,19 +219,22 @@ QWidget* CameraDialog::createNavStateWidget() {
upLayout->addWidget(new QLabel("X"));
_navState.upX = new QLineEdit;
_navState.upX->setValidator(new QDoubleValidator);
_navState.upX->setToolTip("[OPTIONAL] Camera up vector (x)");
_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("[OPTIONAL] Camera up vector (y)");
_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("[OPTIONAL] Camera up vector (z)");
_navState.upZ->setToolTip("Camera up vector (z)");
_navState.upZ->setPlaceholderText("semioptional");
upLayout->addWidget(_navState.upZ);
layout->addWidget(upBox, 4, 1);
}
@@ -238,13 +242,15 @@ QWidget* CameraDialog::createNavStateWidget() {
layout->addWidget(new QLabel("Yaw angle:"), 5, 0);
_navState.yaw = new QLineEdit;
_navState.yaw->setValidator(new QDoubleValidator);
_navState.yaw->setToolTip("[OPTIONAL] yaw angle +/- 360 degrees");
_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("[OPTIONAL] pitch angle +/- 360 degrees");
_navState.pitch->setToolTip("Pitch angle +/- 360 degrees");
_navState.pitch->setPlaceholderText("optional");
layout->addWidget(_navState.pitch, 6, 1);
return box;
@@ -274,8 +280,8 @@ QWidget* CameraDialog::createGeoWidget() {
layout->addWidget(new QLabel("Altitude"), 3, 0);
_geoState.altitude = new QLineEdit;
_geoState.altitude->setValidator(new QDoubleValidator);
_geoState.altitude->setToolTip("[OPTIONAL] Altitude of camera (meters)");
//altitude->setPlaceholderText("optional");
_geoState.altitude->setToolTip("Altitude of camera (meters)");
_geoState.altitude->setPlaceholderText("optional");
layout->addWidget(_geoState.altitude, 3, 1);
return box;
@@ -354,7 +360,7 @@ bool CameraDialog::areRequiredFormsFilledAndValid() {
void CameraDialog::addErrorMsg(QString errorDescription) {
QString contents = _errorMsg->text();
if (contents.length() > 0) {
if (!contents.isEmpty()) {
contents += ", ";
}
contents += errorDescription;

View File

@@ -24,6 +24,7 @@
#include "profile/deltatimesdialog.h"
#include "profile/line.h"
#include <openspace/scene/profile.h>
#include <QDialogButtonBox>
#include <QDoubleValidator>
@@ -76,7 +77,6 @@ namespace {
}
return checkForTimeDescription(i, value);
}
} // namespace
DeltaTimesDialog::DeltaTimesDialog(openspace::Profile& profile, QWidget *parent)
@@ -84,6 +84,19 @@ DeltaTimesDialog::DeltaTimesDialog(openspace::Profile& profile, QWidget *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;
@@ -105,7 +118,7 @@ DeltaTimesDialog::DeltaTimesDialog(openspace::Profile& profile, QWidget *parent)
);
buttonLayout->addWidget(_addButton);
_removeButton = new QPushButton("Remove LastEntry");
_removeButton = new QPushButton("Remove Last Entry");
connect(
_removeButton, &QPushButton::clicked,
this, &DeltaTimesDialog::removeDeltaTimeValue
@@ -130,7 +143,7 @@ DeltaTimesDialog::DeltaTimesDialog(openspace::Profile& profile, QWidget *parent)
box->addWidget(_value);
layout->addLayout(box);
}
{
QBoxLayout* box = new QHBoxLayout;
_saveButton = new QPushButton("Save");
@@ -150,12 +163,7 @@ DeltaTimesDialog::DeltaTimesDialog(openspace::Profile& profile, QWidget *parent)
box->addStretch();
layout->addLayout(box);
}
{
QFrame* line = new QFrame;
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
layout->addWidget(line);
}
layout->addWidget(new Line);
{
QBoxLayout* footer = new QHBoxLayout;
_errorMsg = new QLabel;
@@ -173,16 +181,6 @@ DeltaTimesDialog::DeltaTimesDialog(openspace::Profile& profile, QWidget *parent)
footer->addWidget(_buttonBox);
layout->addLayout(footer);
}
_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);
}
std::string DeltaTimesDialog::createSummaryForDeltaTime(size_t idx, bool forListView) {
@@ -205,9 +203,7 @@ std::string DeltaTimesDialog::createSummaryForDeltaTime(size_t idx, bool forList
}
if (forListView) {
s += "\t" + std::to_string(_data.at(idx));
s += "\t";
s += timeDescription(_data.at(idx));
s += '\t' + std::to_string(_data.at(idx)) + '\t' + timeDescription(_data.at(idx));
}
return s;
}
@@ -220,7 +216,7 @@ void DeltaTimesDialog::listItemSelected() {
_listWidget->setCurrentRow(index);
}
if (_data.size() > 0) {
if (!_data.empty()) {
if (_data.at(index) == 0) {
_seconds->clear();
}
@@ -238,9 +234,7 @@ void DeltaTimesDialog::setLabelForKey(int index, bool editMode, std::string colo
index = _data.size() - 1;
}
if (editMode) {
labelS += " '";
labelS += createSummaryForDeltaTime(index, false);
labelS += "':";
labelS += " '" + createSummaryForDeltaTime(index, false) + "':";
}
_adjustLabel->setText(QString::fromStdString(
"<font color='" + color + "'>" + labelS + "</font>"
@@ -248,7 +242,7 @@ void DeltaTimesDialog::setLabelForKey(int index, bool editMode, std::string colo
}
void DeltaTimesDialog::valueChanged(const QString& text) {
if (_seconds->text() == "") {
if (_seconds->text().isEmpty()) {
_errorMsg->setText("");
}
else {
@@ -297,21 +291,20 @@ void DeltaTimesDialog::addDeltaTimeValue() {
}
void DeltaTimesDialog::saveDeltaTimeValue() {
QListWidgetItem *item = _listWidget->currentItem();
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));
//setLabelForKey(index, true, "black");
transitionEditMode(index, false);
_editModeNewItem = false;
}
}
}
void DeltaTimesDialog::discardDeltaTimeValue(void) {
void DeltaTimesDialog::discardDeltaTimeValue() {
listItemSelected();
transitionEditMode(_listWidget->count() - 1, false);
if (_editModeNewItem && !_data.empty() && _data.back() == 0) {

View File

@@ -24,6 +24,7 @@
#include "profile/keybindingsdialog.h"
#include "profile/line.h"
#include <openspace/scene/profile.h>
#include <openspace/util/keys.h>
#include <qevent.h>
@@ -38,9 +39,11 @@
#include <QTextEdit>
#include <QDialogButtonBox>
using namespace openspace;
namespace {
const openspace::Profile::Keybinding kBlank = {
{ openspace::Key::Unknown, openspace::KeyModifier::NoModifier },
const Profile::Keybinding BlankKey= {
{ Key::Unknown, KeyModifier::NoModifier },
"",
"",
"",
@@ -52,8 +55,7 @@ namespace {
std::string newString;
std::string::size_type found, last = 0;
while ((found = src.find(from, last)) != std::string::npos)
{
while ((found = src.find(from, last)) != std::string::npos) {
newString.append(src, last, (found - last));
newString += to;
last = found + from.length();
@@ -72,16 +74,16 @@ namespace {
return s;
}
std::string createOneLineSummary(openspace::Profile::Keybinding k) {
std::string createOneLineSummary(Profile::Keybinding k) {
std::string summary;
int keymod = static_cast<int>(k.key.modifier);
if (keymod != static_cast<int>(openspace::KeyModifier::NoModifier)) {
summary += openspace::KeyModifierNames.at(keymod) + " ";
if (keymod != static_cast<int>(KeyModifier::NoModifier)) {
summary += KeyModifierNames.at(keymod) + " ";
}
int keyname = static_cast<int>(k.key.key);
summary += openspace::KeyNames.at(keyname) + " ";
summary += KeyNames.at(keyname) + " ";
summary += truncateString(k.name) + " (";
summary += truncateString(k.documentation) + ") @ ";
summary += truncateString(k.guiPath) + " ";
@@ -93,13 +95,18 @@ namespace {
} // namespace
KeybindingsDialog::KeybindingsDialog(openspace::Profile& profile, QWidget *parent)
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;
@@ -136,12 +143,7 @@ KeybindingsDialog::KeybindingsDialog(openspace::Profile& profile, QWidget *paren
box->addStretch();
layout->addLayout(box);
}
{
QFrame* line = new QFrame;
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
layout->addWidget(line);
}
layout->addWidget(new Line);
{
QGridLayout* box = new QGridLayout;
@@ -154,7 +156,7 @@ KeybindingsDialog::KeybindingsDialog(openspace::Profile& profile, QWidget *paren
QStringList comboModKeysStringList;
int modIdx = 0;
for (const std::pair<const int, std::string>& m : openspace::KeyModifierNames) {
for (const std::pair<const int, std::string>& m : KeyModifierNames) {
comboModKeysStringList += QString::fromStdString(m.second);
_mapModKeyComboBoxIndexToKeyValue.push_back(modIdx++);
}
@@ -168,9 +170,9 @@ KeybindingsDialog::KeybindingsDialog(openspace::Profile& profile, QWidget *paren
_keyCombo->setToolTip("Key to press for this keybinding");
QStringList comboKeysStringList;
for (int i = 0; i < static_cast<int>(openspace::Key::Last); ++i) {
if (openspace::KeyNames.find(i) != openspace::KeyNames.end()) {
comboKeysStringList += QString::fromStdString(openspace::KeyNames.at(i));
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);
}
@@ -243,12 +245,7 @@ KeybindingsDialog::KeybindingsDialog(openspace::Profile& profile, QWidget *paren
box->addLayout(buttonBox, 8, 1, 1, 2);
layout->addLayout(box);
}
{
QFrame* line = new QFrame;
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
layout->addWidget(line);
}
layout->addWidget(new Line);
{
QBoxLayout* footerLayout = new QHBoxLayout;
@@ -270,23 +267,21 @@ KeybindingsDialog::KeybindingsDialog(openspace::Profile& profile, QWidget *paren
footerLayout->addWidget(_buttonBox);
layout->addLayout(footerLayout);
}
transitionFromEditMode();
}
void KeybindingsDialog::listItemSelected(void) {
void KeybindingsDialog::listItemSelected() {
QListWidgetItem *item = _list->currentItem();
int index = _list->row(item);
if (_data.size() > 0) {
openspace::Profile::Keybinding& k = _data[index];
Profile::Keybinding& k = _data[index];
const int modifierKey = indexInKeyMapping(
_mapModKeyComboBoxIndexToKeyValue,
static_cast<int>(k.key.modifier)
);
_keyModCombo->setCurrentIndex(modifierKey);
if (k.key.key == openspace::Key::Unknown) {
if (k.key.key == Key::Unknown) {
_keyCombo->setCurrentIndex(0);
}
else {
@@ -308,13 +303,13 @@ void KeybindingsDialog::listItemSelected(void) {
}
void KeybindingsDialog::keySelected(int index) {
const QString numKeyWarning = "Warning: using a number key may conflict with the "
"keybindings for simulation time increments. ";
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>(openspace::Key::Num0)
&& _mapKeyComboBoxIndexToKeyValue[index] <= static_cast<int>(openspace::Key::Num9))
if (_mapKeyComboBoxIndexToKeyValue[index] >= static_cast<int>(Key::Num0)
&& _mapKeyComboBoxIndexToKeyValue[index] <= static_cast<int>(Key::Num9))
{
if (!alreadyContainsWarning) {
errorContents = numKeyWarning + errorContents;
@@ -327,8 +322,8 @@ void KeybindingsDialog::keySelected(int index) {
}
int KeybindingsDialog::indexInKeyMapping(std::vector<int>& mapVector, int keyInt) {
auto it = std::find(mapVector.begin(), mapVector.end(), keyInt);
return std::distance(mapVector.begin(), it);
const auto it = std::find(mapVector.cbegin(), mapVector.cend(), keyInt);
return std::distance(mapVector.cbegin(), it);
}
bool KeybindingsDialog::isLineEmpty(int index) {
@@ -345,25 +340,14 @@ bool KeybindingsDialog::isLineEmpty(int index) {
void KeybindingsDialog::listItemAdded() {
int currentListSize = _list->count();
//if ((currentListSize == 1) && (isLineEmpty(0))) {
//if (currentListSize == 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) = kBlank;
// _list->item(0)->setText(" (Enter details below & click 'Save')");
// transitionToEditMode();
// }
// else {
_data.push_back(kBlank);
_list->addItem(new QListWidgetItem(" (Enter details below & click 'Save')"));
//Scroll down to that blank line highlighted
_list->setCurrentRow(_list->count() - 1);
//}
_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 == openspace::Key::Unknown) {
if (_data.back().key.key == Key::Unknown) {
_keyCombo->setCurrentIndex(0);
}
else {
@@ -379,7 +363,7 @@ void KeybindingsDialog::listItemAdded() {
_editModeNewItem = true;
}
void KeybindingsDialog::listItemSave(void) {
void KeybindingsDialog::listItemSave() {
if (!areRequiredFormsFilled()) {
return;
}
@@ -390,9 +374,9 @@ void KeybindingsDialog::listItemSave(void) {
if (!_data.empty()) {
int keyModIdx = _mapModKeyComboBoxIndexToKeyValue.at(
_keyModCombo->currentIndex());
_data[index].key.modifier = static_cast<openspace::KeyModifier>(keyModIdx);
_data[index].key.modifier = static_cast<KeyModifier>(keyModIdx);
int keyIdx = _mapKeyComboBoxIndexToKeyValue.at(_keyCombo->currentIndex());
_data[index].key.key = static_cast<openspace::Key>(keyIdx);
_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();
@@ -412,14 +396,14 @@ bool KeybindingsDialog::areRequiredFormsFilled() {
requiredFormsFilled = false;
}
if (_nameEdit->text().length() == 0) {
if (errors.length() > 0) {
if (!errors.empty()) {
errors += ", ";
}
errors += "Missing keybinding name";
requiredFormsFilled = false;
}
if (_scriptEdit->toPlainText().length() == 0) {
if (errors.length() > 0) {
if (_scriptEdit->toPlainText().isEmpty()) {
if (!errors.empty()) {
errors += ", ";
}
errors += "Missing script";
@@ -429,31 +413,31 @@ bool KeybindingsDialog::areRequiredFormsFilled() {
return requiredFormsFilled;
}
void KeybindingsDialog::listItemCancelSave(void) {
void KeybindingsDialog::listItemCancelSave() {
listItemSelected();
transitionFromEditMode();
if (_editModeNewItem && !_data.empty() &&
(_data.back().name.length() == 0 || _data.back().script.length() == 0 ||
_data.back().key.key == openspace::Key::Unknown))
_data.back().key.key == Key::Unknown))
{
listItemRemove();
}
_editModeNewItem = false;
}
void KeybindingsDialog::listItemRemove(void) {
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) = kBlank;
_data.at(0) = BlankKey;
_list->item(0)->setText("");
}
else {
int index = _list->currentRow();
if (index >= 0 && index < _list->count()) {
_list->takeItem(index);
if (_data.size() > 0) {
if (!_data.empty()) {
_data.erase(_data.begin() + index);
}
}
@@ -481,7 +465,7 @@ void KeybindingsDialog::transitionToEditMode() {
_errorMsg->setText("");
}
void KeybindingsDialog::transitionFromEditMode(void) {
void KeybindingsDialog::transitionFromEditMode() {
_list->setDisabled(false);
_addButton->setDisabled(false);
_removeButton->setDisabled(false);

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

@@ -24,6 +24,7 @@
#include "profile/marknodesdialog.h"
#include "profile/line.h"
#include <openspace/scene/profile.h>
#include <QDialogButtonBox>
#include <QEvent>
@@ -40,7 +41,10 @@ MarkNodesDialog::MarkNodesDialog(openspace::Profile& profile, QWidget* parent)
, _data(_profile.markNodes())
{
setWindowTitle("Mark Interesting Nodes");
createWidgets();
}
void MarkNodesDialog::createWidgets() {
QBoxLayout* layout = new QVBoxLayout(this);
_list = new QListWidget;
connect(
@@ -80,6 +84,7 @@ MarkNodesDialog::MarkNodesDialog(openspace::Profile& profile, QWidget* parent)
box->addWidget(addButton);
layout->addLayout(box);
}
layout->addWidget(new Line);
{
QDialogButtonBox* buttons = new QDialogButtonBox;
buttons->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel);
@@ -95,11 +100,11 @@ MarkNodesDialog::MarkNodesDialog(openspace::Profile& profile, QWidget* parent)
}
}
void MarkNodesDialog::listItemSelected(void) {
void MarkNodesDialog::listItemSelected() {
_removeButton->setEnabled(true);
}
void MarkNodesDialog::listItemAdded(void) {
void MarkNodesDialog::listItemAdded() {
if (_newNode->text().isEmpty()) {
return;
}
@@ -140,7 +145,7 @@ void MarkNodesDialog::parseSelections() {
accept();
}
void MarkNodesDialog::keyPressEvent(QKeyEvent *evt) {
void MarkNodesDialog::keyPressEvent(QKeyEvent* evt) {
if (evt->key() == Qt::Key_Enter || evt->key() == Qt::Key_Return) {
if (_newNode->text().length() > 0 && _newNode->hasFocus()) {
listItemAdded();

View File

@@ -24,6 +24,7 @@
#include "profile/metadialog.h"
#include "profile/line.h"
#include <openspace/scene/profile.h>
#include <QDialogButtonBox>
#include <QKeyEvent>
@@ -38,40 +39,7 @@ MetaDialog::MetaDialog(openspace::Profile& profile, QWidget *parent)
, _profile(profile)
{
setWindowTitle("Meta");
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);
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);
createWidgets();
if (_profile.meta().has_value()) {
openspace::Profile::Meta meta = *_profile.meta();
@@ -96,6 +64,43 @@ MetaDialog::MetaDialog(openspace::Profile& profile, QWidget *parent)
}
}
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() &&

View File

@@ -24,6 +24,7 @@
#include "profile/modulesdialog.h"
#include "profile/line.h"
#include <QDialogButtonBox>
#include <QEvent>
#include <QKeyEvent>
@@ -33,15 +34,25 @@
#include <QPushButton>
#include <QVBoxLayout>
ModulesDialog::ModulesDialog(openspace::Profile& profile, QWidget *parent)
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(
@@ -52,8 +63,8 @@ ModulesDialog::ModulesDialog(openspace::Profile& profile, QWidget *parent)
_list->setMovement(QListView::Free);
_list->setResizeMode(QListView::Adjust);
for (size_t i = 0; i < _data.size(); ++i) {
_list->addItem(new QListWidgetItem(createOneLineSummary(_data[i])));
for (const Profile::Module& m : _data) {
_list->addItem(new QListWidgetItem(createOneLineSummary(m)));
}
layout->addWidget(_list);
}
@@ -117,12 +128,7 @@ ModulesDialog::ModulesDialog(openspace::Profile& profile, QWidget *parent)
layout->addLayout(box);
}
{
QFrame* line = new QFrame;
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
layout->addWidget(line);
}
layout->addWidget(new Line);
{
QBoxLayout* footerLayout = new QHBoxLayout;
@@ -144,11 +150,9 @@ ModulesDialog::ModulesDialog(openspace::Profile& profile, QWidget *parent)
footerLayout->addWidget(_buttonBox);
layout->addLayout(footerLayout);
}
transitionFromEditMode();
}
QString ModulesDialog::createOneLineSummary(openspace::Profile::Module m) {
QString ModulesDialog::createOneLineSummary(Profile::Module m) {
QString summary = QString::fromStdString(m.name);
bool hasCommandForLoaded = (m.loadedInstruction->length() > 0);
bool hasCommandForNotLoaded = (m.notLoadedInstruction->length() > 0);
@@ -169,11 +173,11 @@ QString ModulesDialog::createOneLineSummary(openspace::Profile::Module m) {
}
void ModulesDialog::listItemSelected() {
QListWidgetItem *item = _list->currentItem();
QListWidgetItem* item = _list->currentItem();
int index = _list->row(item);
if (_data.size() > 0) {
const openspace::Profile::Module& m = _data[index];
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));
@@ -191,7 +195,7 @@ void ModulesDialog::listItemSelected() {
transitionToEditMode();
}
bool ModulesDialog::isLineEmpty(int index) {
bool ModulesDialog::isLineEmpty(int index) const {
bool isEmpty = true;
if (!_list->item(index)->text().isEmpty()) {
isEmpty = false;
@@ -202,20 +206,20 @@ bool ModulesDialog::isLineEmpty(int index) {
return isEmpty;
}
void ModulesDialog::listItemAdded(void) {
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.
// 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) = kBlank;
_data.at(0) = Blank;
_list->item(0)->setText(" (Enter details below & click 'Save')");
_list->setCurrentRow(0);
transitionToEditMode();
}
else {
_data.push_back(kBlank);
_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);
@@ -242,9 +246,8 @@ void ModulesDialog::listItemAdded(void) {
_editModeNewItem = true;
}
void ModulesDialog::listItemSave(void) {
void ModulesDialog::listItemSave() {
if (_moduleEdit->text().isEmpty()) {
//ui->label_module->setText("<font color='red'>Module</font>");
_errorMsg->setText("Missing module name");
return;
}
@@ -262,32 +265,28 @@ void ModulesDialog::listItemSave(void) {
_editModeNewItem = false;
}
void ModulesDialog::listItemCancelSave(void) {
void ModulesDialog::listItemCancelSave() {
transitionFromEditMode();
if (_editModeNewItem) {
if (_data.size() > 0) {
if(_data.back().name.length() == 0) {
listItemRemove();
}
}
if (_editModeNewItem && !_data.empty() && _data.back().name.empty()) {
listItemRemove();
}
_editModeNewItem = false;
}
void ModulesDialog::listItemRemove(void) {
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
// 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) = kBlank;
_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) {
if (!_data.empty()) {
_data.erase(_data.begin() + index);
}
}
@@ -297,7 +296,7 @@ void ModulesDialog::listItemRemove(void) {
transitionFromEditMode();
}
void ModulesDialog::transitionToEditMode(void) {
void ModulesDialog::transitionToEditMode() {
_list->setDisabled(true);
_buttonAdd->setDisabled(true);
_buttonRemove->setDisabled(true);
@@ -312,7 +311,7 @@ void ModulesDialog::transitionToEditMode(void) {
_errorMsg->setText("");
}
void ModulesDialog::transitionFromEditMode(void) {
void ModulesDialog::transitionFromEditMode() {
_list->setDisabled(false);
_buttonAdd->setDisabled(false);
_buttonRemove->setDisabled(false);

View File

@@ -22,22 +22,34 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/scene/profile.h>
#include "profile/profileedit.h"
#include "filesystemaccess.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 <iostream>
#include <QVBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QTextEdit>
#include <QDialogButtonBox>
#include <QVBoxLayout>
#include <QWidget>
#include <filesystem>
#include <iostream>
using namespace openspace;
namespace {
template <class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template <class... Ts> overloaded(Ts...)->overloaded<Ts...>;
QString labelText(int size, QString title) {
QString label;
if (size > 0) {
@@ -48,19 +60,56 @@ namespace {
}
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
using namespace openspace;
ProfileEdit::ProfileEdit(Profile& profile, const std::string reportedAssets,
std::vector<std::string>& readOnlyProfiles, QWidget* parent)
ProfileEdit::ProfileEdit(Profile& profile, const std::string& profileName,
std::string assetBasePath, std::string profileBasePath,
const std::vector<std::string>& readOnlyProfiles,
QWidget* parent)
: QDialog(parent)
, _reportedAssets(reportedAssets)
, _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;
@@ -70,7 +119,7 @@ ProfileEdit::ProfileEdit(Profile& profile, const std::string reportedAssets,
profileLabel->setObjectName("profile");
container->addWidget(profileLabel);
_profileEdit = new QLineEdit;
_profileEdit = new QLineEdit(QString::fromStdString(profileName));
container->addWidget(_profileEdit);
QPushButton* duplicateButton = new QPushButton("Duplicate Profile");
@@ -82,12 +131,7 @@ ProfileEdit::ProfileEdit(Profile& profile, const std::string reportedAssets,
layout->addLayout(container);
}
{
QFrame* line = new QFrame;
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
layout->addWidget(line);
}
layout->addWidget(new Line);
{
QGridLayout* container = new QGridLayout;
container->setColumnStretch(1, 1);
@@ -110,12 +154,7 @@ ProfileEdit::ProfileEdit(Profile& profile, const std::string reportedAssets,
leftLayout->addLayout(container);
}
{
QFrame* line = new QFrame;
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
leftLayout->addWidget(line);
}
leftLayout->addWidget(new Line);
{
QGridLayout* container = new QGridLayout;
container->setColumnStretch(1, 1);
@@ -135,12 +174,7 @@ ProfileEdit::ProfileEdit(Profile& profile, const std::string reportedAssets,
leftLayout->addLayout(container);
}
{
QFrame* line = new QFrame;
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
leftLayout->addWidget(line);
}
leftLayout->addWidget(new Line);
{
QGridLayout* container = new QGridLayout;
container->setColumnStretch(1, 1);
@@ -165,12 +199,7 @@ ProfileEdit::ProfileEdit(Profile& profile, const std::string reportedAssets,
}
topLayout->addLayout(leftLayout, 3);
{
QFrame* line = new QFrame;
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
topLayout->addWidget(line);
}
topLayout->addWidget(new Line);
QBoxLayout* rightLayout = new QVBoxLayout;
{
@@ -186,12 +215,7 @@ ProfileEdit::ProfileEdit(Profile& profile, const std::string reportedAssets,
container->addWidget(metaEdit);
rightLayout->addLayout(container);
}
{
QFrame* line = new QFrame;
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
rightLayout->addWidget(line);
}
rightLayout->addWidget(new Line);
{
QBoxLayout* container = new QVBoxLayout;
_interestingNodesLabel = new QLabel("Mark Interesting Nodes");
@@ -208,12 +232,7 @@ ProfileEdit::ProfileEdit(Profile& profile, const std::string reportedAssets,
container->addWidget(interestingNodesEdit);
rightLayout->addLayout(container);
}
{
QFrame* line = new QFrame;
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
rightLayout->addWidget(line);
}
rightLayout->addWidget(new Line);
{
QBoxLayout* container = new QVBoxLayout;
_deltaTimesLabel = new QLabel("Simulation Time Increments");
@@ -230,12 +249,7 @@ ProfileEdit::ProfileEdit(Profile& profile, const std::string reportedAssets,
container->addWidget(deltaTimesEdit);
rightLayout->addLayout(container);
}
{
QFrame* line = new QFrame;
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
rightLayout->addWidget(line);
}
rightLayout->addWidget(new Line);
{
QBoxLayout* container = new QVBoxLayout;
_cameraLabel = new QLabel("Camera");
@@ -249,12 +263,7 @@ ProfileEdit::ProfileEdit(Profile& profile, const std::string reportedAssets,
container->addWidget(cameraEdit);
rightLayout->addLayout(container);
}
{
QFrame* line = new QFrame;
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
rightLayout->addWidget(line);
}
rightLayout->addWidget(new Line);
{
QBoxLayout* container = new QVBoxLayout;
_timeLabel = new QLabel("Time");
@@ -268,12 +277,7 @@ ProfileEdit::ProfileEdit(Profile& profile, const std::string reportedAssets,
container->addWidget(timeEdit);
rightLayout->addLayout(container);
}
{
QFrame* line = new QFrame;
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
rightLayout->addWidget(line);
}
rightLayout->addWidget(new Line);
{
QBoxLayout* container = new QVBoxLayout;
_modulesLabel = new QLabel("Modules");
@@ -287,12 +291,7 @@ ProfileEdit::ProfileEdit(Profile& profile, const std::string reportedAssets,
container->addWidget(modulesEdit);
rightLayout->addLayout(container);
}
{
QFrame* line = new QFrame;
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
rightLayout->addWidget(line);
}
rightLayout->addWidget(new Line);
{
QBoxLayout* container = new QVBoxLayout;
_additionalScriptsLabel = new QLabel("Additional Scripts");
@@ -312,12 +311,7 @@ ProfileEdit::ProfileEdit(Profile& profile, const std::string reportedAssets,
topLayout->addLayout(rightLayout);
layout->addLayout(topLayout);
{
QFrame* line = new QFrame;
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
layout->addWidget(line);
}
layout->addWidget(new Line);
{
QBoxLayout* footer = new QHBoxLayout;
@@ -333,21 +327,23 @@ ProfileEdit::ProfileEdit(Profile& profile, const std::string reportedAssets,
footer->addWidget(buttons);
layout->addLayout(footer);
}
initSummaryTextForEachCategory();
}
void ProfileEdit::initSummaryTextForEachCategory() {
_modulesLabel->setText(labelText(_profile.modules().size(), "Modules"));
_assetsLabel->setText(labelText(_profile.assets().size(), "Assets"));
_assetsEdit->setText(QString::fromStdString(summarizeAssets()));
_assetsEdit->setText(QString::fromStdString(summarizeAssets(_profile.assets())));
_propertiesLabel->setText(labelText(_profile.properties().size(), "Properties"));
_propertiesEdit->setText(QString::fromStdString(summarizeProperties()));
_propertiesEdit->setText(
QString::fromStdString(summarizeProperties(_profile.properties()))
);
_keybindingsLabel->setText(labelText(_profile.keybindings().size(), "Keybindings"));
_keybindingsEdit->setText(QString::fromStdString(summarizeKeybindings()));
_keybindingsEdit->setText(
QString::fromStdString(summarizeKeybindings(_profile.keybindings()))
);
_deltaTimesLabel->setText(
labelText(_profile.deltaTimes().size(), "Simulation Time Increments")
@@ -357,28 +353,47 @@ void ProfileEdit::initSummaryTextForEachCategory() {
);
}
void ProfileEdit::setProfileName(QString profileToSet) {
_profileEdit->setText(profileToSet);
}
void ProfileEdit::duplicateProfile() {
QString currentProfile = _profileEdit->text();
if (!currentProfile.isEmpty()) {
QString duplicatedName = currentProfile + "_1";
if ((currentProfile.length() > 2)
&& (currentProfile.midRef(currentProfile.length() - 2, 1) == "_"))
{
QStringRef num = currentProfile.midRef(currentProfile.length() - 1, 1);
bool validConversion = false;
int val = num.toInt(&validConversion, 10);
if (validConversion && val < 9) {
duplicatedName = currentProfile.left(currentProfile.length() - 2)
+ "_" + QString::number(val + 1);
}
}
_profileEdit->setText(duplicatedName);
}
_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() {
@@ -396,23 +411,25 @@ void ProfileEdit::openProperties() {
_errorMsg->clear();
PropertiesDialog(_profile, this).exec();
_propertiesLabel->setText(labelText(_profile.properties().size(), "Properties"));
_propertiesEdit->setText(QString::fromStdString(summarizeProperties()));
_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()));
_keybindingsEdit->setText(
QString::fromStdString(summarizeKeybindings(_profile.keybindings()))
);
}
void ProfileEdit::openAssets() {
_errorMsg->clear();
AssetsDialog assets(_profile, _reportedAssets, this);
assets.exec();
AssetsDialog(_profile, _assetBasePath, this).exec();
_assetsLabel->setText(labelText(_profile.assets().size(), "Assets"));
_assetsEdit->setText(assets.createTextSummary());
_assetsEdit->setText(QString::fromStdString(summarizeAssets()));
_assetsEdit->setText(QString::fromStdString(summarizeAssets(_profile.assets())));
}
void ProfileEdit::openTime() {
@@ -446,36 +463,6 @@ void ProfileEdit::openMarkNodes() {
);
}
std::string ProfileEdit::summarizeProperties() {
std::string results;
for (openspace::Profile::Property p : _profile.properties()) {
results += p.name + " = " + p.value + '\n';
}
return results;
}
std::string ProfileEdit::summarizeKeybindings() {
std::string results;
for (openspace::Profile::Keybinding k : _profile.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 ProfileEdit::summarizeAssets() {
std::string results;
for (const std::string& a : _profile.assets()) {
results += a + '\n';
}
return results;
}
bool ProfileEdit::wasSaved() const {
return _saveSelected;
}
@@ -489,34 +476,30 @@ void ProfileEdit::cancel() {
reject();
}
bool ProfileEdit::isReadOnly(std::string profileSave) {
auto it = std::find(_readOnlyProfiles.begin(), _readOnlyProfiles.end(), profileSave);
return !(it == _readOnlyProfiles.end());
}
void ProfileEdit::approved() {
QString profileName = _profileEdit->text();
if ((profileName.length() > 0) && !isReadOnly(profileName.toStdString())) {
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 {
//QString formatText = "<font color='red'>";
//formatText += ui->label_profile->text();
//formatText += "</font>";
//ui->label_profile->setText(formatText);
QString errorLabel = "<font color='red'>";
errorLabel += "This is a read-only profile. Click 'duplicate' or rename & save.";
errorLabel += "</font>";
_errorMsg->setText(errorLabel);
_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)
void ProfileEdit::keyPressEvent(QKeyEvent* evt) {
if (evt->key() == Qt::Key_Enter || evt->key() == Qt::Key_Return) {
return;
}
QDialog::keyPressEvent(evt);
}

View File

@@ -24,6 +24,7 @@
#include "profile/propertiesdialog.h"
#include "profile/line.h"
#include <QComboBox>
#include <QDialogButtonBox>
#include <QEvent>
@@ -35,21 +36,28 @@
#include <QVBoxLayout>
#include <iostream>
using namespace openspace;
namespace {
const openspace::Profile::Property kBlank {
openspace::Profile::Property::SetType::SetPropertyValue,
const Profile::Property Blank {
Profile::Property::SetType::SetPropertyValueSingle,
"",
""
};
} // namespace
PropertiesDialog::PropertiesDialog(openspace::Profile& profile, QWidget *parent)
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;
@@ -82,18 +90,13 @@ PropertiesDialog::PropertiesDialog(openspace::Profile& profile, QWidget *parent)
layout->addLayout(box);
}
{
QFrame* line = new QFrame;
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
layout->addWidget(line);
}
layout->addWidget(new Line);
{
_commandLabel = new QLabel("Property Set Command");
layout->addWidget(_commandLabel);
_commandCombo = new QComboBox;
_commandCombo->addItems({ "SetPropertyValue", "SetPropertyValueSingle" });
_commandCombo->addItems({ "SetPropertyValueSingle", "SetPropertyValue" });
layout->addWidget(_commandCombo);
_propertyLabel = new QLabel("Property");
@@ -128,6 +131,7 @@ PropertiesDialog::PropertiesDialog(openspace::Profile& profile, QWidget *parent)
layout->addLayout(box);
}
}
layout->addWidget(new Line);
{
QBoxLayout* footerLayout = new QHBoxLayout;
@@ -150,16 +154,14 @@ PropertiesDialog::PropertiesDialog(openspace::Profile& profile, QWidget *parent)
footerLayout->addWidget(_buttonBox);
layout->addLayout(footerLayout);
}
transitionFromEditMode();
}
QString PropertiesDialog::createOneLineSummary(openspace::Profile::Property p) {
QString PropertiesDialog::createOneLineSummary(Profile::Property p) {
QString summary = QString::fromStdString(p.name);
summary += " = ";
summary += QString::fromStdString(p.value);
summary += " (SetPropertyValue";
if (p.setType == openspace::Profile::Property::SetType::SetPropertyValueSingle) {
if (p.setType == Profile::Property::SetType::SetPropertyValueSingle) {
summary += "Single";
}
summary += ")";
@@ -171,8 +173,8 @@ void PropertiesDialog::listItemSelected() {
int index = _list->row(item);
if (_data.size() > 0) {
openspace::Profile::Property& p = _data[index];
if (p.setType == openspace::Profile::Property::SetType::SetPropertyValue) {
Profile::Property& p = _data[index];
if (p.setType == Profile::Property::SetType::SetPropertyValueSingle) {
_commandCombo->setCurrentIndex(0);
}
else {
@@ -195,20 +197,20 @@ bool PropertiesDialog::isLineEmpty(int index) {
return isEmpty;
}
void PropertiesDialog::listItemAdded(void) {
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.
// 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) = kBlank;
_data.at(0) = Blank;
_list->item(0)->setText(" (Enter details below & click 'Save')");
_list->setCurrentRow(0);
transitionToEditMode();
}
else {
_data.push_back(kBlank);
_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);
@@ -222,7 +224,7 @@ void PropertiesDialog::listItemAdded(void) {
_editModeNewItem = true;
}
void PropertiesDialog::listItemSave(void) {
void PropertiesDialog::listItemSave() {
if (!areRequiredFormsFilled()) {
return;
}
@@ -232,12 +234,10 @@ void PropertiesDialog::listItemSave(void) {
if ( _data.size() > 0) {
if (_commandCombo->currentIndex() == 0) {
_data[index].setType
= openspace::Profile::Property::SetType::SetPropertyValue;
_data[index].setType = Profile::Property::SetType::SetPropertyValueSingle;
}
else {
_data[index].setType
= openspace::Profile::Property::SetType::SetPropertyValueSingle;
_data[index].setType = Profile::Property::SetType::SetPropertyValue;
}
_data[index].name = _propertyEdit->text().toStdString();
_data[index].value = _valueEdit->text().toStdString();
@@ -265,7 +265,7 @@ bool PropertiesDialog::areRequiredFormsFilled() {
return requiredFormsFilled;
}
void PropertiesDialog::listItemCancelSave(void) {
void PropertiesDialog::listItemCancelSave() {
listItemSelected();
transitionFromEditMode();
if (_editModeNewItem) {
@@ -278,13 +278,13 @@ void PropertiesDialog::listItemCancelSave(void) {
_editModeNewItem = false;
}
void PropertiesDialog::listItemRemove(void) {
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) = kBlank;
_data.at(0) = Blank;
_list->item(0)->setText("");
}
else {
@@ -301,7 +301,7 @@ void PropertiesDialog::listItemRemove(void) {
transitionFromEditMode();
}
void PropertiesDialog::transitionToEditMode(void) {
void PropertiesDialog::transitionToEditMode() {
_list->setDisabled(true);
_addButton->setDisabled(true);
_removeButton->setDisabled(true);
@@ -316,7 +316,7 @@ void PropertiesDialog::transitionToEditMode(void) {
_errorMsg->setText("");
}
void PropertiesDialog::transitionFromEditMode(void) {
void PropertiesDialog::transitionFromEditMode() {
_list->setDisabled(false);
_addButton->setDisabled(false);
_removeButton->setDisabled(false);

View File

@@ -24,6 +24,7 @@
#include "profile/timedialog.h"
#include "profile/line.h"
#include <QComboBox>
#include <QDateTimeEdit>
#include <QDialogButtonBox>
@@ -41,9 +42,32 @@ TimeDialog::TimeDialog(openspace::Profile& profile, QWidget* 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;
@@ -71,12 +95,7 @@ TimeDialog::TimeDialog(openspace::Profile& profile, QWidget* parent)
);
layout->addWidget(_relativeEdit);
}
{
QFrame* line = new QFrame;
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
layout->addWidget(line);
}
layout->addWidget(new Line);
{
QDialogButtonBox* buttons = new QDialogButtonBox;
buttons->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel);
@@ -85,29 +104,6 @@ TimeDialog::TimeDialog(openspace::Profile& profile, QWidget* parent)
QObject::connect(buttons, &QDialogButtonBox::rejected, this, &TimeDialog::reject);
layout->addWidget(buttons);
}
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::enableAccordingToType(int idx) {

View File

@@ -927,29 +927,29 @@ void setSgctDelegateFunctions() {
};
}
void analyzeCommandLineArgsForSettings(int& argc, char** argv, bool& sgct, bool& profile,
std::string& sgctFunctionName)
void checkCommandLineForSettings(int& argc, char** argv, bool& hasSGCT, bool& hasProfile,
std::string& sgctFunctionName)
{
bool haveCliConfigFlag = false;
for (int i = 1; i < argc; ++i) {
std::string a = argv[i];
if (a.compare("-c") == 0 || a.compare("--config") == 0) {
haveCliConfigFlag = true;
}
else if (haveCliConfigFlag) {
a.erase(remove_if(a.begin(), a.end(), isspace), a.end());
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=";
size_t findSgct = a.find(sgctAssignment);
size_t findBracket = a.find("}");
const size_t findSgct = p.find(sgctAssignment);
const size_t findBracket = p.find("}");
if (findSgct != std::string::npos) {
if (findBracket != std::string::npos) {
sgctFunctionName = a.substr(findSgct + sgctAssignment.length(),
findBracket - findSgct);
sgctFunctionName = arg.substr(
findSgct + sgctAssignment.length(),
findBracket - findSgct
);
}
sgct = true;
hasSGCT = true;
}
if (a.find("Profile=") != std::string::npos) {
profile = true;
if (p.find("Profile=") != std::string::npos) {
hasProfile = true;
}
}
}
@@ -959,40 +959,35 @@ std::string setWindowConfigPresetForGui(const std::string labelFromCfgFile,
const std::string xmlExt, bool haveCliSGCTConfig,
const std::string& sgctFunctionName)
{
const std::string labelFromCli = " (from CLI)";
configuration::Configuration& config = global::configuration;
std::string preset;
bool sgctConfigFileSpecifiedByLuaFunction
= (global::configuration.sgctConfigNameInitialized.length() > 0);
bool sgctConfigFileSpecifiedByLuaFunction = !config.sgctConfigNameInitialized.empty();
if (haveCliSGCTConfig) {
preset = (sgctFunctionName.length() > 0) ? sgctFunctionName
: global::configuration.windowConfiguration;
preset += labelFromCli;
preset = sgctFunctionName.empty() ? config.windowConfiguration : sgctFunctionName;
preset += " (from CLI)";
}
else if (sgctConfigFileSpecifiedByLuaFunction) {
preset = global::configuration.sgctConfigNameInitialized;
preset += labelFromCfgFile;
preset = config.sgctConfigNameInitialized + labelFromCfgFile;
}
else {
preset = global::configuration.windowConfiguration;
if (preset.find("/") != std::string::npos) {
preset.erase(0, preset.find_last_of("/") + 1);
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())
.compare(xmlExt) == 0)
{
preset = preset.substr(0, preset.length()
- xmlExt.length());
if (preset.substr(preset.length() - xmlExt.length()) == xmlExt) {
preset = preset.substr(0, preset.length() - xmlExt.length());
}
}
}
return preset;
}
std::string getSelectedSgctProfileFromLauncher(LauncherWindow& lw, bool hasCliSGCTConfig,
std::string windowConfiguration,
const std::string& labelFromCfgFile,
const std::string& xmlExt)
std::string selectedSgctProfileFromLauncher(LauncherWindow& lw, bool hasCliSGCTConfig,
std::string windowConfiguration,
const std::string& labelFromCfgFile,
const std::string& xmlExt)
{
std::string config = windowConfiguration;
if (!hasCliSGCTConfig) {
@@ -1152,39 +1147,40 @@ int main(int argc, char** argv) {
global::openSpaceEngine.registerPathTokens();
bool haveCliSGCTConfig = false;
bool haveCliProfile = false;
std::string sgctFunctionName;
analyzeCommandLineArgsForSettings(argc, argv, haveCliSGCTConfig, haveCliProfile,
sgctFunctionName);
//Call profile GUI
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,
haveCliSGCTConfig, sgctFunctionName);
std::string windowCfgPreset = setWindowConfigPresetForGui(
labelFromCfgFile,
xmlExt,
hasSGCTConfig,
sgctFunctionName
);
std::shared_ptr<QApplication> qaobj;
std::shared_ptr<LauncherWindow> launchwin;
bool skipLauncherSinceProfileAndWindowAreConfiguredInCli =
(haveCliProfile && haveCliSGCTConfig) || global::configuration.bypassLauncher;
if (!skipLauncherSinceProfileAndWindowAreConfiguredInCli) {
bool skipLauncher =
(hasProfile && hasSGCTConfig) || global::configuration.bypassLauncher;
if (!skipLauncher) {
int qac = 0;
qaobj.reset(new QApplication(qac, nullptr));
launchwin.reset(new LauncherWindow(absPath("${BASE}"), !haveCliProfile,
global::configuration, !haveCliSGCTConfig, windowCfgPreset, nullptr));
launchwin->show();
qaobj->exec();
QApplication app(qac, nullptr);
LauncherWindow win(!hasProfile,
global::configuration, !hasSGCTConfig, windowCfgPreset, nullptr);
win.show();
app.exec();
if (!launchwin->wasLaunchSelected()) {
exit(EXIT_FAILURE);
if (!win.wasLaunchSelected()) {
exit(EXIT_SUCCESS);
}
global::configuration.profile = launchwin->selectedProfile();
windowConfiguration = getSelectedSgctProfileFromLauncher(
*launchwin,
haveCliSGCTConfig,
global::configuration.profile = win.selectedProfile();
windowConfiguration = selectedSgctProfileFromLauncher(
win,
hasSGCTConfig,
windowConfiguration,
labelFromCfgFile,
xmlExt
@@ -1305,13 +1301,6 @@ int main(int argc, char** argv) {
}
#endif // OPENSPACE_HAS_SPOUT
if (launchwin != nullptr) {
launchwin->close();
}
if (qaobj != nullptr) {
qaobj->quit();
}
ghoul::deinitialize();
exit(EXIT_SUCCESS);
}

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

@@ -16,7 +16,6 @@ asset.require('scene/solarsystem/planets/mars/moons/deimos')
asset.require('scene/solarsystem/dwarf_planets/pluto/system')
asset.require('scene/solarsystem/dwarf_planets/pluto/default_layers')
asset.require('scene/solarsystem/dwarf_planets/pluto/charon/default_layers')
asset.require('scene/solarsystem/missions/voyagerpioneer/voyager1_2__pioneer10_11')
asset.require('scene/milkyway/milkyway/volume')
asset.require('scene/milkyway/constellations/constellation_art')
asset.require('scene/milkyway/constellations/constellation_keybinds')

View File

@@ -3,7 +3,7 @@ asset.require('./static_server')
local guiCustomization = asset.require('customization/gui')
-- Select which commit hashes to use for the frontend and backend
local frontendHash = "6b5ac33a77fff6f46088c1fffdaf04d59ec5bb5f"
local frontendHash = "5d9b8d52e43260c71f641e73e44e4c90bc9f5d6a"
local dataProvider = "data.openspaceproject.com/files/webgui"
local frontend = asset.syncedResource({
@@ -40,8 +40,12 @@ asset.onInitialize(function ()
-- The GUI contains date and simulation increment,
-- so let's remove these from the dashboard.
if openspace.getPropertyValue('Modules.CefWebGui.Visible') then
openspace.setPropertyValueSingle('Dashboard.Date.Enabled', false)
openspace.setPropertyValueSingle('Dashboard.SimulationIncrement.Enabled', false)
if openspace.hasProperty('Dashboard.Date.Enabled') then
openspace.setPropertyValueSingle('Dashboard.Date.Enabled', false)
end
if openspace.hasProperty('Dashboard.SimulationIncrement.Enabled') then
openspace.setPropertyValueSingle('Dashboard.SimulationIncrement.Enabled', false)
end
end
end)

View File

@@ -8,18 +8,20 @@
"camera": {
"aim": "",
"anchor": "NewHorizons",
"frame": "",
"frame": "Root",
"pitch": 0.036092,
"position": {
"x": -65.72656,
"y": -72.39404,
"z": -21.1189
"x": -111.9326,
"y": -35.20605,
"z": 33.42737
},
"type": "setNavigationState",
"up": {
"x": 0.102164,
"y": -0.362945,
"z": 0.926193
}
"x": -0.188963,
"y": 0.921904,
"z": 0.338209
},
"yaw": 0.0563239
},
"delta_times": [
1.0,

View File

@@ -98,7 +98,7 @@
"is_local": false,
"key": "O",
"name": "Toggle Philae trail",
"script": "openspace.setPropertyValueSingle(Scene.PhilaeTrail.Renderable.Enabled', not openspace.getPropertyValue(Scene.PhilaeTrail.Renderable.Enabled'));"
"script": "openspace.setPropertyValueSingle('Scene.PhilaeTrail.Renderable.Enabled', not openspace.getPropertyValue('Scene.PhilaeTrail.Renderable.Enabled'));"
},
{
"documentation": "Enables or disables the image projection on 67P.",
@@ -106,7 +106,7 @@
"is_local": false,
"key": "P",
"name": "Toggle 67P projection",
"script": "openspace.setPropertyValueSingle(Scene.67P.Renderable.ProjectionComponent.PerformProjection', not openspace.getPropertyValue(Scene.67P.Renderable.ProjectionComponent.PerformProjection'));"
"script": "openspace.setPropertyValueSingle('Scene.67P.Renderable.ProjectionComponent.PerformProjection', not openspace.getPropertyValue('Scene.67P.Renderable.ProjectionComponent.PerformProjection'));"
}
],
"mark_nodes": [

View File

@@ -26,6 +26,8 @@
#define __OPENSPACE_CORE___MESSAGESTRUCTURES___H__
#include <ghoul/glm.h>
#include <ghoul/logging/logmanager.h>
#include <fmt/format.h>
#include <algorithm>
#include <cstring>
#include <fstream>
@@ -373,17 +375,31 @@ struct ScriptMessage {
double _timestamp = 0.0;
void serialize(std::vector<char>& buffer) const {
size_t strLen = _script.size();
size_t writeSize_bytes = sizeof(size_t);
uint32_t strLen = static_cast<uint32_t>(_script.size());
unsigned char const *p = reinterpret_cast<unsigned char const*>(&strLen);
buffer.insert(buffer.end(), p, p + writeSize_bytes);
const char* p = reinterpret_cast<const char*>(&strLen);
buffer.insert(buffer.end(), p, p + sizeof(uint32_t));
buffer.insert(buffer.end(), _script.begin(), _script.end());
};
void deserialize(const std::vector<char>& buffer) {
_script.assign(buffer.begin(), buffer.end());
const char* p = buffer.data();
const uint32_t len = *reinterpret_cast<const uint32_t*>(p);
if (buffer.size() != (sizeof(uint32_t) + len)) {
LERRORC(
"ParallelPeer",
fmt::format(
"Received buffer with wrong size. Expected {} got {}",
len, buffer.size()
)
);
return;
}
// We can skip over the first uint32_t that encoded the length
_script.assign(buffer.begin() + sizeof(uint32_t), buffer.end());
};
void write(std::ostream* out) const {

View File

@@ -50,9 +50,6 @@ public:
private:
struct Peer {
//Peer(size_t id_, std::string name_, ParallelConnection parallelConnection_,
//ParallelConnection::Status status_, std::thread )
size_t id;
std::string name;
ParallelConnection parallelConnection;
@@ -87,7 +84,6 @@ private:
void handleData(const Peer& peer, std::vector<char> data);
void handleHostshipRequest(std::shared_ptr<Peer> peer, std::vector<char> message);
void handleHostshipResignation(Peer& peer);
void handleDisconnection(std::shared_ptr<Peer> peer);
void handleNewPeers();
void eventLoop();

View File

@@ -404,7 +404,6 @@ void DashboardItemAngle::render(glm::vec2& penPosition) {
std::fill(_buffer.begin(), _buffer.end(), 0);
if (glm::length(a) == 0.0 || glm::length(b) == 0) {
penPosition.y -= _font->height();
char* end = fmt::format_to(
_buffer.data(),
"Could not compute angle at {} between {} and {}",
@@ -412,13 +411,13 @@ void DashboardItemAngle::render(glm::vec2& penPosition) {
);
std::string_view text = std::string_view(_buffer.data(), end - _buffer.data());
RenderFont(*_font, penPosition, text);
penPosition.y -= _font->height();
}
else {
const double angle = glm::degrees(
glm::acos(glm::dot(a, b) / (glm::length(a) * glm::length(b)))
);
penPosition.y -= _font->height();
char* end = fmt::format_to(
_buffer.data(),
"Angle at {} between {} and {}: {} degrees",
@@ -426,6 +425,7 @@ void DashboardItemAngle::render(glm::vec2& penPosition) {
);
std::string_view text = std::string_view(_buffer.data(), end - _buffer.data());
RenderFont(*_font, penPosition, text);
penPosition.y -= _font->height();
}
}

View File

@@ -113,12 +113,12 @@ DashboardItemDate::DashboardItemDate(const ghoul::Dictionary& dictionary)
void DashboardItemDate::render(glm::vec2& penPosition) {
ZoneScoped
penPosition.y -= _font->height();
RenderFont(
*_font,
penPosition,
fmt::format("Date: {} UTC", global::timeManager.time().UTC())
);
penPosition.y -= _font->height();
}
glm::vec2 DashboardItemDate::size() const {

View File

@@ -444,7 +444,6 @@ void DashboardItemDistance::render(glm::vec2& penPosition) {
dist = { convertedD, nameForDistanceUnit(unit, convertedD != 1.0) };
}
penPosition.y -= _font->height();
std::fill(_buffer.begin(), _buffer.end(), 0);
char* end = fmt::format_to(
_buffer.data(),
@@ -454,6 +453,7 @@ void DashboardItemDistance::render(glm::vec2& penPosition) {
std::string_view text = std::string_view(_buffer.data(), end - _buffer.data());
RenderFont(*_font, penPosition, text);
penPosition.y -= _font->height();
}
glm::vec2 DashboardItemDistance::size() const {

View File

@@ -149,6 +149,21 @@ namespace {
throw ghoul::MissingCaseException();
}
}
[[ nodiscard ]] int nLines(
openspace::DashboardItemFramerate::FrametimeType frametimeType)
{
using FrametimeType = openspace::DashboardItemFramerate::FrametimeType;
switch (frametimeType) {
case FrametimeType::DtTimeAvg: return 1;
case FrametimeType::DtTimeExtremes: return 2;
case FrametimeType::DtStandardDeviation: return 1;
case FrametimeType::DtCoefficientOfVariation: return 1;
case FrametimeType::FPS: return 1;
case FrametimeType::FPSAvg: return 1;
default: throw ghoul::MissingCaseException();
}
}
} // namespace
namespace openspace {
@@ -309,13 +324,12 @@ void DashboardItemFramerate::render(glm::vec2& penPosition) {
int nLines = output.empty() ? 0 :
static_cast<int>((std::count(output.begin(), output.end(), '\n') + 1));
penPosition.y -= _font->height() * static_cast<float>(nLines);
ghoul::fontrendering::FontRenderer::defaultRenderer().render(
*_font,
penPosition,
output
);
penPosition.y -= _font->height() * static_cast<float>(nLines);
}
glm::vec2 DashboardItemFramerate::size() const {

View File

@@ -209,7 +209,6 @@ void DashboardItemMission::render(glm::vec2& penPosition) {
1.0 - remaining / phase->timeRange().duration()
);
const std::string progress = progressToStr(25, t);
penPosition.y -= _font->height();
RenderFont(
*_font,
penPosition,
@@ -219,16 +218,17 @@ void DashboardItemMission::render(glm::vec2& penPosition) {
),
currentMissionColor
);
penPosition.y -= _font->height();
}
else {
if (!phase->name().empty()) {
penPosition.y -= _font->height();
RenderFont(
*_font,
penPosition,
phase->name(),
nonCurrentMissionColor
);
penPosition.y -= _font->height();
}
}
penPosition.x -= depth * PixelIndentation;

View File

@@ -121,6 +121,8 @@ void DashboardItemParallelConnection::render(glm::vec2& penPosition) {
const size_t nConnections = global::parallelPeer.nConnections();
const std::string& hostName = global::parallelPeer.hostName();
int nLines = 1;
std::string connectionInfo;
int nClients = static_cast<int>(nConnections);
if (status == ParallelConnection::Status::Host) {
@@ -158,11 +160,13 @@ void DashboardItemParallelConnection::render(glm::vec2& penPosition) {
else if (nClients == 1) {
connectionInfo += "You are the only client";
}
nLines = 2;
}
if (!connectionInfo.empty()) {
penPosition.y -= _font->height();
RenderFont(*_font, penPosition, connectionInfo);
penPosition.y -= _font->height() * nLines;
}
}

View File

@@ -163,8 +163,8 @@ void DashboardItemPropertyValue::render(glm::vec2& penPosition) {
std::string value;
_property->getStringValue(value);
penPosition.y -= _font->height();
RenderFont(*_font, penPosition, fmt::format(_displayString.value(), value));
penPosition.y -= _font->height();
}
}

View File

@@ -203,7 +203,6 @@ void DashboardItemSimulationIncrement::render(glm::vec2& penPosition) {
std::string pauseText = global::timeManager.isPaused() ? " (Paused)" : "";
penPosition.y -= _font->height();
if (targetDt != currentDt && !global::timeManager.isPaused()) {
// We are in the middle of a transition
RenderFont(
@@ -227,6 +226,7 @@ void DashboardItemSimulationIncrement::render(glm::vec2& penPosition) {
)
);
}
penPosition.y -= _font->height();
}
glm::vec2 DashboardItemSimulationIncrement::size() const {

View File

@@ -208,7 +208,6 @@ void DashboardItemVelocity::render(glm::vec2& penPosition) {
dist = { convertedD, nameForDistanceUnit(unit, convertedD != 1.0) };
}
penPosition.y -= _font->height();
RenderFont(
*_font,
penPosition,
@@ -216,6 +215,7 @@ void DashboardItemVelocity::render(glm::vec2& penPosition) {
"Camera velocity: {} {}/s", dist.first, dist.second
)
);
penPosition.y -= _font->height();
_prevPosition = currentPos;
}

View File

@@ -120,24 +120,30 @@ void RenderablePlaneImageOnline::update(const UpdateData&) {
return;
}
std::unique_ptr<ghoul::opengl::Texture> texture =
ghoul::io::TextureReader::ref().loadTexture(
reinterpret_cast<void*>(imageFile.buffer),
imageFile.size,
imageFile.format
);
try {
std::unique_ptr<ghoul::opengl::Texture> texture =
ghoul::io::TextureReader::ref().loadTexture(
reinterpret_cast<void*>(imageFile.buffer),
imageFile.size,
imageFile.format
);
if (texture) {
// Images don't need to start on 4-byte boundaries, for example if the
// image is only RGB
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
if (texture) {
// Images don't need to start on 4-byte boundaries, for example if the
// image is only RGB
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
texture->uploadTexture();
texture->setFilter(ghoul::opengl::Texture::FilterMode::LinearMipMap);
texture->purgeFromRAM();
texture->uploadTexture();
texture->setFilter(ghoul::opengl::Texture::FilterMode::LinearMipMap);
texture->purgeFromRAM();
_texture = std::move(texture);
_texture = std::move(texture);
_textureIsDirty = false;
}
}
catch (const ghoul::io::TextureReader::InvalidLoadException& e) {
_textureIsDirty = false;
LERRORC(e.component, e.message);
}
}
}

View File

@@ -129,25 +129,31 @@ void ScreenSpaceImageOnline::update() {
return;
}
std::unique_ptr<ghoul::opengl::Texture> texture =
ghoul::io::TextureReader::ref().loadTexture(
reinterpret_cast<void*>(imageFile.buffer),
imageFile.size,
imageFile.format
);
try {
std::unique_ptr<ghoul::opengl::Texture> texture =
ghoul::io::TextureReader::ref().loadTexture(
reinterpret_cast<void*>(imageFile.buffer),
imageFile.size,
imageFile.format
);
if (texture) {
// Images don't need to start on 4-byte boundaries, for example if the
// image is only RGB
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
if (texture) {
// Images don't need to start on 4-byte boundaries, for example if the
// image is only RGB
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
texture->uploadTexture();
texture->setFilter(ghoul::opengl::Texture::FilterMode::LinearMipMap);
texture->purgeFromRAM();
texture->uploadTexture();
texture->setFilter(ghoul::opengl::Texture::FilterMode::LinearMipMap);
texture->purgeFromRAM();
_texture = std::move(texture);
_objectSize = _texture->dimensions();
_texture = std::move(texture);
_objectSize = _texture->dimensions();
_textureIsDirty = false;
}
}
catch (const ghoul::io::TextureReader::InvalidLoadException& e) {
_textureIsDirty = false;
LERRORC(e.component, e.message);
}
}
}

View File

@@ -186,6 +186,12 @@ namespace {
"astronomical objects."
};
constexpr openspace::properties::Property::PropertyInfo OptionColorRangeInfo = {
"OptionColorRange",
"Option Color Range",
"This value changes the range of values to be mapped with the current color map."
};
constexpr openspace::properties::Property::PropertyInfo SizeOptionInfo = {
"SizeOption",
"Size Option Variable",
@@ -251,6 +257,19 @@ namespace {
"Enable pixel size control.",
"Enable pixel size control for rectangular projections."
};
constexpr openspace::properties::Property::PropertyInfo UseLinearFiltering = {
"UseLinearFiltering",
"Use Linear Filtering",
"Determines whether the provided color map should be sampled nearest neighbor "
"(=off) or linearly (=on"
};
constexpr openspace::properties::Property::PropertyInfo SetRangeFromData = {
"SetRangeFromData",
"Set Data Range from Data",
"Set the data range based on the available data"
};
} // namespace
namespace openspace {
@@ -416,6 +435,12 @@ documentation::Documentation RenderableBillboardsCloud::Documentation() {
new BoolVerifier,
Optional::Yes,
PixelSizeControlInfo.description
},
{
UseLinearFiltering.identifier,
new BoolVerifier,
Optional::Yes,
UseLinearFiltering.description
}
}
};
@@ -435,6 +460,8 @@ RenderableBillboardsCloud::RenderableBillboardsCloud(const ghoul::Dictionary& di
, _drawLabels(DrawLabelInfo, false)
, _pixelSizeControl(PixelSizeControlInfo, false)
, _colorOption(ColorOptionInfo, properties::OptionProperty::DisplayType::Dropdown)
, _optionColorRangeData(OptionColorRangeInfo, glm::vec2(0.f))
, _datavarSizeOption(
SizeOptionInfo,
properties::OptionProperty::DisplayType::Dropdown
@@ -451,6 +478,8 @@ RenderableBillboardsCloud::RenderableBillboardsCloud(const ghoul::Dictionary& di
, _correctionSizeEndDistance(CorrectionSizeEndDistanceInfo, 17.f, 12.f, 25.f)
, _correctionSizeFactor(CorrectionSizeFactorInfo, 8.f, 0.f, 20.f)
, _renderOption(RenderOptionInfo, properties::OptionProperty::DisplayType::Dropdown)
, _setRangeFromData(SetRangeFromData)
, _useLinearFiltering(UseLinearFiltering, false)
{
documentation::testSpecificationAndThrow(
Documentation(),
@@ -473,7 +502,7 @@ RenderableBillboardsCloud::RenderableBillboardsCloud(const ghoul::Dictionary& di
_renderOption.addOption(RenderOptionViewDirection, "Camera View Direction");
_renderOption.addOption(RenderOptionPositionNormal, "Camera Position Normal");
_renderOption = RenderOptionPositionNormal;
_renderOption = RenderOptionViewDirection;
if (dictionary.hasKeyAndValue<std::string>(RenderOptionInfo.identifier)) {
const std::string o = dictionary.value<std::string>(RenderOptionInfo.identifier);
@@ -548,6 +577,8 @@ RenderableBillboardsCloud::RenderableBillboardsCloud(const ghoul::Dictionary& di
}
_colorOption.onChange([&]() {
_dataIsDirty = true;
const glm::vec2 colorRange = _colorRangeData[_colorOption.value()];
_optionColorRangeData = colorRange;
_colorOptionString = _optionConversionMap[_colorOption.value()];
});
addProperty(_colorOption);
@@ -561,7 +592,14 @@ RenderableBillboardsCloud::RenderableBillboardsCloud(const ghoul::Dictionary& di
rangeDataDict.value<glm::vec2>(std::to_string(i + 1))
);
}
_optionColorRangeData = _colorRangeData[_colorRangeData.size() - 1];
}
_optionColorRangeData.onChange([&]() {
const glm::vec2 colorRange = _optionColorRangeData;
_colorRangeData[_colorOption.value()] = colorRange;
_dataIsDirty = true;
});
addProperty(_optionColorRangeData);
if (dictionary.hasKey(ExactColorMapInfo.identifier)) {
_isColorMapExact = dictionary.value<bool>(ExactColorMapInfo.identifier);
@@ -696,6 +734,28 @@ RenderableBillboardsCloud::RenderableBillboardsCloud(const ghoul::Dictionary& di
_pixelSizeControl = dictionary.value<bool>(PixelSizeControlInfo.identifier);
addProperty(_pixelSizeControl);
}
_setRangeFromData.onChange([this]() {
const int colorMapInUse =
_hasColorMapFile ? _variableDataPositionMap[_colorOptionString] : 0;
float minValue = std::numeric_limits<float>::max();
float maxValue = std::numeric_limits<float>::min();
for (size_t i = 0; i < _fullData.size(); i += _nValuesPerAstronomicalObject) {
float colorIdx = _fullData[i + 3 + colorMapInUse];
maxValue = colorIdx >= maxValue ? colorIdx : maxValue;
minValue = colorIdx < minValue ? colorIdx : minValue;
}
_optionColorRangeData = glm::vec2(minValue, maxValue);
});
addProperty(_setRangeFromData);
if (dictionary.hasKey(UseLinearFiltering.identifier)) {
_useLinearFiltering = dictionary.value<bool>(UseLinearFiltering.identifier);
}
_useLinearFiltering.onChange([&]() { _dataIsDirty = true; });
addProperty(_useLinearFiltering);
}
bool RenderableBillboardsCloud::isReady() const {
@@ -1651,11 +1711,9 @@ void RenderableBillboardsCloud::createDataSlice() {
_slicedData.push_back(position[j]);
biggestCoord = biggestCoord < position[j] ? position[j] : biggestCoord;
}
// Note: if exact colormap option is not selected, the first color and the
// last color in the colormap file are the outliers colors.
int variableColor = static_cast<int>(_fullData[i + 3 + colorMapInUse]);
int colorIndex = 0;
float variableColor = _fullData[i + 3 + colorMapInUse];
float cmax, cmin;
if (_colorRangeData.empty()) {
@@ -1669,19 +1727,51 @@ void RenderableBillboardsCloud::createDataSlice() {
}
if (_isColorMapExact) {
colorIndex = variableColor + cmin;
int colorIndex = variableColor + cmin;
for (int j = 0; j < 4; ++j) {
_slicedData.push_back(_colorMapData[colorIndex][j]);
}
}
else {
float ncmap = static_cast<float>(_colorMapData.size());
float normalization = ((cmax != cmin) && (ncmap > 2)) ?
(ncmap - 2) / (cmax - cmin) : 0;
colorIndex = (variableColor - cmin) * normalization + 1;
colorIndex = colorIndex < 0 ? 0 : colorIndex;
colorIndex = colorIndex >= ncmap ? ncmap - 1 : colorIndex;
}
if (_useLinearFiltering) {
const float value = variableColor;
for (int j = 0; j < 4; ++j) {
_slicedData.push_back(_colorMapData[colorIndex][j]);
float valueT = (value - cmin) / (cmax - cmin); // in [0, 1)
valueT = std::clamp(valueT, 0.f, 1.f);
const float idx = valueT * (_colorMapData.size() - 1);
const int floorIdx = static_cast<int>(std::floor(idx));
const int ceilIdx = static_cast<int>(std::ceil(idx));
const glm::vec4 floorColor = _colorMapData[floorIdx];
const glm::vec4 ceilColor = _colorMapData[ceilIdx];
if (floorColor != ceilColor) {
const glm::vec4 c = floorColor + idx * (ceilColor - floorColor);
_slicedData.push_back(c.r);
_slicedData.push_back(c.g);
_slicedData.push_back(c.b);
_slicedData.push_back(c.a);
}
else {
_slicedData.push_back(floorColor.r);
_slicedData.push_back(floorColor.g);
_slicedData.push_back(floorColor.b);
_slicedData.push_back(floorColor.a);
}
}
else {
float ncmap = static_cast<float>(_colorMapData.size());
float normalization = ((cmax != cmin) && (ncmap > 2)) ?
(ncmap - 2) / (cmax - cmin) : 0;
int colorIndex = (variableColor - cmin) * normalization + 1;
colorIndex = colorIndex < 0 ? 0 : colorIndex;
colorIndex = colorIndex >= ncmap ? ncmap - 1 : colorIndex;
for (int j = 0; j < 4; ++j) {
_slicedData.push_back(_colorMapData[colorIndex][j]);
}
}
}
if (_hasDatavarSize) {

View File

@@ -29,6 +29,7 @@
#include <openspace/properties/optionproperty.h>
#include <openspace/properties/stringproperty.h>
#include <openspace/properties/triggerproperty.h>
#include <openspace/properties/scalar/boolproperty.h>
#include <openspace/properties/scalar/floatproperty.h>
#include <openspace/properties/vector/vec2property.h>
@@ -123,6 +124,7 @@ private:
properties::BoolProperty _drawLabels;
properties::BoolProperty _pixelSizeControl;
properties::OptionProperty _colorOption;
properties::Vec2Property _optionColorRangeData;
properties::OptionProperty _datavarSizeOption;
properties::Vec2Property _fadeInDistance;
properties::BoolProperty _disableFadeInDistance;
@@ -130,6 +132,8 @@ private:
properties::FloatProperty _billboardMinSize;
properties::FloatProperty _correctionSizeEndDistance;
properties::FloatProperty _correctionSizeFactor;
properties::BoolProperty _useLinearFiltering;
properties::TriggerProperty _setRangeFromData;
// DEBUG:
properties::OptionProperty _renderOption;

View File

@@ -299,7 +299,7 @@ documentation::Documentation RenderablePlanesCloud::Documentation() {
RenderablePlanesCloud::RenderablePlanesCloud(const ghoul::Dictionary& dictionary)
: Renderable(dictionary)
, _scaleFactor(ScaleFactorInfo, 1.f, 0.f, 10000.f)
, _scaleFactor(ScaleFactorInfo, 1.f, 0.f, 100.f)
, _textColor(TextColorInfo, glm::vec3(1.f), glm::vec3(0.f), glm::vec3(1.f))
, _textOpacity(TextOpacityInfo, 1.f, 0.f, 1.f)
, _textSize(TextSizeInfo, 8.0, 0.5, 24.0)

View File

@@ -24,6 +24,7 @@
#include <modules/exoplanets/exoplanetshelper.h>
#include <openspace/util/spicemanager.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/fmt.h>
#include <ghoul/logging/logmanager.h>
@@ -81,6 +82,17 @@ std::string_view csvStarName(std::string_view name) {
return name;
}
bool hasSufficientData(const Exoplanet& p) {
bool invalidPos = std::isnan(p.positionX)
|| std::isnan(p.positionY)
|| std::isnan(p.positionZ);
bool hasSemiMajorAxis = !std::isnan(p.a);
bool hasOrbitalPeriod = !std::isnan(p.per);
return !invalidPos && hasSemiMajorAxis && hasOrbitalPeriod;
}
std::string starColor(float bv) {
std::ifstream colorMap(absPath(BvColormapPath), std::ios::in);
@@ -126,49 +138,54 @@ glm::dmat4 computeOrbitPlaneRotationMatrix(float i, float bigom, float omega) {
return orbitPlaneRotation;
}
// Rotate the original coordinate system (where x is pointing to First Point of Aries)
// so that x is pointing from star to the sun.
// Modified from "http://www.opengl-tutorial.org/intermediate-tutorials/
// tutorial-17-quaternions/ #how-do-i-find-the-rotation-between-2-vectors"
glm::dmat3 exoplanetSystemRotation(glm::dvec3 start, glm::dvec3 end) {
glm::quat rotationQuat;
glm::dvec3 rotationAxis;
const float cosTheta = static_cast<float>(glm::dot(start, end));
constexpr float Epsilon = 1E-3f;
glm::dmat3 computeSystemRotation(glm::dvec3 starPosition) {
const glm::dvec3 sunPosition = glm::dvec3(0.0, 0.0, 0.0);
const glm::dvec3 starToSunVec = glm::normalize(sunPosition - starPosition);
const glm::dvec3 galacticNorth = glm::dvec3(0.0, 0.0, 1.0);
if (cosTheta < -1.f + Epsilon) {
// special case when vectors in opposite directions:
// there is no "ideal" rotation axis
// So guess one; any will do as long as it's perpendicular to start vector
rotationAxis = glm::cross(glm::dvec3(0.0, 0.0, 1.0), start);
if (glm::length2(rotationAxis) < 0.01f) {
// bad luck, they were parallel, try again!
rotationAxis = glm::cross(glm::dvec3(1.0, 0.0, 0.0), start);
}
const glm::dmat3 galacticToCelestialMatrix =
SpiceManager::ref().positionTransformMatrix("GALACTIC", "J2000", 0.0);
rotationAxis = glm::normalize(rotationAxis);
rotationQuat = glm::quat(glm::radians(180.f), rotationAxis);
return glm::dmat3(glm::toMat4(rotationQuat));
}
rotationAxis = glm::cross(start, end);
const float s = sqrt((1.f + cosTheta) * 2.f);
const float invs = 1.f / s;
rotationQuat = glm::quat(
s * 0.5f,
static_cast<float>(rotationAxis.x * invs),
static_cast<float>(rotationAxis.y * invs),
static_cast<float>(rotationAxis.z * invs)
const glm::dvec3 celestialNorth = glm::normalize(
galacticToCelestialMatrix * galacticNorth
);
return glm::dmat3(glm::toMat4(rotationQuat));
// Earth's north vector projected onto the skyplane, the plane perpendicular to the
// viewing vector (starToSunVec)
const float celestialAngle = static_cast<float>(glm::dot(
celestialNorth,
starToSunVec
));
glm::dvec3 northProjected = glm::normalize(
celestialNorth - (celestialAngle / glm::length(starToSunVec)) * starToSunVec
);
const glm::dvec3 beta = glm::normalize(glm::cross(starToSunVec, northProjected));
return glm::dmat3(
northProjected.x,
northProjected.y,
northProjected.z,
beta.x,
beta.y,
beta.z,
starToSunVec.x,
starToSunVec.y,
starToSunVec.z
);
}
std::string createIdentifier(std::string name) {
std::replace(name.begin(), name.end(), ' ', '_');
sanitizeNameString(name);
return name;
}
void sanitizeNameString(std::string& s) {
// We want to avoid quotes and apostrophes in names, since they cause problems
// when a string is translated to a script call
s.erase(remove(s.begin(), s.end(), '\"'), s.end());
s.erase(remove(s.begin(), s.end(), '\''), s.end());
}
} // namespace openspace::exoplanets

View File

@@ -72,6 +72,9 @@ std::string_view speckStarName(std::string_view name);
// Convert speck-file specific names to the corresponding name in the csv data file
std::string_view csvStarName(std::string_view name);
// Check if the exoplanet p has sufficient data for visualization
bool hasSufficientData(const Exoplanet& p);
// Compute star color in RGB from b-v color index
std::string starColor(float bv);
@@ -79,11 +82,13 @@ glm::dmat4 computeOrbitPlaneRotationMatrix(float i, float bigom, float omega);
// Rotate the original coordinate system (where x is pointing to First Point of Aries)
// so that x is pointing from star to the sun.
glm::dmat3 exoplanetSystemRotation(glm::dvec3 start, glm::dvec3 end);
glm::dmat3 computeSystemRotation(glm::dvec3 starPosition);
// Create an identifier without whitespaces
std::string createIdentifier(std::string name);
void sanitizeNameString(std::string& s);
} // namespace openspace::exoplanets
#endif // __OPENSPACE_MODULE_EXOPLANETS___EXOPLANETSMODULE___H__

View File

@@ -24,12 +24,10 @@
#include <modules/exoplanets/exoplanetshelper.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/query/query.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/scripting/scriptengine.h>
#include <openspace/util/distanceconstants.h>
#include <openspace/util/spicemanager.h>
#include <openspace/util/timeconversion.h>
#include <openspace/util/timemanager.h>
#include <ghoul/filesystem/filesystem.h>
@@ -37,13 +35,7 @@
#include <ghoul/glm.h>
#include <ghoul/logging/logmanager.h>
#include <ghoul/misc/assert.h>
#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/quaternion.hpp>
#include <glm/gtx/transform.hpp>
#include <cfloat>
#include <cmath>
#include <fstream>
#include <iostream>
#include <sstream>
namespace {
@@ -67,7 +59,11 @@ void createExoplanetSystem(std::string_view starName) {
const std::string starNameSpeck = std::string(speckStarName(starName));
const std::string starIdentifier = createIdentifier(starNameSpeck);
const std::string guiPath = ExoplanetsGuiPath + starNameSpeck;
std::string sanitizedStarName = starNameSpeck;
sanitizeNameString(sanitizedStarName);
const std::string guiPath = ExoplanetsGuiPath + sanitizedStarName;
SceneGraphNode* existingStarNode = sceneGraphNode(starIdentifier);
if (existingStarNode) {
@@ -118,9 +114,18 @@ void createExoplanetSystem(std::string_view starName) {
data.seekg(location);
data.read(reinterpret_cast<char*>(&p), sizeof(Exoplanet));
sanitizeNameString(name);
planetNames.push_back(name);
planetSystem.push_back(p);
found = true;
if (!hasSufficientData(p)) {
LERROR(fmt::format(
"Insufficient data available for visualizion of exoplanet system: '{}'",
starName
));
return;
}
}
}
@@ -132,56 +137,13 @@ void createExoplanetSystem(std::string_view starName) {
return;
}
bool notEnoughData = std::isnan(p.positionX) || std::isnan(p.a) || std::isnan(p.per);
if (notEnoughData) {
LERROR(fmt::format(
"Insufficient data available for representing the exoplanet system: '{}'",
starName
));
return;
}
const glm::dvec3 starPosition = glm::dvec3(
p.positionX * distanceconstants::Parsec,
p.positionY * distanceconstants::Parsec,
p.positionZ * distanceconstants::Parsec
);
const glm::dvec3 sunPosition = glm::dvec3(0.0, 0.0, 0.0);
const glm::dvec3 starToSunVec = glm::normalize(sunPosition - starPosition);
const glm::dvec3 galacticNorth = glm::dvec3(0.0, 0.0, 1.0);
const glm::dmat3 galaxticToCelestialMatrix =
SpiceManager::ref().positionTransformMatrix("GALACTIC", "J2000", 0.0);
const glm::dvec3 celestialNorth = glm::normalize(
galaxticToCelestialMatrix * galacticNorth
);
// Earth's north vector projected onto the skyplane, the plane perpendicular to the
// viewing vector (starToSunVec)
const float celestialAngle = static_cast<float>(glm::dot(
celestialNorth,
starToSunVec
));
glm::dvec3 northProjected = glm::normalize(
celestialNorth - (celestialAngle / glm::length(starToSunVec)) * starToSunVec
);
const glm::dvec3 beta = glm::normalize(glm::cross(starToSunVec, northProjected));
const glm::dmat3 exoplanetSystemRotation = glm::dmat3(
northProjected.x,
northProjected.y,
northProjected.z,
beta.x,
beta.y,
beta.z,
starToSunVec.x,
starToSunVec.y,
starToSunVec.z
);
const glm::dmat3 exoplanetSystemRotation = computeSystemRotation(starPosition);
// Star renderable globe, if we have a radius and bv color index
std::string starGlobeRenderableString;
@@ -243,7 +205,7 @@ void createExoplanetSystem(std::string_view starName) {
"},"
"Tag = {'exoplanet_system'},"
"GUI = {"
"Name = '" + starNameSpeck + " (Star)',"
"Name = '" + sanitizedStarName + " (Star)',"
"Path = '" + guiPath + "'"
"}"
"}";
@@ -261,15 +223,18 @@ void createExoplanetSystem(std::string_view starName) {
if (std::isnan(planet.ecc)) {
planet.ecc = 0.f;
}
if (std::isnan(planet.i)) {
planet.i = 90.f;
}
if (std::isnan(planet.bigOmega)) {
planet.bigOmega = 180.f;
}
if (std::isnan(planet.omega)) {
planet.omega = 90.f;
}
// KeplerTranslation requires angles in range [0, 360]
auto validAngle = [](float angle, float defaultValue) {
if (std::isnan(angle)) { return defaultValue; }
if (angle < 0.f) { return angle + 360.f; }
if (angle > 360.f) { return angle - 360.f; }
};
planet.i = validAngle(planet.i, 90.f);
planet.bigOmega = validAngle(planet.bigOmega, 180.f);
planet.omega = validAngle(planet.omega, 90.f);
Time epoch;
std::string sEpoch;
if (!std::isnan(planet.tt)) {
@@ -472,10 +437,22 @@ int removeExoplanetSystem(lua_State* L) {
return 0;
}
std::vector<std::string> readHostStarNames(std::ifstream& lookupTableFile) {
std::vector<std::string> hostStarsWithSufficientData() {
std::vector<std::string> names;
std::string line;
std::ifstream lookupTableFile(absPath(LookUpTablePath));
if (!lookupTableFile.good()) {
LERROR(fmt::format("Failed to open lookup table file '{}'", LookUpTablePath));
return {};
}
std::ifstream data(absPath(ExoplanetsDataPath), std::ios::in | std::ios::binary);
if (!data.good()) {
LERROR(fmt::format("Failed to open data file '{}'", ExoplanetsDataPath));
return {};
}
// Read number of lines
int nExoplanets = 0;
while (getline(lookupTableFile, line)) {
@@ -485,13 +462,26 @@ std::vector<std::string> readHostStarNames(std::ifstream& lookupTableFile) {
lookupTableFile.seekg(0);
names.reserve(nExoplanets);
Exoplanet p;
while (getline(lookupTableFile, line)) {
std::stringstream ss(line);
std::string name;
getline(ss, name, ',');
// Remove the last two characters, that specify the planet
name = name.substr(0, name.size() - 2);
names.push_back(name);
// Don't want to list systems where there is not enough data to visualize.
// So, test if there is before adding the name to the list.
std::string location_s;
getline(ss, location_s);
long location = std::stol(location_s.c_str());
data.seekg(location);
data.read(reinterpret_cast<char*>(&p), sizeof(Exoplanet));
if (hasSufficientData(p)) {
names.push_back(name);
}
}
// For easier read, sort by names and remove duplicates
@@ -504,14 +494,7 @@ std::vector<std::string> readHostStarNames(std::ifstream& lookupTableFile) {
int getListOfExoplanets(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::getListOfExoplanets");
std::ifstream file(absPath(LookUpTablePath));
if (!file.good()) {
return ghoul::lua::luaError(
L, fmt::format("Failed to open file '{}'", LookUpTablePath
));
}
std::vector<std::string> names = readHostStarNames(file);
std::vector<std::string> names = hostStarsWithSufficientData();
lua_newtable(L);
int number = 1;
@@ -527,14 +510,7 @@ int getListOfExoplanets(lua_State* L) {
int listAvailableExoplanetSystems(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::listAvailableExoplanetSystems");
std::ifstream file(absPath(LookUpTablePath));
if (!file.good()) {
return ghoul::lua::luaError(
L, fmt::format("Failed to open file '{}'", LookUpTablePath
));
}
std::vector<std::string> names = readHostStarNames(file);
std::vector<std::string> names = hostStarsWithSufficientData();
std::string output;
for (auto it = names.begin(); it != names.end(); ++it) {

View File

@@ -56,12 +56,16 @@ Fragment getFragment() {
// Moving the origin to the center
vec2 st = (vs_st - vec2(0.5)) * 2.0;
float offsetLower = textureOffset.x;
float offsetUpper = textureOffset.y;
float offsetIntervalSize = offsetLower + offsetUpper;
float AUpper = semiMajorAxis;
float BUpper = semiMinorAxis(AUpper, eccentricity);
float CUpper = sqrt(AUpper*AUpper - BUpper*BUpper);
float outerApoapsisDistance = AUpper * (1 + eccentricity);
float ALower = AUpper - AstronomicalUnit * (textureOffset.x + textureOffset.y);
float ALower = AUpper - AstronomicalUnit * offsetIntervalSize;
float BLower = semiMinorAxis(ALower, eccentricity);
float CLower = sqrt(ALower*ALower - BLower*BLower);
float innerApoapsisDistance = ALower * (1 + eccentricity);
@@ -91,18 +95,28 @@ Fragment getFragment() {
// Find outer ellipse: where along the direction does the equation == 1?
float denominator = pow(BU_n * dir.x, 2.0) + pow(AU_n * dir.y, 2.0);
float first = -(pow(BU_n, 2.0) * dir.x * CU_n) / denominator;
float second = pow((pow(BU_n, 2.0) * dir.x * CU_n) / denominator, 2.0);
float first = -(BU_n * BU_n * dir.x * CU_n) / denominator;
float second = pow((BU_n * BU_n * dir.x * CU_n) / denominator, 2.0);
float third = (pow(BU_n * CU_n, 2.0) - pow(AU_n * BU_n, 2.0)) / denominator;
float scale = first + sqrt(second - third);
vec2 max = dir * scale;
vec2 min = max * (innerApoapsisDistance / outerApoapsisDistance);
vec2 outerPoint = dir * scale;
vec2 innerPoint = outerPoint * (innerApoapsisDistance / outerApoapsisDistance);
float distance1 = distance(max, min);
float distance2 = distance(max, st);
float textureCoord = distance2 / distance1;
float discWidth = distance(outerPoint, innerPoint);
float distanceFromOuterEdge = distance(outerPoint, st);
float textureCoord = distanceFromOuterEdge / discWidth;
// Scale texture coordinate to handle asymmetric offset intervals
float textureMid = offsetUpper / offsetIntervalSize;
if(textureCoord > textureMid) {
textureCoord = 0.5 + 0.5 * (textureCoord - textureMid) / (1.0 - textureMid);
}
else {
textureCoord = 0.5 * textureCoord / textureMid;
}
vec4 diffuse = texture(discTexture, textureCoord);
diffuse.a *= opacity;

View File

@@ -363,7 +363,7 @@ vec4 calculateNight(vec4 currentColor, vec2 uv, vec3 levelWeights,
// Filter to night side
vec4 newColor = vec4(cosineFactor * colorSample.xyz, adjustedAlpha);
color = blendNightLayers#{i}(currentColor, newColor, adjustedAlpha);
color = blendNightLayers#{i}(color, newColor, adjustedAlpha);
}
#endfor

View File

@@ -139,10 +139,10 @@ DashboardItemGlobeLocation::DashboardItemGlobeLocation(
auto updateFormatString = [this]() {
using namespace fmt::literals;
_formatString =
"Position: {{:03.{0}f}}{{}}, {{:03.{0}f}}{{}} Altitude: {{}} {{}}"_format(
_significantDigits.value()
);
_formatString = fmt::format(
"Position: {{:03.{0}f}}{{}}, {{:03.{0}f}}{{}} Altitude: {{:03.{0}f}} {{}}",
_significantDigits.value()
);
};
_significantDigits.onChange(updateFormatString);
addProperty(_significantDigits);
@@ -199,8 +199,6 @@ void DashboardItemGlobeLocation::render(glm::vec2& penPosition) {
std::pair<double, std::string> dist = simplifyDistance(altitude);
penPosition.y -= _font->height();
std::fill(_buffer.begin(), _buffer.end(), 0);
char* end = fmt::format_to(
_buffer.data(),
@@ -212,7 +210,9 @@ void DashboardItemGlobeLocation::render(glm::vec2& penPosition) {
std::string_view text = std::string_view(_buffer.data(), end - _buffer.data());
RenderFont(*_font, penPosition, text);
penPosition.y -= _font->height();
}
glm::vec2 DashboardItemGlobeLocation::size() const {
ZoneScoped

View File

@@ -1050,6 +1050,7 @@ void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&,
if (_globalRenderer.updatedSinceLastCall) {
const std::array<LayerGroup*, LayerManager::NumLayerGroups>& layerGroups =
_layerManager.layerGroups();
for (size_t i = 0; i < layerGroups.size(); ++i) {
const std::string& nameBase = layergroupid::LAYER_GROUP_IDENTIFIERS[i];
_globalRenderer.gpuLayerGroups[i].bind(
@@ -1074,6 +1075,7 @@ void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&,
if (_localRenderer.updatedSinceLastCall) {
const std::array<LayerGroup*, LayerManager::NumLayerGroups>& layerGroups =
_layerManager.layerGroups();
for (size_t i = 0; i < layerGroups.size(); ++i) {
const std::string& nameBase = layergroupid::LAYER_GROUP_IDENTIFIERS[i];
_localRenderer.gpuLayerGroups[i].bind(

View File

@@ -50,12 +50,12 @@ void ParallelServer::start(int port, const std::string& password,
}
void ParallelServer::setDefaultHostAddress(std::string defaultHostAddress) {
std::lock_guard<std::mutex> lock(_hostInfoMutex);
std::lock_guard lock(_hostInfoMutex);
_defaultHostAddress = std::move(defaultHostAddress);
}
std::string ParallelServer::defaultHostAddress() const {
std::lock_guard<std::mutex> lock(_hostInfoMutex);
std::lock_guard lock(_hostInfoMutex);
return _defaultHostAddress;
}
@@ -66,29 +66,26 @@ void ParallelServer::stop() {
void ParallelServer::handleNewPeers() {
while (!_shouldStop) {
std::unique_ptr<ghoul::io::TcpSocket> socket =
_socketServer.awaitPendingTcpSocket();
std::unique_ptr<ghoul::io::TcpSocket> s = _socketServer.awaitPendingTcpSocket();
socket->startStreams();
s->startStreams();
const size_t id = _nextConnectionId++;
std::shared_ptr<Peer> p = std::make_shared<Peer>(Peer{
id,
"",
ParallelConnection(std::move(socket)),
ParallelConnection(std::move(s)),
ParallelConnection::Status::Connecting,
std::thread()
});
auto it = _peers.emplace(p->id, p);
it.first->second->thread = std::thread([this, id]() {
handlePeer(id);
});
it.first->second->thread = std::thread([this, id]() { handlePeer(id); });
}
}
std::shared_ptr<ParallelServer::Peer> ParallelServer::peer(size_t id) {
std::lock_guard<std::mutex> lock(_peerListMutex);
auto it = _peers.find(id);
std::lock_guard lock(_peerListMutex);
const auto it = _peers.find(id);
if (it == _peers.end()) {
return nullptr;
}
@@ -107,15 +104,19 @@ void ParallelServer::handlePeer(size_t id) {
}
try {
ParallelConnection::Message m = p->parallelConnection.receiveMessage();
_incomingMessages.push({id, m});
} catch (const ParallelConnection::ConnectionLostError&) {
PeerMessage msg;
msg.peerId = id;
msg.message = m;
_incomingMessages.push(msg);
}
catch (const ParallelConnection::ConnectionLostError&) {
LERROR(fmt::format("Connection lost to {}", p->id));
_incomingMessages.push({
id,
ParallelConnection::Message(
ParallelConnection::MessageType::Disconnection, std::vector<char>()
)
});
PeerMessage msg;
msg.peerId = id;
msg.message = ParallelConnection::Message(
ParallelConnection::MessageType::Disconnection, std::vector<char>()
);
_incomingMessages.push(msg);
return;
}
}
@@ -137,9 +138,9 @@ void ParallelServer::handlePeerMessage(PeerMessage peerMessage) {
std::shared_ptr<Peer>& peer = it->second;
const ParallelConnection::MessageType messageType = peerMessage.message.type;
const ParallelConnection::MessageType type = peerMessage.message.type;
std::vector<char>& data = peerMessage.message.content;
switch (messageType) {
switch (type) {
case ParallelConnection::MessageType::Authentication:
handleAuthentication(peer, std::move(data));
break;
@@ -156,9 +157,7 @@ void ParallelServer::handlePeerMessage(PeerMessage peerMessage) {
disconnect(*peer);
break;
default:
LERROR(fmt::format(
"Unsupported message type: {}", static_cast<int>(messageType)
));
LERROR(fmt::format("Unsupported message type: {}", static_cast<int>(type)));
break;
}
}
@@ -192,19 +191,19 @@ void ParallelServer::handleAuthentication(std::shared_ptr<Peer> peer,
setName(*peer, name);
LINFO(fmt::format("Connection established with {} \"{}\"", peer->id, name));
LINFO(fmt::format("Connection established with {} ('{}')", peer->id, name));
std::string defaultHostAddress;
{
std::lock_guard<std::mutex> _hostMutex(_hostInfoMutex);
std::lock_guard _hostMutex(_hostInfoMutex);
defaultHostAddress = _defaultHostAddress;
}
if (_hostPeerId == 0 &&
peer->parallelConnection.socket()->address() == defaultHostAddress)
{
// Directly promote the conenction to host (initialize)
// if there is no host, and ip matches default host ip.
LINFO(fmt::format("Connection {} directly promoted to host.", peer->id));
// Directly promote the conenction to host (initialize) if there is no host, and
// ip matches default host ip.
LINFO(fmt::format("Connection {} directly promoted to host", peer->id));
assignHost(peer);
for (std::pair<const size_t, std::shared_ptr<Peer>>& it : _peers) {
// sendConnectionStatus(it->second) ?
@@ -221,11 +220,10 @@ void ParallelServer::handleAuthentication(std::shared_ptr<Peer> peer,
void ParallelServer::handleData(const Peer& peer, std::vector<char> data) {
if (peer.id != _hostPeerId) {
LINFO(fmt::format(
"Connection {} tried to send data without being the host. Ignoring", peer.id
"Ignoring connection {} trying to send data without being host", peer.id
));
}
sendMessageToClients(ParallelConnection::MessageType::Data, data);
}
void ParallelServer::handleHostshipRequest(std::shared_ptr<Peer> peer,
@@ -233,43 +231,43 @@ void ParallelServer::handleHostshipRequest(std::shared_ptr<Peer> peer,
{
std::stringstream input(std::string(message.begin(), message.end()));
LINFO(fmt::format("Connection {} requested hostship.", peer->id));
LINFO(fmt::format("Connection {} requested hostship", peer->id));
uint64_t passwordHash = 0;
input.read(reinterpret_cast<char*>(&passwordHash), sizeof(uint64_t));
if (passwordHash != _changeHostPasswordHash) {
LERROR(fmt::format("Connection {} provided incorrect host password.", peer->id));
LERROR(fmt::format("Connection {} provided incorrect host password", peer->id));
return;
}
size_t oldHostPeerId = 0;
{
std::lock_guard<std::mutex> lock(_hostInfoMutex);
std::lock_guard lock(_hostInfoMutex);
oldHostPeerId = _hostPeerId;
}
if (oldHostPeerId == peer->id) {
LINFO(fmt::format("Connection {} is already the host.", peer->id));
LINFO(fmt::format("Connection {} is already the host", peer->id));
return;
}
assignHost(peer);
LINFO(fmt::format("Switched host from {} to {}.", oldHostPeerId, peer->id));
LINFO(fmt::format("Switched host from {} to {}", oldHostPeerId, peer->id));
}
void ParallelServer::handleHostshipResignation(Peer& peer) {
LINFO(fmt::format("Connection {} wants to resign its hostship.", peer.id));
LINFO(fmt::format("Connection {} wants to resign its hostship", peer.id));
size_t oldHostPeerId = 0;
{
std::lock_guard<std::mutex> lock(_hostInfoMutex);
std::lock_guard lock(_hostInfoMutex);
oldHostPeerId = _hostPeerId;
}
setToClient(peer);
LINFO(fmt::format("Connection {} resigned as host.", peer.id));
LINFO(fmt::format("Connection {} resigned as host", peer.id));
}
bool ParallelServer::isConnected(const Peer& peer) const {
@@ -277,8 +275,7 @@ bool ParallelServer::isConnected(const Peer& peer) const {
peer.status != ParallelConnection::Status::Disconnected;
}
void ParallelServer::sendMessage(Peer& peer,
ParallelConnection::MessageType messageType,
void ParallelServer::sendMessage(Peer& peer, ParallelConnection::MessageType messageType,
const std::vector<char>& message)
{
peer.parallelConnection.sendMessage({ messageType, message });
@@ -311,12 +308,12 @@ void ParallelServer::disconnect(Peer& peer) {
size_t hostPeerId = 0;
{
std::lock_guard<std::mutex> lock(_hostInfoMutex);
std::lock_guard lock(_hostInfoMutex);
hostPeerId = _hostPeerId;
}
// Make sure any disconnecting host is first degraded to client,
// in order to notify other clients about host disconnection.
// Make sure any disconnecting host is first degraded to client, in order to notify
// other clients about host disconnection.
if (peer.id == hostPeerId) {
setToClient(peer);
}
@@ -327,7 +324,7 @@ void ParallelServer::disconnect(Peer& peer) {
}
void ParallelServer::setName(Peer& peer, std::string name) {
peer.name = name;
peer.name = std::move(name);
size_t hostPeerId = 0;
{
std::lock_guard lock(_hostInfoMutex);
@@ -338,7 +335,7 @@ void ParallelServer::setName(Peer& peer, std::string name) {
if (peer.id == hostPeerId) {
{
std::lock_guard lock(_hostInfoMutex);
_hostName = name;
_hostName = peer.name;
}
for (std::pair<const size_t, std::shared_ptr<Peer>>& it : _peers) {
@@ -374,7 +371,7 @@ void ParallelServer::setToClient(Peer& peer) {
{
std::lock_guard lock(_hostInfoMutex);
_hostPeerId = 0;
_hostName = "";
_hostName.clear();
}
// If host becomes client, make all clients hostless.
@@ -421,8 +418,8 @@ void ParallelServer::sendConnectionStatus(Peer& peer) {
data.insert(
data.end(),
reinterpret_cast<const char*>(_hostName.data()),
reinterpret_cast<const char*>(_hostName.data() + outHostNameSize)
_hostName.data(),
_hostName.data() + outHostNameSize
);
sendMessage(peer, ParallelConnection::MessageType::ConnectionStatus, data);

View File

@@ -52,7 +52,7 @@ Dashboard::Dashboard()
: properties::PropertyOwner({ "Dashboard" })
, _isEnabled(EnabledInfo, true)
, _startPositionOffset(
properties::IVec2Property(StartPositionOffsetInfo, glm::ivec2(10, -10))
properties::IVec2Property(StartPositionOffsetInfo, glm::ivec2(10, -25))
)
{
addProperty(_isEnabled);

View File

@@ -171,111 +171,35 @@ void FramebufferRenderer::initialize() {
// GBuffers
glGenTextures(1, &_gBuffers.colorTexture);
if (HasGLDebugInfo) {
glObjectLabel(GL_TEXTURE, _gBuffers.colorTexture, -1, "G-Buffer Color");
}
glGenTextures(1, &_gBuffers.depthTexture);
if (HasGLDebugInfo) {
glObjectLabel(GL_TEXTURE, _gBuffers.depthTexture, -1, "G-Buffer Depth");
}
glGenTextures(1, &_gBuffers.positionTexture);
if (HasGLDebugInfo) {
glObjectLabel(GL_TEXTURE, _gBuffers.positionTexture, -1, "G-Buffer Position");
}
glGenTextures(1, &_gBuffers.normalTexture);
if (HasGLDebugInfo) {
glObjectLabel(GL_TEXTURE, _gBuffers.normalTexture, -1, "G-Buffer Normal");
}
glGenFramebuffers(1, &_gBuffers.framebuffer);
if (HasGLDebugInfo) {
glObjectLabel(GL_FRAMEBUFFER, _gBuffers.framebuffer, -1, "G-Buffer Main");
}
// PingPong Buffers
// The first pingpong buffer shares the color texture with the renderbuffer:
_pingPongBuffers.colorTexture[0] = _gBuffers.colorTexture;
glGenTextures(1, &_pingPongBuffers.colorTexture[1]);
if (glbinding::Binding::ObjectLabel.isResolved()) {
glObjectLabel(
GL_TEXTURE,
_pingPongBuffers.colorTexture[1],
-1,
"G-Buffer Color Ping-Pong"
);
}
glGenFramebuffers(1, &_pingPongBuffers.framebuffer);
if (glbinding::Binding::ObjectLabel.isResolved()) {
glObjectLabel(
GL_FRAMEBUFFER,
_pingPongBuffers.framebuffer,
-1,
"G-Buffer Ping-Pong"
);
}
// Exit framebuffer
glGenTextures(1, &_exitColorTexture);
if (glbinding::Binding::ObjectLabel.isResolved()) {
glObjectLabel(GL_TEXTURE, _exitColorTexture, -1, "Exit color");
}
glGenTextures(1, &_exitDepthTexture);
if (glbinding::Binding::ObjectLabel.isResolved()) {
glObjectLabel(GL_TEXTURE, _exitColorTexture, -1, "Exit depth");
}
glGenTextures(1, &_exitDepthTexture);
glGenFramebuffers(1, &_exitFramebuffer);
if (glbinding::Binding::ObjectLabel.isResolved()) {
glObjectLabel(GL_FRAMEBUFFER, _exitFramebuffer, -1, "Exit");
}
// HDR / Filtering Buffers
glGenFramebuffers(1, &_hdrBuffers.hdrFilteringFramebuffer);
if (glbinding::Binding::ObjectLabel.isResolved()) {
glObjectLabel(GL_FRAMEBUFFER, _exitFramebuffer, -1, "HDR filtering");
}
glGenTextures(1, &_hdrBuffers.hdrFilteringTexture);
if (glbinding::Binding::ObjectLabel.isResolved()) {
glObjectLabel(GL_TEXTURE, _hdrBuffers.hdrFilteringTexture, -1, "HDR filtering");
}
// FXAA Buffers
glGenFramebuffers(1, &_fxaaBuffers.fxaaFramebuffer);
if (glbinding::Binding::ObjectLabel.isResolved()) {
glObjectLabel(GL_FRAMEBUFFER, _fxaaBuffers.fxaaFramebuffer, -1, "FXAA");
}
glGenTextures(1, &_fxaaBuffers.fxaaTexture);
if (glbinding::Binding::ObjectLabel.isResolved()) {
glObjectLabel(GL_TEXTURE, _fxaaBuffers.fxaaTexture, -1, "FXAA");
}
// DownscaleVolumeRendering
glGenFramebuffers(1, &_downscaleVolumeRendering.framebuffer);
if (glbinding::Binding::ObjectLabel.isResolved()) {
glObjectLabel(
GL_FRAMEBUFFER,
_downscaleVolumeRendering.framebuffer,
-1,
"Downscaled Volume"
);
}
glGenTextures(1, &_downscaleVolumeRendering.colorTexture);
if (glbinding::Binding::ObjectLabel.isResolved()) {
glObjectLabel(
GL_TEXTURE,
_downscaleVolumeRendering.colorTexture,
-1,
"Downscaled Volume Color"
);
}
glGenTextures(1, &_downscaleVolumeRendering.depthbuffer);
if (glbinding::Binding::ObjectLabel.isResolved()) {
glObjectLabel(
GL_TEXTURE,
_downscaleVolumeRendering.depthbuffer,
-1,
"Downscaled Volume Depth"
);
}
// Allocate Textures/Buffers Memory
updateResolution();
@@ -311,6 +235,9 @@ void FramebufferRenderer::initialize() {
_gBuffers.depthTexture,
0
);
if (HasGLDebugInfo) {
glObjectLabel(GL_FRAMEBUFFER, _gBuffers.framebuffer, -1, "G-Buffer Main");
}
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
@@ -339,6 +266,14 @@ void FramebufferRenderer::initialize() {
_gBuffers.depthTexture,
0
);
if (glbinding::Binding::ObjectLabel.isResolved()) {
glObjectLabel(
GL_FRAMEBUFFER,
_pingPongBuffers.framebuffer,
-1,
"G-Buffer Ping-Pong"
);
}
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
@@ -362,6 +297,9 @@ void FramebufferRenderer::initialize() {
_exitDepthTexture,
0
);
if (glbinding::Binding::ObjectLabel.isResolved()) {
glObjectLabel(GL_FRAMEBUFFER, _exitFramebuffer, -1, "Exit");
}
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
@@ -378,6 +316,9 @@ void FramebufferRenderer::initialize() {
_hdrBuffers.hdrFilteringTexture,
0
);
if (glbinding::Binding::ObjectLabel.isResolved()) {
glObjectLabel(GL_FRAMEBUFFER, _hdrBuffers.hdrFilteringFramebuffer, -1, "HDR filtering");
}
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
@@ -394,6 +335,9 @@ void FramebufferRenderer::initialize() {
_fxaaBuffers.fxaaTexture,
0
);
if (glbinding::Binding::ObjectLabel.isResolved()) {
glObjectLabel(GL_FRAMEBUFFER, _fxaaBuffers.fxaaFramebuffer, -1, "FXAA");
}
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
@@ -416,6 +360,14 @@ void FramebufferRenderer::initialize() {
_downscaleVolumeRendering.depthbuffer,
0
);
if (glbinding::Binding::ObjectLabel.isResolved()) {
glObjectLabel(
GL_FRAMEBUFFER,
_downscaleVolumeRendering.framebuffer,
-1,
"Downscaled Volume"
);
}
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
@@ -797,6 +749,10 @@ void FramebufferRenderer::updateResolution() {
ZoneScoped
TracyGpuZone("Renderer updateResolution")
HasGLDebugInfo = glbinding::Binding::ObjectLabel.isResolved() &&
glbinding::Binding::PushDebugGroup.isResolved() &&
glbinding::Binding::PopDebugGroup.isResolved();
glBindTexture(GL_TEXTURE_2D, _gBuffers.colorTexture);
glTexImage2D(
GL_TEXTURE_2D,
@@ -811,6 +767,9 @@ void FramebufferRenderer::updateResolution() {
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
if (HasGLDebugInfo) {
glObjectLabel(GL_TEXTURE, _gBuffers.colorTexture, -1, "G-Buffer Color");
}
glBindTexture(GL_TEXTURE_2D, _gBuffers.positionTexture);
glTexImage2D(
@@ -826,6 +785,9 @@ void FramebufferRenderer::updateResolution() {
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
if (HasGLDebugInfo) {
glObjectLabel(GL_TEXTURE, _gBuffers.positionTexture, -1, "G-Buffer Position");
}
glBindTexture(GL_TEXTURE_2D, _gBuffers.normalTexture);
glTexImage2D(
@@ -841,6 +803,9 @@ void FramebufferRenderer::updateResolution() {
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
if (HasGLDebugInfo) {
glObjectLabel(GL_TEXTURE, _gBuffers.normalTexture, -1, "G-Buffer Normal");
}
glBindTexture(GL_TEXTURE_2D, _gBuffers.depthTexture);
glTexImage2D(
@@ -856,6 +821,9 @@ void FramebufferRenderer::updateResolution() {
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
if (HasGLDebugInfo) {
glObjectLabel(GL_TEXTURE, _gBuffers.depthTexture, -1, "G-Buffer Depth");
}
glBindTexture(GL_TEXTURE_2D, _pingPongBuffers.colorTexture[1]);
glTexImage2D(
@@ -871,6 +839,14 @@ void FramebufferRenderer::updateResolution() {
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
if (glbinding::Binding::ObjectLabel.isResolved()) {
glObjectLabel(
GL_TEXTURE,
_pingPongBuffers.colorTexture[1],
-1,
"G-Buffer Color Ping-Pong"
);
}
// HDR / Filtering
glBindTexture(GL_TEXTURE_2D, _hdrBuffers.hdrFilteringTexture);
@@ -887,6 +863,9 @@ void FramebufferRenderer::updateResolution() {
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
if (glbinding::Binding::ObjectLabel.isResolved()) {
glObjectLabel(GL_TEXTURE, _hdrBuffers.hdrFilteringTexture, -1, "HDR filtering");
}
// FXAA
glBindTexture(GL_TEXTURE_2D, _fxaaBuffers.fxaaTexture);
@@ -903,6 +882,9 @@ void FramebufferRenderer::updateResolution() {
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
if (glbinding::Binding::ObjectLabel.isResolved()) {
glObjectLabel(GL_TEXTURE, _fxaaBuffers.fxaaTexture, -1, "FXAA");
}
// Downscale Volume Rendering
glBindTexture(GL_TEXTURE_2D, _downscaleVolumeRendering.colorTexture);
@@ -925,6 +907,14 @@ void FramebufferRenderer::updateResolution() {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
float volumeBorderColor[] = { 0.0f, 0.0f, 0.0f, 1.0f };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, volumeBorderColor);
if (glbinding::Binding::ObjectLabel.isResolved()) {
glObjectLabel(
GL_TEXTURE,
_downscaleVolumeRendering.colorTexture,
-1,
"Downscaled Volume Color"
);
}
glBindTexture(GL_TEXTURE_2D, _downscaleVolumeRendering.depthbuffer);
glTexImage2D(
@@ -944,6 +934,14 @@ void FramebufferRenderer::updateResolution() {
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
if (glbinding::Binding::ObjectLabel.isResolved()) {
glObjectLabel(
GL_TEXTURE,
_downscaleVolumeRendering.depthbuffer,
-1,
"Downscaled Volume Depth"
);
}
// Volume Rendering Textures
glBindTexture(GL_TEXTURE_2D, _exitColorTexture);
@@ -958,12 +956,13 @@ void FramebufferRenderer::updateResolution() {
GL_UNSIGNED_SHORT,
nullptr
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
if (glbinding::Binding::ObjectLabel.isResolved()) {
glObjectLabel(GL_TEXTURE, _exitColorTexture, -1, "Exit color");
}
glBindTexture(GL_TEXTURE_2D, _exitDepthTexture);
glTexImage2D(
GL_TEXTURE_2D,
0,
@@ -975,9 +974,11 @@ void FramebufferRenderer::updateResolution() {
GL_FLOAT,
nullptr
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
if (glbinding::Binding::ObjectLabel.isResolved()) {
glObjectLabel(GL_TEXTURE, _exitColorTexture, -1, "Exit depth");
}
_dirtyResolution = false;
}
@@ -1208,10 +1209,6 @@ void FramebufferRenderer::render(Scene* scene, Camera* camera, float blackoutFac
TracyGpuZone("Raycaster Tasks")
GLDebugGroup group("Raycaster Tasks");
performRaycasterTasks(tasks.raycasterTasks);
if (HasGLDebugInfo) {
glPopDebugGroup();
}
}
if (!tasks.deferredcasterTasks.empty()) {

View File

@@ -758,7 +758,7 @@ bool RenderEngine::mouseActivationCallback(const glm::dvec2& mousePosition) cons
if (intersects(mousePosition, _cameraButtonLocations.rotation)) {
constexpr const char* ToggleRotationFrictionScript = R"(
local f = 'NavigationHandler.OrbitalNavigator.Friction.RotationalFriction';
openspace.setPropertyValue(f, not openspace.getPropertyValue(f));)";
openspace.setPropertyValueSingle(f, not openspace.getPropertyValue(f));)";
global::scriptEngine.queueScript(
ToggleRotationFrictionScript,
@@ -770,7 +770,7 @@ bool RenderEngine::mouseActivationCallback(const glm::dvec2& mousePosition) cons
if (intersects(mousePosition, _cameraButtonLocations.zoom)) {
constexpr const char* ToggleZoomFrictionScript = R"(
local f = 'NavigationHandler.OrbitalNavigator.Friction.ZoomFriction';
openspace.setPropertyValue(f, not openspace.getPropertyValue(f));)";
openspace.setPropertyValueSingle(f, not openspace.getPropertyValue(f));)";
global::scriptEngine.queueScript(
ToggleZoomFrictionScript,
@@ -782,7 +782,7 @@ bool RenderEngine::mouseActivationCallback(const glm::dvec2& mousePosition) cons
if (intersects(mousePosition, _cameraButtonLocations.roll)) {
constexpr const char* ToggleRollFrictionScript = R"(
local f = 'NavigationHandler.OrbitalNavigator.Friction.RollFriction';
openspace.setPropertyValue(f, not openspace.getPropertyValue(f));)";
openspace.setPropertyValueSingle(f, not openspace.getPropertyValue(f));)";
global::scriptEngine.queueScript(
ToggleRollFrictionScript,
@@ -1409,9 +1409,9 @@ void RenderEngine::renderScreenLog() {
_log->removeExpiredEntries();
constexpr const int MaxNumberMessages = 10;
constexpr const int MaxNumberMessages = 20;
constexpr const int CategoryLength = 30;
constexpr const int MessageLength = 140;
constexpr const int MessageLength = 280;
constexpr const std::chrono::seconds FadeTime(5);
const std::vector<ScreenLog::LogEntry>& entries = _log->entries();
@@ -1447,7 +1447,7 @@ void RenderEngine::renderScreenLog() {
const glm::vec4 white(0.9f, 0.9f, 0.9f, alpha);
std::array<char, 15 + CategoryLength + 3> buf;
std::array<char, 15 + 1 + CategoryLength + 3> buf;
{
std::fill(buf.begin(), buf.end(), char(0));
char* end = fmt::format_to(
@@ -1493,7 +1493,7 @@ void RenderEngine::renderScreenLog() {
RenderFont(
*_fontLog,
glm::vec2(
10 + 30 * _fontLog->pointSize(),
10 + (30 + 3) * _fontLog->pointSize(),
_fontLog->pointSize() * nr * 2 + fontRes.y * _verticalLogOffset
),
levelText,
@@ -1504,7 +1504,7 @@ void RenderEngine::renderScreenLog() {
RenderFont(
*_fontLog,
glm::vec2(
10 + 41 * _fontLog->pointSize(),
10 + 44 * _fontLog->pointSize(),
_fontLog->pointSize() * nr * 2 + fontRes.y * _verticalLogOffset
),
message,

View File

@@ -28,6 +28,7 @@
#include <openspace/util/timemanager.h>
#include <ghoul/filesystem/file.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/logging/logmanager.h>
#include <ctime>
#include <filesystem>
@@ -65,11 +66,14 @@ int saveSettingsToProfile(lua_State* L) {
utcTime->tm_min,
utcTime->tm_sec
);
std::string newFile = fmt::format(
"{}_{}.{}",
f.fullBaseName(), time, f.fileExtension()
);
std::filesystem::copy(global::configuration.profile, newFile);
std::string newFile = fmt::format("{}_{}", f.fullBaseName(), time);
std::string sourcePath =
absPath("${PROFILES}") + '/' + global::configuration.profile + ".profile";
std::string destPath =
absPath("${PROFILES}") + '/' + newFile + ".profile";
LINFOC("Profile", fmt::format("Saving a copy of the old profile as {}", newFile));
std::filesystem::copy(sourcePath, destPath);
saveFilePath = global::configuration.profile;
}
else {
@@ -97,14 +101,14 @@ int saveSettingsToProfile(lua_State* L) {
}
const std::string absFilename = absPath("${PROFILES}/" + saveFilePath + ".profile");
const bool overwrite = (n == 2) ? ghoul::lua::value<bool>(L, 2) : false;
const bool overwrite = (n == 2) ? ghoul::lua::value<bool>(L, 2) : true;
if (FileSys.fileExists(absFilename) && !overwrite) {
return luaL_error(
L,
fmt::format(
"Unable to save profile '{}'. File of same name already exists.",
absFilename.c_str()
"Unable to save profile '{}'. File of same name already exists",
absFilename
).c_str()
);
}
@@ -130,8 +134,7 @@ int saveSettingsToProfile(lua_State* L) {
return luaL_error(
L,
fmt::format(
"Data write error to file: {} ({})",
absFilename, e.what()
"Data write error to file: {} ({})", absFilename, e.what()
).c_str()
);
}

View File

@@ -636,13 +636,19 @@ scripting::LuaLibrary Scene::luaLibrary() {
"This is the same as calling the setValue method and passing 'single' as "
"the fourth argument to setPropertyValue."
},
{
"hasProperty",
&luascriptfunctions::property_hasProperty,
{},
"string",
"Returns whether a property with the given URI exists"
},
{
"getPropertyValue",
&luascriptfunctions::property_getValue,
{},
"string",
"Returns the value the property, identified by "
"the provided URI."
"Returns the value the property, identified by the provided URI."
},
{
"getProperty",
@@ -675,6 +681,14 @@ scripting::LuaLibrary Scene::luaLibrary() {
"string",
"Removes the SceneGraphNode identified by name"
},
{
"removeSceneGraphNodesFromRegex",
&luascriptfunctions::removeSceneGraphNodesFromRegex,
{},
"string",
"Removes all SceneGraphNodes with identifiers matching the input regular "
"expression"
},
{
"hasSceneGraphNode",
&luascriptfunctions::hasSceneGraphNode,

View File

@@ -376,6 +376,25 @@ int property_setValueSingle(lua_State* L) {
return property_setValue(L);
}
/**
* \ingroup LuaScripts
* hasProperty(string):
* Returns whether a property with the given URI exists
*/
int property_hasProperty(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::property_hasProperty");
std::string uri = ghoul::lua::value<std::string>(
L,
1,
ghoul::lua::PopValue::Yes
);
openspace::properties::Property* prop = property(uri);
ghoul::lua::push(L, prop != nullptr);
return 1;
}
/**
* \ingroup LuaScripts
* getPropertyValue(string):
@@ -389,7 +408,7 @@ int property_getValue(lua_State* L) {
L,
1,
ghoul::lua::PopValue::Yes
);
);
openspace::properties::Property* prop = property(uri);
if (!prop) {
@@ -531,6 +550,54 @@ int removeSceneGraphNode(lua_State* L) {
std::string name = ghoul::lua::value<std::string>(L, 1, ghoul::lua::PopValue::Yes);
SceneGraphNode* foundNode = sceneGraphNode(name);
if (!foundNode) {
LERRORC(
"removeSceneGraphNode",
fmt::format("Did not find a match for identifier: {} ", name)
);
return 0;
}
SceneGraphNode* parent = foundNode->parent();
if (!parent) {
LERRORC(
"removeSceneGraphNode",
fmt::format("Cannot remove root node")
);
return 0;
}
// Remove the node and all its children
std::function<void(SceneGraphNode*)> removeNode =
[&removeNode](SceneGraphNode* localNode) {
std::vector<SceneGraphNode*> children = localNode->children();
ghoul::mm_unique_ptr<SceneGraphNode> n = localNode->parent()->detachChild(
*localNode
);
ghoul_assert(n.get() == localNode, "Wrong node returned from detaching");
for (SceneGraphNode* c : children) {
removeNode(c);
}
localNode->deinitializeGL();
localNode->deinitialize();
n = nullptr;
};
removeNode(foundNode);
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
return 0;
}
int removeSceneGraphNodesFromRegex(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeSceneGraphNodesFromRegex");
std::string name = ghoul::lua::value<std::string>(L, 1, ghoul::lua::PopValue::Yes);
const std::vector<SceneGraphNode*>& nodes =
global::renderEngine.scene()->allSceneGraphNodes();
@@ -553,8 +620,8 @@ int removeSceneGraphNode(lua_State* L) {
SceneGraphNode* parent = node->parent();
if (!parent) {
LERRORC(
"removeSceneGraphNode",
fmt::format("{}: Cannot remove root node")
"removeSceneGraphNodesFromRegex",
fmt::format("Cannot remove root node")
);
}
else {
@@ -565,8 +632,8 @@ int removeSceneGraphNode(lua_State* L) {
if (!foundMatch) {
LERRORC(
"removeSceneGraphNode",
"Did not find a match for identifier: " + name
"removeSceneGraphNodesFromRegex",
fmt::format("Did not find a match for identifier: {}", name)
);
return 0;
}

View File

@@ -194,6 +194,9 @@ void throwSpiceError(const std::string& errorMessage) {
reset_c();
throw openspace::SpiceManager::SpiceException(errorMessage + ": " + buffer);
}
else {
reset_c();
}
}
SpiceManager::KernelHandle SpiceManager::loadKernel(std::string filePath) {