mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-01-10 13:41:45 -06:00
Merge branch 'master' of https://github.com/OpenSpace/OpenSpace into thesis/2020/software-integration
This commit is contained in:
@@ -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
11
Jenkinsfile
vendored
@@ -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')
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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__
|
||||
|
||||
@@ -47,6 +47,8 @@ private slots:
|
||||
void parseScript();
|
||||
|
||||
private:
|
||||
void createWidgets();
|
||||
|
||||
openspace::Profile& _profile;
|
||||
QTextEdit* _textScripts = nullptr;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -50,6 +50,7 @@ private slots:
|
||||
void tabSelect(int);
|
||||
|
||||
private:
|
||||
void createWidgets();
|
||||
QWidget* createNavStateWidget();
|
||||
QWidget* createGeoWidget();
|
||||
|
||||
|
||||
@@ -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)
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
|
||||
35
apps/OpenSpace/ext/launcher/include/profile/line.h
Normal file
35
apps/OpenSpace/ext/launcher/include/profile/line.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2020 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_UI_LAUNCHER___LINE___H__
|
||||
#define __OPENSPACE_UI_LAUNCHER___LINE___H__
|
||||
|
||||
#include <QFrame>
|
||||
|
||||
class Line : public QFrame {
|
||||
public:
|
||||
Line();
|
||||
};
|
||||
|
||||
#endif // __OPENSPACE_UI_LAUNCHER___LINE___H__
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
30
apps/OpenSpace/ext/launcher/src/profile/line.cpp
Normal file
30
apps/OpenSpace/ext/launcher/src/profile/line.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2020 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include "profile/line.h"
|
||||
|
||||
Line::Line() {
|
||||
setFrameShape(QFrame::HLine);
|
||||
setFrameShadow(QFrame::Sunken);
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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() &&
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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": [
|
||||
|
||||
Submodule ext/ghoul updated: 8f7d89335b...e75af2a3be
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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__
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user