mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-02-23 05:19:18 -06:00
Feature/keybindings (#1708)
* Add action manager to handle actions in replacement of keyboard shortcuts * Implement new Action concept * Remove the shortcutscomponent as it is no longer needed * Update profile version from 1.0 to 1.1 * Add action dialog * Restructure of key specification in keys.h * Remove solid field-of-view keybind from the newhorizons profile as the setting no longer exists
This commit is contained in:
@@ -27,13 +27,13 @@ include(${OPENSPACE_CMAKE_EXT_DIR}/set_openspace_compile_settings.cmake)
|
||||
set(HEADER_FILES
|
||||
include/filesystemaccess.h
|
||||
include/launcherwindow.h
|
||||
include/profile/actiondialog.h
|
||||
include/profile/additionalscriptsdialog.h
|
||||
include/profile/assetsdialog.h
|
||||
include/profile/assettreeitem.h
|
||||
include/profile/assettreemodel.h
|
||||
include/profile/cameradialog.h
|
||||
include/profile/deltatimesdialog.h
|
||||
include/profile/keybindingsdialog.h
|
||||
include/profile/scriptlogdialog.h
|
||||
include/profile/line.h
|
||||
include/profile/marknodesdialog.h
|
||||
@@ -47,13 +47,13 @@ set(HEADER_FILES
|
||||
set(SOURCE_FILES
|
||||
src/launcherwindow.cpp
|
||||
src/filesystemaccess.cpp
|
||||
src/profile/actiondialog.cpp
|
||||
src/profile/additionalscriptsdialog.cpp
|
||||
src/profile/assetsdialog.cpp
|
||||
src/profile/assettreeitem.cpp
|
||||
src/profile/assettreemodel.cpp
|
||||
src/profile/cameradialog.cpp
|
||||
src/profile/deltatimesdialog.cpp
|
||||
src/profile/keybindingsdialog.cpp
|
||||
src/profile/scriptlogdialog.cpp
|
||||
src/profile/line.cpp
|
||||
src/profile/marknodesdialog.cpp
|
||||
@@ -70,12 +70,12 @@ set(MOC_FILES "")
|
||||
qt5_wrap_cpp(
|
||||
MOC_FILES
|
||||
include/launcherwindow.h
|
||||
include/profile/actiondialog.h
|
||||
include/profile/additionalscriptsdialog.h
|
||||
include/profile/assetsdialog.h
|
||||
include/profile/assettreemodel.h
|
||||
include/profile/cameradialog.h
|
||||
include/profile/deltatimesdialog.h
|
||||
include/profile/keybindingsdialog.h
|
||||
include/profile/scriptlogdialog.h
|
||||
include/profile/marknodesdialog.h
|
||||
include/profile/metadialog.h
|
||||
|
||||
103
apps/OpenSpace/ext/launcher/include/profile/actiondialog.h
Normal file
103
apps/OpenSpace/ext/launcher/include/profile/actiondialog.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2021 *
|
||||
* *
|
||||
* 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___ACTIONDIALOG___H__
|
||||
#define __OPENSPACE_UI_LAUNCHER___ACTIONDIALOG___H__
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include <openspace/scene/profile.h>
|
||||
|
||||
class QCheckBox;
|
||||
class QComboBox;
|
||||
class QDialogButtonBox;
|
||||
class QGridLayout;
|
||||
class QLineEdit;
|
||||
class QListWidget;
|
||||
class QPushButton;
|
||||
class QTextEdit;
|
||||
|
||||
class ActionDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ActionDialog(QWidget* parent,
|
||||
std::vector<openspace::Profile::Action>* actions,
|
||||
std::vector<openspace::Profile::Keybinding>* keybindings);
|
||||
|
||||
private:
|
||||
void createWidgets();
|
||||
void createActionWidgets(QGridLayout* layout);
|
||||
void createKeyboardWidgets(QGridLayout* layout);
|
||||
void applyChanges();
|
||||
|
||||
openspace::Profile::Action* selectedAction();
|
||||
void actionAdd();
|
||||
void actionRemove();
|
||||
void actionSelected();
|
||||
void actionSaved();
|
||||
void clearActionFields();
|
||||
void actionRejected();
|
||||
|
||||
openspace::Profile::Keybinding* selectedKeybinding();
|
||||
void keybindingAdd();
|
||||
void keybindingRemove();
|
||||
void keybindingSelected();
|
||||
void keybindingActionSelected(int);
|
||||
void keybindingSaved();
|
||||
void clearKeybindingFields();
|
||||
void keybindingRejected();
|
||||
|
||||
std::vector<openspace::Profile::Action>* _actions = nullptr;
|
||||
std::vector<openspace::Profile::Action> _actionData;
|
||||
std::vector<openspace::Profile::Keybinding>* _keybindings = nullptr;
|
||||
std::vector<openspace::Profile::Keybinding> _keybindingsData;
|
||||
|
||||
struct {
|
||||
QListWidget* list = nullptr;
|
||||
QLineEdit* identifier = nullptr;
|
||||
QLineEdit* name = nullptr;
|
||||
QLineEdit* guiPath = nullptr;
|
||||
QLineEdit* documentation = nullptr;
|
||||
QCheckBox* isLocal = nullptr;
|
||||
QTextEdit* script = nullptr;
|
||||
QPushButton* addButton = nullptr;
|
||||
QPushButton* removeButton = nullptr;
|
||||
QDialogButtonBox* saveButtons = nullptr;
|
||||
} _actionWidgets;
|
||||
|
||||
struct {
|
||||
QListWidget* list = nullptr;
|
||||
QCheckBox* shiftModifier = nullptr;
|
||||
QCheckBox* ctrlModifier = nullptr;
|
||||
QCheckBox* altModifier = nullptr;
|
||||
QComboBox* key = nullptr;
|
||||
QComboBox* action = nullptr;
|
||||
QLineEdit* actionText = nullptr;
|
||||
QPushButton* addButton = nullptr;
|
||||
QPushButton* removeButton = nullptr;
|
||||
QDialogButtonBox* saveButtons = nullptr;
|
||||
} _keybindingWidgets;
|
||||
};
|
||||
|
||||
#endif // __OPENSPACE_UI_LAUNCHER___ACTIONDIALOG___H__
|
||||
@@ -27,8 +27,6 @@
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace openspace { class Profile; }
|
||||
|
||||
class QTextEdit;
|
||||
|
||||
class AdditionalScriptsDialog : public QDialog {
|
||||
@@ -41,7 +39,7 @@ public:
|
||||
* new or imported profile.
|
||||
* \param parent Pointer to parent Qt widget
|
||||
*/
|
||||
AdditionalScriptsDialog(openspace::Profile& profile, QWidget* parent);
|
||||
AdditionalScriptsDialog(QWidget* parent, std::vector<std::string>* scripts);
|
||||
|
||||
private slots:
|
||||
void parseScript();
|
||||
@@ -57,7 +55,8 @@ private slots:
|
||||
private:
|
||||
void createWidgets();
|
||||
|
||||
openspace::Profile& _profile;
|
||||
std::vector<std::string>* _scripts = nullptr;
|
||||
std::vector<std::string> _scriptsData;
|
||||
QTextEdit* _textScripts = nullptr;
|
||||
QPushButton* _chooseScriptsButton = nullptr;
|
||||
};
|
||||
|
||||
@@ -29,8 +29,6 @@
|
||||
|
||||
#include "assettreemodel.h"
|
||||
|
||||
namespace openspace { class Profile; }
|
||||
|
||||
class QTextEdit;
|
||||
class QTreeView;
|
||||
|
||||
@@ -43,11 +41,12 @@ public:
|
||||
* \param profile The #openspace::Profile object containing all data of the
|
||||
* new or imported profile.
|
||||
* \param assetBasePath The path to the folder in which all of the assets are living
|
||||
* \param userAssetBasePath The path to the folder in which the users' assets are living
|
||||
* \param userAssetBasePath The path to the folder in which the users' assets are
|
||||
* living
|
||||
* \param parent Pointer to parent Qt widget
|
||||
*/
|
||||
AssetsDialog(openspace::Profile& profile, const std::string& assetBasePath,
|
||||
const std::string& userAssetBasePath, QWidget* parent);
|
||||
AssetsDialog(QWidget* parent, openspace::Profile* profile,
|
||||
const std::string& assetBasePath, const std::string& userAssetBasePath);
|
||||
|
||||
private slots:
|
||||
void parseSelections();
|
||||
@@ -62,7 +61,7 @@ private:
|
||||
*/
|
||||
QString createTextSummary();
|
||||
|
||||
openspace::Profile& _profile;
|
||||
openspace::Profile* _profile = nullptr;
|
||||
AssetTreeModel _assetTreeModel;
|
||||
QTreeView* _assetTree = nullptr;
|
||||
QTextEdit* _summary = nullptr;
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace openspace { class Profile; }
|
||||
#include <openspace/scene/profile.h>
|
||||
#include <optional>
|
||||
|
||||
class QLabel;
|
||||
class QLineEdit;
|
||||
@@ -43,7 +44,7 @@ public:
|
||||
* new or imported profile.
|
||||
* \param parent Pointer to parent Qt widget (optional)
|
||||
*/
|
||||
CameraDialog(openspace::Profile& profile, QWidget* parent);
|
||||
CameraDialog(QWidget* parent, std::optional<openspace::Profile::CameraType>* camera);
|
||||
|
||||
private slots:
|
||||
void approved();
|
||||
@@ -57,7 +58,7 @@ private:
|
||||
void addErrorMsg(QString errorDescription);
|
||||
bool areRequiredFormsFilledAndValid();
|
||||
|
||||
openspace::Profile& _profile;
|
||||
std::optional<openspace::Profile::CameraType>* _camera = nullptr;
|
||||
QTabWidget* _tabWidget = nullptr;
|
||||
struct {
|
||||
QLineEdit* anchor = nullptr;
|
||||
|
||||
@@ -27,8 +27,6 @@
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace openspace { class Profile; }
|
||||
|
||||
class QDialogButtonBox;
|
||||
class QLabel;
|
||||
class QListWidget;
|
||||
@@ -45,7 +43,7 @@ public:
|
||||
* new or imported profile.
|
||||
* \param parent Pointer to parent Qt widget
|
||||
*/
|
||||
DeltaTimesDialog(openspace::Profile& profile, QWidget* parent);
|
||||
DeltaTimesDialog(QWidget* parent, std::vector<double>* deltaTimes);
|
||||
|
||||
/**
|
||||
* Returns a text summary of the delta time list for display purposes
|
||||
@@ -87,8 +85,8 @@ private:
|
||||
void setLabelForKey(int index, bool editMode, std::string color);
|
||||
bool isLineEmpty(int index);
|
||||
|
||||
openspace::Profile& _profile;
|
||||
std::vector<double> _data;
|
||||
std::vector<double>* _deltaTimes = nullptr;
|
||||
std::vector<double> _deltaTimesData;
|
||||
bool _editModeNewItem = false;
|
||||
|
||||
QListWidget* _listWidget = nullptr;
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2021 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_UI_LAUNCHER___KEYBINDINGS___H__
|
||||
#define __OPENSPACE_UI_LAUNCHER___KEYBINDINGS___H__
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
#include <openspace/scene/profile.h>
|
||||
#include <openspace/util/keys.h>
|
||||
#include <QWidget>
|
||||
#include <QListWidgetItem>
|
||||
|
||||
class QComboBox;
|
||||
class QCheckBox;
|
||||
class QTextEdit;
|
||||
class QDialogButtonBox;
|
||||
class QListWidget;
|
||||
class QLabel;
|
||||
class QPushButton;
|
||||
|
||||
class KeybindingsDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Constructor for keybindings class
|
||||
*
|
||||
* \param profile The #openspace::Profile object containing all data of the
|
||||
* new or imported profile.
|
||||
* \param parent Pointer to parent Qt widget (optional)
|
||||
*/
|
||||
KeybindingsDialog(openspace::Profile& profile, QWidget* parent);
|
||||
|
||||
/**
|
||||
* Handles keypress while the Qt dialog window is open
|
||||
*
|
||||
* \param evt #QKeyEvent object for the key press event
|
||||
*/
|
||||
virtual void keyPressEvent(QKeyEvent* evt) override;
|
||||
|
||||
private slots:
|
||||
void listItemSelected();
|
||||
void listItemAdded();
|
||||
void listItemRemove();
|
||||
void listItemSave();
|
||||
void listItemCancelSave();
|
||||
void transitionToEditMode();
|
||||
void parseSelections();
|
||||
void chooseScripts();
|
||||
void keySelected(int index);
|
||||
void keyModSelected(int index);
|
||||
|
||||
/**
|
||||
* Adds scripts to the _scriptEdit from outside dialogs
|
||||
*
|
||||
* \param scripts #std::string scripts to be appended
|
||||
*/
|
||||
void appendScriptsToKeybind(std::string scripts);
|
||||
|
||||
private:
|
||||
void createWidgets();
|
||||
void transitionFromEditMode();
|
||||
void editBoxDisabled(bool disabled);
|
||||
int indexInKeyMapping(std::vector<int>& mapVector, int keyInt);
|
||||
bool areRequiredFormsFilled();
|
||||
bool isLineEmpty(int index);
|
||||
void addStringToErrorDisplay(const QString& newString);
|
||||
void checkForNumberKeyConflict(int key);
|
||||
void checkForBindingConflict(int selectedModKey, int selectedKey);
|
||||
|
||||
openspace::Profile& _profile;
|
||||
std::vector<openspace::Profile::Keybinding> _data;
|
||||
std::vector<int> _mapModKeyComboBoxIndexToKeyValue;
|
||||
std::vector<int> _mapKeyComboBoxIndexToKeyValue;
|
||||
bool _editModeNewItem = false;
|
||||
int _currentKeybindingSelection = 0;
|
||||
|
||||
QListWidget* _list = nullptr;
|
||||
QLabel* _keyModLabel = nullptr;
|
||||
QComboBox* _keyModCombo = nullptr;
|
||||
QLabel* _keyLabel = nullptr;
|
||||
QComboBox* _keyCombo = nullptr;
|
||||
QLabel* _nameLabel = nullptr;
|
||||
QLineEdit* _nameEdit = nullptr;
|
||||
QLabel* _guiPathLabel = nullptr;
|
||||
QLineEdit* _guiPathEdit = nullptr;
|
||||
QLabel* _documentationLabel = nullptr;
|
||||
QLineEdit* _documentationEdit = nullptr;
|
||||
QCheckBox* _localCheck = nullptr;
|
||||
QLabel* _scriptLabel = nullptr;
|
||||
QTextEdit* _scriptEdit = nullptr;
|
||||
|
||||
QPushButton* _addButton = nullptr;
|
||||
QPushButton* _removeButton = nullptr;
|
||||
QPushButton* _chooseScriptsButton = nullptr;
|
||||
QPushButton* _saveButton = nullptr;
|
||||
QPushButton* _cancelButton = nullptr;
|
||||
QDialogButtonBox* _buttonBox = nullptr;
|
||||
|
||||
QLabel* _errorMsg = nullptr;
|
||||
};
|
||||
|
||||
#endif // __OPENSPACE_UI_LAUNCHER___KEYBINDINGS___H__
|
||||
@@ -27,8 +27,6 @@
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace openspace { class Profile; }
|
||||
|
||||
class QLineEdit;
|
||||
class QListWidget;
|
||||
class QListWidgetItem;
|
||||
@@ -44,7 +42,7 @@ public:
|
||||
* new or imported profile.
|
||||
* \param parent Pointer to parent Qt widget
|
||||
*/
|
||||
MarkNodesDialog(openspace::Profile& profile, QWidget* parent);
|
||||
MarkNodesDialog(QWidget* parent, std::vector<std::string>* markedNodes);
|
||||
|
||||
/**
|
||||
* Handles keypress while the Qt dialog window is open
|
||||
@@ -63,8 +61,8 @@ private:
|
||||
void createWidgets();
|
||||
|
||||
std::vector<QListWidgetItem*> _markedNodesListItems;
|
||||
openspace::Profile& _profile;
|
||||
std::vector<std::string> _data;
|
||||
std::vector<std::string>* _markedNodes;
|
||||
std::vector<std::string> _markedNodesData;
|
||||
|
||||
QListWidget* _list = nullptr;
|
||||
QPushButton* _removeButton = nullptr;
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace openspace { class Profile; }
|
||||
#include <openspace/scene/profile.h>
|
||||
#include <optional>
|
||||
|
||||
class QLineEdit;
|
||||
class QTextEdit;
|
||||
@@ -42,7 +43,7 @@ public:
|
||||
* new or imported profile.
|
||||
* \param parent Pointer to parent Qt widget
|
||||
*/
|
||||
MetaDialog(openspace::Profile& profile, QWidget* parent);
|
||||
MetaDialog(QWidget* parent, std::optional<openspace::Profile::Meta>* meta);
|
||||
|
||||
private slots:
|
||||
void save();
|
||||
@@ -50,7 +51,7 @@ private slots:
|
||||
private:
|
||||
void createWidgets();
|
||||
|
||||
openspace::Profile& _profile;
|
||||
std::optional<openspace::Profile::Meta>* _meta = nullptr;
|
||||
|
||||
QLineEdit* _nameEdit = nullptr;
|
||||
QLineEdit* _versionEdit = nullptr;
|
||||
|
||||
@@ -45,7 +45,7 @@ public:
|
||||
* new or imported profile.
|
||||
* \param parent Pointer to parent Qt widget
|
||||
*/
|
||||
ModulesDialog(openspace::Profile& profile, QWidget* parent);
|
||||
ModulesDialog(QWidget* parent, std::vector<openspace::Profile::Module>* modules);
|
||||
|
||||
/**
|
||||
* Handles keypress while the Qt dialog window is open
|
||||
@@ -71,8 +71,8 @@ private:
|
||||
void editBoxDisabled(bool disabled);
|
||||
bool isLineEmpty(int index) const;
|
||||
|
||||
openspace::Profile& _profile;
|
||||
std::vector<openspace::Profile::Module> _data;
|
||||
std::vector<openspace::Profile::Module>* _modules = nullptr;
|
||||
std::vector<openspace::Profile::Module> _moduleData;
|
||||
bool _editModeNewItem = false;
|
||||
|
||||
QListWidget* _list = nullptr;
|
||||
|
||||
@@ -46,7 +46,8 @@ public:
|
||||
* new or imported profile.
|
||||
* \param parent Pointer to parent Qt widget
|
||||
*/
|
||||
PropertiesDialog(openspace::Profile& profile, QWidget* parent);
|
||||
PropertiesDialog(QWidget* parent,
|
||||
std::vector<openspace::Profile::Property>* properties);
|
||||
|
||||
/**
|
||||
* Handles keypress while the Qt dialog window is open
|
||||
@@ -73,8 +74,8 @@ private:
|
||||
bool areRequiredFormsFilled();
|
||||
bool isLineEmpty(int index);
|
||||
|
||||
openspace::Profile& _profile;
|
||||
std::vector<openspace::Profile::Property> _data;
|
||||
std::vector<openspace::Profile::Property>* _properties = nullptr;
|
||||
std::vector<openspace::Profile::Property> _propertyData;
|
||||
bool _editModeNewItem = false;
|
||||
|
||||
QListWidget* _list = nullptr;
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#ifndef __OPENSPACE_UI_LAUNCHER___SCRIPTLOG___H__
|
||||
#define __OPENSPACE_UI_LAUNCHER___SCRIPTLOG___H__
|
||||
|
||||
#include "profile/keybindingsdialog.h"
|
||||
#include <QDialog>
|
||||
#include <QListWidget>
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ public:
|
||||
* new or imported profile.
|
||||
* \param parent Pointer to parent Qt widget
|
||||
*/
|
||||
TimeDialog(openspace::Profile& profile, QWidget* parent);
|
||||
TimeDialog(QWidget* parent, std::optional<openspace::Profile::Time>* time);
|
||||
|
||||
private slots:
|
||||
void enableAccordingToType(int);
|
||||
@@ -54,8 +54,8 @@ private:
|
||||
void createWidgets();
|
||||
void enableFormatForAbsolute(bool enableAbs);
|
||||
|
||||
openspace::Profile& _profile;
|
||||
openspace::Profile::Time _data;
|
||||
std::optional<openspace::Profile::Time>* _time = nullptr;
|
||||
openspace::Profile::Time _timeData;
|
||||
bool _initializedAsAbsolute = true;
|
||||
|
||||
QComboBox* _typeCombo = nullptr;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
}
|
||||
|
||||
QLabel#heading {
|
||||
font-size: 12pt;
|
||||
font-size: 12pt;
|
||||
}
|
||||
|
||||
QLabel#error-message {
|
||||
@@ -18,12 +18,12 @@ QLabel#error-message {
|
||||
*/
|
||||
LauncherWindow QLabel {
|
||||
font-family: Segoe UI;
|
||||
font-weight:600;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
LauncherWindow QLabel#label_choose, QLabel#label_options {
|
||||
color: #ddd;
|
||||
font-size:10pt;
|
||||
color: #dddddd;
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
LauncherWindow QLabel#clear {
|
||||
@@ -119,12 +119,22 @@ AssetsDialog QTreeView {
|
||||
}
|
||||
|
||||
/*
|
||||
* Keybindings
|
||||
* ActionDialog
|
||||
*/
|
||||
KeybindingsDialog QListWidget {
|
||||
ActionDialog QListWidget {
|
||||
min-width: 40em;
|
||||
}
|
||||
|
||||
ActionDialog QPushButton#add-button, QPushButton#remove-button {
|
||||
font-weight: bold;
|
||||
|
||||
padding: 0px 0px 0px 0px;
|
||||
min-width: 1.5em;
|
||||
max-width: 1.5em;
|
||||
min-height: 1.5em;
|
||||
max-height: 1.5em;
|
||||
}
|
||||
|
||||
/*
|
||||
* DeltaTimes
|
||||
*/
|
||||
|
||||
700
apps/OpenSpace/ext/launcher/src/profile/actiondialog.cpp
Normal file
700
apps/OpenSpace/ext/launcher/src/profile/actiondialog.cpp
Normal file
@@ -0,0 +1,700 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2021 *
|
||||
* *
|
||||
* 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/actiondialog.h"
|
||||
|
||||
#include "profile/line.h"
|
||||
#include <openspace/util/keys.h>
|
||||
#include <ghoul/fmt.h>
|
||||
#include <ghoul/misc/assert.h>
|
||||
#include <QCheckBox>
|
||||
#include <QComboBox>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QGridLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QListWidget>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QTextEdit>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
using namespace openspace;
|
||||
|
||||
namespace {
|
||||
void updateListItem(QListWidgetItem* item, const Profile::Action& action) {
|
||||
ghoul_assert(item, "Item must exist at this point");
|
||||
item->setText(
|
||||
action.name.empty() ?
|
||||
QString::fromStdString(action.identifier) :
|
||||
QString::fromStdString(action.name)
|
||||
);
|
||||
}
|
||||
|
||||
void updateListItem(QListWidgetItem* item, const Profile::Keybinding& kb) {
|
||||
ghoul_assert(item, "Item must exist at this point");
|
||||
std::string name = fmt::format("{}\t{}", ghoul::to_string(kb.key), kb.action);
|
||||
item->setText(QString::fromStdString(name));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
ActionDialog::ActionDialog(QWidget* parent,
|
||||
std::vector<openspace::Profile::Action>* actions,
|
||||
std::vector<openspace::Profile::Keybinding>* keybindings)
|
||||
: QDialog(parent)
|
||||
, _actions(actions)
|
||||
, _keybindings(keybindings)
|
||||
, _actionData(*_actions)
|
||||
, _keybindingsData(*_keybindings)
|
||||
{
|
||||
setWindowTitle("Actions and Keybindings");
|
||||
createWidgets();
|
||||
}
|
||||
|
||||
void ActionDialog::createWidgets() {
|
||||
// Column 0 Column 1 Column 2
|
||||
// *----------------------*---------------*----------------*
|
||||
// | Actions | Row 0
|
||||
// | | Identifier | [oooooooooooo] | Row 1
|
||||
// | | Name | [oooooooooooo] | Row 2
|
||||
// | | GUI Path | [oooooooooooo] | Row 3
|
||||
// | | Documentation | [oooooooooooo] | Row 4
|
||||
// | | Is Local | [] | Row 5
|
||||
// | | Script | [oooooooooooo] | Row 6
|
||||
// *----------------------*---------------*----------------*
|
||||
// | [+] [-] | | [Save] [Cancel]| Row 7
|
||||
// *----------------------*---------------*----------------*
|
||||
// |=======================================================| Row 8
|
||||
// | Keybindings | Row 9
|
||||
// *----------------------*---------------*----------------|
|
||||
// | | Modifier | []S []C []A | Row 10
|
||||
// | | Key | DDDDDDDDDDDD> | Row 11
|
||||
// | | Add actions | DDDDDDDDDDDD> | Row 12
|
||||
// | | Action | [oooooooooooo] | Row 13
|
||||
// *----------------------*---------------*----------------*
|
||||
// | [+] [-] | | [Save] [Cancel]| Row 14
|
||||
// *----------------------*---------------*----------------*
|
||||
// |=======================================================| Row 14
|
||||
// *----------------------*---------------*----------------*
|
||||
// | | [Save] [Cancel]| Row 15
|
||||
// *----------------------*---------------*----------------*
|
||||
|
||||
QGridLayout* layout = new QGridLayout(this);
|
||||
|
||||
createActionWidgets(layout);
|
||||
clearActionFields();
|
||||
|
||||
layout->addWidget(new Line, 8, 0, 1, 3);
|
||||
|
||||
createKeyboardWidgets(layout);
|
||||
clearKeybindingFields();
|
||||
|
||||
layout->addWidget(new Line, 16, 0, 1, 3);
|
||||
|
||||
QDialogButtonBox* buttonBox = new QDialogButtonBox;
|
||||
buttonBox->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel);
|
||||
QObject::connect(
|
||||
buttonBox, &QDialogButtonBox::accepted,
|
||||
this, &ActionDialog::applyChanges
|
||||
);
|
||||
QObject::connect(
|
||||
buttonBox, &QDialogButtonBox::rejected,
|
||||
this, &ActionDialog::reject
|
||||
);
|
||||
layout->addWidget(buttonBox, 17, 2, Qt::AlignRight);
|
||||
}
|
||||
|
||||
void ActionDialog::createActionWidgets(QGridLayout* layout) {
|
||||
QLabel* title = new QLabel("Actions");
|
||||
title->setObjectName("heading");
|
||||
layout->addWidget(title, 0, 0, 1, 3);
|
||||
|
||||
_actionWidgets.list = new QListWidget;
|
||||
_actionWidgets.list->setToolTip(
|
||||
"The list of all actions currently defined in the profile. Select one to edit it "
|
||||
"or use the + button below to create a new action"
|
||||
);
|
||||
_actionWidgets.list->setAlternatingRowColors(true);
|
||||
_actionWidgets.list->setResizeMode(QListView::Adjust);
|
||||
connect(
|
||||
_actionWidgets.list, &QListWidget::itemSelectionChanged,
|
||||
this, &ActionDialog::actionSelected
|
||||
);
|
||||
|
||||
for (size_t i = 0; i < _actionData.size(); ++i) {
|
||||
const Profile::Action& action = _actionData[i];
|
||||
std::string name = action.name.empty() ? action.identifier : action.name;
|
||||
_actionWidgets.list->addItem(new QListWidgetItem(QString::fromStdString(name)));
|
||||
}
|
||||
|
||||
layout->addWidget(_actionWidgets.list, 1, 0, 6, 1);
|
||||
|
||||
layout->addWidget(new QLabel("Identifier"), 1, 1);
|
||||
_actionWidgets.identifier = new QLineEdit;
|
||||
_actionWidgets.identifier->setToolTip(
|
||||
"The unique identifier for this action. The identifier name cannot be reused "
|
||||
"between different actions and will lead to a failure to load the profile if it "
|
||||
"happens. There are no restrictions on the name of the identifier, but a dot "
|
||||
"separated hierarchical structure is suggested to prevent name clashes"
|
||||
);
|
||||
_actionWidgets.identifier->setEnabled(false);
|
||||
layout->addWidget(_actionWidgets.identifier, 1, 2);
|
||||
|
||||
layout->addWidget(new QLabel("Name"), 2, 1);
|
||||
_actionWidgets.name = new QLineEdit;
|
||||
_actionWidgets.name->setToolTip(
|
||||
"The user-facing name of this action. As it is displayed in user interfaces, the "
|
||||
"name should be as concise and informative as possible"
|
||||
);
|
||||
_actionWidgets.name->setEnabled(false);
|
||||
layout->addWidget(_actionWidgets.name, 2, 2);
|
||||
|
||||
layout->addWidget(new QLabel("GUI Path"), 3, 1);
|
||||
_actionWidgets.guiPath = new QLineEdit;
|
||||
_actionWidgets.guiPath->setToolTip(
|
||||
"The path under which this action will be shown in user interfaces. The path "
|
||||
"must use the '/' character as separators between folders and start with a '/' "
|
||||
"character that denotes the root folder"
|
||||
);
|
||||
_actionWidgets.guiPath->setEnabled(false);
|
||||
layout->addWidget(_actionWidgets.guiPath, 3, 2);
|
||||
|
||||
layout->addWidget(new QLabel("Documentation"), 4, 1);
|
||||
_actionWidgets.documentation = new QLineEdit;
|
||||
_actionWidgets.documentation->setToolTip(
|
||||
"A longer user-facing documentation that describes the action in more detail. "
|
||||
"The user can request the documentation on demand, so it might be longer and "
|
||||
"more descriptive than the name itself and might also explain some optional "
|
||||
"parameters that that action can consume"
|
||||
);
|
||||
_actionWidgets.documentation->setEnabled(false);
|
||||
layout->addWidget(_actionWidgets.documentation, 4, 2);
|
||||
|
||||
layout->addWidget(new QLabel("Is Local"), 5, 1);
|
||||
_actionWidgets.isLocal = new QCheckBox;
|
||||
_actionWidgets.isLocal->setToolTip(
|
||||
"If this value is checked, the action will only ever affect the OpenSpace "
|
||||
"instance that is executing it. If running a 'regular' OpenSpace instance, this "
|
||||
"setting will not make any difference, but it is necessary in a clustered "
|
||||
"environment or when using a parallel connection, in which case it determines "
|
||||
"whether a command should be executed only locally or send to all remote "
|
||||
"instances as well"
|
||||
);
|
||||
_actionWidgets.isLocal->setEnabled(false);
|
||||
layout->addWidget(_actionWidgets.isLocal, 5, 2);
|
||||
|
||||
layout->addWidget(new QLabel("Script"), 6, 1);
|
||||
_actionWidgets.script = new QTextEdit;
|
||||
_actionWidgets.script->setToolTip(
|
||||
"This is the Lua script that gets executed when this action is triggered. "
|
||||
"Actions can make use of optional arguments which are already defined as the "
|
||||
"`args` variable when this script executes. If no arguments are passed, this "
|
||||
"variable does not exist"
|
||||
);
|
||||
_actionWidgets.script->setEnabled(false);
|
||||
layout->addWidget(_actionWidgets.script, 6, 2);
|
||||
|
||||
|
||||
// + / - buttons
|
||||
QWidget* container = new QWidget;
|
||||
QBoxLayout* containerLayout = new QHBoxLayout(container);
|
||||
_actionWidgets.addButton = new QPushButton("+");
|
||||
_actionWidgets.addButton->setObjectName("add-button");
|
||||
_actionWidgets.addButton->setToolTip("Adds a new action to the list of all actions");
|
||||
QObject::connect(
|
||||
_actionWidgets.addButton, &QPushButton::clicked,
|
||||
this, &ActionDialog::actionAdd
|
||||
);
|
||||
containerLayout->addWidget(_actionWidgets.addButton);
|
||||
|
||||
_actionWidgets.removeButton = new QPushButton("-");
|
||||
_actionWidgets.removeButton->setObjectName("remove-button");
|
||||
_actionWidgets.removeButton->setToolTip("Removes the currently selected action");
|
||||
_actionWidgets.removeButton->setEnabled(false);
|
||||
QObject::connect(
|
||||
_actionWidgets.removeButton, &QPushButton::clicked,
|
||||
this, &ActionDialog::actionRemove
|
||||
);
|
||||
containerLayout->addWidget(_actionWidgets.removeButton);
|
||||
layout->addWidget(container, 7, 0, Qt::AlignLeft);
|
||||
|
||||
|
||||
// Save / Cancel buttons
|
||||
_actionWidgets.saveButtons = new QDialogButtonBox;
|
||||
_actionWidgets.saveButtons->setToolTip(
|
||||
"Saves or discards all changes to the currently selected action"
|
||||
);
|
||||
_actionWidgets.saveButtons->setEnabled(false);
|
||||
_actionWidgets.saveButtons->setStandardButtons(
|
||||
QDialogButtonBox::Save | QDialogButtonBox::Cancel
|
||||
);
|
||||
QObject::connect(
|
||||
_actionWidgets.saveButtons, &QDialogButtonBox::accepted,
|
||||
this, &ActionDialog::actionSaved
|
||||
);
|
||||
QObject::connect(
|
||||
_actionWidgets.saveButtons, &QDialogButtonBox::rejected,
|
||||
this, &ActionDialog::actionRejected
|
||||
);
|
||||
layout->addWidget(_actionWidgets.saveButtons, 7, 2, Qt::AlignRight);
|
||||
}
|
||||
|
||||
void ActionDialog::createKeyboardWidgets(QGridLayout* layout) {
|
||||
QLabel* title = new QLabel("Keybindings");
|
||||
title->setObjectName("heading");
|
||||
layout->addWidget(title);
|
||||
|
||||
_keybindingWidgets.list = new QListWidget;
|
||||
_keybindingWidgets.list->setToolTip(
|
||||
"The list of all keybindings currently assigned in this profile"
|
||||
);
|
||||
_keybindingWidgets.list->setAlternatingRowColors(true);
|
||||
_keybindingWidgets.list->setResizeMode(QListView::Adjust);
|
||||
connect(
|
||||
_keybindingWidgets.list, &QListWidget::itemSelectionChanged,
|
||||
this, &ActionDialog::keybindingSelected
|
||||
);
|
||||
|
||||
for (size_t i = 0; i < _keybindingsData.size(); ++i) {
|
||||
const Profile::Keybinding& kv = _keybindingsData[i];
|
||||
QListWidgetItem* item = new QListWidgetItem;
|
||||
updateListItem(item, kv);
|
||||
_keybindingWidgets.list->addItem(item);
|
||||
}
|
||||
|
||||
layout->addWidget(_keybindingWidgets.list, 10, 0, 4, 1);
|
||||
|
||||
layout->addWidget(new QLabel("Modifier"), 10, 1);
|
||||
{
|
||||
QWidget* container = new QWidget;
|
||||
QBoxLayout* containerLayout = new QHBoxLayout(container);
|
||||
_keybindingWidgets.shiftModifier = new QCheckBox("Shift");
|
||||
_keybindingWidgets.shiftModifier->setEnabled(false);
|
||||
containerLayout->addWidget(_keybindingWidgets.shiftModifier);
|
||||
_keybindingWidgets.ctrlModifier = new QCheckBox("Control");
|
||||
_keybindingWidgets.ctrlModifier->setEnabled(false);
|
||||
containerLayout->addWidget(_keybindingWidgets.ctrlModifier);
|
||||
_keybindingWidgets.altModifier = new QCheckBox("Alt");
|
||||
_keybindingWidgets.altModifier->setEnabled(false);
|
||||
containerLayout->addWidget(_keybindingWidgets.altModifier);
|
||||
layout->addWidget(container, 10, 2);
|
||||
}
|
||||
|
||||
layout->addWidget(new QLabel("Key"), 11, 1);
|
||||
_keybindingWidgets.key = new QComboBox;
|
||||
QStringList keyList;
|
||||
for (const KeyInfo& ki : KeyInfos) {
|
||||
keyList += QString::fromStdString(std::string(ki.name));
|
||||
}
|
||||
_keybindingWidgets.key->addItems(keyList);
|
||||
_keybindingWidgets.key->setCurrentIndex(-1);
|
||||
_keybindingWidgets.key->setEnabled(false);
|
||||
layout->addWidget(_keybindingWidgets.key, 11, 2);
|
||||
|
||||
layout->addWidget(new QLabel("Action chooser"), 12, 1);
|
||||
_keybindingWidgets.action = new QComboBox;
|
||||
_keybindingWidgets.action->setToolTip(
|
||||
"You can select any of the actions defined above here to be associated with the "
|
||||
"selected keybind. Selecting an action from this dropdown menu will "
|
||||
"automatically enter it into the text field below and overwrite any value that "
|
||||
"already is entered in there"
|
||||
);
|
||||
for (const Profile::Action& action : _actionData) {
|
||||
_keybindingWidgets.action->addItem(QString::fromStdString(action.identifier));
|
||||
}
|
||||
connect(
|
||||
_keybindingWidgets.action, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
this, &ActionDialog::keybindingActionSelected
|
||||
);
|
||||
|
||||
_keybindingWidgets.action->setEnabled(false);
|
||||
layout->addWidget(_keybindingWidgets.action, 12, 2);
|
||||
|
||||
layout->addWidget(new QLabel("Action"), 13, 1);
|
||||
_keybindingWidgets.actionText = new QLineEdit;
|
||||
_keybindingWidgets.actionText->setToolTip(
|
||||
"This is the action that will be triggered when the keybind is pressed. In the "
|
||||
"majority of cases, you do not need to enter something here manually, but "
|
||||
"instead select the action from the dropdown list above. However, if you know "
|
||||
"that an action with a specific identifier will exist at runtime, for example if "
|
||||
"it is defined in an asset included in this profile, you can enter the "
|
||||
"identifier of that action manually here to associate a key with it. If the "
|
||||
"identifer does not exist, an error will be logged when trying to bind the key "
|
||||
"at startup."
|
||||
);
|
||||
_keybindingWidgets.actionText->setEnabled(false);
|
||||
layout->addWidget(_keybindingWidgets.actionText, 13, 2);
|
||||
|
||||
|
||||
// +/- buttons
|
||||
QWidget* container = new QWidget;
|
||||
QBoxLayout* containerLayout = new QHBoxLayout(container);
|
||||
_keybindingWidgets.addButton = new QPushButton("+");
|
||||
_keybindingWidgets.addButton->setObjectName("add-button");
|
||||
_keybindingWidgets.addButton->setToolTip(
|
||||
"Adds a new keybinding to the list of all keybindings"
|
||||
);
|
||||
QObject::connect(
|
||||
_keybindingWidgets.addButton, &QPushButton::clicked,
|
||||
this, &ActionDialog::keybindingAdd
|
||||
);
|
||||
containerLayout->addWidget(_keybindingWidgets.addButton);
|
||||
|
||||
_keybindingWidgets.removeButton = new QPushButton("-");
|
||||
_keybindingWidgets.removeButton->setObjectName("remove-button");
|
||||
_keybindingWidgets.removeButton->setToolTip(
|
||||
"Removes the currently selected keybinding"
|
||||
);
|
||||
_keybindingWidgets.removeButton->setEnabled(false);
|
||||
QObject::connect(
|
||||
_keybindingWidgets.removeButton, &QPushButton::clicked,
|
||||
this, &ActionDialog::keybindingRemove
|
||||
);
|
||||
containerLayout->addWidget(_keybindingWidgets.removeButton);
|
||||
layout->addWidget(container, 14, 0, Qt::AlignLeft);
|
||||
|
||||
// Save/Cancel
|
||||
_keybindingWidgets.saveButtons = new QDialogButtonBox;
|
||||
_keybindingWidgets.saveButtons->setToolTip(
|
||||
"Saves or discards all changes to the currently selected keybinding"
|
||||
);
|
||||
_keybindingWidgets.saveButtons->setEnabled(false);
|
||||
_keybindingWidgets.saveButtons->setStandardButtons(
|
||||
QDialogButtonBox::Save | QDialogButtonBox::Cancel
|
||||
);
|
||||
QObject::connect(
|
||||
_keybindingWidgets.saveButtons, &QDialogButtonBox::accepted,
|
||||
this, &ActionDialog::keybindingSaved
|
||||
);
|
||||
QObject::connect(
|
||||
_keybindingWidgets.saveButtons, &QDialogButtonBox::rejected,
|
||||
this, &ActionDialog::keybindingRejected
|
||||
);
|
||||
|
||||
layout->addWidget(_keybindingWidgets.saveButtons, 14, 2, Qt::AlignRight);
|
||||
}
|
||||
|
||||
void ActionDialog::applyChanges() {
|
||||
*_actions = std::move(_actionData);
|
||||
*_keybindings = std::move(_keybindingsData);
|
||||
accept();
|
||||
}
|
||||
|
||||
Profile::Action* ActionDialog::selectedAction() {
|
||||
QListWidgetItem* item = _actionWidgets.list->currentItem();
|
||||
const int idx = _actionWidgets.list->row(item);
|
||||
return idx != -1 ? &_actionData[idx] : nullptr;
|
||||
}
|
||||
|
||||
void ActionDialog::actionAdd() {
|
||||
_actionWidgets.list->addItem("");
|
||||
_actionData.push_back(Profile::Action());
|
||||
_actionWidgets.list->setCurrentRow(_actionWidgets.list->count() - 1);
|
||||
}
|
||||
|
||||
void ActionDialog::actionRemove() {
|
||||
const openspace::Profile::Action* action = selectedAction();
|
||||
ghoul_assert(action, "An action must exist at this point");
|
||||
|
||||
ghoul_assert(
|
||||
_actionWidgets.list->count() == static_cast<int>(_actionData.size()),
|
||||
"Action list and data has desynced"
|
||||
);
|
||||
|
||||
// We can't remove an action if it has a keyboard shortcut attached to it
|
||||
for (size_t i = 0; i < _keybindingsData.size(); ++i) {
|
||||
const Profile::Keybinding& kb = _keybindingsData[i];
|
||||
if (kb.action != action->identifier) {
|
||||
continue;
|
||||
}
|
||||
QMessageBox::StandardButton button = QMessageBox::information(
|
||||
this,
|
||||
"Remove action",
|
||||
QString::fromStdString(fmt::format(
|
||||
"Action '{}' is used in the keybind '{}' and cannot be removed unless "
|
||||
"the keybind is removed as well. Do you want to remove the keybind as "
|
||||
"well?",
|
||||
action->identifier, ghoul::to_string(kb.key)
|
||||
)),
|
||||
QMessageBox::StandardButton::Yes,
|
||||
QMessageBox::StandardButton::No
|
||||
);
|
||||
if (button == QMessageBox::StandardButton::Yes) {
|
||||
_keybindingsData.erase(_keybindingsData.begin() + i);
|
||||
delete _keybindingWidgets.list->takeItem(static_cast<int>(i));
|
||||
i--;
|
||||
}
|
||||
else {
|
||||
// If the user chooses 'No' at least once, we have to bail
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _actionData.size(); ++i) {
|
||||
if (_actionData[i].identifier == action->identifier) {
|
||||
_actionData.erase(_actionData.begin() + i);
|
||||
delete _actionWidgets.list->takeItem(static_cast<int>(i));
|
||||
clearActionFields();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ghoul_assert(false, "We shouldn't be able to get here");
|
||||
}
|
||||
|
||||
void ActionDialog::actionSelected() {
|
||||
const Profile::Action* action = selectedAction();
|
||||
if (action) {
|
||||
// Action selected
|
||||
_actionWidgets.identifier->setText(QString::fromStdString(action->identifier));
|
||||
_actionWidgets.identifier->setEnabled(true);
|
||||
_actionWidgets.name->setText(QString::fromStdString(action->name));
|
||||
_actionWidgets.name->setEnabled(true);
|
||||
_actionWidgets.guiPath->setText(QString::fromStdString(action->guiPath));
|
||||
_actionWidgets.guiPath->setEnabled(true);
|
||||
_actionWidgets.documentation->setText(
|
||||
QString::fromStdString(action->documentation)
|
||||
);
|
||||
_actionWidgets.documentation->setEnabled(true);
|
||||
_actionWidgets.isLocal->setChecked(action->isLocal);
|
||||
_actionWidgets.isLocal->setEnabled(true);
|
||||
_actionWidgets.script->setText(QString::fromStdString(action->script));
|
||||
_actionWidgets.script->setEnabled(true);
|
||||
_actionWidgets.addButton->setEnabled(false);
|
||||
_actionWidgets.removeButton->setEnabled(true);
|
||||
_actionWidgets.saveButtons->setEnabled(true);
|
||||
}
|
||||
else {
|
||||
// No action selected
|
||||
_actionWidgets.addButton->setEnabled(true);
|
||||
_actionWidgets.removeButton->setEnabled(false);
|
||||
_actionWidgets.saveButtons->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void ActionDialog::actionSaved() {
|
||||
std::string newIdentifier = _actionWidgets.identifier->text().toStdString();
|
||||
if (newIdentifier.empty()) {
|
||||
QMessageBox::critical(this, "Empty identifier", "Identifier must not be empty");
|
||||
return;
|
||||
}
|
||||
|
||||
Profile::Action* action = selectedAction();
|
||||
std::string oldIdentifier = action->identifier;
|
||||
if (oldIdentifier != newIdentifier) {
|
||||
// The identifier is a bit special as we need to make sure that we didn't
|
||||
// accidentally create a duplicate while renaming the currently selected action.
|
||||
// Also if we didn't create a duplicate, meaning that we renamed an action to a
|
||||
// new valid identifier, we need to make sure that we update all keybinds that
|
||||
// referenced the old value are updated to use the new name instead
|
||||
|
||||
const auto it = std::find_if(
|
||||
_actionData.begin(), _actionData.end(),
|
||||
[id = newIdentifier](const Profile::Action& action) {
|
||||
return action.identifier == id;
|
||||
}
|
||||
);
|
||||
if (it != _actionData.end()) {
|
||||
QMessageBox::critical(
|
||||
this,
|
||||
"Duplicate identifier",
|
||||
"The chosen identifier was already used in another action. Identifiers "
|
||||
"have to be unique. Please choose a different identfier."
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// If we got this far, we have a new identifier and it is a new one, so we need to
|
||||
// update other keybinds now
|
||||
ghoul_assert(
|
||||
_keybindingWidgets.list->count() == _keybindingsData.size(),
|
||||
"The list and data got out of sync"
|
||||
);
|
||||
for (int i = 0; i < _keybindingWidgets.list->count(); ++i) {
|
||||
if (_keybindingsData[i].action == oldIdentifier) {
|
||||
_keybindingsData[i].action = newIdentifier;
|
||||
updateListItem(_keybindingWidgets.list->item(i), _keybindingsData[i]);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < _keybindingWidgets.action->count(); ++i) {
|
||||
if (_keybindingWidgets.action->itemText(i).toStdString() == oldIdentifier) {
|
||||
_keybindingWidgets.action->setItemText(
|
||||
i,
|
||||
QString::fromStdString(newIdentifier)
|
||||
);
|
||||
}
|
||||
}
|
||||
action->identifier = newIdentifier;
|
||||
}
|
||||
|
||||
|
||||
action->name = _actionWidgets.name->text().toStdString();
|
||||
action->guiPath = _actionWidgets.guiPath->text().toStdString();
|
||||
action->documentation = _actionWidgets.documentation->text().toStdString();
|
||||
action->isLocal = _actionWidgets.isLocal->isChecked();
|
||||
action->script = _actionWidgets.script->toPlainText().toStdString();
|
||||
|
||||
updateListItem(_actionWidgets.list->currentItem(), *action);
|
||||
clearActionFields();
|
||||
}
|
||||
|
||||
void ActionDialog::clearActionFields() {
|
||||
_actionWidgets.list->setCurrentRow(-1);
|
||||
_actionWidgets.identifier->clear();
|
||||
_actionWidgets.identifier->setEnabled(false);
|
||||
_actionWidgets.name->clear();
|
||||
_actionWidgets.name->setEnabled(false);
|
||||
_actionWidgets.guiPath->clear();
|
||||
_actionWidgets.guiPath->setEnabled(false);
|
||||
_actionWidgets.documentation->clear();
|
||||
_actionWidgets.documentation->setEnabled(false);
|
||||
_actionWidgets.isLocal->setChecked(false);
|
||||
_actionWidgets.isLocal->setEnabled(false);
|
||||
_actionWidgets.script->clear();
|
||||
_actionWidgets.script->setEnabled(false);
|
||||
_actionWidgets.saveButtons->setEnabled(false);
|
||||
}
|
||||
|
||||
void ActionDialog::actionRejected() {
|
||||
if (_actionData.back().identifier.empty()) {
|
||||
// This happens if someone creates a new action and never gave an identifier
|
||||
delete _actionWidgets.list->takeItem(_actionWidgets.list->count() - 1);
|
||||
_actionData.erase(_actionData.begin() + _actionData.size() - 1);
|
||||
}
|
||||
|
||||
clearActionFields();
|
||||
}
|
||||
|
||||
Profile::Keybinding* ActionDialog::selectedKeybinding() {
|
||||
QListWidgetItem* item = _keybindingWidgets.list->currentItem();
|
||||
const int idx = _keybindingWidgets.list->row(item);
|
||||
return idx != -1 ? &_keybindingsData[idx] : nullptr;
|
||||
}
|
||||
|
||||
void ActionDialog::keybindingAdd() {
|
||||
_keybindingWidgets.list->addItem("");
|
||||
_keybindingsData.push_back(Profile::Keybinding());
|
||||
_keybindingWidgets.list->setCurrentRow(_keybindingWidgets.list->count() - 1);
|
||||
}
|
||||
|
||||
void ActionDialog::keybindingRemove() {
|
||||
const Profile::Keybinding* keybinding = selectedKeybinding();
|
||||
ghoul_assert(keybinding, "A keybinding must be selected at this point");
|
||||
|
||||
for (size_t i = 0; i < _keybindingsData.size(); ++i) {
|
||||
if (_keybindingsData[i].key == keybinding->key &&
|
||||
_keybindingsData[i].action == keybinding->action)
|
||||
{
|
||||
_keybindingsData.erase(_keybindingsData.begin() + i);
|
||||
delete _keybindingWidgets.list->takeItem(static_cast<int>(i));
|
||||
clearKeybindingFields();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ActionDialog::keybindingSelected() {
|
||||
const Profile::Keybinding* keybinding = selectedKeybinding();
|
||||
if (keybinding) {
|
||||
_keybindingWidgets.shiftModifier->setEnabled(true);
|
||||
_keybindingWidgets.shiftModifier->setChecked(
|
||||
hasKeyModifier(keybinding->key.modifier, KeyModifier::Shift)
|
||||
);
|
||||
_keybindingWidgets.ctrlModifier->setEnabled(true);
|
||||
_keybindingWidgets.ctrlModifier->setChecked(
|
||||
hasKeyModifier(keybinding->key.modifier, KeyModifier::Control)
|
||||
);
|
||||
_keybindingWidgets.altModifier->setEnabled(true);
|
||||
_keybindingWidgets.altModifier->setChecked(
|
||||
hasKeyModifier(keybinding->key.modifier, KeyModifier::Alt)
|
||||
);
|
||||
|
||||
std::string key = ghoul::to_string(keybinding->key.key);
|
||||
_keybindingWidgets.key->setCurrentText(QString::fromStdString(key));
|
||||
_keybindingWidgets.key->setEnabled(true);
|
||||
_keybindingWidgets.action->setCurrentText(QString::fromStdString(keybinding->action));
|
||||
_keybindingWidgets.action->setEnabled(true);
|
||||
_keybindingWidgets.actionText->setText(
|
||||
QString::fromStdString(keybinding->action)
|
||||
);
|
||||
_keybindingWidgets.actionText->setEnabled(true);
|
||||
_keybindingWidgets.addButton->setEnabled(false);
|
||||
_keybindingWidgets.removeButton->setEnabled(true);
|
||||
_keybindingWidgets.saveButtons->setEnabled(true);
|
||||
}
|
||||
else {
|
||||
// No keybinding selected
|
||||
_keybindingWidgets.addButton->setEnabled(true);
|
||||
_keybindingWidgets.removeButton->setEnabled(false);
|
||||
_keybindingWidgets.saveButtons->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void ActionDialog::keybindingActionSelected(int) {
|
||||
_keybindingWidgets.actionText->setText(_keybindingWidgets.action->currentText());
|
||||
}
|
||||
|
||||
void ActionDialog::keybindingSaved() {
|
||||
Profile::Keybinding* keybinding = selectedKeybinding();
|
||||
ghoul_assert(keybinding, "There must be a selected action at this point");
|
||||
|
||||
KeyModifier km = KeyModifier::None;
|
||||
if (_keybindingWidgets.shiftModifier->isChecked()) {
|
||||
km |= KeyModifier::Shift;
|
||||
}
|
||||
if (_keybindingWidgets.altModifier->isChecked()) {
|
||||
km |= KeyModifier::Alt;
|
||||
}
|
||||
if (_keybindingWidgets.ctrlModifier->isChecked()) {
|
||||
km |= KeyModifier::Control;
|
||||
}
|
||||
|
||||
keybinding->key = stringToKey(_keybindingWidgets.key->currentText().toStdString());
|
||||
keybinding->key.modifier = km;
|
||||
keybinding->action = _keybindingWidgets.actionText->text().toStdString();
|
||||
|
||||
updateListItem(_keybindingWidgets.list->currentItem(), *keybinding);
|
||||
clearKeybindingFields();
|
||||
}
|
||||
|
||||
void ActionDialog::clearKeybindingFields() {
|
||||
_keybindingWidgets.list->setCurrentRow(-1);
|
||||
_keybindingWidgets.shiftModifier->setChecked(false);
|
||||
_keybindingWidgets.shiftModifier->setEnabled(false);
|
||||
_keybindingWidgets.ctrlModifier->setChecked(false);
|
||||
_keybindingWidgets.ctrlModifier->setEnabled(false);
|
||||
_keybindingWidgets.altModifier->setChecked(false);
|
||||
_keybindingWidgets.altModifier->setEnabled(false);
|
||||
_keybindingWidgets.key->setCurrentIndex(-1);
|
||||
_keybindingWidgets.key->setEnabled(false);
|
||||
_keybindingWidgets.action->setCurrentIndex(-1);
|
||||
_keybindingWidgets.action->setEnabled(false);
|
||||
_keybindingWidgets.actionText->clear();
|
||||
_keybindingWidgets.actionText->setEnabled(false);
|
||||
}
|
||||
|
||||
void ActionDialog::keybindingRejected() {
|
||||
clearKeybindingFields();
|
||||
}
|
||||
@@ -35,17 +35,17 @@
|
||||
#include <QVBoxLayout>
|
||||
#include <sstream>
|
||||
|
||||
AdditionalScriptsDialog::AdditionalScriptsDialog(openspace::Profile& profile,
|
||||
QWidget* parent)
|
||||
AdditionalScriptsDialog::AdditionalScriptsDialog(QWidget* parent,
|
||||
std::vector<std::string>* scripts)
|
||||
: QDialog(parent)
|
||||
, _profile(profile)
|
||||
, _scripts(scripts)
|
||||
, _scriptsData(*_scripts)
|
||||
{
|
||||
setWindowTitle("Additional Scripts");
|
||||
createWidgets();
|
||||
|
||||
std::vector<std::string> scripts = _profile.additionalScripts();
|
||||
std::string scriptText = std::accumulate(
|
||||
scripts.begin(), scripts.end(),
|
||||
_scriptsData.begin(), _scriptsData.end(),
|
||||
std::string(), [](std::string lhs, std::string rhs) { return lhs + rhs + '\n'; }
|
||||
);
|
||||
_textScripts->setText(QString::fromStdString(std::move(scriptText)));
|
||||
@@ -96,7 +96,7 @@ void AdditionalScriptsDialog::parseScript() {
|
||||
std::getline(iss, s);
|
||||
additionalScripts.push_back(std::move(s));
|
||||
}
|
||||
_profile.setAdditionalScripts(additionalScripts);
|
||||
*_scripts = std::move(additionalScripts);
|
||||
accept();
|
||||
}
|
||||
|
||||
|
||||
@@ -123,8 +123,9 @@ namespace {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
AssetsDialog::AssetsDialog(openspace::Profile& profile, const std::string& assetBasePath,
|
||||
const std::string& userAssetBasePath, QWidget* parent)
|
||||
AssetsDialog::AssetsDialog(QWidget* parent, openspace::Profile* profile,
|
||||
const std::string& assetBasePath,
|
||||
const std::string& userAssetBasePath)
|
||||
: QDialog(parent)
|
||||
, _profile(profile)
|
||||
{
|
||||
@@ -158,10 +159,10 @@ AssetsDialog::AssetsDialog(openspace::Profile& profile, const std::string& asset
|
||||
connect(_assetTree, &QTreeView::clicked, this, &AssetsDialog::selected);
|
||||
|
||||
|
||||
for (const std::string& a : _profile.assets()) {
|
||||
QModelIndex parent = _assetTreeModel.index(-1, 0);
|
||||
int nRows = _assetTreeModel.rowCount(parent);
|
||||
traverseToFindFilesystemMatch(_assetTreeModel, parent, nRows, a);
|
||||
for (const std::string& a : _profile->assets) {
|
||||
QModelIndex p = _assetTreeModel.index(-1, 0);
|
||||
int nRows = _assetTreeModel.rowCount(p);
|
||||
traverseToFindFilesystemMatch(_assetTreeModel, p, nRows, a);
|
||||
}
|
||||
|
||||
int nRows = _assetTreeModel.rowCount(_assetTreeModel.index(-1, 0));
|
||||
@@ -224,13 +225,13 @@ QString AssetsDialog::createTextSummary() {
|
||||
}
|
||||
|
||||
void AssetsDialog::parseSelections() {
|
||||
_profile.clearAssets();
|
||||
_profile->assets.clear();
|
||||
std::vector<std::string> summaryPaths;
|
||||
std::vector<AssetTreeItem*> summaryItems;
|
||||
_assetTreeModel.getSelectedAssets(summaryPaths, summaryItems);
|
||||
|
||||
for (const std::string& sel : summaryPaths) {
|
||||
_profile.addAsset(sel);
|
||||
_profile->addAsset(sel);
|
||||
}
|
||||
accept();
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include "profile/cameradialog.h"
|
||||
|
||||
#include "profile/line.h"
|
||||
#include <openspace/scene/profile.h>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QDoubleValidator>
|
||||
#include <QFrame>
|
||||
@@ -56,15 +55,16 @@ namespace {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
CameraDialog::CameraDialog(openspace::Profile& profile, QWidget *parent)
|
||||
CameraDialog::CameraDialog(QWidget* parent,
|
||||
std::optional<openspace::Profile::CameraType>* camera)
|
||||
: QDialog(parent)
|
||||
, _profile(profile)
|
||||
, _camera(camera)
|
||||
{
|
||||
setWindowTitle("Set Camera Position");
|
||||
createWidgets();
|
||||
|
||||
if (_profile.camera().has_value()) {
|
||||
openspace::Profile::CameraType type = *_profile.camera();
|
||||
if (_camera->has_value()) {
|
||||
const openspace::Profile::CameraType& type = **_camera;
|
||||
std::visit(overloaded {
|
||||
[this](const openspace::Profile::CameraNavState& nav) {
|
||||
_tabWidget->setCurrentIndex(CameraTypeNav);
|
||||
@@ -406,7 +406,7 @@ void CameraDialog::approved() {
|
||||
else {
|
||||
nav.pitch = std::nullopt;
|
||||
}
|
||||
_profile.setCamera(nav);
|
||||
*_camera = std::move(nav);
|
||||
}
|
||||
else if (_tabWidget->currentIndex() == CameraTypeGeo) {
|
||||
openspace::Profile::CameraGoToGeo geo;
|
||||
@@ -416,7 +416,7 @@ void CameraDialog::approved() {
|
||||
if (!_geoState.altitude->text().isEmpty()) {
|
||||
geo.altitude = _geoState.altitude->text().toDouble();
|
||||
}
|
||||
_profile.setCamera(geo);
|
||||
*_camera = std::move(geo);
|
||||
}
|
||||
|
||||
accept();
|
||||
|
||||
@@ -80,16 +80,15 @@ namespace {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
DeltaTimesDialog::DeltaTimesDialog(openspace::Profile& profile, QWidget *parent)
|
||||
DeltaTimesDialog::DeltaTimesDialog(QWidget* parent, std::vector<double>* deltaTimes)
|
||||
: QDialog(parent)
|
||||
, _profile(profile)
|
||||
, _deltaTimes(deltaTimes)
|
||||
, _deltaTimesData(*_deltaTimes)
|
||||
{
|
||||
setWindowTitle("Simulation Time Increments");
|
||||
createWidgets();
|
||||
|
||||
_data = _profile.deltaTimes();
|
||||
|
||||
for (size_t d = 0; d < _data.size(); ++d) {
|
||||
for (size_t d = 0; d < _deltaTimesData.size(); ++d) {
|
||||
std::string summary = createSummaryForDeltaTime(d, true);
|
||||
_listWidget->addItem(new QListWidgetItem(QString::fromStdString(summary)));
|
||||
}
|
||||
@@ -204,7 +203,11 @@ std::string DeltaTimesDialog::createSummaryForDeltaTime(size_t idx, bool forList
|
||||
}
|
||||
|
||||
if (forListView) {
|
||||
s += '\t' + std::to_string(_data.at(idx)) + '\t' + timeDescription(_data.at(idx));
|
||||
s += fmt::format(
|
||||
"\t{}\t{}",
|
||||
std::to_string(_deltaTimesData.at(idx)),
|
||||
timeDescription(_deltaTimesData.at(idx))
|
||||
);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
@@ -213,16 +216,16 @@ void DeltaTimesDialog::listItemSelected() {
|
||||
QListWidgetItem *item = _listWidget->currentItem();
|
||||
int index = _listWidget->row(item);
|
||||
|
||||
if (index < (static_cast<int>(_data.size()) - 1)) {
|
||||
if (index < (static_cast<int>(_deltaTimesData.size()) - 1)) {
|
||||
_listWidget->setCurrentRow(index);
|
||||
}
|
||||
|
||||
if (!_data.empty()) {
|
||||
if (_data.at(index) == 0) {
|
||||
if (!_deltaTimesData.empty()) {
|
||||
if (_deltaTimesData.at(index) == 0) {
|
||||
_seconds->clear();
|
||||
}
|
||||
else {
|
||||
_seconds->setText(QString::number(_data.at(index)));
|
||||
_seconds->setText(QString::number(_deltaTimesData.at(index)));
|
||||
}
|
||||
}
|
||||
_editModeNewItem = true;
|
||||
@@ -231,8 +234,8 @@ void DeltaTimesDialog::listItemSelected() {
|
||||
|
||||
void DeltaTimesDialog::setLabelForKey(int index, bool editMode, std::string color) {
|
||||
std::string labelS = "Set Simulation Time Increment for key";
|
||||
if (index >= static_cast<int>(_data.size())) {
|
||||
index = static_cast<int>(_data.size()) - 1;
|
||||
if (index >= static_cast<int>(_deltaTimesData.size())) {
|
||||
index = static_cast<int>(_deltaTimesData.size()) - 1;
|
||||
}
|
||||
if (editMode) {
|
||||
labelS += " '" + createSummaryForDeltaTime(index, false) + "':";
|
||||
@@ -262,7 +265,7 @@ bool DeltaTimesDialog::isLineEmpty(int index) {
|
||||
if (!_listWidget->item(index)->text().isEmpty()) {
|
||||
isEmpty = false;
|
||||
}
|
||||
if (!_data.empty() && (_data.at(0) != 0)) {
|
||||
if (!_deltaTimesData.empty() && (_deltaTimesData.at(0) != 0)) {
|
||||
isEmpty = false;
|
||||
}
|
||||
return isEmpty;
|
||||
@@ -276,11 +279,11 @@ void DeltaTimesDialog::addDeltaTimeValue() {
|
||||
// Special case where list is "empty" but really has one line that is blank.
|
||||
// This is done because QListWidget does not seem to like having its sole
|
||||
// remaining item being removed.
|
||||
_data.at(0) = 0;
|
||||
_deltaTimesData.at(0) = 0;
|
||||
_listWidget->item(0)->setText(messageAddValue);
|
||||
}
|
||||
else if (_data.size() < MaxNumberOfKeys) {
|
||||
_data.push_back(0);
|
||||
else if (_deltaTimesData.size() < MaxNumberOfKeys) {
|
||||
_deltaTimesData.push_back(0);
|
||||
_listWidget->addItem(new QListWidgetItem(messageAddValue));
|
||||
}
|
||||
else {
|
||||
@@ -295,8 +298,8 @@ void DeltaTimesDialog::saveDeltaTimeValue() {
|
||||
QListWidgetItem* item = _listWidget->currentItem();
|
||||
if (item != nullptr) {
|
||||
int index = _listWidget->row(item);
|
||||
if (_data.size() > 0) {
|
||||
_data.at(index) = _seconds->text().toDouble();
|
||||
if (_deltaTimesData.size() > 0) {
|
||||
_deltaTimesData.at(index) = _seconds->text().toDouble();
|
||||
std::string summary = createSummaryForDeltaTime(index, true);
|
||||
_listWidget->item(index)->setText(QString::fromStdString(summary));
|
||||
transitionEditMode(index, false);
|
||||
@@ -308,7 +311,7 @@ void DeltaTimesDialog::saveDeltaTimeValue() {
|
||||
void DeltaTimesDialog::discardDeltaTimeValue() {
|
||||
listItemSelected();
|
||||
transitionEditMode(_listWidget->count() - 1, false);
|
||||
if (_editModeNewItem && !_data.empty() && _data.back() == 0) {
|
||||
if (_editModeNewItem && !_deltaTimesData.empty() && _deltaTimesData.back() == 0) {
|
||||
removeDeltaTimeValue();
|
||||
}
|
||||
_editModeNewItem = false;
|
||||
@@ -317,13 +320,13 @@ void DeltaTimesDialog::discardDeltaTimeValue() {
|
||||
void DeltaTimesDialog::removeDeltaTimeValue() {
|
||||
if (_listWidget->count() > 0) {
|
||||
if (_listWidget->count() == 1) {
|
||||
_data.at(0) = 0;
|
||||
_deltaTimesData.at(0) = 0;
|
||||
_listWidget->item(0)->setText("");
|
||||
}
|
||||
else {
|
||||
delete _listWidget->takeItem(_listWidget->count() - 1);
|
||||
if (!_data.empty()) {
|
||||
_data.pop_back();
|
||||
if (!_deltaTimesData.empty()) {
|
||||
_deltaTimesData.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -356,20 +359,20 @@ void DeltaTimesDialog::transitionEditMode(int index, bool state) {
|
||||
}
|
||||
|
||||
void DeltaTimesDialog::parseSelections() {
|
||||
if ((_data.size() == 1) && (_data.at(0) == 0)) {
|
||||
_data.clear();
|
||||
if ((_deltaTimesData.size() == 1) && (_deltaTimesData.at(0) == 0)) {
|
||||
_deltaTimesData.clear();
|
||||
}
|
||||
int finalNonzeroIndex = static_cast<int>(_data.size()) - 1;
|
||||
int finalNonzeroIndex = static_cast<int>(_deltaTimesData.size()) - 1;
|
||||
for (; finalNonzeroIndex >= 0; --finalNonzeroIndex) {
|
||||
if (_data.at(finalNonzeroIndex) != 0) {
|
||||
if (_deltaTimesData.at(finalNonzeroIndex) != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::vector<double> tempDt;
|
||||
for (int i = 0; i < (finalNonzeroIndex + 1); ++i) {
|
||||
tempDt.push_back(_data[i]);
|
||||
tempDt.push_back(_deltaTimesData[i]);
|
||||
}
|
||||
_profile.setDeltaTimes(tempDt);
|
||||
*_deltaTimes = std::move(_deltaTimesData);
|
||||
accept();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,577 +0,0 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2021 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include "profile/keybindingsdialog.h"
|
||||
|
||||
#include "profile/line.h"
|
||||
#include "profile/scriptlogdialog.h"
|
||||
|
||||
#include <openspace/scene/profile.h>
|
||||
#include <qevent.h>
|
||||
#include <algorithm>
|
||||
#include <QKeyEvent>
|
||||
#include <QCheckBox>
|
||||
#include <QVBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <QLabel>
|
||||
#include <QComboBox>
|
||||
#include <QLineEdit>
|
||||
#include <QTextEdit>
|
||||
#include <QDialogButtonBox>
|
||||
|
||||
using namespace openspace;
|
||||
|
||||
namespace {
|
||||
const Profile::Keybinding BlankKey= {
|
||||
{ Key::Unknown, KeyModifier::NoModifier },
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
true,
|
||||
""
|
||||
};
|
||||
|
||||
void replaceChars(std::string& src, const std::string& from, const std::string& to) {
|
||||
std::string newString;
|
||||
std::string::size_type found, last = 0;
|
||||
|
||||
while ((found = src.find(from, last)) != std::string::npos) {
|
||||
newString.append(src, last, (found - last));
|
||||
newString += to;
|
||||
last = found + from.length();
|
||||
}
|
||||
newString += src.substr(last);
|
||||
src.swap(newString);
|
||||
}
|
||||
|
||||
std::string truncateString(std::string& s) {
|
||||
const size_t maxLength = 50;
|
||||
replaceChars(s, "\n", ";");
|
||||
if (s.length() > maxLength) {
|
||||
s.resize(maxLength);
|
||||
s += "...";
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
std::string createOneLineSummary(Profile::Keybinding k) {
|
||||
std::string summary;
|
||||
|
||||
int keymod = static_cast<int>(k.key.modifier);
|
||||
if (keymod != static_cast<int>(KeyModifier::NoModifier)) {
|
||||
summary += KeyModifierNames.at(keymod) + " ";
|
||||
}
|
||||
int keyname = static_cast<int>(k.key.key);
|
||||
|
||||
summary += KeyNames.at(keyname) + " ";
|
||||
summary += truncateString(k.name) + " (";
|
||||
summary += truncateString(k.documentation) + ") @ ";
|
||||
summary += truncateString(k.guiPath) + " ";
|
||||
summary += (k.isLocal) ? "local" : "remote";
|
||||
summary += " `" + truncateString(k.script) + "`";
|
||||
|
||||
return summary;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
KeybindingsDialog::KeybindingsDialog(Profile& profile, QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, _profile(profile)
|
||||
, _data(_profile.keybindings())
|
||||
{
|
||||
setWindowTitle("Assign Keybindings");
|
||||
createWidgets();
|
||||
|
||||
transitionFromEditMode();
|
||||
}
|
||||
|
||||
void KeybindingsDialog::appendScriptsToKeybind(std::string scripts) {
|
||||
_scriptEdit->append(QString::fromStdString(std::move(scripts)));
|
||||
}
|
||||
|
||||
void KeybindingsDialog::createWidgets() {
|
||||
QBoxLayout* layout = new QVBoxLayout(this);
|
||||
{
|
||||
_list = new QListWidget;
|
||||
connect(
|
||||
_list, &QListWidget::itemSelectionChanged,
|
||||
this, &KeybindingsDialog::listItemSelected
|
||||
);
|
||||
_list->setAlternatingRowColors(true);
|
||||
_list->setMovement(QListView::Free);
|
||||
_list->setResizeMode(QListView::Adjust);
|
||||
|
||||
for (size_t i = 0; i < _data.size(); ++i) {
|
||||
std::string summary = createOneLineSummary(_data[i]);
|
||||
_list->addItem(new QListWidgetItem(QString::fromStdString(summary)));
|
||||
}
|
||||
|
||||
layout->addWidget(_list);
|
||||
}
|
||||
{
|
||||
QBoxLayout* box = new QHBoxLayout;
|
||||
_addButton = new QPushButton("Add new");
|
||||
connect(
|
||||
_addButton, &QPushButton::clicked,
|
||||
this, &KeybindingsDialog::listItemAdded
|
||||
);
|
||||
box->addWidget(_addButton);
|
||||
|
||||
_removeButton = new QPushButton("Remove");
|
||||
connect(
|
||||
_removeButton, &QPushButton::clicked,
|
||||
this, &KeybindingsDialog::listItemRemove
|
||||
);
|
||||
box->addWidget(_removeButton);
|
||||
box->addStretch();
|
||||
layout->addLayout(box);
|
||||
}
|
||||
layout->addWidget(new Line);
|
||||
{
|
||||
QGridLayout* box = new QGridLayout;
|
||||
|
||||
_keyModLabel = new QLabel("Key Modifier");
|
||||
box->addWidget(_keyModLabel, 0, 0);
|
||||
_keyModCombo = new QComboBox;
|
||||
_keyModCombo->setToolTip(
|
||||
"Modifier keys to hold while key is pressed (blank means none)"
|
||||
);
|
||||
|
||||
QStringList comboModKeysStringList;
|
||||
int modIdx = 0;
|
||||
for (const std::pair<const int, std::string>& m : KeyModifierNames) {
|
||||
comboModKeysStringList += QString::fromStdString(m.second);
|
||||
_mapModKeyComboBoxIndexToKeyValue.push_back(modIdx++);
|
||||
}
|
||||
_keyModCombo->addItems(comboModKeysStringList);
|
||||
connect(
|
||||
_keyModCombo, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
this, &KeybindingsDialog::keyModSelected
|
||||
);
|
||||
box->addWidget(_keyModCombo, 0, 1);
|
||||
|
||||
|
||||
_keyLabel = new QLabel("Key");
|
||||
box->addWidget(_keyLabel, 1, 0);
|
||||
_keyCombo = new QComboBox;
|
||||
_keyCombo->setToolTip("Key to press for this keybinding");
|
||||
|
||||
QStringList comboKeysStringList;
|
||||
for (int i = 0; i < static_cast<int>(Key::Last); ++i) {
|
||||
if (KeyNames.find(i) != KeyNames.end()) {
|
||||
comboKeysStringList += QString::fromStdString(KeyNames.at(i));
|
||||
// Create map to relate key combo box to integer value defined in Key
|
||||
_mapKeyComboBoxIndexToKeyValue.push_back(i);
|
||||
}
|
||||
}
|
||||
_keyCombo->addItems(comboKeysStringList);
|
||||
connect(
|
||||
_keyCombo, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
this, &KeybindingsDialog::keySelected
|
||||
);
|
||||
box->addWidget(_keyCombo, 1, 1);
|
||||
|
||||
|
||||
_nameLabel = new QLabel("Name:");
|
||||
box->addWidget(_nameLabel, 2, 0);
|
||||
_nameEdit = new QLineEdit;
|
||||
_nameEdit->setToolTip("Name assigned to this keybinding");
|
||||
box->addWidget(_nameEdit, 2, 1);
|
||||
|
||||
|
||||
_guiPathLabel = new QLabel("GUI Path:");
|
||||
box->addWidget(_guiPathLabel, 3, 0);
|
||||
_guiPathEdit = new QLineEdit;
|
||||
_guiPathEdit->setToolTip(
|
||||
"[OPTIONAL] Path for where this keybinding appears in GUI menu"
|
||||
);
|
||||
box->addWidget(_guiPathEdit, 3, 1);
|
||||
|
||||
|
||||
_documentationLabel = new QLabel("Documentation:");
|
||||
box->addWidget(_documentationLabel, 4, 0);
|
||||
_documentationEdit = new QLineEdit;
|
||||
_documentationEdit->setToolTip(
|
||||
"[OPTIONAL] Documentation entry for keybinding"
|
||||
);
|
||||
box->addWidget(_documentationEdit, 4, 1);
|
||||
|
||||
|
||||
_localCheck = new QCheckBox("Local");
|
||||
_localCheck->setToolTip(
|
||||
"Determines whether the command, when executed, should be shared with "
|
||||
"connected instances or only executed locally"
|
||||
);
|
||||
box->addWidget(_localCheck, 5, 0, 1, 2);
|
||||
|
||||
|
||||
_scriptLabel = new QLabel("Script");
|
||||
box->addWidget(_scriptLabel, 6, 0, 1, 2);
|
||||
|
||||
_chooseScriptsButton = new QPushButton("Choose Scripts");
|
||||
connect(
|
||||
_chooseScriptsButton, &QPushButton::clicked,
|
||||
this, &KeybindingsDialog::chooseScripts
|
||||
);
|
||||
box->addWidget(_chooseScriptsButton, 6, 1, 1, 1);
|
||||
|
||||
_scriptEdit = new QTextEdit;
|
||||
_scriptEdit->setAcceptRichText(false);
|
||||
_scriptEdit->setToolTip("Command(s) to execute at keypress event");
|
||||
_scriptEdit->setTabChangesFocus(true);
|
||||
box->addWidget(_scriptEdit, 7, 0, 1, 2);
|
||||
box->setRowStretch(7, 1);
|
||||
|
||||
QBoxLayout* buttonBox = new QHBoxLayout;
|
||||
_saveButton = new QPushButton("Save");
|
||||
connect(
|
||||
_saveButton, &QPushButton::clicked,
|
||||
this, &KeybindingsDialog::listItemSave
|
||||
);
|
||||
buttonBox->addWidget(_saveButton);
|
||||
|
||||
_cancelButton = new QPushButton("Cancel");
|
||||
connect(
|
||||
_cancelButton, &QPushButton::clicked,
|
||||
this, &KeybindingsDialog::listItemCancelSave
|
||||
);
|
||||
buttonBox->addWidget(_cancelButton);
|
||||
buttonBox->addStretch();
|
||||
box->addLayout(buttonBox, 8, 1, 1, 2);
|
||||
layout->addLayout(box);
|
||||
}
|
||||
layout->addWidget(new Line);
|
||||
{
|
||||
QBoxLayout* footerLayout = new QHBoxLayout;
|
||||
|
||||
_errorMsg = new QLabel;
|
||||
_errorMsg->setObjectName("error-message");
|
||||
_errorMsg->setWordWrap(true);
|
||||
footerLayout->addWidget(_errorMsg);
|
||||
|
||||
_buttonBox = new QDialogButtonBox;
|
||||
_buttonBox->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel);
|
||||
QObject::connect(
|
||||
_buttonBox, &QDialogButtonBox::accepted,
|
||||
this, &KeybindingsDialog::parseSelections
|
||||
);
|
||||
QObject::connect(
|
||||
_buttonBox, &QDialogButtonBox::rejected,
|
||||
this, &KeybindingsDialog::reject
|
||||
);
|
||||
footerLayout->addWidget(_buttonBox);
|
||||
layout->addLayout(footerLayout);
|
||||
}
|
||||
}
|
||||
|
||||
void KeybindingsDialog::listItemSelected() {
|
||||
QListWidgetItem *item = _list->currentItem();
|
||||
int index = _list->row(item);
|
||||
_currentKeybindingSelection = index;
|
||||
|
||||
if (_data.size() > 0) {
|
||||
Profile::Keybinding& k = _data[index];
|
||||
const int modifierKey = indexInKeyMapping(
|
||||
_mapModKeyComboBoxIndexToKeyValue,
|
||||
static_cast<int>(k.key.modifier)
|
||||
);
|
||||
_keyModCombo->setCurrentIndex(modifierKey);
|
||||
|
||||
if (k.key.key == Key::Unknown) {
|
||||
_keyCombo->setCurrentIndex(0);
|
||||
}
|
||||
else {
|
||||
const int key = indexInKeyMapping(
|
||||
_mapKeyComboBoxIndexToKeyValue,
|
||||
static_cast<int>(k.key.key)
|
||||
);
|
||||
_keyCombo->setCurrentIndex(key);
|
||||
}
|
||||
|
||||
// Do key here
|
||||
_nameEdit->setText(QString::fromStdString(k.name));
|
||||
_guiPathEdit->setText(QString::fromStdString(k.guiPath));
|
||||
_documentationEdit->setText(QString::fromStdString(k.documentation));
|
||||
_localCheck->setChecked(k.isLocal);
|
||||
_scriptEdit->setText(QString::fromStdString(k.script));
|
||||
}
|
||||
transitionToEditMode();
|
||||
}
|
||||
|
||||
void KeybindingsDialog::keySelected(int index) {
|
||||
_errorMsg->clear();
|
||||
int selectedKey = _mapKeyComboBoxIndexToKeyValue[index];
|
||||
checkForNumberKeyConflict(selectedKey);
|
||||
checkForBindingConflict(_keyModCombo->currentIndex(), selectedKey);
|
||||
}
|
||||
|
||||
void KeybindingsDialog::keyModSelected(int index) {
|
||||
_errorMsg->clear();
|
||||
int selectedKey = _mapModKeyComboBoxIndexToKeyValue[index];
|
||||
checkForBindingConflict(selectedKey,
|
||||
_mapKeyComboBoxIndexToKeyValue.at(_keyCombo->currentIndex()));
|
||||
}
|
||||
|
||||
void KeybindingsDialog::addStringToErrorDisplay(const QString& newString) {
|
||||
QString errorContents = _errorMsg->text();
|
||||
bool alreadyContainsString = (errorContents.indexOf(newString, 0) != -1);
|
||||
if (!alreadyContainsString) {
|
||||
errorContents = newString + errorContents;
|
||||
_errorMsg->setText(errorContents);
|
||||
}
|
||||
}
|
||||
|
||||
int KeybindingsDialog::indexInKeyMapping(std::vector<int>& mapVector, int keyInt) {
|
||||
const auto it = std::find(mapVector.cbegin(), mapVector.cend(), keyInt);
|
||||
return static_cast<int>(std::distance(mapVector.cbegin(), it));
|
||||
}
|
||||
|
||||
bool KeybindingsDialog::isLineEmpty(int index) {
|
||||
bool isEmpty = true;
|
||||
if (!_list->item(index)->text().isEmpty()) {
|
||||
isEmpty = false;
|
||||
}
|
||||
if (!_data.empty() && !_data.at(0).name.empty()) {
|
||||
isEmpty = false;
|
||||
}
|
||||
return isEmpty;
|
||||
}
|
||||
|
||||
void KeybindingsDialog::listItemAdded() {
|
||||
_data.push_back(BlankKey);
|
||||
_list->addItem(new QListWidgetItem(" (Enter details below & click 'Save')"));
|
||||
// Scroll down to that blank line highlighted
|
||||
_list->setCurrentRow(_list->count() - 1);
|
||||
|
||||
// Blank-out the 2 text fields, set combo box to index 0
|
||||
_keyModCombo->setCurrentIndex(static_cast<int>(_data.back().key.modifier));
|
||||
if (_data.back().key.key == Key::Unknown) {
|
||||
_keyCombo->setCurrentIndex(0);
|
||||
}
|
||||
else {
|
||||
_keyCombo->setCurrentIndex(static_cast<int>(_data.back().key.key));
|
||||
}
|
||||
_keyModCombo->setFocus(Qt::OtherFocusReason);
|
||||
_nameEdit->setText(QString::fromStdString(_data.back().name));
|
||||
_guiPathEdit->setText("/");
|
||||
_documentationEdit->setText(QString::fromStdString(_data.back().documentation));
|
||||
_localCheck->setChecked(false);
|
||||
_scriptEdit->setText(QString::fromStdString(_data.back().script));
|
||||
_currentKeybindingSelection = static_cast<int>(_data.size() - 1);
|
||||
_editModeNewItem = true;
|
||||
}
|
||||
|
||||
void KeybindingsDialog::checkForNumberKeyConflict(int key) {
|
||||
const QString numKeyWarning = "Warning: Using a number key may conflict with the "
|
||||
"keybindings for simulation time increments.\n";
|
||||
if (key >= static_cast<int>(Key::Num0) && key <= static_cast<int>(Key::Num9)) {
|
||||
addStringToErrorDisplay(numKeyWarning);
|
||||
}
|
||||
}
|
||||
|
||||
void KeybindingsDialog::checkForBindingConflict(int selectedModKey, int selectedKey) {
|
||||
const QString localWarn = "Warning: New selection conflicts with binding '";
|
||||
if (_currentKeybindingSelection >= static_cast<int>(_data.size())) {
|
||||
return;
|
||||
}
|
||||
KeyModifier newModifier = static_cast<KeyModifier>(selectedModKey);
|
||||
Key newKey = static_cast<Key>(selectedKey);
|
||||
for (int i = 0; i < static_cast<int>(_data.size()); ++i) {
|
||||
if (i == _currentKeybindingSelection) {
|
||||
continue;
|
||||
}
|
||||
openspace::Profile::Keybinding k = _data[i];
|
||||
if ((k.key.key == newKey) && (k.key.modifier == newModifier)) {
|
||||
addStringToErrorDisplay(localWarn + QString::fromStdString(k.name) + "'.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeybindingsDialog::listItemSave() {
|
||||
if (!areRequiredFormsFilled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QListWidgetItem* item = _list->currentItem();
|
||||
int index = _list->row(item);
|
||||
|
||||
if (!_data.empty()) {
|
||||
int keyModIdx = _mapModKeyComboBoxIndexToKeyValue.at(
|
||||
_keyModCombo->currentIndex());
|
||||
_data[index].key.modifier = static_cast<KeyModifier>(keyModIdx);
|
||||
int keyIdx = _mapKeyComboBoxIndexToKeyValue.at(_keyCombo->currentIndex());
|
||||
_data[index].key.key = static_cast<Key>(keyIdx);
|
||||
_data[index].name = _nameEdit->text().toStdString();
|
||||
_data[index].guiPath = _guiPathEdit->text().toStdString();
|
||||
_data[index].documentation = _documentationEdit->text().toStdString();
|
||||
_data[index].script = _scriptEdit->toPlainText().toStdString();
|
||||
_data[index].isLocal = (_localCheck->isChecked());
|
||||
std::string summary = createOneLineSummary(_data[index]);
|
||||
_list->item(index)->setText(QString::fromStdString(summary));
|
||||
}
|
||||
transitionFromEditMode();
|
||||
}
|
||||
|
||||
bool KeybindingsDialog::areRequiredFormsFilled() {
|
||||
bool requiredFormsFilled = true;
|
||||
std::string errors;
|
||||
if (_keyCombo->currentIndex() < 0) {
|
||||
errors += "Missing key";
|
||||
requiredFormsFilled = false;
|
||||
}
|
||||
if (_nameEdit->text().length() == 0) {
|
||||
if (!errors.empty()) {
|
||||
errors += ", ";
|
||||
}
|
||||
errors += "Missing keybinding name";
|
||||
requiredFormsFilled = false;
|
||||
}
|
||||
if (_scriptEdit->toPlainText().isEmpty()) {
|
||||
if (!errors.empty()) {
|
||||
errors += ", ";
|
||||
}
|
||||
errors += "Missing script";
|
||||
requiredFormsFilled = false;
|
||||
}
|
||||
_errorMsg->setText(QString::fromStdString(errors));
|
||||
return requiredFormsFilled;
|
||||
}
|
||||
|
||||
void KeybindingsDialog::listItemCancelSave() {
|
||||
listItemSelected();
|
||||
transitionFromEditMode();
|
||||
if (_editModeNewItem && !_data.empty() &&
|
||||
(_data.back().name.length() == 0 || _data.back().script.length() == 0 ||
|
||||
_data.back().key.key == Key::Unknown))
|
||||
{
|
||||
listItemRemove();
|
||||
}
|
||||
_editModeNewItem = false;
|
||||
}
|
||||
|
||||
void KeybindingsDialog::listItemRemove() {
|
||||
if (_list->count() > 0) {
|
||||
if (_list->count() == 1) {
|
||||
// Special case where last remaining item is being removed (QListWidget does
|
||||
// not like the final item being removed so instead clear it & leave it)
|
||||
_data.at(0) = BlankKey;
|
||||
_list->item(0)->setText("");
|
||||
}
|
||||
else {
|
||||
int index = _list->currentRow();
|
||||
if (index >= 0 && index < _list->count()) {
|
||||
_list->takeItem(index);
|
||||
if (!_data.empty()) {
|
||||
_data.erase(_data.begin() + index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_list->clearSelection();
|
||||
transitionFromEditMode();
|
||||
}
|
||||
|
||||
void KeybindingsDialog::transitionToEditMode() {
|
||||
_saveButton->setDisabled(true);
|
||||
_cancelButton->setDisabled(true);
|
||||
_buttonBox->setDisabled(true);
|
||||
_keyLabel->setText("<font color='black'>Key</font>");
|
||||
_keyModLabel->setText("<font color='black'>Key Modifier</font>");
|
||||
_nameLabel->setText("<font color='black'>Name</font>");
|
||||
_scriptLabel->setText("<font color='black'>Script</font>");
|
||||
_guiPathLabel->setText("<font color='black'>GUI Path</font>");
|
||||
_documentationLabel->setText("<font color='black'>Documentation</font>");
|
||||
|
||||
editBoxDisabled(false);
|
||||
_errorMsg->setText("");
|
||||
}
|
||||
|
||||
void KeybindingsDialog::transitionFromEditMode() {
|
||||
_list->setDisabled(false);
|
||||
_addButton->setDisabled(false);
|
||||
_removeButton->setDisabled(false);
|
||||
_saveButton->setDisabled(false);
|
||||
_cancelButton->setDisabled(false);
|
||||
_buttonBox->setDisabled(false);
|
||||
|
||||
_keyLabel->setText("<font color='light gray'>Key</font>");
|
||||
_keyModLabel->setText("<font color='light gray'>Key Modifier</font>");
|
||||
_nameLabel->setText("<font color='light gray'>Name</font>");
|
||||
_scriptLabel->setText("<font color='light gray'>Script</font>");
|
||||
_guiPathLabel->setText("<font color='light gray'>GUI Path</font>");
|
||||
_documentationLabel->setText("<font color='light gray'>Documentation</font>");
|
||||
editBoxDisabled(true);
|
||||
_errorMsg->setText("");
|
||||
}
|
||||
|
||||
void KeybindingsDialog::editBoxDisabled(bool disabled) {
|
||||
_keyLabel->setDisabled(disabled);
|
||||
_keyCombo->setDisabled(disabled);
|
||||
_keyModLabel->setDisabled(disabled);
|
||||
_keyModCombo->setDisabled(disabled);
|
||||
_nameLabel->setDisabled(disabled);
|
||||
_nameEdit->setDisabled(disabled);
|
||||
_guiPathLabel->setDisabled(disabled);
|
||||
_guiPathEdit->setDisabled(disabled);
|
||||
_documentationLabel->setDisabled(disabled);
|
||||
_documentationEdit->setDisabled(disabled);
|
||||
_localCheck->setDisabled(disabled);
|
||||
_scriptLabel->setDisabled(disabled);
|
||||
_scriptEdit->setDisabled(disabled);
|
||||
_cancelButton->setDisabled(disabled);
|
||||
_saveButton->setDisabled(disabled);
|
||||
_chooseScriptsButton->setDisabled(disabled);
|
||||
}
|
||||
|
||||
void KeybindingsDialog::parseSelections() {
|
||||
// Handle case with only one remaining but empty line
|
||||
if ((_data.size() == 1) && (_data.at(0).name.empty())) {
|
||||
_data.clear();
|
||||
}
|
||||
_profile.setKeybindings(_data);
|
||||
accept();
|
||||
}
|
||||
|
||||
void KeybindingsDialog::chooseScripts() {
|
||||
_errorMsg->clear();
|
||||
ScriptlogDialog d(this);
|
||||
connect(&d, &ScriptlogDialog::scriptsSelected, this, &KeybindingsDialog::appendScriptsToKeybind);
|
||||
d.exec();
|
||||
}
|
||||
|
||||
void KeybindingsDialog::keyPressEvent(QKeyEvent* evt) {
|
||||
if (evt->key() == Qt::Key_Enter || evt->key() == Qt::Key_Return) {
|
||||
return;
|
||||
}
|
||||
else if (evt->key() == Qt::Key_Escape) {
|
||||
if (_editModeNewItem) {
|
||||
listItemCancelSave();
|
||||
return;
|
||||
}
|
||||
}
|
||||
QDialog::keyPressEvent(evt);
|
||||
}
|
||||
|
||||
@@ -35,10 +35,10 @@
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
MarkNodesDialog::MarkNodesDialog(openspace::Profile& profile, QWidget* parent)
|
||||
MarkNodesDialog::MarkNodesDialog(QWidget* parent, std::vector<std::string>* markedNodes)
|
||||
: QDialog(parent)
|
||||
, _profile(profile)
|
||||
, _data(_profile.markNodes())
|
||||
, _markedNodes(markedNodes)
|
||||
, _markedNodesData(*_markedNodes)
|
||||
{
|
||||
setWindowTitle("Mark Interesting Nodes");
|
||||
createWidgets();
|
||||
@@ -55,9 +55,9 @@ void MarkNodesDialog::createWidgets() {
|
||||
_list->setMovement(QListView::Free);
|
||||
_list->setResizeMode(QListView::Adjust);
|
||||
|
||||
for (size_t i = 0; i < _data.size(); ++i) {
|
||||
for (size_t i = 0; i < _markedNodesData.size(); ++i) {
|
||||
_markedNodesListItems.push_back(
|
||||
new QListWidgetItem(QString::fromStdString(_data[i]))
|
||||
new QListWidgetItem(QString::fromStdString(_markedNodesData[i]))
|
||||
);
|
||||
_list->addItem(_markedNodesListItems[i]);
|
||||
}
|
||||
@@ -110,12 +110,17 @@ void MarkNodesDialog::listItemAdded() {
|
||||
}
|
||||
|
||||
std::string itemToAdd = _newNode->text().toStdString();
|
||||
const auto it = std::find(_data.cbegin(), _data.cend(), itemToAdd);
|
||||
if (it != _data.end()) {
|
||||
_list->setCurrentRow(static_cast<int>(std::distance(_data.cbegin(), it)));
|
||||
const auto it = std::find(
|
||||
_markedNodesData.cbegin(), _markedNodesData.cend(),
|
||||
itemToAdd
|
||||
);
|
||||
if (it != _markedNodesData.end()) {
|
||||
_list->setCurrentRow(
|
||||
static_cast<int>(std::distance(_markedNodesData.cbegin(), it))
|
||||
);
|
||||
}
|
||||
else {
|
||||
_data.push_back(itemToAdd);
|
||||
_markedNodesData.push_back(itemToAdd);
|
||||
_markedNodesListItems.push_back(new QListWidgetItem(_newNode->text()));
|
||||
_list->addItem(_markedNodesListItems.back());
|
||||
|
||||
@@ -136,12 +141,12 @@ void MarkNodesDialog::listItemRemove() {
|
||||
}
|
||||
|
||||
_list->takeItem(index);
|
||||
_data.erase(_data.begin() + index);
|
||||
_markedNodesData.erase(_markedNodesData.begin() + index);
|
||||
_markedNodesListItems.erase(_markedNodesListItems.begin() + index);
|
||||
}
|
||||
|
||||
void MarkNodesDialog::parseSelections() {
|
||||
_profile.setMarkNodes(_data);
|
||||
*_markedNodes = std::move(_markedNodesData);
|
||||
accept();
|
||||
}
|
||||
|
||||
|
||||
@@ -34,32 +34,32 @@
|
||||
#include <QVBoxLayout>
|
||||
#include <algorithm>
|
||||
|
||||
MetaDialog::MetaDialog(openspace::Profile& profile, QWidget *parent)
|
||||
MetaDialog::MetaDialog(QWidget* parent, std::optional<openspace::Profile::Meta>* meta)
|
||||
: QDialog(parent)
|
||||
, _profile(profile)
|
||||
, _meta(meta)
|
||||
{
|
||||
setWindowTitle("Meta");
|
||||
createWidgets();
|
||||
|
||||
if (_profile.meta().has_value()) {
|
||||
openspace::Profile::Meta meta = *_profile.meta();
|
||||
if (meta.name.has_value()) {
|
||||
_nameEdit->setText(QString::fromStdString(*meta.name));
|
||||
if (_meta->has_value()) {
|
||||
const openspace::Profile::Meta& m = **_meta;
|
||||
if (m.name.has_value()) {
|
||||
_nameEdit->setText(QString::fromStdString(*m.name));
|
||||
}
|
||||
if (meta.version.has_value()) {
|
||||
_versionEdit->setText(QString::fromStdString(*meta.version));
|
||||
if (m.version.has_value()) {
|
||||
_versionEdit->setText(QString::fromStdString(*m.version));
|
||||
}
|
||||
if (meta.description.has_value()) {
|
||||
_descriptionEdit->setText(QString::fromStdString(*meta.description));
|
||||
if (m.description.has_value()) {
|
||||
_descriptionEdit->setText(QString::fromStdString(*m.description));
|
||||
}
|
||||
if (meta.author.has_value()) {
|
||||
_authorEdit->setText(QString::fromStdString(*meta.author));
|
||||
if (m.author.has_value()) {
|
||||
_authorEdit->setText(QString::fromStdString(*m.author));
|
||||
}
|
||||
if (meta.url.has_value()) {
|
||||
_urlEdit->setText(QString::fromStdString(*meta.url));
|
||||
if (m.url.has_value()) {
|
||||
_urlEdit->setText(QString::fromStdString(*m.url));
|
||||
}
|
||||
if (meta.license.has_value()) {
|
||||
_licenseEdit->setText(QString::fromStdString(*meta.license));
|
||||
if (m.license.has_value()) {
|
||||
_licenseEdit->setText(QString::fromStdString(*m.license));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -127,10 +127,10 @@ void MetaDialog::save() {
|
||||
if (!_licenseEdit->text().isEmpty()) {
|
||||
m.license = _licenseEdit->text().toStdString();
|
||||
}
|
||||
_profile.setMeta(m);
|
||||
*_meta = std::move(m);
|
||||
}
|
||||
else {
|
||||
_profile.clearMeta();
|
||||
*_meta = std::nullopt;
|
||||
}
|
||||
accept();
|
||||
}
|
||||
|
||||
@@ -40,10 +40,11 @@ namespace {
|
||||
const Profile::Module Blank = { "", "", "" };
|
||||
} // namespace
|
||||
|
||||
ModulesDialog::ModulesDialog(Profile& profile, QWidget *parent)
|
||||
ModulesDialog::ModulesDialog(QWidget* parent,
|
||||
std::vector<openspace::Profile::Module>* modules)
|
||||
: QDialog(parent)
|
||||
, _profile(profile)
|
||||
, _data(_profile.modules())
|
||||
, _modules(modules)
|
||||
, _moduleData(*_modules)
|
||||
{
|
||||
setWindowTitle("Modules");
|
||||
createWidgets();
|
||||
@@ -63,7 +64,7 @@ void ModulesDialog::createWidgets() {
|
||||
_list->setMovement(QListView::Free);
|
||||
_list->setResizeMode(QListView::Adjust);
|
||||
|
||||
for (const Profile::Module& m : _data) {
|
||||
for (const Profile::Module& m : _moduleData) {
|
||||
_list->addItem(new QListWidgetItem(createOneLineSummary(m)));
|
||||
}
|
||||
layout->addWidget(_list);
|
||||
@@ -176,8 +177,8 @@ void ModulesDialog::listItemSelected() {
|
||||
QListWidgetItem* item = _list->currentItem();
|
||||
int index = _list->row(item);
|
||||
|
||||
if (!_data.empty()) {
|
||||
const Profile::Module& m = _data[index];
|
||||
if (!_moduleData.empty()) {
|
||||
const Profile::Module& m = _moduleData[index];
|
||||
_moduleEdit->setText(QString::fromStdString(m.name));
|
||||
if (m.loadedInstruction.has_value()) {
|
||||
_loadedEdit->setText(QString::fromStdString(*m.loadedInstruction));
|
||||
@@ -200,7 +201,7 @@ bool ModulesDialog::isLineEmpty(int index) const {
|
||||
if (!_list->item(index)->text().isEmpty()) {
|
||||
isEmpty = false;
|
||||
}
|
||||
if (!_data.empty() && !_data.at(0).name.empty()) {
|
||||
if (!_moduleData.empty() && !_moduleData.at(0).name.empty()) {
|
||||
isEmpty = false;
|
||||
}
|
||||
return isEmpty;
|
||||
@@ -213,13 +214,13 @@ void ModulesDialog::listItemAdded() {
|
||||
// Special case where list is "empty" but really has one line that is blank.
|
||||
// This is done because QListWidget does not seem to like having its sole
|
||||
// remaining item being removed.
|
||||
_data.at(0) = Blank;
|
||||
_moduleData.at(0) = Blank;
|
||||
_list->item(0)->setText(" (Enter details below & click 'Save')");
|
||||
_list->setCurrentRow(0);
|
||||
transitionToEditMode();
|
||||
}
|
||||
else {
|
||||
_data.push_back(Blank);
|
||||
_moduleData.push_back(Blank);
|
||||
_list->addItem(new QListWidgetItem(" (Enter details below & click 'Save')"));
|
||||
//Scroll down to that blank line highlighted
|
||||
_list->setCurrentRow(_list->count() - 1);
|
||||
@@ -227,16 +228,18 @@ void ModulesDialog::listItemAdded() {
|
||||
}
|
||||
|
||||
// Blank-out the 2 text fields, set combo box to index 0
|
||||
_moduleEdit->setText(QString::fromStdString(_data.back().name));
|
||||
if (_data.back().loadedInstruction.has_value()) {
|
||||
_loadedEdit->setText(QString::fromStdString(*_data.back().loadedInstruction));
|
||||
_moduleEdit->setText(QString::fromStdString(_moduleData.back().name));
|
||||
if (_moduleData.back().loadedInstruction.has_value()) {
|
||||
_loadedEdit->setText(QString::fromStdString(
|
||||
*_moduleData.back().loadedInstruction
|
||||
));
|
||||
}
|
||||
else {
|
||||
_loadedEdit->clear();
|
||||
}
|
||||
if (_data.back().notLoadedInstruction.has_value()) {
|
||||
if (_moduleData.back().notLoadedInstruction.has_value()) {
|
||||
_notLoadedEdit->setText(
|
||||
QString::fromStdString(*_data.back().notLoadedInstruction)
|
||||
QString::fromStdString(*_moduleData.back().notLoadedInstruction)
|
||||
);
|
||||
}
|
||||
else {
|
||||
@@ -255,11 +258,11 @@ void ModulesDialog::listItemSave() {
|
||||
QListWidgetItem* item = _list->currentItem();
|
||||
int index = _list->row(item);
|
||||
|
||||
if ( _data.size() > 0) {
|
||||
_data[index].name = _moduleEdit->text().toStdString();
|
||||
_data[index].loadedInstruction = _loadedEdit->text().toStdString();
|
||||
_data[index].notLoadedInstruction = _notLoadedEdit->text().toStdString();
|
||||
_list->item(index)->setText(createOneLineSummary(_data[index]));
|
||||
if (_moduleData.size() > 0) {
|
||||
_moduleData[index].name = _moduleEdit->text().toStdString();
|
||||
_moduleData[index].loadedInstruction = _loadedEdit->text().toStdString();
|
||||
_moduleData[index].notLoadedInstruction = _notLoadedEdit->text().toStdString();
|
||||
_list->item(index)->setText(createOneLineSummary(_moduleData[index]));
|
||||
}
|
||||
transitionFromEditMode();
|
||||
_editModeNewItem = false;
|
||||
@@ -267,7 +270,7 @@ void ModulesDialog::listItemSave() {
|
||||
|
||||
void ModulesDialog::listItemCancelSave() {
|
||||
transitionFromEditMode();
|
||||
if (_editModeNewItem && !_data.empty() && _data.back().name.empty()) {
|
||||
if (_editModeNewItem && !_moduleData.empty() && _moduleData.back().name.empty()) {
|
||||
listItemRemove();
|
||||
}
|
||||
_editModeNewItem = false;
|
||||
@@ -279,15 +282,15 @@ void ModulesDialog::listItemRemove() {
|
||||
if (_list->count() == 1) {
|
||||
// Special case where last remaining item is being removed (QListWidget
|
||||
// doesn't like the final item being removed so instead clear it)
|
||||
_data.at(0) = Blank;
|
||||
_moduleData.at(0) = Blank;
|
||||
_list->item(0)->setText("");
|
||||
}
|
||||
else {
|
||||
int index = _list->currentRow();
|
||||
if (index >= 0 && index < _list->count()) {
|
||||
delete _list->takeItem(index);
|
||||
if (!_data.empty()) {
|
||||
_data.erase(_data.begin() + index);
|
||||
if (!_moduleData.empty()) {
|
||||
_moduleData.erase(_moduleData.begin() + index);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -336,10 +339,10 @@ void ModulesDialog::editBoxDisabled(bool disabled) {
|
||||
|
||||
void ModulesDialog::parseSelections() {
|
||||
// Handle case with only one remaining but empty line
|
||||
if ((_data.size() == 1) && (_data.at(0).name.empty())) {
|
||||
_data.clear();
|
||||
if ((_moduleData.size() == 1) && (_moduleData.at(0).name.empty())) {
|
||||
_moduleData.clear();
|
||||
}
|
||||
_profile.setModules(_data);
|
||||
*_modules = std::move(_moduleData);
|
||||
accept();
|
||||
}
|
||||
|
||||
|
||||
@@ -24,11 +24,11 @@
|
||||
|
||||
#include "profile/profileedit.h"
|
||||
|
||||
#include "profile/actiondialog.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"
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "profile/propertiesdialog.h"
|
||||
#include "profile/timedialog.h"
|
||||
#include <openspace/scene/profile.h>
|
||||
#include <ghoul/fmt.h>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QKeyEvent>
|
||||
#include <QLabel>
|
||||
@@ -69,17 +70,18 @@ namespace {
|
||||
return results;
|
||||
}
|
||||
|
||||
std::string summarizeKeybindings(const std::vector<Profile::Keybinding>& keybindings)
|
||||
std::string summarizeKeybindings(const std::vector<Profile::Keybinding>& keybindings,
|
||||
const std::vector<Profile::Action>& actions)
|
||||
{
|
||||
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";
|
||||
const auto it = std::find_if(
|
||||
actions.cbegin(), actions.cend(),
|
||||
[id = k.action](const Profile::Action& a) { return a.identifier == id; }
|
||||
);
|
||||
|
||||
std::string name = it != actions.end() ? it->name : "Unknown action";
|
||||
results += fmt::format("{} ({})\n", name, ghoul::to_string(k.key));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
@@ -87,7 +89,7 @@ namespace {
|
||||
std::string summarizeProperties(const std::vector<Profile::Property>& properties) {
|
||||
std::string results;
|
||||
for (openspace::Profile::Property p : properties) {
|
||||
results += p.name + " = " + p.value + '\n';
|
||||
results += fmt::format("{} = {}\n", p.name, p.value);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
@@ -333,26 +335,26 @@ void ProfileEdit::createWidgets(const std::string& profileName) {
|
||||
}
|
||||
|
||||
void ProfileEdit::initSummaryTextForEachCategory() {
|
||||
_modulesLabel->setText(labelText(_profile.modules().size(), "Modules"));
|
||||
_modulesLabel->setText(labelText(_profile.modules.size(), "Modules"));
|
||||
|
||||
_assetsLabel->setText(labelText(_profile.assets().size(), "Assets"));
|
||||
_assetsEdit->setText(QString::fromStdString(summarizeAssets(_profile.assets())));
|
||||
_assetsLabel->setText(labelText(_profile.assets.size(), "Assets"));
|
||||
_assetsEdit->setText(QString::fromStdString(summarizeAssets(_profile.assets)));
|
||||
|
||||
_propertiesLabel->setText(labelText(_profile.properties().size(), "Properties"));
|
||||
_propertiesLabel->setText(labelText(_profile.properties.size(), "Properties"));
|
||||
_propertiesEdit->setText(
|
||||
QString::fromStdString(summarizeProperties(_profile.properties()))
|
||||
QString::fromStdString(summarizeProperties(_profile.properties))
|
||||
);
|
||||
|
||||
_keybindingsLabel->setText(labelText(_profile.keybindings().size(), "Keybindings"));
|
||||
_keybindingsEdit->setText(
|
||||
QString::fromStdString(summarizeKeybindings(_profile.keybindings()))
|
||||
);
|
||||
_keybindingsLabel->setText(labelText(_profile.keybindings.size(), "Keybindings"));
|
||||
_keybindingsEdit->setText(QString::fromStdString(
|
||||
summarizeKeybindings(_profile.keybindings, _profile.actions)
|
||||
));
|
||||
|
||||
_deltaTimesLabel->setText(
|
||||
labelText(_profile.deltaTimes().size(), "Simulation Time Increments")
|
||||
labelText(_profile.deltaTimes.size(), "Simulation Time Increments")
|
||||
);
|
||||
_interestingNodesLabel->setText(
|
||||
labelText(_profile.markNodes().size(), "Mark Interesting Nodes")
|
||||
labelText(_profile.markNodes.size(), "Mark Interesting Nodes")
|
||||
);
|
||||
}
|
||||
|
||||
@@ -401,68 +403,68 @@ void ProfileEdit::duplicateProfile() {
|
||||
|
||||
void ProfileEdit::openMeta() {
|
||||
_errorMsg->clear();
|
||||
MetaDialog(_profile, this).exec();
|
||||
MetaDialog(this, &_profile.meta).exec();
|
||||
}
|
||||
|
||||
void ProfileEdit::openModules() {
|
||||
_errorMsg->clear();
|
||||
ModulesDialog(_profile, this).exec();
|
||||
_modulesLabel->setText(labelText(_profile.modules().size(), "Modules"));
|
||||
ModulesDialog(this, &_profile.modules).exec();
|
||||
_modulesLabel->setText(labelText(_profile.modules.size(), "Modules"));
|
||||
}
|
||||
|
||||
void ProfileEdit::openProperties() {
|
||||
_errorMsg->clear();
|
||||
PropertiesDialog(_profile, this).exec();
|
||||
_propertiesLabel->setText(labelText(_profile.properties().size(), "Properties"));
|
||||
PropertiesDialog(this, &_profile.properties).exec();
|
||||
_propertiesLabel->setText(labelText(_profile.properties.size(), "Properties"));
|
||||
_propertiesEdit->setText(
|
||||
QString::fromStdString(summarizeProperties(_profile.properties()))
|
||||
QString::fromStdString(summarizeProperties(_profile.properties))
|
||||
);
|
||||
}
|
||||
|
||||
void ProfileEdit::openKeybindings() {
|
||||
_errorMsg->clear();
|
||||
KeybindingsDialog(_profile, this).exec();
|
||||
_keybindingsLabel->setText(labelText(_profile.keybindings().size(), "Keybindings"));
|
||||
_keybindingsEdit->setText(
|
||||
QString::fromStdString(summarizeKeybindings(_profile.keybindings()))
|
||||
);
|
||||
ActionDialog(this, &_profile.actions, &_profile.keybindings).exec();
|
||||
_keybindingsLabel->setText(labelText(_profile.keybindings.size(), "Keybindings"));
|
||||
_keybindingsEdit->setText(QString::fromStdString(
|
||||
summarizeKeybindings(_profile.keybindings, _profile.actions)
|
||||
));
|
||||
}
|
||||
|
||||
void ProfileEdit::openAssets() {
|
||||
_errorMsg->clear();
|
||||
AssetsDialog(_profile, _assetBasePath, _userAssetBasePath, this).exec();
|
||||
_assetsLabel->setText(labelText(_profile.assets().size(), "Assets"));
|
||||
_assetsEdit->setText(QString::fromStdString(summarizeAssets(_profile.assets())));
|
||||
AssetsDialog(this, &_profile, _assetBasePath, _userAssetBasePath).exec();
|
||||
_assetsLabel->setText(labelText(_profile.assets.size(), "Assets"));
|
||||
_assetsEdit->setText(QString::fromStdString(summarizeAssets(_profile.assets)));
|
||||
}
|
||||
|
||||
void ProfileEdit::openTime() {
|
||||
_errorMsg->clear();
|
||||
TimeDialog(_profile, this).exec();
|
||||
TimeDialog(this, &_profile.time).exec();
|
||||
}
|
||||
|
||||
void ProfileEdit::openDeltaTimes() {
|
||||
_errorMsg->clear();
|
||||
DeltaTimesDialog(_profile, this).exec();
|
||||
DeltaTimesDialog(this, &_profile.deltaTimes).exec();
|
||||
_deltaTimesLabel->setText(
|
||||
labelText(_profile.deltaTimes().size(), "Simulation Time Increments")
|
||||
labelText(_profile.deltaTimes.size(), "Simulation Time Increments")
|
||||
);
|
||||
}
|
||||
|
||||
void ProfileEdit::openAddedScripts() {
|
||||
_errorMsg->clear();
|
||||
AdditionalScriptsDialog(_profile, this).exec();
|
||||
AdditionalScriptsDialog(this, &_profile.additionalScripts).exec();
|
||||
}
|
||||
|
||||
void ProfileEdit::openCamera() {
|
||||
_errorMsg->clear();
|
||||
CameraDialog(_profile, this).exec();
|
||||
CameraDialog(this, &_profile.camera).exec();
|
||||
}
|
||||
|
||||
void ProfileEdit::openMarkNodes() {
|
||||
_errorMsg->clear();
|
||||
MarkNodesDialog(_profile, this).exec();
|
||||
MarkNodesDialog(this, &_profile.markNodes).exec();
|
||||
_interestingNodesLabel->setText(
|
||||
labelText(_profile.markNodes().size(), "Mark Interesting Nodes")
|
||||
labelText(_profile.markNodes.size(), "Mark Interesting Nodes")
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -46,10 +46,11 @@ namespace {
|
||||
};
|
||||
} // namespace
|
||||
|
||||
PropertiesDialog::PropertiesDialog(Profile& profile, QWidget *parent)
|
||||
PropertiesDialog::PropertiesDialog(QWidget* parent,
|
||||
std::vector<openspace::Profile::Property>* properties)
|
||||
: QDialog(parent)
|
||||
, _profile(profile)
|
||||
, _data(_profile.properties())
|
||||
, _properties(properties)
|
||||
, _propertyData(*_properties)
|
||||
{
|
||||
setWindowTitle("Set Property Values");
|
||||
createWidgets();
|
||||
@@ -65,8 +66,8 @@ void PropertiesDialog::createWidgets() {
|
||||
_list, &QListWidget::itemSelectionChanged,
|
||||
this, &PropertiesDialog::listItemSelected
|
||||
);
|
||||
for (size_t i = 0; i < _data.size(); ++i) {
|
||||
_list->addItem(new QListWidgetItem(createOneLineSummary(_data[i])));
|
||||
for (size_t i = 0; i < _propertyData.size(); ++i) {
|
||||
_list->addItem(new QListWidgetItem(createOneLineSummary(_propertyData[i])));
|
||||
}
|
||||
layout->addWidget(_list);
|
||||
}
|
||||
@@ -172,8 +173,8 @@ void PropertiesDialog::listItemSelected() {
|
||||
QListWidgetItem* item = _list->currentItem();
|
||||
int index = _list->row(item);
|
||||
|
||||
if (_data.size() > 0) {
|
||||
Profile::Property& p = _data[index];
|
||||
if (_propertyData.size() > 0) {
|
||||
Profile::Property& p = _propertyData[index];
|
||||
if (p.setType == Profile::Property::SetType::SetPropertyValueSingle) {
|
||||
_commandCombo->setCurrentIndex(0);
|
||||
}
|
||||
@@ -191,7 +192,7 @@ bool PropertiesDialog::isLineEmpty(int index) {
|
||||
if (!_list->item(index)->text().isEmpty()) {
|
||||
isEmpty = false;
|
||||
}
|
||||
if (!_data.empty() && !_data.at(0).name.empty()) {
|
||||
if (!_propertyData.empty() && !_propertyData.at(0).name.empty()) {
|
||||
isEmpty = false;
|
||||
}
|
||||
return isEmpty;
|
||||
@@ -204,13 +205,13 @@ void PropertiesDialog::listItemAdded() {
|
||||
// Special case where list is "empty" but really has one line that is blank.
|
||||
// This is done because QListWidget does not seem to like having its sole
|
||||
// remaining item being removed.
|
||||
_data.at(0) = Blank;
|
||||
_propertyData.at(0) = Blank;
|
||||
_list->item(0)->setText(" (Enter details below & click 'Save')");
|
||||
_list->setCurrentRow(0);
|
||||
transitionToEditMode();
|
||||
}
|
||||
else {
|
||||
_data.push_back(Blank);
|
||||
_propertyData.push_back(Blank);
|
||||
_list->addItem(new QListWidgetItem(" (Enter details below & click 'Save')"));
|
||||
//Scroll down to that blank line highlighted
|
||||
_list->setCurrentRow(_list->count() - 1);
|
||||
@@ -218,8 +219,8 @@ void PropertiesDialog::listItemAdded() {
|
||||
|
||||
// Blank-out the 2 text fields, set combo box to index 0
|
||||
_commandCombo->setCurrentIndex(0);
|
||||
_propertyEdit->setText(QString::fromStdString(_data.back().name));
|
||||
_valueEdit->setText(QString::fromStdString(_data.back().value));
|
||||
_propertyEdit->setText(QString::fromStdString(_propertyData.back().name));
|
||||
_valueEdit->setText(QString::fromStdString(_propertyData.back().value));
|
||||
_commandCombo->setFocus(Qt::OtherFocusReason);
|
||||
_editModeNewItem = true;
|
||||
}
|
||||
@@ -232,16 +233,17 @@ void PropertiesDialog::listItemSave() {
|
||||
QListWidgetItem* item = _list->currentItem();
|
||||
int index = _list->row(item);
|
||||
|
||||
if ( _data.size() > 0) {
|
||||
if (_propertyData.size() > 0) {
|
||||
if (_commandCombo->currentIndex() == 0) {
|
||||
_data[index].setType = Profile::Property::SetType::SetPropertyValueSingle;
|
||||
_propertyData[index].setType =
|
||||
Profile::Property::SetType::SetPropertyValueSingle;
|
||||
}
|
||||
else {
|
||||
_data[index].setType = Profile::Property::SetType::SetPropertyValue;
|
||||
_propertyData[index].setType = Profile::Property::SetType::SetPropertyValue;
|
||||
}
|
||||
_data[index].name = _propertyEdit->text().toStdString();
|
||||
_data[index].value = _valueEdit->text().toStdString();
|
||||
_list->item(index)->setText(createOneLineSummary(_data[index]));
|
||||
_propertyData[index].name = _propertyEdit->text().toStdString();
|
||||
_propertyData[index].value = _valueEdit->text().toStdString();
|
||||
_list->item(index)->setText(createOneLineSummary(_propertyData[index]));
|
||||
}
|
||||
transitionFromEditMode();
|
||||
_editModeNewItem = false;
|
||||
@@ -269,8 +271,10 @@ void PropertiesDialog::listItemCancelSave() {
|
||||
listItemSelected();
|
||||
transitionFromEditMode();
|
||||
if (_editModeNewItem) {
|
||||
if (_data.size() > 0) {
|
||||
if (_data.back().name.length() == 0 || _data.back().value.length() == 0) {
|
||||
if (_propertyData.size() > 0) {
|
||||
if (_propertyData.back().name.length() == 0 ||
|
||||
_propertyData.back().value.length() == 0)
|
||||
{
|
||||
listItemRemove();
|
||||
}
|
||||
}
|
||||
@@ -284,15 +288,15 @@ void PropertiesDialog::listItemRemove() {
|
||||
if (_list->count() == 1) {
|
||||
//Special case where last remaining item is being removed (QListWidget
|
||||
// doesn't like the final item being removed so instead clear it)
|
||||
_data.at(0) = Blank;
|
||||
_propertyData.at(0) = Blank;
|
||||
_list->item(0)->setText("");
|
||||
}
|
||||
else {
|
||||
int index = _list->currentRow();
|
||||
if (index >= 0 && index < _list->count()) {
|
||||
delete _list->takeItem(index);
|
||||
if (_data.size() > 0) {
|
||||
_data.erase(_data.begin() + index);
|
||||
if (_propertyData.size() > 0) {
|
||||
_propertyData.erase(_propertyData.begin() + index);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -341,10 +345,10 @@ void PropertiesDialog::editBoxDisabled(bool disabled) {
|
||||
|
||||
void PropertiesDialog::parseSelections() {
|
||||
// Handle case with only one remaining but empty line
|
||||
if ((_data.size() == 1) && (_data.at(0).name.compare("") == 0)) {
|
||||
_data.clear();
|
||||
if ((_propertyData.size() == 1) && (_propertyData.at(0).name.compare("") == 0)) {
|
||||
_propertyData.clear();
|
||||
}
|
||||
_profile.setProperties(_data);
|
||||
*_properties = std::move(_propertyData);
|
||||
accept();
|
||||
}
|
||||
|
||||
|
||||
@@ -37,20 +37,20 @@
|
||||
|
||||
using namespace openspace;
|
||||
|
||||
TimeDialog::TimeDialog(openspace::Profile& profile, QWidget* parent)
|
||||
TimeDialog::TimeDialog(QWidget* parent, std::optional<openspace::Profile::Time>* time)
|
||||
: QDialog(parent)
|
||||
, _profile(profile)
|
||||
, _time(time)
|
||||
{
|
||||
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";
|
||||
if (_time->has_value()) {
|
||||
_timeData = **_time;
|
||||
if (_timeData.type == Profile::Time::Type::Relative) {
|
||||
if (_timeData.value == "") {
|
||||
_timeData.value = "now";
|
||||
}
|
||||
_relativeEdit->setSelection(0, _relativeEdit->text().length());
|
||||
}
|
||||
@@ -59,11 +59,11 @@ TimeDialog::TimeDialog(openspace::Profile& profile, QWidget* parent)
|
||||
}
|
||||
}
|
||||
else {
|
||||
_data.type = Profile::Time::Type::Relative;
|
||||
_data.value = "now";
|
||||
_timeData.type = Profile::Time::Type::Relative;
|
||||
_timeData.value = "now";
|
||||
}
|
||||
_initializedAsAbsolute = (_data.type == Profile::Time::Type::Absolute);
|
||||
enableAccordingToType(static_cast<int>(_data.type));
|
||||
_initializedAsAbsolute = (_timeData.type == Profile::Time::Type::Absolute);
|
||||
enableAccordingToType(static_cast<int>(_timeData.type));
|
||||
}
|
||||
|
||||
void TimeDialog::createWidgets() {
|
||||
@@ -117,15 +117,15 @@ void TimeDialog::enableAccordingToType(int idx) {
|
||||
_relativeEdit->setText("now");
|
||||
}
|
||||
else {
|
||||
_relativeEdit->setText(QString::fromStdString(_data.value));
|
||||
_relativeEdit->setText(QString::fromStdString(_timeData.value));
|
||||
}
|
||||
_relativeEdit->setFocus(Qt::OtherFocusReason);
|
||||
}
|
||||
else {
|
||||
_relativeEdit->setText("<font color='gray'>Relative Time:</font>");
|
||||
size_t tIdx = _data.value.find_first_of('T', 0);
|
||||
QString importDate = QString::fromStdString(_data.value.substr(0, tIdx));
|
||||
QString importTime = QString::fromStdString(_data.value.substr(tIdx + 1));
|
||||
size_t tIdx = _timeData.value.find_first_of('T', 0);
|
||||
QString importDate = QString::fromStdString(_timeData.value.substr(0, tIdx));
|
||||
QString importTime = QString::fromStdString(_timeData.value.substr(tIdx + 1));
|
||||
_absoluteEdit->setDate(QDate::fromString(importDate, Qt::DateFormat::ISODate));
|
||||
_absoluteEdit->setTime(QTime::fromString(importTime));
|
||||
_relativeEdit->clear();
|
||||
@@ -144,13 +144,13 @@ void TimeDialog::approved() {
|
||||
constexpr const int Relative = static_cast<int>(Profile::Time::Type::Relative);
|
||||
if (_typeCombo->currentIndex() == Relative) {
|
||||
if (_relativeEdit->text().isEmpty()) {
|
||||
_profile.clearTime();
|
||||
*_time = std::nullopt;
|
||||
}
|
||||
else {
|
||||
Profile::Time t;
|
||||
t.type = Profile::Time::Type::Relative;
|
||||
t.value = _relativeEdit->text().toStdString();
|
||||
_profile.setTime(t);
|
||||
*_time = t;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -161,7 +161,7 @@ void TimeDialog::approved() {
|
||||
_absoluteEdit->date().toString("yyyy-MM-dd").toStdString(),
|
||||
_absoluteEdit->time().toString().toStdString()
|
||||
);
|
||||
_profile.setTime(t);
|
||||
*_time = t;
|
||||
}
|
||||
accept();
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
-- This is a blank scene that that just sets up the default menus/dasboard/keys, etc.
|
||||
|
||||
local assetHelper = asset.require('util/asset_helper')
|
||||
local sceneHelper = asset.require('util/scene_helper')
|
||||
local propertyHelper = asset.require('util/property_helper')
|
||||
|
||||
-- Specifying which other assets should be loaded in this scene
|
||||
@@ -14,36 +13,47 @@ asset.require('util/default_keybindings')
|
||||
-- Load web gui
|
||||
local webGui = asset.require('util/webgui')
|
||||
|
||||
-- Keybindings that are specific for this scene
|
||||
local Keybindings = {
|
||||
{
|
||||
Key = "h",
|
||||
Name="Toggle Trails",
|
||||
Command = "local list = openspace.getProperty('{planetTrail_solarSystem}.Renderable.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end\n" ..
|
||||
"local moonlist = openspace.getProperty('{moonTrail_solarSystem}.Renderable.Enabled'); for _,v in pairs(moonlist) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end",
|
||||
Documentation = "Toggles the visibility of planet and moon trails",
|
||||
GuiPath = "/Rendering",
|
||||
Local = false
|
||||
},
|
||||
{
|
||||
Key = "l",
|
||||
Name = "Toggle planet labels",
|
||||
Command = "local list = openspace.getProperty('{solarsystem_labels}.Renderable.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end",
|
||||
Documentation = "Turns on visibility for all solar system labels",
|
||||
GuiPath = "/Rendering",
|
||||
Local = false
|
||||
}
|
||||
local toggle_trails = {
|
||||
Identifier = "os_default.toggle_trails",
|
||||
Name = "Toggle Trails",
|
||||
Command = "local list = openspace.getProperty('{planetTrail_solarSystem}.Renderable.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end\n" ..
|
||||
"local moonlist = openspace.getProperty('{moonTrail_solarSystem}.Renderable.Enabled'); for _,v in pairs(moonlist) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end",
|
||||
Documentation = "Toggles the visibility of planet and moon trails",
|
||||
GuiPath = "/Rendering",
|
||||
IsLocal = false,
|
||||
|
||||
Key = "h"
|
||||
}
|
||||
|
||||
local toggle_planet_labels = {
|
||||
Identifier = "os_default.toggle_planet_labels",
|
||||
Name = "Toggle planet labels",
|
||||
Command = "local list = openspace.getProperty('{solarsystem_labels}.Renderable.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end",
|
||||
Documentation = "Turns on visibility for all solar system labels",
|
||||
GuiPath = "/Rendering",
|
||||
IsLocal = false,
|
||||
|
||||
Key = "l"
|
||||
}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
webGui.setCefRoute("onscreen")
|
||||
|
||||
sceneHelper.bindKeys(Keybindings)
|
||||
openspace.action.registerAction(toggle_trails)
|
||||
openspace.bindKey(toggle_trails.Key, toggle_trails.Identifier)
|
||||
|
||||
openspace.action.registerAction(toggle_planet_labels)
|
||||
openspace.bindKey(toggle_planet_labels.Key, toggle_planet_labels.Identifier)
|
||||
|
||||
openspace.setDefaultGuiSorting()
|
||||
|
||||
openspace.setPropertyValueSingle("RenderEngine.VerticalLogOffset", 0.100000)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
sceneHelper.unbindKeys(Keybindings)
|
||||
openspace.action.removeAction(toggle_trails.Identifier)
|
||||
openspace.clearKey(toggle_trails.Key)
|
||||
|
||||
openspace.action.removeAction(toggle_planet_labels.Identifier)
|
||||
openspace.clearKey(toggle_planet_labels.Key)
|
||||
end)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
local assetHelper = asset.require('util/asset_helper')
|
||||
local sceneHelper = asset.require('util/scene_helper')
|
||||
local propertyHelper = asset.require('util/property_helper')
|
||||
local debugHelper = asset.require('util/debug_helper')
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ local sunstar = {
|
||||
}
|
||||
},
|
||||
GUI = {
|
||||
Name = "Sun",
|
||||
Name = "Sun Star",
|
||||
Path = "/Milky Way/Stars",
|
||||
Description = [[Individual star to represent the sun when outside of the solar
|
||||
system]]
|
||||
|
||||
@@ -78,6 +78,60 @@ local createConstellations = function (baseIdentifier, guiPath, constellationfil
|
||||
end
|
||||
|
||||
|
||||
local show_art = {
|
||||
Identifier = "constellation_art.show_art",
|
||||
Name = "Show Constellation Art",
|
||||
Command = "openspace.setPropertyValue('Scene.ConstellationArt*.Renderable.Opacity', 0);" ..
|
||||
"openspace.setPropertyValue('Scene.ConstellationArt*.Renderable.Enabled', true);" ..
|
||||
"openspace.setPropertyValue('Scene.ConstellationArt*.Renderable.Opacity', 0.2, 2);",
|
||||
Documentation = "Enables and fades up constellation art work",
|
||||
GuiPath = "/Rendering",
|
||||
IsLocal = false
|
||||
}
|
||||
asset.export("ShowArtAction", show_art)
|
||||
|
||||
local hide_art = {
|
||||
Identifier = "constellation_art.hide_art",
|
||||
Name = "Hide Constellation Art",
|
||||
Command = "openspace.setPropertyValue('Scene.ConstellationArt*.Renderable.Opacity', 0, 2);",
|
||||
Documentation = "Fades out constellation artwork",
|
||||
GuiPath = "/Rendering",
|
||||
IsLocal = false
|
||||
}
|
||||
asset.export("HideArtAction", hide_art)
|
||||
|
||||
local disable_art = {
|
||||
Identifier = "constellation_art.disable_art",
|
||||
Name = "Disable Constellation Art",
|
||||
Command = "openspace.setPropertyValue('Scene.ConstellationArt*.Renderable.Enabled', false);",
|
||||
Documentation = "Disable constellation artwork",
|
||||
GuiPath = "/Rendering",
|
||||
IsLocal = false
|
||||
}
|
||||
asset.export("DisableArtAction", disable_art)
|
||||
|
||||
local show_zodiac_art = {
|
||||
Identifier = "constellation_art.show_zodiac_art",
|
||||
Name = "Show Zodiac Art",
|
||||
Command = "openspace.setPropertyValue('Scene.ConstellationArt*.Renderable.Opacity', 0);" ..
|
||||
"openspace.setPropertyValue('{zodiac}.Renderable.Enabled',true);" ..
|
||||
"openspace.setPropertyValue('{zodiac}.Renderable.Opacity', 1, 2);",
|
||||
Documentation = "Enables and fades up zodiac art work",
|
||||
GuiPath = "/Rendering",
|
||||
IsLocal = false
|
||||
}
|
||||
asset.export("ShowZodiacArt", show_zodiac_art)
|
||||
|
||||
local hide_zodiac_art = {
|
||||
Identifier = "constellation_art.hide_zodiac_art",
|
||||
Name = "Hide Zodiac Art",
|
||||
Command = "openspace.setPropertyValue('{zodiac}.Renderable.Opacity', 0, 2);",
|
||||
Documentation = "fades down zodiac art work",
|
||||
GuiPath = "/Rendering",
|
||||
IsLocal = false
|
||||
}
|
||||
asset.export("HideZodiacArt", hide_zodiac_art)
|
||||
|
||||
local nodes = {}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
@@ -87,12 +141,20 @@ asset.onInitialize(function ()
|
||||
for _, n in ipairs(nodes) do
|
||||
openspace.addSceneGraphNode(n);
|
||||
end
|
||||
|
||||
openspace.action.registerAction(show_art)
|
||||
openspace.action.registerAction(hide_art)
|
||||
openspace.action.registerAction(disable_art)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
for _, n in ipairs(nodes) do
|
||||
openspace.removeSceneGraphNode(n.Identifier);
|
||||
end
|
||||
|
||||
openspace.action.removeAction(show_art.Identifier)
|
||||
openspace.action.removeAction(hide_art.Identifier)
|
||||
openspace.action.removeAction(disable_art.Identifier)
|
||||
end)
|
||||
|
||||
|
||||
|
||||
@@ -1,32 +1,13 @@
|
||||
local scene_helper = asset.require('util/scene_helper')
|
||||
|
||||
local Keybindings = {
|
||||
{
|
||||
Key = "v",
|
||||
Name = "Show Constellation Art",
|
||||
Command = "openspace.setPropertyValue('Scene.ConstellationArt*.Renderable.Opacity', 0);" ..
|
||||
"openspace.setPropertyValue('{zodiac}.Renderable.Enabled',true);" ..
|
||||
"openspace.setPropertyValue('{zodiac}.Renderable.Opacity', 1, 2);",
|
||||
Documentation = "Enables and fades up zodiac art work",
|
||||
GuiPath = "/Rendering",
|
||||
Local = false
|
||||
},
|
||||
{
|
||||
Key = "Shift+v",
|
||||
Name = "Show Constellation Art",
|
||||
Command = "openspace.setPropertyValue('{zodiac}.Renderable.Opacity', 0, 2);",
|
||||
Documentation = "fades down zodiac art work",
|
||||
GuiPath = "/Rendering",
|
||||
Local = false
|
||||
},
|
||||
}
|
||||
local mainAsset = asset.require('./constellation_art')
|
||||
|
||||
asset.onInitialize(function ()
|
||||
scene_helper.bindKeys(Keybindings)
|
||||
openspace.bindKey("v", mainAsset.ShowZodiacArt.Identifier)
|
||||
openspace.bindKey("Shift+v", mainAsset.HideZodiacArt.Identifier)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
scene_helper.unbindKeys(Keybindings)
|
||||
openspace.clearKey("v")
|
||||
openspace.clearKey("Shift+v")
|
||||
end)
|
||||
|
||||
asset.meta = {
|
||||
|
||||
@@ -1,40 +1,15 @@
|
||||
local scene_helper = asset.require('util/scene_helper')
|
||||
|
||||
local Keybindings = {
|
||||
{
|
||||
Key = "c",
|
||||
Name = "Show Constellation Art",
|
||||
Command = "openspace.setPropertyValue('Scene.ConstellationArt*.Renderable.Opacity', 0);" ..
|
||||
"openspace.setPropertyValue('Scene.ConstellationArt*.Renderable.Enabled', true);" ..
|
||||
"openspace.setPropertyValue('Scene.ConstellationArt*.Renderable.Opacity', 0.2, 2);",
|
||||
Documentation = "Enables and fades up constellation art work",
|
||||
GuiPath = "/Rendering",
|
||||
Local = false
|
||||
},
|
||||
{
|
||||
Key = "SHIFT+c",
|
||||
Name = "Hide Constellation Art",
|
||||
Command = "openspace.setPropertyValue('Scene.ConstellationArt*.Renderable.Opacity', 0, 2);",
|
||||
Documentation = "Fades out constellation artwork",
|
||||
GuiPath = "/Rendering",
|
||||
Local = false
|
||||
},
|
||||
{
|
||||
Key = "CTRL+c",
|
||||
Name = "Disable Constellation Art",
|
||||
Command = "openspace.setPropertyValue('Scene.ConstellationArt*.Renderable.Enabled', false);",
|
||||
Documentation = "Disable constellation artwork",
|
||||
GuiPath = "/Rendering",
|
||||
Local = false
|
||||
}
|
||||
}
|
||||
local mainAsset = asset.require('./constellation_art')
|
||||
|
||||
asset.onInitialize(function ()
|
||||
scene_helper.bindKeys(Keybindings)
|
||||
openspace.bindKey("c", mainAsset.ShowArtAction.Identifier)
|
||||
openspace.bindKey("SHIFT+c", mainAsset.HideArtAction.Identifier)
|
||||
openspace.bindKey("CTRL+c", mainAsset.DisableArtAction.Identifier)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
scene_helper.unbindKeys(Keybindings)
|
||||
openspace.clearKey("c")
|
||||
openspace.clearKey("SHIFT+c")
|
||||
openspace.clearKey("CTRL+c")
|
||||
end)
|
||||
|
||||
|
||||
|
||||
@@ -14,21 +14,42 @@ local vrts = asset.syncedResource({
|
||||
Version = 1
|
||||
})
|
||||
|
||||
|
||||
|
||||
asset.onInitialize(function ()
|
||||
openspace.globebrowsing.addBlendingLayersFromDirectory(vrts, assetGlobe);
|
||||
flipbook = helper.createFlipbook(assetPrefix, assetGlobe, 19);
|
||||
|
||||
rawset(_G, "nextFlip", function() helper.nextFlipbookPage(flipbook) end)
|
||||
rawset(_G, "previousFlip", function() helper.previousFlipbookPage(flipbook) end)
|
||||
openspace.action.registerAction({
|
||||
Identifier = "lem_flipbook.next_flip",
|
||||
Name = "Next A11 flip",
|
||||
Command = "nextFlip()",
|
||||
Documentation = "Show the next Apollo 11 flipbook image",
|
||||
GuiPath = "/Missions/Apollo/11",
|
||||
IsLocal = false
|
||||
})
|
||||
|
||||
openspace.bindKey("p", "nextFlip()", "Show the next Apollo 11 flipbook image.", "Next A11 flip", "/Missions/Apollo/11")
|
||||
openspace.bindKey("o", "previousFlip()","Show the previous Apollo 11 flipbook image.", "Prev A11 flip", "/Missions/Apollo/11")
|
||||
rawset(_G, "previousFlip", function() helper.previousFlipbookPage(flipbook) end)
|
||||
openspace.action.registerAction({
|
||||
Identifier = "lem_flipbook.prev_flip",
|
||||
Name = "Prev A11 flip",
|
||||
Command = "previousFlip()",
|
||||
Documentation = "Show the previous Apollo 11 flipbook image",
|
||||
GuiPath = "/Missions/Apollo/11",
|
||||
IsLocal = false
|
||||
})
|
||||
|
||||
openspace.bindKey("p", "lem_flipbook.next_flip")
|
||||
openspace.bindKey("o", "lem_flipbook.prev_flip")
|
||||
end)
|
||||
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
flipbook = nil;
|
||||
|
||||
openspace.action.removeAction("lem_flipbook.next_flip")
|
||||
openspace.action.removeAction("lem_flipbook.prev_flip")
|
||||
openspace.clearKey("o")
|
||||
openspace.clearKey("p")
|
||||
end)
|
||||
|
||||
@@ -85,20 +85,32 @@ for i = 1, #landingData do
|
||||
}
|
||||
end
|
||||
|
||||
asset.onInitialize(function ()
|
||||
openspace.bindShortcut(
|
||||
'Show Apollo Landing Labels',
|
||||
'openspace.setPropertyValue("Scene.Apollo*Insignia.Renderable.Opacity", 1, 0.5)',
|
||||
'Show patches of the Apollo missions on their respective landing sites',
|
||||
'/Missions/Apollo'
|
||||
)
|
||||
local show_apollo_labels = {
|
||||
Identifier = "apollo_insignias.show_insignias",
|
||||
Name = "Show Apollo Landing Labels",
|
||||
Command = "openspace.setPropertyValue('Scene.Apollo*Insignia.Renderable.Opacity', 1, 0.5)",
|
||||
Documentation = "Show patches of the Apollo missions on their respective landing sites",
|
||||
GuiPath = "/Missions/Apollo",
|
||||
IsLocal = true
|
||||
}
|
||||
|
||||
openspace.bindShortcut(
|
||||
'Hide Apollo Landing Labels',
|
||||
'openspace.setPropertyValue("Scene.Apollo*Insignia.Renderable.Opacity", 0, 0.5)',
|
||||
'Hide patches of the Apollo missions on their respective landing sites',
|
||||
'/Missions/Apollo'
|
||||
)
|
||||
local hide_apollo_labels = {
|
||||
Identifier = "apollo_insignias.hide_insignias",
|
||||
Name = "Hide Apollo Landing Labels",
|
||||
Command = "openspace.setPropertyValue('Scene.Apollo*Insignia.Renderable.Opacity', 0, 0.5)",
|
||||
Documentation = "Hide patches of the Apollo missions on their respective landing sites",
|
||||
GuiPath = "/Missions/Apollo",
|
||||
IsLocal = true
|
||||
}
|
||||
|
||||
asset.onInitialize(function ()
|
||||
openspace.action.registerAction(show_apollo_labels)
|
||||
openspace.action.registerAction(hide_apollo_labels)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
openspace.action.removeAction(show_apollo_labels.Identifier)
|
||||
openspace.action.removeAction(hide_apollo_labels.Identifier)
|
||||
end)
|
||||
|
||||
asset.export('showInsignia', function (missinNumber, interpolationDuration)
|
||||
|
||||
@@ -1,155 +1,202 @@
|
||||
local sceneHelper = asset.require('./scene_helper')
|
||||
local propertyHelper = asset.require('./property_helper')
|
||||
|
||||
local Keybindings = {
|
||||
{
|
||||
Key = "F1",
|
||||
Name = "Show Native GUI",
|
||||
Command = propertyHelper.invert('Modules.ImGUI.Main.Enabled'),
|
||||
Documentation = "Shows or hides the native UI",
|
||||
GuiPath = "/Native GUI",
|
||||
Local = true
|
||||
},
|
||||
{
|
||||
Key = "ESC",
|
||||
Name = "Toggle Shutdown",
|
||||
Command = "openspace.toggleShutdown()",
|
||||
Documentation = "Toggles the shutdown that will stop OpenSpace after a grace period. Press again to cancel the shutdown during this period.",
|
||||
Local = true
|
||||
},
|
||||
{
|
||||
Key = "PRINT_SCREEN",
|
||||
Name = "Take Screenshot",
|
||||
Command = "openspace.takeScreenshot()",
|
||||
Documentation = "Saves the contents of the screen to a file in the ${SCREENSHOTS} directory.",
|
||||
GuiPath = "/Rendering",
|
||||
Local = true
|
||||
},
|
||||
{
|
||||
Key = "F12",
|
||||
Name = "Take Screenshot",
|
||||
Command = "openspace.takeScreenshot()",
|
||||
Documentation = "Saves the contents of the screen to a file in the ${SCREENSHOTS} directory.",
|
||||
GuiPath = "/Rendering",
|
||||
Local = true
|
||||
},
|
||||
{
|
||||
Key = "SPACE",
|
||||
Name = "Toggle Pause (Interpolated)",
|
||||
Command = "openspace.time.pauseToggleViaKeyboard()",
|
||||
Documentation = "Smoothly starts and stops the simulation time.",
|
||||
GuiPath = "/Simulation Speed",
|
||||
Local = true
|
||||
},
|
||||
{
|
||||
Key = "Shift+SPACE",
|
||||
Name = "Toggle Pause (Immediate)",
|
||||
Command = "openspace.time.togglePause()",
|
||||
Documentation = "Immediately starts and stops the simulation time.",
|
||||
GuiPath = "/Simulation Speed",
|
||||
Local = true
|
||||
},
|
||||
{
|
||||
Key = "f",
|
||||
Name = "Toggle Rotation friction",
|
||||
Command = propertyHelper.invert('NavigationHandler.OrbitalNavigator.Friction.RotationalFriction'),
|
||||
Documentation = "Toggles the rotational friction of the camera. If it is disabled, the camera rotates around the focus object indefinitely.",
|
||||
GuiPath = "/Navigation",
|
||||
Local = false
|
||||
},
|
||||
{
|
||||
Key = "Shift+f",
|
||||
Name = "Toggle Zoom Friction",
|
||||
Command = propertyHelper.invert('NavigationHandler.OrbitalNavigator.Friction.ZoomFriction'),
|
||||
Documentation = "Toggles the zoom friction of the camera. If it is disabled, the camera rises up from or closes in towards the focus object indefinitely.",
|
||||
GuiPath = "/Navigation",
|
||||
Local = false
|
||||
},
|
||||
{
|
||||
Key = "Ctrl+f",
|
||||
Name = "Toggle Roll Friction",
|
||||
Command = propertyHelper.invert('NavigationHandler.OrbitalNavigator.Friction.RollFriction'),
|
||||
Documentation = "Toggles the roll friction of the camera. If it is disabled, the camera rolls around its own axis indefinitely.",
|
||||
GuiPath = "/Navigation",
|
||||
Local = false
|
||||
},
|
||||
{
|
||||
Key = "w",
|
||||
Name = "Fade to/from black",
|
||||
Command = "if openspace.getPropertyValue('RenderEngine.BlackoutFactor') > 0.5 then openspace.setPropertyValueSingle('RenderEngine.BlackoutFactor', 0.0, 3) else openspace.setPropertyValueSingle('RenderEngine.BlackoutFactor', 1.0, 3) end",
|
||||
Documentation = "Toggles the fade to black within 3 seconds or shows the rendering after 3 seconds.",
|
||||
GuiPath = "/Rendering",
|
||||
Local = false
|
||||
},
|
||||
{
|
||||
Key = "Tab",
|
||||
Name = "Toggle main GUI",
|
||||
Command = propertyHelper.invert('Modules.CefWebGui.Visible'),
|
||||
Documentation = "Toggles the main GUI",
|
||||
GuiPath = "/GUI",
|
||||
Local = true
|
||||
},
|
||||
{
|
||||
Key = "Shift+Tab",
|
||||
Name = "Toggle dashboard and overlays",
|
||||
Command =
|
||||
local toggle_native_ui = {
|
||||
Identifier = "os_default.toggle_native_ui",
|
||||
Name = "Show Native GUI",
|
||||
Command = propertyHelper.invert('Modules.ImGUI.Main.Enabled'),
|
||||
Documentation = "Shows or hides the native UI",
|
||||
GuiPath = "/Native GUI",
|
||||
IsLocal = true,
|
||||
|
||||
Key = "F1"
|
||||
}
|
||||
|
||||
local toggle_shutdown = {
|
||||
Identifier = "os_default.toggle_shutdown",
|
||||
Name = "Toggle Shutdown",
|
||||
Command = "openspace.toggleShutdown()",
|
||||
Documentation = "Toggles the shutdown that will stop OpenSpace after a grace period. Press again to cancel the shutdown during this period.",
|
||||
IsLocal = true,
|
||||
|
||||
Key = "ESC"
|
||||
}
|
||||
|
||||
local take_screenshot = {
|
||||
Identifier = "os_default.take_screenshot",
|
||||
Name = "Take Screenshot",
|
||||
Command = "openspace.takeScreenshot()",
|
||||
Documentation = "Saves the contents of the screen to a file in the ${SCREENSHOTS} directory.",
|
||||
GuiPath = "/Rendering",
|
||||
IsLocal = true,
|
||||
|
||||
Key = "F12"
|
||||
}
|
||||
|
||||
local toggle_pause_interpolated = {
|
||||
Identifier = "os_default.toggle_pause_interpolated",
|
||||
Name = "Toggle Pause (Interpolated)",
|
||||
Command = "openspace.time.pauseToggleViaKeyboard()",
|
||||
Documentation = "Smoothly starts and stops the simulation time.",
|
||||
GuiPath = "/Simulation Speed",
|
||||
IsLocal = true,
|
||||
|
||||
Key = "SPACE"
|
||||
}
|
||||
|
||||
local toggle_pause_immediate = {
|
||||
Identifier = "os_default.toggle_pause_immediate",
|
||||
Name = "Toggle Pause (Immediate)",
|
||||
Command = "openspace.time.togglePause()",
|
||||
Documentation = "Immediately starts and stops the simulation time.",
|
||||
GuiPath = "/Simulation Speed",
|
||||
IsLocal = true,
|
||||
|
||||
Key = "Shift+SPACE"
|
||||
}
|
||||
|
||||
local toggle_rotation_friction = {
|
||||
Identifier = "os_default.toggle_rotation_friction",
|
||||
Name = "Toggle Rotation friction",
|
||||
Command = propertyHelper.invert('NavigationHandler.OrbitalNavigator.Friction.RotationalFriction'),
|
||||
Documentation = "Toggles the rotational friction of the camera. If it is disabled, the camera rotates around the focus object indefinitely.",
|
||||
GuiPath = "/Navigation",
|
||||
IsLocal = false,
|
||||
|
||||
Key = "f"
|
||||
}
|
||||
|
||||
local toggle_zoom_friction = {
|
||||
Identifier = "os_default.toggle_zoom_friction",
|
||||
Name = "Toggle Zoom Friction",
|
||||
Command = propertyHelper.invert('NavigationHandler.OrbitalNavigator.Friction.ZoomFriction'),
|
||||
Documentation = "Toggles the zoom friction of the camera. If it is disabled, the camera rises up from or closes in towards the focus object indefinitely.",
|
||||
GuiPath = "/Navigation",
|
||||
IsLocal = false,
|
||||
|
||||
Key = "Shift+f"
|
||||
}
|
||||
|
||||
local toggle_roll_friction = {
|
||||
Identifier = "os_default.toggle_roll_friction",
|
||||
Name = "Toggle Roll Friction",
|
||||
Command = propertyHelper.invert('NavigationHandler.OrbitalNavigator.Friction.RollFriction'),
|
||||
Documentation = "Toggles the roll friction of the camera. If it is disabled, the camera rolls around its own axis indefinitely.",
|
||||
GuiPath = "/Navigation",
|
||||
IsLocal = false,
|
||||
|
||||
Key = "Ctrl+f"
|
||||
}
|
||||
|
||||
local fade_to_black = {
|
||||
Identifier = "os_default.fade_to_black",
|
||||
Name = "Fade to/from black",
|
||||
Command = "if openspace.getPropertyValue('RenderEngine.BlackoutFactor') > 0.5 then openspace.setPropertyValueSingle('RenderEngine.BlackoutFactor', 0.0, 3) else openspace.setPropertyValueSingle('RenderEngine.BlackoutFactor', 1.0, 3) end",
|
||||
Documentation = "Toggles the fade to black within 3 seconds or shows the rendering after 3 seconds.",
|
||||
GuiPath = "/Rendering",
|
||||
IsLocal = false,
|
||||
|
||||
Key = "w"
|
||||
}
|
||||
|
||||
local toggle_main_gui = {
|
||||
Identifier = "os_default.toggle_main_gui",
|
||||
Name = "Toggle main GUI",
|
||||
Command = propertyHelper.invert('Modules.CefWebGui.Visible'),
|
||||
Documentation = "Toggles the main GUI",
|
||||
GuiPath = "/GUI",
|
||||
IsLocal = true,
|
||||
|
||||
Key = "Tab"
|
||||
}
|
||||
|
||||
local toggle_overlays = {
|
||||
Identifier = "os_default.toggle_overlays",
|
||||
Name = "Toggle dashboard and overlays",
|
||||
Command =
|
||||
[[local isEnabled = openspace.getPropertyValue('Dashboard.IsEnabled');
|
||||
openspace.setPropertyValueSingle('Dashboard.IsEnabled', not isEnabled);
|
||||
openspace.setPropertyValueSingle("RenderEngine.ShowLog", not isEnabled);
|
||||
openspace.setPropertyValueSingle("RenderEngine.ShowVersion", not isEnabled);
|
||||
openspace.setPropertyValueSingle("RenderEngine.ShowCamera", not isEnabled)]],
|
||||
Documentation = "Toggles the dashboard and overlays",
|
||||
GuiPath = "/GUI",
|
||||
Local = true
|
||||
},
|
||||
{
|
||||
Key = "Alt+R",
|
||||
Name = "Toggle rendering on master",
|
||||
Command = propertyHelper.invert('RenderEngine.DisableMasterRendering'),
|
||||
Documentation = "Toggles the rendering on master",
|
||||
GuiPath = "/Rendering",
|
||||
Local = true
|
||||
},
|
||||
{
|
||||
Key = "Right",
|
||||
Name = "Next Delta Time Step (Interpolate)",
|
||||
Command = "openspace.time.interpolateNextDeltaTimeStep()",
|
||||
Documentation = "Smoothly interpolates the simulation speed to the next delta time step, if one exists.",
|
||||
GuiPath = "/Simulation Speed",
|
||||
Local = true
|
||||
},
|
||||
{
|
||||
Key = "Shift+Right",
|
||||
Name = "Next Delta Time Step (Immediate)",
|
||||
Command = "openspace.time.setNextDeltaTimeStep()",
|
||||
Documentation = "Immediately set the simulation speed to the next delta time step, if one exists.",
|
||||
GuiPath = "/Simulation Speed",
|
||||
Local = true
|
||||
},
|
||||
{
|
||||
Key = "Left",
|
||||
Name = "Previous Delta Time Step (Interpolate)",
|
||||
Command = "openspace.time.interpolatePreviousDeltaTimeStep()",
|
||||
Documentation = "Smoothly interpolates the simulation speed to the previous delta time step, if one exists.",
|
||||
GuiPath = "/Simulation Speed",
|
||||
Local = true
|
||||
},
|
||||
{
|
||||
Key = "Shift+Left",
|
||||
Name = "Previous Delta Time Step (Immediate)",
|
||||
Command = "openspace.time.setPreviousDeltaTimeStep()",
|
||||
Documentation = "Immediately set the simulation speed to the previous delta time step, if one exists.",
|
||||
GuiPath = "/Simulation Speed",
|
||||
Local = true
|
||||
}
|
||||
Documentation = "Toggles the dashboard and overlays",
|
||||
GuiPath = "/GUI",
|
||||
IsLocal = true,
|
||||
|
||||
Key = "Shift+Tab"
|
||||
}
|
||||
|
||||
local toggle_master_rendering = {
|
||||
Identifier = "os_default.toggle_master_rendering",
|
||||
Name = "Toggle rendering on master",
|
||||
Command = propertyHelper.invert('RenderEngine.DisableMasterRendering'),
|
||||
Documentation = "Toggles the rendering on master",
|
||||
GuiPath = "/Rendering",
|
||||
IsLocal = true,
|
||||
|
||||
Key = "Alt+R"
|
||||
}
|
||||
|
||||
local next_delta_step_interpolate = {
|
||||
Identifier = "os_default.next_delta_step_interpolate",
|
||||
Name = "Next Delta Time Step (Interpolate)",
|
||||
Command = "openspace.time.interpolateNextDeltaTimeStep()",
|
||||
Documentation = "Smoothly interpolates the simulation speed to the next delta time step, if one exists.",
|
||||
GuiPath = "/Simulation Speed",
|
||||
IsLocal = true,
|
||||
|
||||
Key = "Right"
|
||||
}
|
||||
|
||||
local next_delta_step_immediate = {
|
||||
Identifier = "os_default.next_delta_step_immediate",
|
||||
Name = "Next Delta Time Step (Immediate)",
|
||||
Command = "openspace.time.setNextDeltaTimeStep()",
|
||||
Documentation = "Immediately set the simulation speed to the next delta time step, if one exists.",
|
||||
GuiPath = "/Simulation Speed",
|
||||
IsLocal = true,
|
||||
|
||||
Key = "Shift+Right"
|
||||
}
|
||||
|
||||
local previous_delta_step_interpolate = {
|
||||
Identifier = "os_default.previous_delta_step_interpolate",
|
||||
Name = "Previous Delta Time Step (Interpolate)",
|
||||
Command = "openspace.time.interpolatePreviousDeltaTimeStep()",
|
||||
Documentation = "Smoothly interpolates the simulation speed to the previous delta time step, if one exists.",
|
||||
GuiPath = "/Simulation Speed",
|
||||
IsLocal = true,
|
||||
|
||||
Key = "Left"
|
||||
}
|
||||
|
||||
local previous_delta_step_immediate = {
|
||||
Identifier = "os_default.previous_delta_step_immediate",
|
||||
Name = "Previous Delta Time Step (Immediate)",
|
||||
Command = "openspace.time.setPreviousDeltaTimeStep()",
|
||||
Documentation = "Immediately set the simulation speed to the previous delta time step, if one exists.",
|
||||
GuiPath = "/Simulation Speed",
|
||||
IsLocal = true,
|
||||
|
||||
Key = "Shift+Left"
|
||||
}
|
||||
|
||||
local Actions = {
|
||||
toggle_native_ui,toggle_shutdown,take_screenshot,toggle_pause_interpolated,toggle_pause_immediate,
|
||||
toggle_rotation_friction,toggle_zoom_friction,toggle_roll_friction,fade_to_black,
|
||||
toggle_main_gui,toggle_overlays,toggle_master_rendering,next_delta_step_interpolate,
|
||||
next_delta_step_immediate,previous_delta_step_interpolate,previous_delta_step_immediate
|
||||
}
|
||||
|
||||
asset.onInitialize(function()
|
||||
sceneHelper.bindKeys(Keybindings)
|
||||
for _, action in ipairs(Actions) do
|
||||
openspace.action.registerAction(action)
|
||||
openspace.bindKey(action.Key, action.Identifier)
|
||||
end
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
sceneHelper.unbindKeys(Keybindings)
|
||||
for _, action in ipairs(Actions) do
|
||||
openspace.action.removeAction(action.Identifier)
|
||||
openspace.clearKey(action.Key)
|
||||
end
|
||||
end)
|
||||
|
||||
asset.export("DefaultKeybindings", Keybindings)
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
local bindKeys = function(t, ignoreWarning)
|
||||
ignoreWarning = ignoreWarning or false
|
||||
for _, k in ipairs(t) do
|
||||
assert(k.Key, 'No key provided')
|
||||
assert(k.Command, 'No command provided for key ' .. k.Key)
|
||||
|
||||
k.Name = k.Name or k.Key
|
||||
k.GuiPath = k.GuiPath or ''
|
||||
|
||||
local currentKey = openspace.getKeyBinding(k.Key)
|
||||
if (next(currentKey) ~= nil) and (not ignoreWarning) then
|
||||
openspace.printWarning('New keybind for "' .. k.Key .. '" is added, but a previous keybind already existed. If you want to silence this warning, pass "true", to this call to bindKeys')
|
||||
end
|
||||
|
||||
if k.Local then
|
||||
openspace.bindKeyLocal(k.Key, k.Command, k.Documentation, k.Name, k.GuiPath)
|
||||
else
|
||||
openspace.bindKey(k.Key, k.Command, k.Documentation, k.Name, k.GuiPath)
|
||||
end
|
||||
end
|
||||
end
|
||||
asset.export("bindKeys", bindKeys)
|
||||
|
||||
local unbindKeys = function(keys)
|
||||
-- We check against k and k.Key to provide compatability
|
||||
-- for both calls with the same table that goes to bindKeys
|
||||
-- as well as the return values from setDeltaTimeKeys
|
||||
for _, k in ipairs(keys) do
|
||||
openspace.clearKey(k.Key or k)
|
||||
end
|
||||
end
|
||||
asset.export("unbindKeys", unbindKeys)
|
||||
|
||||
--shortcut function
|
||||
local function has_value (tab, val)
|
||||
for index, value in ipairs(tab) do
|
||||
-- We grab the first index of our sub-table instead
|
||||
if value[1] == val then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local extractShortcuts = function(names, shortcuts)
|
||||
local foundShortcuts = {};
|
||||
|
||||
if type(names) ~= "table" then
|
||||
openspace.printWarning("scene_helper.extractShortcuts invalid paramater names (not Table)")
|
||||
end
|
||||
|
||||
if type(shortcuts) ~= "table" then
|
||||
openspace.printWarning("scene_helper.extractShortcuts invalid paramater shortcuts (not Table)")
|
||||
end
|
||||
|
||||
for _, shortcut in ipairs(shortcuts) do
|
||||
for _, name in ipairs(names ) do
|
||||
if (shortcut.Name == name) then
|
||||
foundShortcuts[#foundShortcuts+1] = shortcut
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return foundShortcuts
|
||||
end
|
||||
asset.export("extractShortcuts", extractShortcuts)
|
||||
|
||||
local createKeyBindFromShortcuts = function(key, shortcuts, guipath, title, documentation)
|
||||
if type(key) ~= "string" then
|
||||
openspace.printWarning("scene_helper.createKeyBindFromShortcuts invalid paramater key (not String)")
|
||||
end
|
||||
|
||||
if type(shortcuts) ~= "table" or #shortcuts == 0 then
|
||||
openspace.printWarning("scene_helper.createKeyBindFromShortcuts invalid paramater shortcuts (not Table or empty)")
|
||||
end
|
||||
|
||||
-- if type(guipath) ~= "string" then
|
||||
-- guipath = shortcuts[0].GuiPath
|
||||
-- end
|
||||
|
||||
local concatTitle = type(title) ~= "string"
|
||||
local concatDocumentation = type(documentation) ~= "string"
|
||||
|
||||
local keybind = {
|
||||
Key = key,
|
||||
Command = "",
|
||||
Name = name or "",
|
||||
Documentation = documentation or "",
|
||||
GuiPath = guipath or "",
|
||||
Local = false
|
||||
}
|
||||
|
||||
for _, shortcut in ipairs(shortcuts) do
|
||||
keybind.Command = keybind.Command .. shortcut.Command
|
||||
if concatTitle then
|
||||
keybind.Name = keybind.Name .. "/" .. shortcut.Name
|
||||
end
|
||||
if concatDocumentation then
|
||||
keybind.Documentation = keybind.Documentation .. "," .. shortcut.Documentation
|
||||
end
|
||||
|
||||
keybind.Local = keybind.Local and shortcut.Local
|
||||
end
|
||||
|
||||
return keybind
|
||||
end
|
||||
asset.export("createKeyBindFromShortcuts", createKeyBindFromShortcuts)
|
||||
@@ -1,23 +1,22 @@
|
||||
--testing_keybindings.asset
|
||||
|
||||
local sceneHelper = asset.require('./scene_helper')
|
||||
local propertyHelper = asset.require('./property_helper')
|
||||
|
||||
local Keybindings = {
|
||||
{
|
||||
Key = "F7",
|
||||
Name = "Take Screenshot",
|
||||
Command = "openspace.takeScreenshot()",
|
||||
Documentation = "Saves the contents of the screen to a file in the ${SCREENSHOTS} directory.",
|
||||
GuiPath = "/Rendering",
|
||||
Local = true
|
||||
}
|
||||
local take_screenshot = {
|
||||
Identifier = "testing_keyboard.take_screenshot",
|
||||
Name = "Take Screenshot",
|
||||
Command = "openspace.takeScreenshot()",
|
||||
Documentation = "Saves the contents of the screen to a file in the ${SCREENSHOTS} directory.",
|
||||
GuiPath = "/Rendering",
|
||||
IsLocal = true
|
||||
}
|
||||
|
||||
asset.onInitialize(function()
|
||||
Keys = sceneHelper.bindKeys(Keybindings)
|
||||
openspace.action.registerAction(take_screenshot)
|
||||
openspace.bindKey("F7", take_screenshot.Identifier)
|
||||
end)
|
||||
|
||||
asset.onDeinitialize(function ()
|
||||
sceneHelper.unbindKeys(Keybindings)
|
||||
openspace.action.removeAction(take_screenshot.Identifier)
|
||||
openspace.clearKey("F7")
|
||||
end)
|
||||
|
||||
@@ -1,4 +1,78 @@
|
||||
{
|
||||
"actions": [
|
||||
{
|
||||
"documentation": "Jump to right before the earthrise photo",
|
||||
"gui_path": "/Missions/Apollo/8",
|
||||
"identifier": "profile.setup.earthrise",
|
||||
"is_local": false,
|
||||
"name": "Set Earthrise time",
|
||||
"script": "openspace.time.setPause(true); openspace.time.setDeltaTime(1); openspace.time.setTime('1968 DEC 24 16:37:31'); openspace.navigation.setNavigationState({Anchor = 'Apollo8', Position = { 1.494592E1, 3.236777E1, -4.171296E1 }, ReferenceFrame = 'Root', Up = { 0.960608E0, -0.212013E0, 0.179675E0 }}); openspace.setPropertyValue('*Trail.Renderable.Enabled', false);"
|
||||
},
|
||||
{
|
||||
"documentation": "Jump to time right before Apollo 8 liftoff, with its trail enabled",
|
||||
"gui_path": "/Missions/Apollo/8",
|
||||
"identifier": "profile.setup.apollo8",
|
||||
"is_local": false,
|
||||
"name": "Set Apollo 8 launch time",
|
||||
"script": "openspace.time.setTime('1968-12-21T12:51:37.00'); openspace.setPropertyValueSingle('Scene.Apollo8LaunchTrail.Renderable.Enabled', true);"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggles Moon Kaguya color layer",
|
||||
"gui_path": "/Missions/Apollo",
|
||||
"identifier": "profile.moon.kaguyalayer",
|
||||
"is_local": false,
|
||||
"name": "Toggle Kaguya layer",
|
||||
"script": "openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.Kaguya_Utah.Enabled', not openspace.getPropertyValue('Scene.Moon.Renderable.Layers.ColorLayers.Kaguya_Utah.Enabled'));"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggles shading for the Moon",
|
||||
"gui_path": "/Missions/Apollo",
|
||||
"identifier": "profile.moon.shading",
|
||||
"is_local": false,
|
||||
"name": "Toggle Moon shading",
|
||||
"script": "openspace.setPropertyValueSingle('Scene.Moon.Renderable.PerformShading', not openspace.getPropertyValue('Scene.Moon.Renderable.PerformShading'));"
|
||||
},
|
||||
{
|
||||
"documentation": "Set camera focus to the Earth",
|
||||
"gui_path": "/Missions/Apollo",
|
||||
"identifier": "profile.focus.earth",
|
||||
"is_local": false,
|
||||
"name": "Focus on Earth",
|
||||
"script": "openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Aim', ''); openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Anchor', 'Earth'); openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil);"
|
||||
},
|
||||
{
|
||||
"documentation": "Set camera focus to the Moon",
|
||||
"gui_path": "/Missions/Apollo",
|
||||
"identifier": "profile.focus.moon",
|
||||
"is_local": false,
|
||||
"name": "Focus on Moon",
|
||||
"script": "openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Aim', ''); openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Anchor', 'Moon'); openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil);"
|
||||
},
|
||||
{
|
||||
"documentation": "Disable apollo site on moon when leaving",
|
||||
"gui_path": "/Missions/Apollo",
|
||||
"identifier": "profile.moon.disableapollosites",
|
||||
"is_local": false,
|
||||
"name": "Disable Apollo sites",
|
||||
"script": "openspace.setPropertyValue('Scene.Moon.Renderable.Layers.ColorLayers.A17_*.Enabled', false); openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.HeightLayers.LRO_NAC_Apollo_11.Enabled', false); openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A11_M177481212_p_longlat.Enabled', false); openspace.setPropertyValueSingle('Scene.Apollo11MoonTrail.Renderable.Enabled', false); openspace.setPropertyValueSingle('Scene.Apollo11LemTrail.Renderable.Enabled', false); openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.HeightLayers.LRO_NAC_Apollo_17.Enabled', false);"
|
||||
},
|
||||
{
|
||||
"documentation": "Setup for Apollo 11 landing site",
|
||||
"gui_path": "/Missions/Apollo/11",
|
||||
"identifier": "profile.setup.apollo11",
|
||||
"is_local": false,
|
||||
"name": "Setup A11 site",
|
||||
"script": "openspace.time.setTime('1969 JUL 20 20:17:40'); openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.HeightLayers.LRO_NAC_Apollo_11.Enabled', true); openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A11_M177481212_p_longlat.Enabled', true); openspace.setPropertyValueSingle('Scene.Moon.Renderable.TargetLodScaleFactor', 20.11); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'Apollo11LemPosition'); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil); openspace.setPropertyValueSingle('Scene.Apollo11MoonTrail.Renderable.Enabled', true); openspace.setPropertyValueSingle('Scene.Apollo11LemTrail.Renderable.Enabled', true);"
|
||||
},
|
||||
{
|
||||
"documentation": "Setup for Apollo 17 landing site",
|
||||
"gui_path": "/Missions/Apollo/17",
|
||||
"identifier": "profile.setup.apollo17",
|
||||
"is_local": false,
|
||||
"name": "Setup A17 site",
|
||||
"script": "openspace.time.setTime('1972 DEC 12 19:47:11'); openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A17_travmap.BlendMode', 0.000000); openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A17_travmap.Enabled', true); openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.HeightLayers.LRO_NAC_Apollo_17.Enabled', true); openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A17_LEM.Enabled', true); openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A17_LEM.BlendMode', 0.000000); openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A17_NAC_Alt_p.Enabled', true); openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A17_NAC_Alt_p.BlendMode', 0.000000); openspace.setPropertyValueSingle('Scene.Moon.Renderable.TargetLodScaleFactor', 20.17); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'Apollo17LemModel'); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil); openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A17_station7.BlendMode', 0.000000);"
|
||||
}
|
||||
],
|
||||
"assets": [
|
||||
"base",
|
||||
"scene/solarsystem/missions/apollo/11/apollo11",
|
||||
@@ -39,76 +113,40 @@
|
||||
],
|
||||
"keybindings": [
|
||||
{
|
||||
"documentation": "Jump to right before the earthrise photo",
|
||||
"gui_path": "/Missions/Apollo/8",
|
||||
"is_local": false,
|
||||
"key": "E",
|
||||
"name": "Set Earthrise time",
|
||||
"script": "openspace.time.setPause(true); openspace.time.setDeltaTime(1); openspace.time.setTime('1968 DEC 24 16:37:31'); openspace.navigation.setNavigationState({Anchor = 'Apollo8', Position = { 1.494592E1, 3.236777E1, -4.171296E1 }, ReferenceFrame = 'Root', Up = { 0.960608E0, -0.212013E0, 0.179675E0 }}); openspace.setPropertyValue('*Trail.Renderable.Enabled', false);"
|
||||
"action": "profile.setup.earthrise",
|
||||
"key": "E"
|
||||
},
|
||||
{
|
||||
"documentation": "Jump to time right before Apollo 8 liftoff, with its trail enabled",
|
||||
"gui_path": "/Missions/Apollo/8",
|
||||
"is_local": false,
|
||||
"key": "U",
|
||||
"name": "Set Apollo 8 launch time",
|
||||
"script": "openspace.time.setTime('1968-12-21T12:51:37.00'); openspace.setPropertyValueSingle('Scene.Apollo8LaunchTrail.Renderable.Enabled', true);"
|
||||
"action": "profile.setup.apollo8",
|
||||
"key": "U"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggles Moon Kaguya color layer",
|
||||
"gui_path": "/Missions/Apollo",
|
||||
"is_local": false,
|
||||
"key": "K",
|
||||
"name": "Toggle Kaguya layer",
|
||||
"script": "openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.Kaguya_Utah.Enabled', not openspace.getPropertyValue('Scene.Moon.Renderable.Layers.ColorLayers.Kaguya_Utah.Enabled'));"
|
||||
"action": "profile.moon.kaguyalayer",
|
||||
"key": "K"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggles shading for the Moon",
|
||||
"gui_path": "/Missions/Apollo",
|
||||
"is_local": false,
|
||||
"key": "S",
|
||||
"name": "Toggle Moon shading",
|
||||
"script": "openspace.setPropertyValueSingle('Scene.Moon.Renderable.PerformShading', not openspace.getPropertyValue('Scene.Moon.Renderable.PerformShading'));"
|
||||
"action": "profile.moon.shading",
|
||||
"key": "S"
|
||||
},
|
||||
{
|
||||
"documentation": "Set camera focus to the Earth",
|
||||
"gui_path": "/Missions/Apollo",
|
||||
"is_local": false,
|
||||
"key": "HOME",
|
||||
"name": "Focus on Earth",
|
||||
"script": "openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Aim', ''); openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Anchor', 'Earth'); openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil);"
|
||||
"action": "profile.focus.earth",
|
||||
"key": "Home"
|
||||
},
|
||||
{
|
||||
"documentation": "Set camera focus to the Moon",
|
||||
"gui_path": "/Missions/Apollo",
|
||||
"is_local": false,
|
||||
"key": "M",
|
||||
"name": "Focus on Moon",
|
||||
"script": "openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Aim', ''); openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Anchor', 'Moon'); openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil);"
|
||||
"action": "profile.focus.moon",
|
||||
"key": "M"
|
||||
},
|
||||
{
|
||||
"documentation": "Disable apollo site on moon when leaving",
|
||||
"gui_path": "/Missions/Apollo",
|
||||
"is_local": false,
|
||||
"key": "F9",
|
||||
"name": "Disable Apollo sites",
|
||||
"script": "openspace.setPropertyValue('Scene.Moon.Renderable.Layers.ColorLayers.A17_*.Enabled', false); openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.HeightLayers.LRO_NAC_Apollo_11.Enabled', false); openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A11_M177481212_p_longlat.Enabled', false); openspace.setPropertyValueSingle('Scene.Apollo11MoonTrail.Renderable.Enabled', false); openspace.setPropertyValueSingle('Scene.Apollo11LemTrail.Renderable.Enabled', false); openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.HeightLayers.LRO_NAC_Apollo_17.Enabled', false);"
|
||||
"action": "profile.moon.disableapollosites",
|
||||
"key": "F9"
|
||||
},
|
||||
{
|
||||
"documentation": "Setup for Apollo 11 landing site",
|
||||
"gui_path": "/Missions/Apollo/11",
|
||||
"is_local": false,
|
||||
"key": "F11",
|
||||
"name": "Setup A11 site",
|
||||
"script": "openspace.time.setTime('1969 JUL 20 20:17:40'); openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.HeightLayers.LRO_NAC_Apollo_11.Enabled', true); openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A11_M177481212_p_longlat.Enabled', true); openspace.setPropertyValueSingle('Scene.Moon.Renderable.TargetLodScaleFactor', 20.11); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'Apollo11LemPosition'); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil); openspace.setPropertyValueSingle('Scene.Apollo11MoonTrail.Renderable.Enabled', true); openspace.setPropertyValueSingle('Scene.Apollo11LemTrail.Renderable.Enabled', true);"
|
||||
"action": "profile.setup.apollo11",
|
||||
"key": "F11"
|
||||
},
|
||||
{
|
||||
"documentation": "Setup for Apollo 17 landing site",
|
||||
"gui_path": "/Missions/Apollo/17",
|
||||
"is_local": false,
|
||||
"key": "F7",
|
||||
"name": "Setup A17 site",
|
||||
"script": "openspace.time.setTime('1972 DEC 12 19:47:11'); openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A17_travmap.BlendMode', 0.000000); openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A17_travmap.Enabled', true); openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.HeightLayers.LRO_NAC_Apollo_17.Enabled', true); openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A17_LEM.Enabled', true); openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A17_LEM.BlendMode', 0.000000); openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A17_NAC_Alt_p.Enabled', true); openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A17_NAC_Alt_p.BlendMode', 0.000000); openspace.setPropertyValueSingle('Scene.Moon.Renderable.TargetLodScaleFactor', 20.17); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'Apollo17LemModel'); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil); openspace.setPropertyValueSingle('Scene.Moon.Renderable.Layers.ColorLayers.A17_station7.BlendMode', 0.000000);"
|
||||
"action": "profile.setup.apollo17",
|
||||
"key": "F7"
|
||||
}
|
||||
],
|
||||
"mark_nodes": [
|
||||
@@ -145,6 +183,6 @@
|
||||
},
|
||||
"version": {
|
||||
"major": 1,
|
||||
"minor": 0
|
||||
"minor": 1
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,30 @@
|
||||
{
|
||||
"actions": [
|
||||
{
|
||||
"documentation": "Toggle trails on or off for satellites around Earth",
|
||||
"gui_path": "/Earth",
|
||||
"identifier": "profile.toggle.satellite",
|
||||
"is_local": false,
|
||||
"name": "Toggle satellite trails",
|
||||
"script": "local list = openspace.getProperty('{earth_satellites}.Renderable.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end"
|
||||
},
|
||||
{
|
||||
"documentation": "Refocuses the camera on the ISS",
|
||||
"gui_path": "/Earth",
|
||||
"identifier": "profile.focus.iss",
|
||||
"is_local": false,
|
||||
"name": "Focus ISS",
|
||||
"script": "openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Aim', '');openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Anchor', 'ISS');openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil);"
|
||||
},
|
||||
{
|
||||
"documentation": "Retargets the camera on Earth",
|
||||
"gui_path": "/Earth",
|
||||
"identifier": "profile.focus.earth",
|
||||
"is_local": false,
|
||||
"name": "Focus on Earth",
|
||||
"script": "openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Aim', '');openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Anchor', 'Earth')openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil);"
|
||||
}
|
||||
],
|
||||
"assets": [
|
||||
"base",
|
||||
"scene/solarsystem/planets/earth/earth",
|
||||
@@ -35,28 +61,16 @@
|
||||
],
|
||||
"keybindings": [
|
||||
{
|
||||
"documentation": "Toggle trails on or off for satellites around Earth",
|
||||
"gui_path": "/Earth",
|
||||
"is_local": false,
|
||||
"key": "S",
|
||||
"name": "Toggle satellite trails",
|
||||
"script": "local list = openspace.getProperty('{earth_satellites}.Renderable.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end"
|
||||
"action": "profile.toggle.satellite",
|
||||
"key": "S"
|
||||
},
|
||||
{
|
||||
"documentation": "Refocuses the camera on the ISS",
|
||||
"gui_path": "/Earth",
|
||||
"is_local": false,
|
||||
"key": "I",
|
||||
"name": "Focus ISS",
|
||||
"script": "openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Aim', '');openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Anchor', 'ISS');openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil);"
|
||||
"action": "profile.focus.iss",
|
||||
"key": "I"
|
||||
},
|
||||
{
|
||||
"documentation": "Retargets the camera on Earth",
|
||||
"gui_path": "/Earth",
|
||||
"is_local": false,
|
||||
"key": "HOME",
|
||||
"name": "Focus on Earth",
|
||||
"script": "openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Aim', '');openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Anchor', 'Earth')openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil);"
|
||||
"action": "profile.focus.earth",
|
||||
"key": "HOME"
|
||||
}
|
||||
],
|
||||
"mark_nodes": [
|
||||
@@ -88,6 +102,6 @@
|
||||
},
|
||||
"version": {
|
||||
"major": 1,
|
||||
"minor": 0
|
||||
"minor": 1
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,38 @@
|
||||
{
|
||||
"actions": [
|
||||
{
|
||||
"documentation": "Toggle trails on or off for satellites around Earth",
|
||||
"gui_path": "/Earth",
|
||||
"identifier": "profile.toggle.satellite",
|
||||
"is_local": false,
|
||||
"name": "Toggle satellite trails",
|
||||
"script": "local list = openspace.getProperty('{earth_satellites}.Renderable.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end"
|
||||
},
|
||||
{
|
||||
"documentation": "Refocuses the camera on the ISS",
|
||||
"gui_path": "/Earth",
|
||||
"identifier": "profile.focus.iss",
|
||||
"is_local": false,
|
||||
"name": "Focus ISS",
|
||||
"script": "openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Aim', '');openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Anchor', 'ISS');openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil);"
|
||||
},
|
||||
{
|
||||
"documentation": "Retargets the camera on Earth",
|
||||
"gui_path": "/Earth",
|
||||
"identifier": "profile.focus.earth",
|
||||
"is_local": false,
|
||||
"name": "Focus on Earth",
|
||||
"script": "openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Aim', '');openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Anchor', 'Earth')openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil);"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggle on/off minor moon trails for all planets in the solar system",
|
||||
"gui_path": "/Solar System",
|
||||
"identifier": "profile.toggle.minormoons",
|
||||
"is_local": false,
|
||||
"name": "Toggle Minor Moon Trails",
|
||||
"script": "local list = openspace.getProperty('{moonTrail_minor}.Renderable.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end"
|
||||
}
|
||||
],
|
||||
"assets": [
|
||||
"base",
|
||||
"scene/solarsystem/planets/earth/earth",
|
||||
@@ -43,36 +77,20 @@
|
||||
],
|
||||
"keybindings": [
|
||||
{
|
||||
"documentation": "Toggle trails on or off for satellites around Earth",
|
||||
"gui_path": "/Earth",
|
||||
"is_local": false,
|
||||
"key": "S",
|
||||
"name": "Toggle satellite trails",
|
||||
"script": "local list = openspace.getProperty('{earth_satellites}.Renderable.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end"
|
||||
"action": "profile.toggle.satellite",
|
||||
"key": "S"
|
||||
},
|
||||
{
|
||||
"documentation": "Refocuses the camera on the ISS",
|
||||
"gui_path": "/Earth",
|
||||
"is_local": false,
|
||||
"key": "I",
|
||||
"name": "Focus ISS",
|
||||
"script": "openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Aim', '');openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Anchor', 'ISS');openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil);"
|
||||
"action": "profile.focus.iss",
|
||||
"key": "I"
|
||||
},
|
||||
{
|
||||
"documentation": "Retargets the camera on Earth",
|
||||
"gui_path": "/Earth",
|
||||
"is_local": false,
|
||||
"key": "HOME",
|
||||
"name": "Focus on Earth",
|
||||
"script": "openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Aim', '');openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Anchor', 'Earth')openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil);"
|
||||
"action": "profile.focus.earth",
|
||||
"key": "HOME"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggle on/off minor moon trails for all planets in the solar system",
|
||||
"gui_path": "/Solar System",
|
||||
"is_local": false,
|
||||
"key": "SHIFT+H",
|
||||
"name": "Toggle Minor Moon Trails",
|
||||
"script": "local list = openspace.getProperty('{moonTrail_minor}.Renderable.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end"
|
||||
"action": "profile.toggle.minormoons",
|
||||
"key": "SHIFT+H"
|
||||
}
|
||||
],
|
||||
"mark_nodes": [
|
||||
@@ -110,6 +128,6 @@
|
||||
},
|
||||
"version": {
|
||||
"major": 1,
|
||||
"minor": 0
|
||||
"minor": 1
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,46 @@
|
||||
{
|
||||
"actions": [
|
||||
{
|
||||
"documentation": "Toggle trails on or off for satellites around Earth",
|
||||
"gui_path": "/Earth",
|
||||
"identifier": "profile.toggle.satellitetrails",
|
||||
"is_local": false,
|
||||
"name": "Toggle satellite trails",
|
||||
"script": "local list = openspace.getProperty('{earth_satellites}.Renderable.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggle points and labels for the Lagrangian points for Earth Sun system",
|
||||
"gui_path": "/JWST",
|
||||
"identifier": "profile.toggle.lagrangianpoints",
|
||||
"is_local": false,
|
||||
"name": "Toggle Lagrangian points",
|
||||
"script": "local list = openspace.getProperty('{lagrange_points_earth}.Renderable.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggle Hubble Ultra Deep Field image and line towards its coordinate",
|
||||
"gui_path": "/JWST",
|
||||
"identifier": "profile.toggle.hudf",
|
||||
"is_local": false,
|
||||
"name": "Toggle Hubble Ultra Deep Field",
|
||||
"script": "local list = openspace.getProperty('{mission_jwst_hudf}.*.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggle L2 label, point and line",
|
||||
"gui_path": "/JWST",
|
||||
"identifier": "profile.toggle.l2",
|
||||
"is_local": false,
|
||||
"name": "Toggle L2",
|
||||
"script": "local list = openspace.getProperty('{lagrange_points_earth_l2_small}.*.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggle James Webb Space Telecope field of view and view band",
|
||||
"gui_path": "/JWST",
|
||||
"identifier": "profile.toggle.jwst_fov",
|
||||
"is_local": false,
|
||||
"name": "Toggle JWST field of view and view band",
|
||||
"script": "local list = openspace.getProperty('{mission_jwst_fov}.*.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end"
|
||||
}
|
||||
],
|
||||
"assets": [
|
||||
"base",
|
||||
"scene/solarsystem/planets/earth/earth",
|
||||
@@ -38,44 +80,24 @@
|
||||
],
|
||||
"keybindings": [
|
||||
{
|
||||
"documentation": "Toggle trails on or off for satellites around Earth",
|
||||
"gui_path": "/Earth",
|
||||
"is_local": false,
|
||||
"key": "S",
|
||||
"name": "Toggle satellite trails",
|
||||
"script": "local list = openspace.getProperty('{earth_satellites}.Renderable.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end"
|
||||
"action": "profile.toggle.satellitetrails",
|
||||
"key": "S"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggle points and labels for the Lagrangian points for Earth Sun system",
|
||||
"gui_path": "/JWST",
|
||||
"is_local": false,
|
||||
"key": "P",
|
||||
"name": "Toggle Lagrangian points",
|
||||
"script": "local list = openspace.getProperty('{lagrange_points_earth}.Renderable.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end"
|
||||
"action": "profile.toggle.lagrangianpoints",
|
||||
"key": "P"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggle Hubble Ultra Deep Field image and line towards its coordinate",
|
||||
"gui_path": "/JWST",
|
||||
"is_local": false,
|
||||
"key": "U",
|
||||
"name": "Toggle Hubble Ultra Deep Field",
|
||||
"script": "local list = openspace.getProperty('{mission_jwst_hudf}.*.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end"
|
||||
"action": "profile.toggle.hudf",
|
||||
"key": "U"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggle L2 label, point and line",
|
||||
"gui_path": "/JWST",
|
||||
"is_local": false,
|
||||
"key": "O",
|
||||
"name": "Toggle L2",
|
||||
"script": "local list = openspace.getProperty('{lagrange_points_earth_l2_small}.*.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end"
|
||||
"action": "profile.toggle.l2",
|
||||
"key": "O"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggle James Webb Space Telecope field of view and view band",
|
||||
"gui_path": "/JWST",
|
||||
"is_local": false,
|
||||
"key": "V",
|
||||
"name": "Toggle JWST field of view and view band",
|
||||
"script": "local list = openspace.getProperty('{mission_jwst_fov}.*.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end"
|
||||
"action": "profile.toggle.jwst_fov",
|
||||
"key": "V"
|
||||
}
|
||||
],
|
||||
"mark_nodes": [
|
||||
@@ -107,6 +129,6 @@
|
||||
},
|
||||
"version": {
|
||||
"major": 1,
|
||||
"minor": 0
|
||||
"minor": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,30 @@
|
||||
{
|
||||
"actions": [
|
||||
{
|
||||
"documentation": "Set and goto Insight Landing",
|
||||
"gui_path": "/Missions/Insight",
|
||||
"identifier": "profile.setup.insight",
|
||||
"is_local": false,
|
||||
"name": "Setup scene for insight EDL",
|
||||
"script": "openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.Mola_Utah.Settings.Offset', -469.300000);openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.HiRISE-LS-DEM.Settings.Offset', -470.800006);openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.HiRISE-LS-DEM.Enabled', true);openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.ColorLayers.HiRISE-LS.Enabled', true);openspace.time.setPause(true);openspace.time.setTime('2018 NOV 26 19:39:01.68');openspace.navigation.setNavigationState({Anchor = 'Insight',Pitch = 0.567457E-4,Position = { 1.240506E1,-1.369270E1,-2.423553E0 },ReferenceFrame = 'Root',Up = { 0.441211E0,0.247019E0,0.862737E0 },Yaw = -0.446853E-4});"
|
||||
},
|
||||
{
|
||||
"documentation": "Disable Mars layer settings used for insight EDL",
|
||||
"gui_path": "/Missions/Insight",
|
||||
"identifier": "profile.unsetup.insight",
|
||||
"is_local": false,
|
||||
"name": "Unset Insight Landing",
|
||||
"script": "openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.Mola_Utah.Settings.Offset', 0);openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.HiRISE-LS-DEM.Settings.Offset', 0);openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.HiRISE-LS-DEM.Enabled', false);openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.ColorLayers.HiRISE-LS.Enabled', false);"
|
||||
},
|
||||
{
|
||||
"documentation": "Sets time and layers for Perseverance landing",
|
||||
"gui_path": "/Missions/Perseverance",
|
||||
"identifier": "profile.setup.perseverance",
|
||||
"is_local": false,
|
||||
"name": "Setup and Goto Perseverance",
|
||||
"script": "openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.Mola_Utah.Settings.Offset', -1674.0);openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.HiRISE-LS-DEM.Settings.Offset', -1674.0);openspace.time.setPause(true);openspace.time.setTime('2021 FEB 18 20:32:16');openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.HiRISE-LS-DEM.Enabled', true);openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.ColorLayers.HiRISE-LS.Enabled', true);openspace.navigation.setNavigationState({Anchor = 'Perseverance',Pitch = 0.567457E-4,Position = { 1.240506E1,-1.369270E1,-2.423553E0 },ReferenceFrame = 'Root',Up = { 0.441211E0,0.247019E0,0.862737E0 },Yaw = -0.446853E-4});"
|
||||
}
|
||||
],
|
||||
"assets": [
|
||||
"base",
|
||||
"scene/solarsystem/missions/insight/edl",
|
||||
@@ -34,28 +60,16 @@
|
||||
],
|
||||
"keybindings": [
|
||||
{
|
||||
"documentation": "Set and goto Insight Landing",
|
||||
"gui_path": "/Missions/Insight",
|
||||
"is_local": false,
|
||||
"key": "I",
|
||||
"name": "Setup scene for insight EDL",
|
||||
"script": "openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.Mola_Utah.Settings.Offset', -469.300000);openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.HiRISE-LS-DEM.Settings.Offset', -470.800006);openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.HiRISE-LS-DEM.Enabled', true);openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.ColorLayers.HiRISE-LS.Enabled', true);openspace.time.setPause(true);openspace.time.setTime('2018 NOV 26 19:39:01.68');openspace.navigation.setNavigationState({Anchor = 'Insight',Pitch = 0.567457E-4,Position = { 1.240506E1,-1.369270E1,-2.423553E0 },ReferenceFrame = 'Root',Up = { 0.441211E0,0.247019E0,0.862737E0 },Yaw = -0.446853E-4});"
|
||||
"action": "profile.setup.insight",
|
||||
"key": "I"
|
||||
},
|
||||
{
|
||||
"documentation": "Disable Mars layer settings used for insight EDL",
|
||||
"gui_path": "/Missions/Insight",
|
||||
"is_local": false,
|
||||
"key": "SHIFT+I",
|
||||
"name": "Unset Insight Landing",
|
||||
"script": "openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.Mola_Utah.Settings.Offset', 0);openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.HiRISE-LS-DEM.Settings.Offset', 0);openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.HiRISE-LS-DEM.Enabled', false);openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.ColorLayers.HiRISE-LS.Enabled', false);"
|
||||
"action": "profile.unsetup.insight",
|
||||
"key": "SHIFT+I"
|
||||
},
|
||||
{
|
||||
"documentation": "Sets time and layers for Perseverance landing",
|
||||
"gui_path": "/Missions/Perseverance",
|
||||
"is_local": false,
|
||||
"key": "P",
|
||||
"name": "Setup and Goto Perseverance",
|
||||
"script": "openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.Mola_Utah.Settings.Offset', -1674.0);openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.HiRISE-LS-DEM.Settings.Offset', -1674.0);openspace.time.setPause(true);openspace.time.setTime('2021 FEB 18 20:32:16');openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.HiRISE-LS-DEM.Enabled', true);openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.ColorLayers.HiRISE-LS.Enabled', true);openspace.navigation.setNavigationState({Anchor = 'Perseverance',Pitch = 0.567457E-4,Position = { 1.240506E1,-1.369270E1,-2.423553E0 },ReferenceFrame = 'Root',Up = { 0.441211E0,0.247019E0,0.862737E0 },Yaw = -0.446853E-4});"
|
||||
"action": "profile.setup.perseverance",
|
||||
"key": "P"
|
||||
}
|
||||
],
|
||||
"mark_nodes": [
|
||||
@@ -77,6 +91,6 @@
|
||||
},
|
||||
"version": {
|
||||
"major": 1,
|
||||
"minor": 2
|
||||
"minor": 1
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,134 @@
|
||||
{
|
||||
"actions": [
|
||||
{
|
||||
"documentation": "Sets the focus of the camera on 'NewHorizons'.",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"identifier": "profile.focus.newhorizons",
|
||||
"is_local": false,
|
||||
"name": "Focus on New Horizons",
|
||||
"script": "openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'NewHorizons');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', '');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil);"
|
||||
},
|
||||
{
|
||||
"documentation": "Anchor at New Horizons, Aim at Pluto",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"identifier": "profile.focus.anchor_nh|aim_pluto",
|
||||
"is_local": false,
|
||||
"name": "Anchor NH, Aim Pluto",
|
||||
"script": "openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'NewHorizons');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', 'Pluto');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)"
|
||||
},
|
||||
{
|
||||
"documentation": "Sets the focus of the camera on 'Pluto'",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"identifier": "profile.focus.pluto",
|
||||
"is_local": false,
|
||||
"name": "Focus on Pluto",
|
||||
"script": "openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'PlutoProjection') ;openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', ''); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil);"
|
||||
},
|
||||
{
|
||||
"documentation": "Sets the focus of the camera on 'Charon'.",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"identifier": "profile.focus.charon",
|
||||
"is_local": false,
|
||||
"name": "Focus on Charon",
|
||||
"script": "openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'Charon');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', '');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil);"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggles New Horizons image projection",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"identifier": "profile.toggle_nh_image_projections",
|
||||
"is_local": false,
|
||||
"name": "Toggle NH Image Projection",
|
||||
"script": "local enabled = openspace.getPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.PerformProjection'); openspace.setPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.PerformProjection', not enabled); openspace.setPropertyValue('Scene.CharonProjection.Renderable.ProjectionComponent.PerformProjection', not enabled);"
|
||||
},
|
||||
{
|
||||
"documentation": "Removes all image projections from Pluto and Charon.",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"identifier": "profile.clear_image_projections",
|
||||
"is_local": false,
|
||||
"name": "Clear image projections",
|
||||
"script": "openspace.setPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.ClearAllProjections', true); openspace.setPropertyValue('Scene.CharonProjection.Renderable.ProjectionComponent.ClearAllProjections', true);"
|
||||
},
|
||||
{
|
||||
"documentation": "Jumps to the 14th of July 2015 at 0900 UTC and clears all projections.",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"identifier": "profile.setup.approach",
|
||||
"is_local": false,
|
||||
"name": "Reset time and projections",
|
||||
"script": "openspace.time.setTime('2015-07-14T09:00:00.00');openspace.setPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.ClearAllProjections', true);openspace.setPropertyValue('Scene.CharonProjection.Renderable.ProjectionComponent.ClearAllProjections', true);"
|
||||
},
|
||||
{
|
||||
"documentation": "Increases the height map exaggeration on Pluto.",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"identifier": "profile.pluto.increase_height_exaggeration",
|
||||
"is_local": false,
|
||||
"name": "Pluto HeightExaggeration +",
|
||||
"script": "openspace.setPropertyValueSingle(\"Scene.PlutoProjection.Renderable.HeightExaggeration\", openspace.getPropertyValue(\"Scene.PlutoProjection.Renderable.HeightExaggeration\") + 5000);"
|
||||
},
|
||||
{
|
||||
"documentation": "Decreases the height map exaggeration on Pluto.",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"identifier": "profile.pluto.decrease_height_exaggeration",
|
||||
"is_local": false,
|
||||
"name": "Pluto HeightExaggeration -",
|
||||
"script": "openspace.setPropertyValueSingle(\"Scene.PlutoProjection.Renderable.HeightExaggeration\", openspace.getPropertyValue(\"Scene.PlutoProjection.Renderable.HeightExaggeration\") - 5000);"
|
||||
},
|
||||
{
|
||||
"documentation": "Increases the height map exaggeration on Charon.",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"identifier": "profile.charon.increase_height_exaggeration",
|
||||
"is_local": false,
|
||||
"name": "Charon HeightExaggeration +",
|
||||
"script": "openspace.setPropertyValueSingle(\"Scene.CharonProjection.Renderable.HeightExaggeration\", openspace.getPropertyValue(\"Scene.CharonProjection.Renderable.HeightExaggeration\") + 5000);"
|
||||
},
|
||||
{
|
||||
"documentation": "Decreases the height map exaggeration on Charon.",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"identifier": "profile.charon.decrease_height_exaggeration",
|
||||
"is_local": false,
|
||||
"name": "Charon HeightExaggeration -",
|
||||
"script": "openspace.setPropertyValueSingle(\"Scene.CharonProjection.Renderable.HeightExaggeration\", openspace.getPropertyValue(\"Scene.CharonProjection.Renderable.HeightExaggeration\") - 5000);"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggles the visibility of the trail behind Pluto.",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"identifier": "profile.toggle.pluto_trail",
|
||||
"is_local": false,
|
||||
"name": "Toggle Pluto Trail",
|
||||
"script": "openspace.setPropertyValueSingle('Scene.PlutoBarycentricTrail.Renderable.Enabled', not openspace.getPropertyValue('Scene.PlutoBarycentricTrail.Renderable.Enabled'));"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggles the visibility of the text labels of Pluto, Charon, Hydra, Nix, Kerberos, and Styx.",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"identifier": "profile.toggle.pluto_labels",
|
||||
"is_local": false,
|
||||
"name": "Toggle Pluto Labels",
|
||||
"script": "local list = {\"Scene.PlutoText.Renderable.Enabled\", \"Scene.CharonText.Renderable.Enabled\", \"Scene.HydraText.Renderable.Enabled\", \"Scene.NixText.Renderable.Enabled\", \"Scene.KerberosText.Renderable.Enabled\", \"Scene.StyxText.Renderable.Enabled\"}; for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggles the visibility of the labels for the New Horizons instruments.",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"identifier": "profile.toggle_nh_labels",
|
||||
"is_local": false,
|
||||
"name": "Toggle New Horizons Labels",
|
||||
"script": "local v = openspace.getPropertyValue(\"Scene.Labels.Renderable.Opacity\"); if v <= 0.5 then openspace.setPropertyValueSingle(\"Scene.Labels.Renderable.Opacity\",1.0,2.0) else openspace.setPropertyValueSingle(\"Scene.Labels.Renderable.Opacity\",0.0,2.0) end"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggles the visibility of the shadow visualization of Pluto and Charon.",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"identifier": "profile.toggle_shadows",
|
||||
"is_local": false,
|
||||
"name": "Toggle Shadows",
|
||||
"script": "openspace.setPropertyValueSingle('Scene.PlutoShadow.Renderable.Enabled', not openspace.getPropertyValue('Scene.PlutoShadow.Renderable.Enabled'));openspace.setPropertyValueSingle('Scene.CharonShadow.Renderable.Enabled', not openspace.getPropertyValue('Scene.CharonShadow.Renderable.Enabled'));"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggles the trail of New Horizons",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"identifier": "profile.toggle.nh_trail",
|
||||
"is_local": false,
|
||||
"name": "Toggle NH Trail",
|
||||
"script": "openspace.setPropertyValueSingle('Scene.NewHorizonsTrailPluto.Renderable.Enabled', not openspace.getPropertyValue('Scene.NewHorizonsTrailPluto.Renderable.Enabled'));"
|
||||
}
|
||||
],
|
||||
"assets": [
|
||||
"base",
|
||||
"scene/solarsystem/missions/newhorizons/dashboard",
|
||||
@@ -37,172 +167,84 @@
|
||||
],
|
||||
"keybindings": [
|
||||
{
|
||||
"documentation": "Sets the focus of the camera on 'NewHorizons'.",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"is_local": false,
|
||||
"key": "A",
|
||||
"name": "Focus on New Horizons",
|
||||
"script": "openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'NewHorizons');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', '');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil);"
|
||||
"action": "profile.focus.newhorizons",
|
||||
"key": "A"
|
||||
},
|
||||
{
|
||||
"documentation": "Anchor at New Horizons, Aim at Pluto",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"is_local": false,
|
||||
"key": "SHIFT+A",
|
||||
"name": "Anchor NH, Aim Pluto",
|
||||
"script": "openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'NewHorizons');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', 'Pluto');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil)"
|
||||
"action": "profile.focus.anchor_nh|aim_pluto",
|
||||
"key": "SHIFT+A"
|
||||
},
|
||||
{
|
||||
"documentation": "Sets the focus of the camera on 'Pluto'",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"is_local": false,
|
||||
"key": "S",
|
||||
"name": "Focus on Pluto",
|
||||
"script": "openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'PlutoProjection') ;openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', ''); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil);"
|
||||
"action": "profile.focus.pluto",
|
||||
"key": "S"
|
||||
},
|
||||
{
|
||||
"documentation": "Sets the focus of the camera on 'Charon'.",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"is_local": false,
|
||||
"key": "D",
|
||||
"name": "Focus on Charon",
|
||||
"script": "openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'Charon');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', '');openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil);"
|
||||
"action": "profile.focus.charon",
|
||||
"key": "D"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggles New Horizons image projection",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"is_local": false,
|
||||
"key": "F7",
|
||||
"name": "Toggle NH Image Projection",
|
||||
"script": "local enabled = openspace.getPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.PerformProjection'); openspace.setPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.PerformProjection', not enabled); openspace.setPropertyValue('Scene.CharonProjection.Renderable.ProjectionComponent.PerformProjection', not enabled);"
|
||||
"action": "profile.toggle_nh_image_projections",
|
||||
"key": "F7"
|
||||
},
|
||||
{
|
||||
"documentation": "Removes all image projections from Pluto and Charon.",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"is_local": false,
|
||||
"key": "F8",
|
||||
"name": "Clear image projections",
|
||||
"script": "openspace.setPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.ClearAllProjections', true); openspace.setPropertyValue('Scene.CharonProjection.Renderable.ProjectionComponent.ClearAllProjections', true);"
|
||||
"action": "profile.clear_image_projections",
|
||||
"key": "F8"
|
||||
},
|
||||
{
|
||||
"documentation": "Jumps to the 14th of July 2015 at 0900 UTC and clears all projections.",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"is_local": false,
|
||||
"key": "F9",
|
||||
"name": "Reset time and projections",
|
||||
"script": "openspace.time.setTime('2015-07-14T09:00:00.00');openspace.setPropertyValue('Scene.PlutoProjection.Renderable.ProjectionComponent.ClearAllProjections', true);openspace.setPropertyValue('Scene.CharonProjection.Renderable.ProjectionComponent.ClearAllProjections', true);"
|
||||
"action": "profile.setup.approach",
|
||||
"key": "F9"
|
||||
},
|
||||
{
|
||||
"documentation": "Increases the height map exaggeration on Pluto.",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"is_local": false,
|
||||
"key": "KP8",
|
||||
"name": "Pluto HeightExaggeration + (KP)",
|
||||
"script": "openspace.setPropertyValueSingle(\"Scene.PlutoProjection.Renderable.HeightExaggeration\", openspace.getPropertyValue(\"Scene.PlutoProjection.Renderable.HeightExaggeration\") + 5000);"
|
||||
"action": "profile.pluto.increase_height_exaggeration",
|
||||
"key": "KP_8"
|
||||
},
|
||||
{
|
||||
"documentation": "Increases the height map exaggeration on Pluto.",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"is_local": false,
|
||||
"key": "CTRL+I",
|
||||
"name": "Pluto HeightExaggeration +",
|
||||
"script": "openspace.setPropertyValueSingle(\"Scene.PlutoProjection.Renderable.HeightExaggeration\", openspace.getPropertyValue(\"Scene.PlutoProjection.Renderable.HeightExaggeration\") + 5000);"
|
||||
"action": "profile.pluto.increase_height_exaggeration",
|
||||
"key": "CTRL+I"
|
||||
},
|
||||
{
|
||||
"documentation": "Decreases the height map exaggeration on Pluto.",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"is_local": false,
|
||||
"key": "CTRL+K",
|
||||
"name": "Pluto HeightExaggeration -",
|
||||
"script": "openspace.setPropertyValueSingle(\"Scene.PlutoProjection.Renderable.HeightExaggeration\", openspace.getPropertyValue(\"Scene.PlutoProjection.Renderable.HeightExaggeration\") - 5000);"
|
||||
"action": "profile.pluto.decrease_height_exaggeration",
|
||||
"key": "CTRL+K"
|
||||
},
|
||||
{
|
||||
"documentation": "Decreases the height map exaggeration on Pluto.",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"is_local": false,
|
||||
"key": "KP2",
|
||||
"name": "Pluto HeightExaggeration - (KP)",
|
||||
"script": "openspace.setPropertyValueSingle(\"Scene.PlutoProjection.Renderable.HeightExaggeration\", openspace.getPropertyValue(\"Scene.PlutoProjection.Renderable.HeightExaggeration\") - 5000);"
|
||||
"action": "profile.pluto.decrease_height_exaggeration",
|
||||
"key": "KP_2"
|
||||
},
|
||||
{
|
||||
"documentation": "Increases the height map exaggeration on Charon.",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"is_local": false,
|
||||
"key": "KP9",
|
||||
"name": "Charon HeightExaggeration + (KP)",
|
||||
"script": "openspace.setPropertyValueSingle(\"Scene.CharonProjection.Renderable.HeightExaggeration\", openspace.getPropertyValue(\"Scene.CharonProjection.Renderable.HeightExaggeration\") + 5000);"
|
||||
"action": "profile.charon.increase_height_exaggeration",
|
||||
"key": "KP_9"
|
||||
},
|
||||
{
|
||||
"documentation": "Increases the height map exaggeration on Charon.",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"is_local": false,
|
||||
"key": "CTRL+O",
|
||||
"name": "Charon HeightExaggeration +",
|
||||
"script": "openspace.setPropertyValueSingle(\"Scene.CharonProjection.Renderable.HeightExaggeration\", openspace.getPropertyValue(\"Scene.CharonProjection.Renderable.HeightExaggeration\") + 5000);"
|
||||
"action": "profile.charon.increase_height_exaggeration",
|
||||
"key": "CTRL+O"
|
||||
},
|
||||
{
|
||||
"documentation": "Decreases the height map exaggeration on Charon.",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"is_local": false,
|
||||
"key": "KP3",
|
||||
"name": "Charon HeightExaggeration - (KP)",
|
||||
"script": "openspace.setPropertyValueSingle(\"Scene.CharonProjection.Renderable.HeightExaggeration\", openspace.getPropertyValue(\"Scene.CharonProjection.Renderable.HeightExaggeration\") - 5000);"
|
||||
"action": "profile.charon.decrease_height_exaggeration",
|
||||
"key": "KP_3"
|
||||
},
|
||||
{
|
||||
"documentation": "Decreases the height map exaggeration on Charon.",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"is_local": false,
|
||||
"key": "CTRL+L",
|
||||
"name": "Charon HeightExaggeration -",
|
||||
"script": "openspace.setPropertyValueSingle(\"Scene.CharonProjection.Renderable.HeightExaggeration\", openspace.getPropertyValue(\"Scene.CharonProjection.Renderable.HeightExaggeration\") - 5000);"
|
||||
"action": "profile.charon.decrease_height_exaggeration",
|
||||
"key": "CTRL+L"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggles the visibility of the trail behind Pluto.",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"is_local": false,
|
||||
"key": "O",
|
||||
"name": "Toggle Pluto Trail",
|
||||
"script": "openspace.setPropertyValueSingle('Scene.PlutoBarycentricTrail.Renderable.Enabled', not openspace.getPropertyValue('Scene.PlutoBarycentricTrail.Renderable.Enabled'));"
|
||||
"action": "profile.toggle.pluto_trail",
|
||||
"key": "O"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggles the visibility of the text labels of Pluto, Charon, Hydra, Nix, Kerberos, and Styx.",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"is_local": false,
|
||||
"key": "J",
|
||||
"name": "Toggle Pluto Labels",
|
||||
"script": "local list = {\"Scene.PlutoText.Enabled\", \"Scene.CharonText.Enabled\", \"Scene.HydraText.Enabled\", \"Scene.NixText.Enabled\", \"Scene.KerberosText.Enabled\", \"Scene.StyxText.Enabled\"}; for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end"
|
||||
"action": "profile.toggle.pluto_labels",
|
||||
"key": "J"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggles the visibility of the labels for the New Horizons instruments.",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"is_local": false,
|
||||
"key": "I",
|
||||
"name": "Toggle New Horizons Labels",
|
||||
"script": "local v = openspace.getPropertyValue(\"Scene.Labels.Renderable.Opacity\"); if v <= 0.5 then openspace.setPropertyValueSingle(\"Scene.Labels.Renderable.Opacity\",1.0,2.0) else openspace.setPropertyValueSingle(\"Scene.Labels.Renderable.Opacity\",0.0,2.0) end"
|
||||
"action": "profile.toggle_nh_labels",
|
||||
"key": "I"
|
||||
},
|
||||
{
|
||||
"documentation": "Draws the instrument field of views in a solid color or as lines.",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"is_local": false,
|
||||
"key": "M",
|
||||
"name": "Toggle instrument FOVs",
|
||||
"script": "local list = {\"Scene.PlutoText.Enabled\", \"Scene.NH_LORRI.Renderable.SolidDraw\", \"Scene.NH_RALPH_LEISA.Renderable.SolidDraw\", \"Scene.NH_RALPH_MVIC_PAN1.Renderable.SolidDraw\", \"Scene.NH_RALPH_MVIC_PAN2.Renderable.SolidDraw\", \"Scene.NH_RALPH_MVIC_RED.Renderable.SolidDraw\", \"Scene.NH_RALPH_MVIC_BLUE.Renderable.SolidDraw\", \"Scene.NH_RALPH_MVIC_FT.Renderable.SolidDraw\", \"Scene.NH_RALPH_MVIC_METHANE.Renderable.SolidDraw\", \"Scene.NH_RALPH_MVIC_NIR.Renderable.SolidDraw\", \"Scene.NH_ALICE_AIRGLOW.Renderable.SolidDraw\", \"Scene.NH_ALICE_SOC.Renderable.SolidDraw\"}; for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end"
|
||||
"action": "profile.toggle_shadows",
|
||||
"key": "SHIFT+T"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggles the visibility of the shadow visualization of Pluto and Charon.",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"is_local": false,
|
||||
"key": "SHIFT+T",
|
||||
"name": "Toggle Shadows",
|
||||
"script": "openspace.setPropertyValueSingle('Scene.PlutoShadow.Renderable.Enabled', not openspace.getPropertyValue('Scene.PlutoShadow.Renderable.Enabled'));openspace.setPropertyValueSingle('Scene.CharonShadow.Renderable.Enabled', not openspace.getPropertyValue('Scene.CharonShadow.Renderable.Enabled'));"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggles the trail of New Horizons",
|
||||
"gui_path": "/Missions/New Horizons",
|
||||
"is_local": false,
|
||||
"key": "T",
|
||||
"name": "Toggle NH Trail",
|
||||
"script": "openspace.setPropertyValueSingle('Scene.NewHorizonsTrailPluto.Renderable.Enabled', not openspace.getPropertyValue('Scene.NewHorizonsTrailPluto.Renderable.Enabled'));"
|
||||
"action": "profile.toggle.nh_trail",
|
||||
"key": "T"
|
||||
}
|
||||
],
|
||||
"mark_nodes": [
|
||||
@@ -246,6 +288,6 @@
|
||||
},
|
||||
"version": {
|
||||
"major": 1,
|
||||
"minor": 0
|
||||
"minor": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,62 @@
|
||||
{
|
||||
"actions": [
|
||||
{
|
||||
"documentation": "Sets the focus of the camera on 'OsirisRex'",
|
||||
"gui_path": "/Missions/Osiris Rex",
|
||||
"identifier": "profile.focus.osirisrex",
|
||||
"is_local": false,
|
||||
"name": "Focus on OsirisRex",
|
||||
"script": "openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'OsirisRex'); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', ''); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil);"
|
||||
},
|
||||
{
|
||||
"documentation": "Sets the focus of the camera on 'Bennu'",
|
||||
"gui_path": "/Missions/Osiris Rex",
|
||||
"identifier": "profile.focus.bennu",
|
||||
"is_local": false,
|
||||
"name": "Focus on Bennu",
|
||||
"script": "openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'BennuBarycenter'); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', ''); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil);"
|
||||
},
|
||||
{
|
||||
"documentation": "Sets the time to the approach at Bennu",
|
||||
"gui_path": "/Missions/Osiris Rex",
|
||||
"identifier": "profile.setup.bennu_approach",
|
||||
"is_local": false,
|
||||
"name": "Set Bennu approach time",
|
||||
"script": "openspace.printInfo('Set time: Approach');openspace.time.setTime('2018-SEP-11 21:31:01.183');"
|
||||
},
|
||||
{
|
||||
"documentation": "Sets the time to the preliminary survey of Bennu",
|
||||
"gui_path": "/Missions/Osiris Rex",
|
||||
"identifier": "profile.setup.bennu_survey",
|
||||
"is_local": false,
|
||||
"name": "Set Bennu survey time",
|
||||
"script": "openspace.printInfo('Set time: Preliminary Survey'); openspace.time.setTime('2018-NOV-20 01:13:12.183');"
|
||||
},
|
||||
{
|
||||
"documentation": "Sets the time to the orbital B event",
|
||||
"gui_path": "/Missions/Osiris Rex",
|
||||
"identifier": "profile.setup.orbital_b_event",
|
||||
"is_local": false,
|
||||
"name": "Set orbital B event time",
|
||||
"script": "openspace.printInfo('Set time: Orbital B'); openspace.time.setTime('2019-APR-08 10:35:27.186');"
|
||||
},
|
||||
{
|
||||
"documentation": "Sets the time to the recon event",
|
||||
"gui_path": "/Missions/Osiris Rex",
|
||||
"identifier": "profile.setup.recon_event",
|
||||
"is_local": false,
|
||||
"name": "Set recon event time",
|
||||
"script": "openspace.printInfo('Set time: Recon'); openspace.time.setTime('2019-MAY-25 03:50:31.195');"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggles the visibility of the text marking the location of the Sun",
|
||||
"gui_path": "/Missions/Osiris Rex",
|
||||
"identifier": "profile.toggle.sun_marker",
|
||||
"is_local": false,
|
||||
"name": "Toggle Sun marker",
|
||||
"script": "openspace.setPropertyValueSingle('Scene.SunMarker.Renderable.Enabled', not openspace.getPropertyValue('Scene.SunMarker.Renderable.Enabled'));"
|
||||
}
|
||||
],
|
||||
"assets": [
|
||||
"base",
|
||||
"scene/solarsystem/missions/osirisrex/dashboard",
|
||||
@@ -41,60 +99,32 @@
|
||||
],
|
||||
"keybindings": [
|
||||
{
|
||||
"documentation": "Sets the focus of the camera on 'OsirisRex'",
|
||||
"gui_path": "/Missions/Osiris Rex",
|
||||
"is_local": false,
|
||||
"key": "A",
|
||||
"name": "Focus on OsirisRex",
|
||||
"script": "openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'OsirisRex'); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', ''); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil);"
|
||||
"action": "profile.focus.osirisrex",
|
||||
"key": "A"
|
||||
},
|
||||
{
|
||||
"documentation": "Sets the focus of the camera on 'Bennu'",
|
||||
"gui_path": "/Missions/Osiris Rex",
|
||||
"is_local": false,
|
||||
"key": "S",
|
||||
"name": "Focus on Bennu",
|
||||
"script": "openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'BennuBarycenter'); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', ''); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil);"
|
||||
"action": "profile.focus.bennu",
|
||||
"key": "S"
|
||||
},
|
||||
{
|
||||
"documentation": "Sets the time to the approach at Bennu",
|
||||
"gui_path": "/Missions/Osiris Rex",
|
||||
"is_local": false,
|
||||
"key": "F8",
|
||||
"name": "Set Bennu approach time",
|
||||
"script": "openspace.printInfo('Set time: Approach');openspace.time.setTime('2018-SEP-11 21:31:01.183');"
|
||||
"action": "profile.setup.bennu_approach",
|
||||
"key": "F8"
|
||||
},
|
||||
{
|
||||
"documentation": "Sets the time to the preliminary survey of Bennu",
|
||||
"gui_path": "/Missions/Osiris Rex",
|
||||
"is_local": false,
|
||||
"key": "F9",
|
||||
"name": "Set Bennu survey time",
|
||||
"script": "openspace.printInfo('Set time: Preliminary Survey'); openspace.time.setTime('2018-NOV-20 01:13:12.183');"
|
||||
"action": "profile.setup.bennu_survey",
|
||||
"key": "F9"
|
||||
},
|
||||
{
|
||||
"documentation": "Sets the time to the orbital B event",
|
||||
"gui_path": "/Missions/Osiris Rex",
|
||||
"is_local": false,
|
||||
"key": "F10",
|
||||
"name": "Set orbital B event time",
|
||||
"script": "openspace.printInfo('Set time: Orbital B'); openspace.time.setTime('2019-APR-08 10:35:27.186');"
|
||||
"action": "profile.setup.orbital_b_event",
|
||||
"key": "F10"
|
||||
},
|
||||
{
|
||||
"documentation": "Sets the time to the recon event",
|
||||
"gui_path": "/Missions/Osiris Rex",
|
||||
"is_local": false,
|
||||
"key": "F11",
|
||||
"name": "Set recon event time",
|
||||
"script": "openspace.printInfo('Set time: Recon'); openspace.time.setTime('2019-MAY-25 03:50:31.195');"
|
||||
"action": "profile.setup.recon_event",
|
||||
"key": "F11"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggles the visibility of the text marking the location of the Sun",
|
||||
"gui_path": "/Missions/Osiris Rex",
|
||||
"is_local": false,
|
||||
"key": "Q",
|
||||
"name": "Toggle Sun marker",
|
||||
"script": "openspace.setPropertyValueSingle('Scene.SunMarker.Renderable.Enabled', not openspace.getPropertyValue('Scene.SunMarker.Renderable.Enabled'));"
|
||||
"action": "profile.toggle.sun_marker",
|
||||
"key": "Q"
|
||||
}
|
||||
],
|
||||
"mark_nodes": [
|
||||
@@ -123,6 +153,6 @@
|
||||
},
|
||||
"version": {
|
||||
"major": 1,
|
||||
"minor": 0
|
||||
"minor": 1
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,70 @@
|
||||
{
|
||||
"actions": [
|
||||
{
|
||||
"documentation": "Sets the focus of the camera on 67P",
|
||||
"gui_path": "/Missions/Rosetta",
|
||||
"identifier": "profile.focus.67P",
|
||||
"is_local": false,
|
||||
"name": "Focus on 67P",
|
||||
"script": "openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', '67P'); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', ''); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil);"
|
||||
},
|
||||
{
|
||||
"documentation": "Sets the focus of the camera on Rosetta",
|
||||
"gui_path": "/Missions/Rosetta",
|
||||
"identifier": "profile.focus.rosetta",
|
||||
"is_local": false,
|
||||
"name": "Focus on Rosetta",
|
||||
"script": "openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'Rosetta'); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', ''); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil);"
|
||||
},
|
||||
{
|
||||
"documentation": "Jumps to the time when the Philae lander is released.",
|
||||
"gui_path": "/Missions/Rosetta",
|
||||
"identifier": "profile.setup.lander_release",
|
||||
"is_local": false,
|
||||
"name": "Set lander release time",
|
||||
"script": "openspace.time.setTime('2014-11-12T08:20:00.00');"
|
||||
},
|
||||
{
|
||||
"documentation": "Removes all image projections from 67P.",
|
||||
"gui_path": "/Missions/Rosetta",
|
||||
"identifier": "profile.67p.clear_projections",
|
||||
"is_local": false,
|
||||
"name": "Clear 67P projections",
|
||||
"script": "openspace.setPropertyValue('Scene.67P.Renderable.ProjectionComponent.ClearAllProjections', true);"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggles the visibility of all trails further from the Sun than 67P.",
|
||||
"gui_path": "/Missions/Rosetta",
|
||||
"identifier": "profile.toggle.outerplanet_trails",
|
||||
"is_local": false,
|
||||
"name": "Toggle outer planetary trails",
|
||||
"script": "local list = openspace.getProperty('{planetTrail_giants}.Renderable.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggles the visibility of the free floating image plane.",
|
||||
"gui_path": "/Missions/Rosetta",
|
||||
"identifier": "profile.toggle.image_plane",
|
||||
"is_local": false,
|
||||
"name": "Toggle image plane",
|
||||
"script": "openspace.setPropertyValueSingle('Scene.ImagePlaneRosetta.Renderable.Enabled', not openspace.getPropertyValue('Scene.ImagePlaneRosetta.Renderable.Enabled'));"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggles the visibility of Philae's trail.",
|
||||
"gui_path": "/Missions/Rosetta",
|
||||
"identifier": "profile.toggle.philae_trail",
|
||||
"is_local": false,
|
||||
"name": "Toggle Philae trail",
|
||||
"script": "openspace.setPropertyValueSingle('Scene.PhilaeTrail.Renderable.Enabled', not openspace.getPropertyValue('Scene.PhilaeTrail.Renderable.Enabled'));"
|
||||
},
|
||||
{
|
||||
"documentation": "Enables or disables the image projection on 67P.",
|
||||
"gui_path": "/Missions/Rosetta",
|
||||
"identifier": "profile.toggle.67p_projection",
|
||||
"is_local": false,
|
||||
"name": "Toggle 67P projection",
|
||||
"script": "openspace.setPropertyValueSingle('Scene.67P.Renderable.ProjectionComponent.PerformProjection', not openspace.getPropertyValue('Scene.67P.Renderable.ProjectionComponent.PerformProjection'));"
|
||||
}
|
||||
],
|
||||
"assets": [
|
||||
"base",
|
||||
"scene/solarsystem/missions/rosetta/67p",
|
||||
@@ -45,68 +111,36 @@
|
||||
],
|
||||
"keybindings": [
|
||||
{
|
||||
"documentation": "Sets the focus of the camera on 67P",
|
||||
"gui_path": "/Missions/Rosetta",
|
||||
"is_local": false,
|
||||
"key": "A",
|
||||
"name": "Focus on 67P",
|
||||
"script": "openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', '67P'); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', ''); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil);"
|
||||
"action": "profile.focus.67P",
|
||||
"key": "A"
|
||||
},
|
||||
{
|
||||
"documentation": "Sets the focus of the camera on Rosetta",
|
||||
"gui_path": "/Missions/Rosetta",
|
||||
"is_local": false,
|
||||
"key": "S",
|
||||
"name": "Focus on Rosetta",
|
||||
"script": "openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Anchor', 'Rosetta'); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.Aim', ''); openspace.setPropertyValue('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil);"
|
||||
"action": "profile.focus.rosetta",
|
||||
"key": "S"
|
||||
},
|
||||
{
|
||||
"documentation": "Jumps to the time when the Philae lander is released.",
|
||||
"gui_path": "/Missions/Rosetta",
|
||||
"is_local": false,
|
||||
"key": "F6",
|
||||
"name": "Set lander release time",
|
||||
"script": "openspace.time.setTime('2014-11-12T08:20:00.00');"
|
||||
"action": "profile.setup.lander_release",
|
||||
"key": "F6"
|
||||
},
|
||||
{
|
||||
"documentation": "Removes all image projections from 67P.",
|
||||
"gui_path": "/Missions/Rosetta",
|
||||
"is_local": false,
|
||||
"key": "F8",
|
||||
"name": "Clear 67P projections",
|
||||
"script": "openspace.setPropertyValue('Scene.67P.Renderable.ProjectionComponent.ClearAllProjections', true);"
|
||||
"action": "profile.67p.clear_projections",
|
||||
"key": "F8"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggles the visibility of all trails further from the Sun than 67P.",
|
||||
"gui_path": "/Missions/Rosetta",
|
||||
"is_local": false,
|
||||
"key": "E",
|
||||
"name": "Toggle outer planetary trails",
|
||||
"script": "local list = openspace.getProperty('{planetTrail_giants}.Renderable.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end"
|
||||
"action": "profile.toggle.outerplanet_trails",
|
||||
"key": "E"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggles the visibility of the free floating image plane.",
|
||||
"gui_path": "/Missions/Rosetta",
|
||||
"is_local": false,
|
||||
"key": "I",
|
||||
"name": "Toggle image plane",
|
||||
"script": "openspace.setPropertyValueSingle('Scene.ImagePlaneRosetta.Renderable.Enabled', not openspace.getPropertyValue('Scene.ImagePlaneRosetta.Renderable.Enabled'));"
|
||||
"action": "profile.toggle.image_plane",
|
||||
"key": "I"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggles the visibility of Philae's trail.",
|
||||
"gui_path": "/Missions/Rosetta",
|
||||
"is_local": false,
|
||||
"key": "O",
|
||||
"name": "Toggle Philae trail",
|
||||
"script": "openspace.setPropertyValueSingle('Scene.PhilaeTrail.Renderable.Enabled', not openspace.getPropertyValue('Scene.PhilaeTrail.Renderable.Enabled'));"
|
||||
"action": "profile.toggle.philae_trail",
|
||||
"key": "O"
|
||||
},
|
||||
{
|
||||
"documentation": "Enables or disables the image projection on 67P.",
|
||||
"gui_path": "/Missions/Rosetta",
|
||||
"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'));"
|
||||
"action": "profile.toggle.67p_projection",
|
||||
"key": "P"
|
||||
}
|
||||
],
|
||||
"mark_nodes": [
|
||||
@@ -140,6 +174,6 @@
|
||||
},
|
||||
"version": {
|
||||
"major": 1,
|
||||
"minor": 0
|
||||
"minor": 1
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,62 @@
|
||||
{
|
||||
"actions": [
|
||||
{
|
||||
"documentation": "Set camera focus to Voyager 1",
|
||||
"gui_path": "/Missions/Voyager",
|
||||
"identifier": "profile.focus.voyager1",
|
||||
"is_local": false,
|
||||
"name": "Focus on Voyager",
|
||||
"script": "openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.RetargetAnchor\", nil);openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.Anchor\", 'Voyager_1');openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.Aim\", '')"
|
||||
},
|
||||
{
|
||||
"documentation": "Sets the camera focus on Voyager 2",
|
||||
"gui_path": "/Missions/Voyager",
|
||||
"identifier": "profile.focus.voyager2",
|
||||
"is_local": false,
|
||||
"name": "Focus on Voyager2",
|
||||
"script": "openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.RetargetAnchor\", nil);openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.Anchor\", 'Voyager_2');openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.Aim\", '');"
|
||||
},
|
||||
{
|
||||
"documentation": "Sets the time for Voyager's approach to Jupiter",
|
||||
"gui_path": "/",
|
||||
"identifier": "profile.setup.jupiter_approach",
|
||||
"is_local": false,
|
||||
"name": "Set Jupiter Approach",
|
||||
"script": "openspace.time.setTime(\"1979-01-20T01:32:07.914\")"
|
||||
},
|
||||
{
|
||||
"documentation": "Sets the time for Voyager's approach to Saturn",
|
||||
"gui_path": "/Missions/Voyager",
|
||||
"identifier": "profile.setup.saturn_approach",
|
||||
"is_local": false,
|
||||
"name": "Set Saturn Approach",
|
||||
"script": "openspace.time.setTime(\"1980-10-20T07:43:42.645\");"
|
||||
},
|
||||
{
|
||||
"documentation": "Set the camera focus to Jupiter",
|
||||
"gui_path": "/Missions/Voyager",
|
||||
"identifier": "profile.focus.jupiter",
|
||||
"is_local": false,
|
||||
"name": "Focus on Jupiter",
|
||||
"script": "openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.RetargetAnchor\", nil);openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.Anchor\", 'Jupiter');openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.Aim\", '');"
|
||||
},
|
||||
{
|
||||
"documentation": "Sets the camera focus on Saturn",
|
||||
"gui_path": "/Missions/Voyager",
|
||||
"identifier": "profile.focus.saturn",
|
||||
"is_local": false,
|
||||
"name": "Focus on Saturn",
|
||||
"script": "openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.RetargetAnchor\", nil);openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.Anchor\", 'Saturn');openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.Aim\", '');"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggles the trails of the minor moons",
|
||||
"gui_path": "/Solar System",
|
||||
"identifier": "profile.toggle.minor_trails",
|
||||
"is_local": false,
|
||||
"name": "Toggle minor trails",
|
||||
"script": "local list = openspace.getProperty('{moonTrail_minor}.Renderable.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end"
|
||||
}
|
||||
],
|
||||
"assets": [
|
||||
"base",
|
||||
"scene/solarsystem/missions/voyager/dashboard",
|
||||
@@ -37,60 +95,32 @@
|
||||
],
|
||||
"keybindings": [
|
||||
{
|
||||
"documentation": "Set camera focus to Voyager 1",
|
||||
"gui_path": "/Missions/Voyager",
|
||||
"is_local": false,
|
||||
"key": "V",
|
||||
"name": "Focvus on Voyager",
|
||||
"script": "openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.RetargetAnchor\", nil);openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.Anchor\", 'Voyager_1');openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.Aim\", '')"
|
||||
"action": "profile.focus.voyager1",
|
||||
"key": "V"
|
||||
},
|
||||
{
|
||||
"documentation": "Sets the camera focus on Voyager 2",
|
||||
"gui_path": "/Missions/Voyager",
|
||||
"is_local": false,
|
||||
"key": "SHIFT+V",
|
||||
"name": "Focus on Voyager2",
|
||||
"script": "openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.RetargetAnchor\", nil);openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.Anchor\", 'Voyager_2');openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.Aim\", '');"
|
||||
"action": "profile.focus.voyager2",
|
||||
"key": "SHIFT+V"
|
||||
},
|
||||
{
|
||||
"documentation": "Sets the time for Voyager's approach to Jupiter",
|
||||
"gui_path": "/",
|
||||
"is_local": false,
|
||||
"key": "SHIFT+J",
|
||||
"name": "Set Jupiter Approach",
|
||||
"script": "openspace.time.setTime(\"1979-01-20T01:32:07.914\")"
|
||||
"action": "profile.setup.jupiter_approach",
|
||||
"key": "SHIFT+J"
|
||||
},
|
||||
{
|
||||
"documentation": "Sets the time for Voyager's approach to Saturn",
|
||||
"gui_path": "/Missions/Voyager",
|
||||
"is_local": false,
|
||||
"key": "SHIFT+S",
|
||||
"name": "Set Saturn Approach",
|
||||
"script": "openspace.time.setTime(\"1980-10-20T07:43:42.645\");"
|
||||
"action": "profile.setup.saturn_approach",
|
||||
"key": "SHIFT+S"
|
||||
},
|
||||
{
|
||||
"documentation": "Set the camera focus to Jupiter",
|
||||
"gui_path": "/Missions/Voyager",
|
||||
"is_local": false,
|
||||
"key": "J",
|
||||
"name": "Focus on Jupiter",
|
||||
"script": "openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.RetargetAnchor\", nil);openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.Anchor\", 'Jupiter');openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.Aim\", '');"
|
||||
"action": "profile.focus.jupiter",
|
||||
"key": "J"
|
||||
},
|
||||
{
|
||||
"documentation": "Sets the camera focus on Saturn",
|
||||
"gui_path": "/Missions/Voyager",
|
||||
"is_local": false,
|
||||
"key": "S",
|
||||
"name": "Focus on Saturn",
|
||||
"script": "openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.RetargetAnchor\", nil);openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.Anchor\", 'Saturn');openspace.setPropertyValueSingle(\"NavigationHandler.OrbitalNavigator.Aim\", '');"
|
||||
"action": "profile.focus.saturn",
|
||||
"key": "S"
|
||||
},
|
||||
{
|
||||
"documentation": "Toggles the trails of the minor moons",
|
||||
"gui_path": "/Solar System",
|
||||
"is_local": false,
|
||||
"key": "SHIFT+H",
|
||||
"name": "Toggle minor trails",
|
||||
"script": "local list = openspace.getProperty('{moonTrail_minor}.Renderable.Enabled'); for _,v in pairs(list) do openspace.setPropertyValueSingle(v, not openspace.getPropertyValue(v)) end"
|
||||
"action": "profile.toggle.minor_trails",
|
||||
"key": "SHIFT+H"
|
||||
}
|
||||
],
|
||||
"mark_nodes": [
|
||||
@@ -123,6 +153,6 @@
|
||||
},
|
||||
"version": {
|
||||
"major": 1,
|
||||
"minor": 0
|
||||
"minor": 1
|
||||
}
|
||||
}
|
||||
@@ -54,6 +54,7 @@ namespace configuration { struct Configuration; }
|
||||
namespace interaction {
|
||||
struct JoystickInputStates;
|
||||
struct WebsocketInputStates;
|
||||
class ActionManager;
|
||||
class InteractionMonitor;
|
||||
class KeybindingManager;
|
||||
class NavigationHandler;
|
||||
@@ -88,6 +89,7 @@ inline VersionChecker* versionChecker;
|
||||
inline VirtualPropertyManager* virtualPropertyManager;
|
||||
inline WindowDelegate* windowDelegate;
|
||||
inline configuration::Configuration* configuration;
|
||||
inline interaction::ActionManager* actionManager;
|
||||
inline interaction::InteractionMonitor* interactionMonitor;
|
||||
inline interaction::JoystickInputStates* joystickInputStates;
|
||||
inline interaction::WebsocketInputStates* websocketInputStates;
|
||||
|
||||
@@ -22,58 +22,49 @@
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#ifndef __OPENSPACE_CORE___ACTION___H__
|
||||
#define __OPENSPACE_CORE___ACTION___H__
|
||||
|
||||
namespace {
|
||||
#include <ghoul/misc/boolean.h>
|
||||
#include <string>
|
||||
|
||||
openspace::interaction::ShortcutManager::ShortcutInformation extractInfo(lua_State* L,
|
||||
int nArguments,
|
||||
bool isSync)
|
||||
{
|
||||
openspace::interaction::ShortcutManager::ShortcutInformation i = {
|
||||
ghoul::lua::value<std::string>(L, 1, ghoul::lua::PopValue::No),
|
||||
ghoul::lua::value<std::string>(L, 2, ghoul::lua::PopValue::No),
|
||||
openspace::interaction::ShortcutManager::IsSynchronized(isSync),
|
||||
nArguments >= 3 ?
|
||||
ghoul::lua::value<std::string>(L, 3, ghoul::lua::PopValue::No) :
|
||||
"",
|
||||
nArguments == 4 ?
|
||||
ghoul::lua::value<std::string>(L, 4, ghoul::lua::PopValue::No) :
|
||||
""
|
||||
};
|
||||
lua_pop(L, nArguments);
|
||||
return i;
|
||||
}
|
||||
namespace openspace::interaction {
|
||||
|
||||
} // namespace
|
||||
struct Action {
|
||||
BooleanType(IsSynchronized);
|
||||
|
||||
namespace openspace::luascriptfunctions {
|
||||
/// Unique identifier that identifies this action. There is no special naming scheme
|
||||
/// that we enforce, we are trying to stick to the same . separated structure that
|
||||
/// hopefully provides some protection against accidentally reusing identifiers
|
||||
std::string identifier;
|
||||
|
||||
int clearShortcuts(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::clearShortcuts");
|
||||
global::shortcutManager->resetShortcuts();
|
||||
return 0;
|
||||
}
|
||||
/// The Lua script that gets executed whenever this action is triggered. Optional
|
||||
/// parameters can be passed to actions which are accessible through an `args`
|
||||
/// variable that contains all of the arguments passed into the action. This means
|
||||
/// that the provided script must not use this variable name itself or the script will
|
||||
/// not successfully execute
|
||||
std::string command;
|
||||
|
||||
int bindShortcut(lua_State* L) {
|
||||
int n = ghoul::lua::checkArgumentsAndThrow(L, { 2, 4 }, "lua::bindShortcut");
|
||||
/// The human-readable name of this action. This name must not be unique, but it is
|
||||
/// recommended that the combination of GuiPath + name should be unique to prevent
|
||||
/// user confusion
|
||||
std::string name;
|
||||
|
||||
interaction::ShortcutManager::ShortcutInformation info = extractInfo(L, n, true);
|
||||
global::shortcutManager->addShortcut(std::move(info));
|
||||
/// A user-facing description of what the action does when it gets triggered. If the
|
||||
/// action uses optional arguments, they should be described in here, too
|
||||
std::string documentation;
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
/// This variable defines a subdivision of where this action is placed in a user
|
||||
/// interface. The individual path components are separated by '/' with a leading '/'
|
||||
/// for the root path
|
||||
std::string guiPath;
|
||||
|
||||
int bindShortcutLocal(lua_State* L) {
|
||||
int n = ghoul::lua::checkArgumentsAndThrow(L, { 2, 4 }, "lua::bindShortcutLocal");
|
||||
/// If this value is set to `Yes`, the execution of this action is synchronized to
|
||||
/// other OpenSpace instances, for example other nodes in a cluster environment, or
|
||||
/// to other OpenSpace instances using a parallel connection
|
||||
IsSynchronized synchronization = IsSynchronized::Yes;
|
||||
};
|
||||
|
||||
interaction::ShortcutManager::ShortcutInformation info = extractInfo(L, n, false);
|
||||
global::shortcutManager->addShortcut(std::move(info));
|
||||
} // namespace openspace::interaction
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace openspace::luascriptfunctions
|
||||
#endif // __OPENSPACE_CORE___ACTION___H__
|
||||
@@ -22,39 +22,34 @@
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_CORE___SHORTCUTMANAGER___H__
|
||||
#define __OPENSPACE_CORE___SHORTCUTMANAGER___H__
|
||||
#ifndef __OPENSPACE_CORE___ACTIONMANAGER___H__
|
||||
#define __OPENSPACE_CORE___ACTIONMANAGER___H__
|
||||
|
||||
#include <ghoul/misc/boolean.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <openspace/interaction/action.h>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace ghoul { class Dictionary; }
|
||||
namespace openspace::scripting { struct LuaLibrary; }
|
||||
|
||||
namespace openspace::interaction {
|
||||
|
||||
class ShortcutManager {
|
||||
class ActionManager {
|
||||
public:
|
||||
BooleanType(IsSynchronized);
|
||||
bool hasAction(const std::string& identifier) const;
|
||||
void registerAction(Action action);
|
||||
void removeAction(const std::string& identifier);
|
||||
const Action& action(const std::string& identifier) const;
|
||||
std::vector<Action> actions() const;
|
||||
|
||||
struct ShortcutInformation {
|
||||
std::string name;
|
||||
std::string script;
|
||||
IsSynchronized synchronization;
|
||||
std::string documentation;
|
||||
std::string guiPath;
|
||||
};
|
||||
|
||||
void resetShortcuts();
|
||||
void addShortcut(ShortcutInformation info);
|
||||
const std::vector<ShortcutInformation>& shortcuts() const;
|
||||
void triggerAction(const std::string& identifier,
|
||||
const ghoul::Dictionary& arguments) const;
|
||||
|
||||
static scripting::LuaLibrary luaLibrary();
|
||||
|
||||
private:
|
||||
std::vector<ShortcutInformation> _shortcuts;
|
||||
std::unordered_map<unsigned int, Action> _actions;
|
||||
};
|
||||
|
||||
} // namespace openspace::interaction
|
||||
|
||||
#endif // __OPENSPACE_CORE___SHORTCUTMANAGER___H__
|
||||
#endif // __OPENSPACE_CORE___ACTIONMANAGER___H__
|
||||
@@ -28,7 +28,6 @@
|
||||
#include <openspace/documentation/documentationgenerator.h>
|
||||
|
||||
#include <openspace/util/keys.h>
|
||||
#include <ghoul/misc/boolean.h>
|
||||
|
||||
namespace openspace {
|
||||
class Camera;
|
||||
@@ -41,33 +40,15 @@ namespace openspace::interaction {
|
||||
|
||||
class KeybindingManager : public DocumentationGenerator {
|
||||
public:
|
||||
BooleanType(IsSynchronized);
|
||||
|
||||
struct KeyInformation {
|
||||
std::string command;
|
||||
IsSynchronized synchronization;
|
||||
std::string documentation;
|
||||
std::string name;
|
||||
std::string guiPath;
|
||||
};
|
||||
|
||||
KeybindingManager();
|
||||
|
||||
void resetKeyBindings();
|
||||
|
||||
void bindKeyLocal(Key key, KeyModifier modifier, std::string luaCommand,
|
||||
std::string documentation = "", std::string name = "", std::string guiPath = "");
|
||||
void bindKey(Key key, KeyModifier modifier, std::string action);
|
||||
|
||||
void bindKey(Key key, KeyModifier modifier, std::string luaCommand,
|
||||
std::string documentation = "", std::string name = "", std::string guiPath = "");
|
||||
|
||||
void removeKeyBinding(const std::string& key);
|
||||
void removeKeyBinding(const KeyWithModifier& key);
|
||||
|
||||
std::vector<std::pair<KeyWithModifier, KeyInformation>> keyBinding(
|
||||
const std::string& key) const;
|
||||
|
||||
std::vector<std::pair<KeyWithModifier, KeyInformation>> keyBinding(
|
||||
std::vector<std::pair<KeyWithModifier, std::string>> keyBinding(
|
||||
const KeyWithModifier& key) const;
|
||||
|
||||
static scripting::LuaLibrary luaLibrary();
|
||||
@@ -76,10 +57,10 @@ public:
|
||||
|
||||
std::string generateJson() const override;
|
||||
|
||||
const std::multimap<KeyWithModifier, KeyInformation>& keyBindings() const;
|
||||
const std::multimap<KeyWithModifier, std::string>& keyBindings() const;
|
||||
|
||||
private:
|
||||
std::multimap<KeyWithModifier, KeyInformation> _keyLua;
|
||||
std::multimap<KeyWithModifier, std::string> _keyLua;
|
||||
};
|
||||
|
||||
} // namespace openspace::interaction
|
||||
|
||||
@@ -79,15 +79,20 @@ public:
|
||||
SetType setType;
|
||||
std::string name;
|
||||
std::string value;
|
||||
|
||||
};
|
||||
struct Keybinding {
|
||||
KeyWithModifier key;
|
||||
struct Action {
|
||||
std::string identifier;
|
||||
std::string documentation;
|
||||
std::string name;
|
||||
std::string guiPath;
|
||||
bool isLocal;
|
||||
std::string script;
|
||||
};
|
||||
struct Keybinding {
|
||||
KeyWithModifier key;
|
||||
std::string action;
|
||||
};
|
||||
struct Time {
|
||||
enum class Type {
|
||||
Absolute,
|
||||
@@ -122,8 +127,6 @@ public:
|
||||
explicit Profile(const std::string& content);
|
||||
std::string serialize() const;
|
||||
|
||||
std::string convertToScene() const;
|
||||
|
||||
/**
|
||||
* Saves all current settings, starting from the profile that was loaded at startup,
|
||||
* and all of the property & asset changes that were made since startup.
|
||||
@@ -131,46 +134,29 @@ public:
|
||||
void saveCurrentSettingsToProfile(const properties::PropertyOwner& rootOwner,
|
||||
std::string currentTime, interaction::NavigationState navState);
|
||||
|
||||
/// If the value passed to this function is 'true', the addAsset and removeAsset
|
||||
/// functions will be no-ops instead
|
||||
void setIgnoreUpdates(bool ignoreUpdates);
|
||||
|
||||
/// Adds a new asset and checks for duplicates
|
||||
/// Adds a new asset and checks for duplicates unless the `ignoreUpdates` member is
|
||||
/// set to `true`
|
||||
void addAsset(const std::string& path);
|
||||
|
||||
/// Removes an asset
|
||||
/// Removes an asset unless the `ignoreUpdates` member is set to `true`
|
||||
void removeAsset(const std::string& path);
|
||||
|
||||
/// Removes all assets
|
||||
void clearAssets();
|
||||
static constexpr const Version CurrentVersion = Version{ 1, 1 };
|
||||
|
||||
Version version() const;
|
||||
std::vector<Module> modules() const;
|
||||
std::optional<Meta> meta() const;
|
||||
std::vector<std::string> assets() const;
|
||||
std::vector<Property> properties() const;
|
||||
std::vector<Keybinding> keybindings() const;
|
||||
std::optional<Time> time() const;
|
||||
std::vector<double> deltaTimes() const;
|
||||
std::optional<CameraType> camera() const;
|
||||
std::vector<std::string> markNodes() const;
|
||||
std::vector<std::string> additionalScripts() const;
|
||||
|
||||
void clearMeta();
|
||||
void clearTime();
|
||||
void clearCamera();
|
||||
|
||||
void setVersion(Version v);
|
||||
void setModules(std::vector<Module>& m);
|
||||
void setMeta(Meta m);
|
||||
void setProperties(std::vector<Property>& p);
|
||||
void setKeybindings(std::vector<Keybinding>& k);
|
||||
void setTime(Time t);
|
||||
void setDeltaTimes(std::vector<double> dt);
|
||||
void setCamera(CameraType c);
|
||||
void setMarkNodes(std::vector<std::string>& n);
|
||||
void setAdditionalScripts(std::vector<std::string>& s);
|
||||
Version version = CurrentVersion;
|
||||
std::vector<Module> modules;
|
||||
std::optional<Meta> meta;
|
||||
std::vector<std::string> assets;
|
||||
std::vector<Property> properties;
|
||||
std::vector<Action> actions;
|
||||
std::vector<Keybinding> keybindings;
|
||||
std::optional<Time> time;
|
||||
std::vector<double> deltaTimes;
|
||||
std::optional<CameraType> camera;
|
||||
std::vector<std::string> markNodes;
|
||||
std::vector<std::string> additionalScripts;
|
||||
|
||||
bool ignoreUpdates = false;
|
||||
|
||||
/**
|
||||
* Returns the Lua library that contains all Lua functions available to provide
|
||||
@@ -178,25 +164,21 @@ public:
|
||||
* \return The Lua library that contains all Lua functions available for profiles
|
||||
*/
|
||||
static scripting::LuaLibrary luaLibrary();
|
||||
|
||||
private:
|
||||
static constexpr const Version CurrentVersion = Version { 1, 0 };
|
||||
|
||||
Version _version = CurrentVersion;
|
||||
std::vector<Module> _modules;
|
||||
std::optional<Meta> _meta;
|
||||
std::vector<std::string> _assets;
|
||||
std::vector<Property> _properties;
|
||||
std::vector<Keybinding> _keybindings;
|
||||
std::optional<Time> _time;
|
||||
std::vector<double> _deltaTimes;
|
||||
std::optional<CameraType> _camera;
|
||||
std::vector<std::string> _markNodes;
|
||||
std::vector<std::string> _additionalScripts;
|
||||
|
||||
bool _ignoreUpdates = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* This function takes a profile and returns its asset-ifyied version as a string. This
|
||||
* is the format that is saved as a scene file that, in turn, is provided to OpenSpace as
|
||||
* the root asset to load. This function is a key step to be able to load a Profile in
|
||||
* OpenSpace (at the moment).
|
||||
*
|
||||
* \param profile The profile that should be converted to the asset-file format
|
||||
*
|
||||
* \return The string representation of the provided profile, ready to be loaded as an
|
||||
* asset
|
||||
*/
|
||||
std::string convertToScene(const Profile& profile);
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_CORE___PROFILE___H__
|
||||
|
||||
@@ -58,545 +58,366 @@
|
||||
// definitions GLFW v3.1
|
||||
|
||||
#include <ghoul/misc/stringconversion.h>
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
enum class KeyAction : int {
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum class KeyAction : uint8_t {
|
||||
Release = 0,
|
||||
Press = 1,
|
||||
Repeat = 2
|
||||
};
|
||||
|
||||
bool hasKeyAction(KeyAction lhs, KeyAction rhs);
|
||||
constexpr bool hasKeyAction(KeyAction lhs, KeyAction rhs) {
|
||||
return static_cast<std::underlying_type_t<KeyAction>>(lhs) &
|
||||
static_cast<std::underlying_type_t<KeyAction>>(rhs);
|
||||
}
|
||||
|
||||
KeyAction operator|(KeyAction lhs, KeyAction rhs);
|
||||
KeyAction operator|=(KeyAction& lhs, KeyAction rhs);
|
||||
constexpr KeyAction operator|(KeyAction lhs, KeyAction rhs) {
|
||||
return static_cast<KeyAction>(
|
||||
static_cast<std::underlying_type_t<KeyAction>>(lhs) |
|
||||
static_cast<std::underlying_type_t<KeyAction>>(rhs)
|
||||
);
|
||||
}
|
||||
|
||||
enum class KeyModifier : int {
|
||||
NoModifier = 0,
|
||||
Shift = 0x0001,
|
||||
Control = 0x0002,
|
||||
Alt = 0x0004,
|
||||
Super = 0x0008
|
||||
constexpr KeyAction operator|=(KeyAction& lhs, KeyAction rhs) {
|
||||
return (lhs | rhs);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum class KeyModifier : uint8_t {
|
||||
None = 0,
|
||||
Shift = 0x01,
|
||||
Control = 0x02,
|
||||
Alt = 0x04,
|
||||
Super = 0x08
|
||||
};
|
||||
|
||||
static const std::map<int, std::string> KeyModifierNames = {
|
||||
{0, ""},
|
||||
{0x0001, "Shift"},
|
||||
{0x0002, "Control"},
|
||||
{0x0004, "Alt"},
|
||||
{0x0008, "Super"},
|
||||
{0x0003, "Shift+Control"},
|
||||
{0x0005, "Shift+Alt"},
|
||||
{0x0009, "Shift+Super"},
|
||||
{0x0006, "Control+Alt"},
|
||||
{0x000A, "Control+Super"},
|
||||
{0x000C, "Alt+Super"},
|
||||
{0x0007, "Shift+Control+Alt"},
|
||||
{0x000B, "Shift+Control+Super"},
|
||||
{0x000D, "Shift+Alt+Super"},
|
||||
{0x000E, "Control+Alt+Super"},
|
||||
{0x000F, "Shift+Control+Alt+Super"}
|
||||
constexpr KeyModifier operator|(KeyModifier lhs, KeyModifier rhs) {
|
||||
return static_cast<KeyModifier>(
|
||||
static_cast<std::underlying_type_t<KeyModifier>>(lhs) |
|
||||
static_cast<std::underlying_type_t<KeyModifier>>(rhs)
|
||||
);
|
||||
}
|
||||
|
||||
constexpr KeyModifier operator|=(KeyModifier& lhs, KeyModifier rhs) {
|
||||
return lhs = (lhs | rhs);
|
||||
}
|
||||
|
||||
struct KeyModifierInfo {
|
||||
KeyModifier modifier;
|
||||
std::string_view name;
|
||||
std::string_view identifier;
|
||||
};
|
||||
|
||||
bool hasKeyModifier(KeyModifier lhs, KeyModifier rhs);
|
||||
|
||||
KeyModifier operator|(KeyModifier lhs, KeyModifier rhs);
|
||||
KeyModifier operator|=(KeyModifier& lhs, KeyModifier rhs);
|
||||
|
||||
enum class Key {
|
||||
Unknown = -1,
|
||||
Space = 32,
|
||||
Apostrophe = 39,
|
||||
Comma = 44,
|
||||
Minus = 45,
|
||||
Period = 46,
|
||||
Slash = 47,
|
||||
Num0 = 48,
|
||||
Num1 = 49,
|
||||
Num2 = 50,
|
||||
Num3 = 51,
|
||||
Num4 = 52,
|
||||
Num5 = 53,
|
||||
Num6 = 54,
|
||||
Num7 = 55,
|
||||
Num8 = 56,
|
||||
Num9 = 57,
|
||||
SemiColon = 59,
|
||||
Equal = 61,
|
||||
A = 65,
|
||||
B = 66,
|
||||
C = 67,
|
||||
D = 68,
|
||||
E = 69,
|
||||
F = 70,
|
||||
G = 71,
|
||||
H = 72,
|
||||
I = 73,
|
||||
J = 74,
|
||||
K = 75,
|
||||
L = 76,
|
||||
M = 77,
|
||||
N = 78,
|
||||
O = 79,
|
||||
P = 80,
|
||||
Q = 81,
|
||||
R = 82,
|
||||
S = 83,
|
||||
T = 84,
|
||||
U = 85,
|
||||
V = 86,
|
||||
W = 87,
|
||||
X = 88,
|
||||
Y = 89,
|
||||
Z = 90,
|
||||
LeftBracket = 91,
|
||||
BackSlash = 92,
|
||||
RightBracket = 93,
|
||||
GraveAccent = 96,
|
||||
World1 = 161,
|
||||
World2 = 162,
|
||||
Escape = 256,
|
||||
Enter = 257,
|
||||
Tab = 258,
|
||||
BackSpace = 259,
|
||||
Insert = 260,
|
||||
Delete = 261,
|
||||
Right = 262,
|
||||
Left = 263,
|
||||
Down = 264,
|
||||
Up = 265,
|
||||
PageUp = 266,
|
||||
PageDown = 267,
|
||||
Home = 268,
|
||||
End = 269,
|
||||
CapsLock = 280,
|
||||
ScrollLock = 281,
|
||||
NumLock = 282,
|
||||
PrintScreen = 283,
|
||||
Pause = 284,
|
||||
F1 = 290,
|
||||
F2 = 291,
|
||||
F3 = 292,
|
||||
F4 = 293,
|
||||
F5 = 294,
|
||||
F6 = 295,
|
||||
F7 = 296,
|
||||
F8 = 297,
|
||||
F9 = 298,
|
||||
F10 = 299,
|
||||
F11 = 300,
|
||||
F12 = 301,
|
||||
F13 = 302,
|
||||
F14 = 303,
|
||||
F15 = 304,
|
||||
F16 = 305,
|
||||
F17 = 306,
|
||||
F18 = 307,
|
||||
F19 = 308,
|
||||
F20 = 309,
|
||||
F21 = 310,
|
||||
F22 = 311,
|
||||
F23 = 312,
|
||||
F24 = 313,
|
||||
F25 = 314,
|
||||
Keypad0 = 320,
|
||||
Keypad1 = 321,
|
||||
Keypad2 = 322,
|
||||
Keypad3 = 323,
|
||||
Keypad4 = 324,
|
||||
Keypad5 = 325,
|
||||
Keypad6 = 326,
|
||||
Keypad7 = 327,
|
||||
Keypad8 = 328,
|
||||
Keypad9 = 329,
|
||||
KeypadDecimal = 330,
|
||||
KeypadDivide = 331,
|
||||
KeypadMultiply = 332,
|
||||
KeypadSubtract = 333,
|
||||
KeypadAdd = 334,
|
||||
KeypadEnter = 335,
|
||||
LeftShift = 340,
|
||||
LeftControl = 341,
|
||||
LeftAlt = 342,
|
||||
LeftSuper = 343,
|
||||
RightShift = 344,
|
||||
RightControl = 345,
|
||||
RightAlt = 346,
|
||||
RightSuper = 347,
|
||||
Menu = 348,
|
||||
Last = Menu
|
||||
constexpr std::array<KeyModifierInfo, 5> KeyModifierInfos = {
|
||||
KeyModifierInfo{ KeyModifier::None, "", "" },
|
||||
KeyModifierInfo{ KeyModifier::Shift, "Shift", "SHIFT" },
|
||||
KeyModifierInfo{ KeyModifier::Control, "Control", "CTRL" },
|
||||
KeyModifierInfo{ KeyModifier::Alt, "Alt", "ALT" },
|
||||
KeyModifierInfo{ KeyModifier::Super, "Super", "SUPER" },
|
||||
};
|
||||
|
||||
static const std::map<int, std::string> KeyNames = {
|
||||
{32, "Space"},
|
||||
{39, "'"},
|
||||
{44, ","},
|
||||
{45, "-"},
|
||||
{46, "."},
|
||||
{47, "/"},
|
||||
{48, "0"},
|
||||
{49, "1"},
|
||||
{50, "2"},
|
||||
{51, "3"},
|
||||
{52, "4"},
|
||||
{53, "5"},
|
||||
{54, "6"},
|
||||
{55, "7"},
|
||||
{56, "8"},
|
||||
{57, "9"},
|
||||
{59, ";"},
|
||||
{61, "="},
|
||||
{65, "A"},
|
||||
{66, "B"},
|
||||
{67, "C"},
|
||||
{68, "D"},
|
||||
{69, "E"},
|
||||
{70, "F"},
|
||||
{71, "G"},
|
||||
{72, "H"},
|
||||
{73, "I"},
|
||||
{74, "J"},
|
||||
{75, "K"},
|
||||
{76, "L"},
|
||||
{77, "M"},
|
||||
{78, "N"},
|
||||
{79, "O"},
|
||||
{80, "P"},
|
||||
{81, "Q"},
|
||||
{82, "R"},
|
||||
{83, "S"},
|
||||
{84, "T"},
|
||||
{85, "U"},
|
||||
{86, "V"},
|
||||
{87, "W"},
|
||||
{88, "X"},
|
||||
{89, "Y"},
|
||||
{90, "Z"},
|
||||
{91, "["},
|
||||
{92, "\\"},
|
||||
{93, "]"},
|
||||
{96, "`"},
|
||||
{161, "World1"},
|
||||
{162, "World2"},
|
||||
{256, "Escape"},
|
||||
{257, "Enter"},
|
||||
{258, "Tab"},
|
||||
{259, "BackSpace"},
|
||||
{260, "Insert"},
|
||||
{261, "Delete"},
|
||||
{262, "Right"},
|
||||
{263, "Left"},
|
||||
{264, "Down"},
|
||||
{265, "Up"},
|
||||
{266, "PageUp"},
|
||||
{267, "PageDown"},
|
||||
{268, "Home"},
|
||||
{269, "End"},
|
||||
{280, "CapsLock"},
|
||||
{281, "ScrollLock"},
|
||||
{282, "NumLock"},
|
||||
{283, "PrintScreen"},
|
||||
{284, "Pause"},
|
||||
{290, "F1"},
|
||||
{291, "F2"},
|
||||
{292, "F3"},
|
||||
{293, "F4"},
|
||||
{294, "F5"},
|
||||
{295, "F6"},
|
||||
{296, "F7"},
|
||||
{297, "F8"},
|
||||
{298, "F9"},
|
||||
{299, "F10"},
|
||||
{300, "F11"},
|
||||
{301, "F12"},
|
||||
{302, "F13"},
|
||||
{303, "F14"},
|
||||
{304, "F15"},
|
||||
{305, "F16"},
|
||||
{306, "F17"},
|
||||
{307, "F18"},
|
||||
{308, "F19"},
|
||||
{309, "F20"},
|
||||
{310, "F21"},
|
||||
{311, "F22"},
|
||||
{312, "F23"},
|
||||
{313, "F24"},
|
||||
{314, "F25"},
|
||||
{320, "Keypad 0"},
|
||||
{321, "Keypad 1"},
|
||||
{322, "Keypad 2"},
|
||||
{323, "Keypad 3"},
|
||||
{324, "Keypad 4"},
|
||||
{325, "Keypad 5"},
|
||||
{326, "Keypad 6"},
|
||||
{327, "Keypad 7"},
|
||||
{328, "Keypad 8"},
|
||||
{329, "Keypad 9"},
|
||||
{330, "Keypad ."},
|
||||
{331, "Keypad /"},
|
||||
{332, "Keypad *"},
|
||||
{333, "Keypad -"},
|
||||
{334, "Keypad +"},
|
||||
{335, "Keypad Enter"},
|
||||
{340, "Left Shift"},
|
||||
{341, "Left Control"},
|
||||
{342, "Left Alt"},
|
||||
{343, "Left Super"},
|
||||
{344, "Right Shift"},
|
||||
{345, "Right Control"},
|
||||
{346, "Right Alt"},
|
||||
{347, "Right Super"},
|
||||
{348, "Menu"}
|
||||
constexpr bool hasKeyModifier(KeyModifier lhs, KeyModifier rhs) {
|
||||
return static_cast<std::underlying_type_t<KeyModifier>>(lhs) &
|
||||
static_cast<std::underlying_type_t<KeyModifier>>(rhs);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum class Key : uint16_t {
|
||||
Unknown = uint16_t(-1),
|
||||
Space = 32,
|
||||
Apostrophe = 39,
|
||||
Comma = 44,
|
||||
Minus = 45,
|
||||
Period = 46,
|
||||
Slash = 47,
|
||||
Num0 = 48,
|
||||
Num1 = 49,
|
||||
Num2 = 50,
|
||||
Num3 = 51,
|
||||
Num4 = 52,
|
||||
Num5 = 53,
|
||||
Num6 = 54,
|
||||
Num7 = 55,
|
||||
Num8 = 56,
|
||||
Num9 = 57,
|
||||
SemiColon = 59,
|
||||
Equal = 61,
|
||||
A = 65,
|
||||
B = 66,
|
||||
C = 67,
|
||||
D = 68,
|
||||
E = 69,
|
||||
F = 70,
|
||||
G = 71,
|
||||
H = 72,
|
||||
I = 73,
|
||||
J = 74,
|
||||
K = 75,
|
||||
L = 76,
|
||||
M = 77,
|
||||
N = 78,
|
||||
O = 79,
|
||||
P = 80,
|
||||
Q = 81,
|
||||
R = 82,
|
||||
S = 83,
|
||||
T = 84,
|
||||
U = 85,
|
||||
V = 86,
|
||||
W = 87,
|
||||
X = 88,
|
||||
Y = 89,
|
||||
Z = 90,
|
||||
LeftBracket = 91,
|
||||
BackSlash = 92,
|
||||
RightBracket = 93,
|
||||
GraveAccent = 96,
|
||||
World1 = 161,
|
||||
World2 = 162,
|
||||
Escape = 256,
|
||||
Enter = 257,
|
||||
Tab = 258,
|
||||
BackSpace = 259,
|
||||
Insert = 260,
|
||||
Delete = 261,
|
||||
Right = 262,
|
||||
Left = 263,
|
||||
Down = 264,
|
||||
Up = 265,
|
||||
PageUp = 266,
|
||||
PageDown = 267,
|
||||
Home = 268,
|
||||
End = 269,
|
||||
CapsLock = 280,
|
||||
ScrollLock = 281,
|
||||
NumLock = 282,
|
||||
PrintScreen = 283,
|
||||
Pause = 284,
|
||||
F1 = 290,
|
||||
F2 = 291,
|
||||
F3 = 292,
|
||||
F4 = 293,
|
||||
F5 = 294,
|
||||
F6 = 295,
|
||||
F7 = 296,
|
||||
F8 = 297,
|
||||
F9 = 298,
|
||||
F10 = 299,
|
||||
F11 = 300,
|
||||
F12 = 301,
|
||||
F13 = 302,
|
||||
F14 = 303,
|
||||
F15 = 304,
|
||||
F16 = 305,
|
||||
F17 = 306,
|
||||
F18 = 307,
|
||||
F19 = 308,
|
||||
F20 = 309,
|
||||
F21 = 310,
|
||||
F22 = 311,
|
||||
F23 = 312,
|
||||
F24 = 313,
|
||||
F25 = 314,
|
||||
Keypad0 = 320,
|
||||
Keypad1 = 321,
|
||||
Keypad2 = 322,
|
||||
Keypad3 = 323,
|
||||
Keypad4 = 324,
|
||||
Keypad5 = 325,
|
||||
Keypad6 = 326,
|
||||
Keypad7 = 327,
|
||||
Keypad8 = 328,
|
||||
Keypad9 = 329,
|
||||
KeypadDecimal = 330,
|
||||
KeypadDivide = 331,
|
||||
KeypadMultiply = 332,
|
||||
KeypadSubtract = 333,
|
||||
KeypadAdd = 334,
|
||||
KeypadEnter = 335,
|
||||
LeftShift = 340,
|
||||
LeftControl = 341,
|
||||
LeftAlt = 342,
|
||||
LeftSuper = 343,
|
||||
RightShift = 344,
|
||||
RightControl = 345,
|
||||
RightAlt = 346,
|
||||
RightSuper = 347,
|
||||
Menu = 348,
|
||||
Last = Menu
|
||||
};
|
||||
|
||||
struct KeyInfo {
|
||||
Key key;
|
||||
std::string_view name;
|
||||
std::string_view identifier;
|
||||
};
|
||||
|
||||
constexpr const std::array<KeyInfo, 120> KeyInfos = {
|
||||
KeyInfo { Key::Unknown, "", "" },
|
||||
KeyInfo { Key::Space, "Space", "SPACE" },
|
||||
KeyInfo { Key::Apostrophe, "'", "APOSTROPHE" },
|
||||
KeyInfo { Key::Comma, ",", "COMMA" },
|
||||
KeyInfo { Key::Minus, "-", "MINUS" },
|
||||
KeyInfo { Key::Period, ".", "PERIOD" },
|
||||
KeyInfo { Key::Slash, "/", "SLASH" },
|
||||
KeyInfo { Key::Num0, "0", "0" },
|
||||
KeyInfo { Key::Num1, "1", "1" },
|
||||
KeyInfo { Key::Num2, "2", "2" },
|
||||
KeyInfo { Key::Num3, "3", "3" },
|
||||
KeyInfo { Key::Num4, "4", "4" },
|
||||
KeyInfo { Key::Num5, "5", "5" },
|
||||
KeyInfo { Key::Num6, "6", "6" },
|
||||
KeyInfo { Key::Num7, "7", "7" },
|
||||
KeyInfo { Key::Num8, "8", "8" },
|
||||
KeyInfo { Key::Num9, "9", "9" },
|
||||
KeyInfo { Key::SemiColon, ";", "SEMICOLON" },
|
||||
KeyInfo { Key::Equal, "=", "EQUAL" },
|
||||
KeyInfo { Key::A, "A", "A" },
|
||||
KeyInfo { Key::B, "B", "B" },
|
||||
KeyInfo { Key::C, "C", "C" },
|
||||
KeyInfo { Key::D, "D", "D" },
|
||||
KeyInfo { Key::E, "E", "E" },
|
||||
KeyInfo { Key::F, "F", "F" },
|
||||
KeyInfo { Key::G, "G", "G" },
|
||||
KeyInfo { Key::H, "H", "H" },
|
||||
KeyInfo { Key::I, "I", "I" },
|
||||
KeyInfo { Key::J, "J", "J" },
|
||||
KeyInfo { Key::K, "K", "K" },
|
||||
KeyInfo { Key::L, "L", "L" },
|
||||
KeyInfo { Key::M, "M", "M" },
|
||||
KeyInfo { Key::N, "N", "N" },
|
||||
KeyInfo { Key::O, "O", "O" },
|
||||
KeyInfo { Key::P, "P", "P" },
|
||||
KeyInfo { Key::Q, "Q", "Q" },
|
||||
KeyInfo { Key::R, "R", "R" },
|
||||
KeyInfo { Key::S, "S", "S" },
|
||||
KeyInfo { Key::T, "T", "T" },
|
||||
KeyInfo { Key::U, "U", "U" },
|
||||
KeyInfo { Key::V, "V", "V" },
|
||||
KeyInfo { Key::W, "W", "W" },
|
||||
KeyInfo { Key::X, "X", "X" },
|
||||
KeyInfo { Key::Y, "Y", "Y" },
|
||||
KeyInfo { Key::Z, "Z", "Z" },
|
||||
KeyInfo { Key::LeftBracket, "[", "LEFTBRACKET" },
|
||||
KeyInfo { Key::BackSlash, "\\", "BACKSLASH" },
|
||||
KeyInfo { Key::RightBracket, "]", "RIGHTBRACKET" },
|
||||
KeyInfo { Key::GraveAccent, "`", "GRAVEACCENT" },
|
||||
KeyInfo { Key::World1, "World1", "WORLD1" },
|
||||
KeyInfo { Key::World2, "World2", "WORLD2" },
|
||||
KeyInfo { Key::Escape, "Escape", "ESC" },
|
||||
KeyInfo { Key::Enter, "Enter", "ENTER" },
|
||||
KeyInfo { Key::Tab, "Tab", "TAB" },
|
||||
KeyInfo { Key::BackSpace, "Backspace", "BACKSPACE" },
|
||||
KeyInfo { Key::Insert, "Insert", "INSERT" },
|
||||
KeyInfo { Key::Delete, "Delete", "DELETE" },
|
||||
KeyInfo { Key::Right, "Right", "RIGHT" },
|
||||
KeyInfo { Key::Left, "Left", "LEFT" },
|
||||
KeyInfo { Key::Down, "Down", "DOWN" },
|
||||
KeyInfo { Key::Up, "Up", "UP" },
|
||||
KeyInfo { Key::PageUp, "PageUp", "PAGEUP" },
|
||||
KeyInfo { Key::PageDown, "PageDown", "PAGEDOWN" },
|
||||
KeyInfo { Key::Home, "Home", "HOME" },
|
||||
KeyInfo { Key::End, "End", "END" },
|
||||
KeyInfo { Key::CapsLock, "CapsLock", "CAPS_LOCK" },
|
||||
KeyInfo { Key::ScrollLock, "ScrollLock", "SCROLL_LOCK" },
|
||||
KeyInfo { Key::NumLock, "NumLock", "NUM_LOCK" },
|
||||
KeyInfo { Key::PrintScreen, "PrintScreen", "PRINT_SCREEN" },
|
||||
KeyInfo { Key::Pause, "Pause", "PAUSE" },
|
||||
KeyInfo { Key::F1, "F1", "F1" },
|
||||
KeyInfo { Key::F2, "F2", "F2" },
|
||||
KeyInfo { Key::F3, "F3", "F3" },
|
||||
KeyInfo { Key::F4, "F4", "F4" },
|
||||
KeyInfo { Key::F5, "F5", "F5" },
|
||||
KeyInfo { Key::F6, "F6", "F6" },
|
||||
KeyInfo { Key::F7, "F7", "F7" },
|
||||
KeyInfo { Key::F8, "F8", "F8" },
|
||||
KeyInfo { Key::F9, "F9", "F9" },
|
||||
KeyInfo { Key::F10, "F10", "F10" },
|
||||
KeyInfo { Key::F11, "F11", "F11" },
|
||||
KeyInfo { Key::F12, "F12", "F12" },
|
||||
KeyInfo { Key::F13, "F13", "F13" },
|
||||
KeyInfo { Key::F14, "F14", "F14" },
|
||||
KeyInfo { Key::F15, "F15", "F15" },
|
||||
KeyInfo { Key::F16, "F16", "F16" },
|
||||
KeyInfo { Key::F17, "F17", "F17" },
|
||||
KeyInfo { Key::F18, "F18", "F18" },
|
||||
KeyInfo { Key::F19, "F19", "F19" },
|
||||
KeyInfo { Key::F20, "F20", "F20" },
|
||||
KeyInfo { Key::F21, "F21", "F21" },
|
||||
KeyInfo { Key::F22, "F22", "F22" },
|
||||
KeyInfo { Key::F23, "F23", "F23" },
|
||||
KeyInfo { Key::F24, "F24", "F24" },
|
||||
KeyInfo { Key::F25, "F25", "F25" },
|
||||
KeyInfo { Key::Keypad0, "Keypad 0", "KP_0" },
|
||||
KeyInfo { Key::Keypad1, "Keypad 1", "KP_1" },
|
||||
KeyInfo { Key::Keypad2, "Keypad 2", "KP_2" },
|
||||
KeyInfo { Key::Keypad3, "Keypad 3", "KP_3" },
|
||||
KeyInfo { Key::Keypad4, "Keypad 4", "KP_4" },
|
||||
KeyInfo { Key::Keypad5, "Keypad 5", "KP_5" },
|
||||
KeyInfo { Key::Keypad6, "Keypad 6", "KP_6" },
|
||||
KeyInfo { Key::Keypad7, "Keypad 7", "KP_7" },
|
||||
KeyInfo { Key::Keypad8, "Keypad 8", "KP_8" },
|
||||
KeyInfo { Key::Keypad9, "Keypad 9", "KP_9" },
|
||||
KeyInfo { Key::KeypadDecimal, "Keypad .", "KP_DECIMAL" },
|
||||
KeyInfo { Key::KeypadDivide, "Keypad /", "KP_DIVIDE" },
|
||||
KeyInfo { Key::KeypadMultiply, "Keypad *", "KP_MULTIPLY" },
|
||||
KeyInfo { Key::KeypadSubtract, "Keypad -", "KP_SUBTRACT" },
|
||||
KeyInfo { Key::KeypadAdd, "Keypad +", "KP_ADD" },
|
||||
KeyInfo { Key::KeypadEnter, "Keypad Enter", "KP_ENTER" },
|
||||
KeyInfo { Key::LeftShift, "Left Shift", "LEFT_SHIFT" },
|
||||
KeyInfo { Key::LeftControl, "Left Control", "LEFT_CONTROL" },
|
||||
KeyInfo { Key::LeftAlt, "Left Alt", "LEFT_ALT" },
|
||||
KeyInfo { Key::LeftSuper, "Left Super", "LEFT_SUPER" },
|
||||
KeyInfo { Key::RightShift, "Right Shift", "RIGHT_SHIFT" },
|
||||
KeyInfo { Key::RightControl, "Right Control", "RIGHT_CONTROL" },
|
||||
KeyInfo { Key::RightAlt, "Right Alt", "RIGHT_ALT" },
|
||||
KeyInfo { Key::RightSuper, "Right Super", "RIGHT_SUPER" },
|
||||
KeyInfo { Key::Menu, "Menu", "MENU" }
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct KeyWithModifier {
|
||||
Key key;
|
||||
KeyModifier modifier;
|
||||
Key key = Key::Unknown;
|
||||
KeyModifier modifier = KeyModifier::None;
|
||||
};
|
||||
|
||||
constexpr inline bool isKeypadKey(Key key) noexcept {
|
||||
return key == Key::Keypad0 || key == Key::Keypad1 || key == Key::Keypad2 ||
|
||||
key == Key::Keypad3 || key == Key::Keypad4 || key == Key::Keypad5 ||
|
||||
key == Key::Keypad6 || key == Key::Keypad7 || key == Key::Keypad8 ||
|
||||
key == Key::Keypad9 || key == Key::KeypadEnter || key == Key::KeypadAdd ||
|
||||
key == Key::KeypadSubtract || key == Key::KeypadMultiply ||
|
||||
key == Key::KeypadDivide;
|
||||
}
|
||||
|
||||
KeyWithModifier stringToKey(std::string str);
|
||||
bool operator<(const KeyWithModifier& lhs, const KeyWithModifier& rhs);
|
||||
bool operator==(const KeyWithModifier& lhs, const KeyWithModifier& rhs);
|
||||
std::string keyToString(KeyWithModifier keyWithModifier);
|
||||
|
||||
static const std::map<std::string, KeyModifier> KeyModifierMapping = {
|
||||
{ "SHIFT", KeyModifier::Shift },
|
||||
{ "ALT", KeyModifier::Alt },
|
||||
{ "CTRL", KeyModifier::Control },
|
||||
{ "SUPER", KeyModifier::Super }
|
||||
};
|
||||
// @TODO (abock, 2021-08-12) This function should die
|
||||
constexpr bool operator<(const KeyWithModifier& lhs, const KeyWithModifier& rhs) noexcept
|
||||
{
|
||||
if (lhs.modifier == rhs.modifier) {
|
||||
return lhs.key < rhs.key;
|
||||
}
|
||||
else {
|
||||
return lhs.modifier < rhs.modifier;
|
||||
}
|
||||
}
|
||||
|
||||
static const std::map<std::string, Key> KeyMapping = {
|
||||
{ "0", Key::Num0 },
|
||||
{ "1", Key::Num1 },
|
||||
{ "2", Key::Num2 },
|
||||
{ "3", Key::Num3 },
|
||||
{ "4", Key::Num4 },
|
||||
{ "5", Key::Num5 },
|
||||
{ "6", Key::Num6 },
|
||||
{ "7", Key::Num7 },
|
||||
{ "8", Key::Num8 },
|
||||
{ "9", Key::Num9 },
|
||||
|
||||
{ "A", Key::A },
|
||||
{ "B", Key::B },
|
||||
{ "C", Key::C },
|
||||
{ "D", Key::D },
|
||||
{ "E", Key::E },
|
||||
{ "F", Key::F },
|
||||
{ "G", Key::G },
|
||||
{ "H", Key::H },
|
||||
{ "I", Key::I },
|
||||
{ "J", Key::J },
|
||||
{ "K", Key::K },
|
||||
{ "L", Key::L },
|
||||
{ "M", Key::M },
|
||||
{ "N", Key::N },
|
||||
{ "O", Key::O },
|
||||
{ "P", Key::P },
|
||||
{ "Q", Key::Q },
|
||||
{ "R", Key::R },
|
||||
{ "S", Key::S },
|
||||
{ "T", Key::T },
|
||||
{ "U", Key::U },
|
||||
{ "V", Key::V },
|
||||
{ "W", Key::W },
|
||||
{ "X", Key::X },
|
||||
{ "Y", Key::Y },
|
||||
{ "Z", Key::Z },
|
||||
|
||||
{ "LeftBracket", Key::LeftBracket },
|
||||
{ "LEFTBRACKET", Key::LeftBracket },
|
||||
{ "LEFT_BRACKET", Key::LeftBracket },
|
||||
{ "Backslash", Key::BackSlash },
|
||||
{ "BACKSLASH", Key::BackSlash },
|
||||
{ "RightBracket", Key::RightBracket },
|
||||
{ "RIGHTBRACKET", Key::RightBracket },
|
||||
{ "RIGHT_BRACKET", Key::RightBracket },
|
||||
{ "GraveAccent", Key::GraveAccent },
|
||||
{ "GRAVEACCENT", Key::GraveAccent },
|
||||
{ "GRAVE_ACCENT", Key::GraveAccent },
|
||||
{ "Space", Key::Space },
|
||||
{ "SPACE", Key::Space },
|
||||
{ "Apostrophe", Key::Apostrophe },
|
||||
{ "APOSTROPHE", Key::Apostrophe },
|
||||
{ "Comma", Key::Comma },
|
||||
{ "COMMA", Key::Comma },
|
||||
{ "Minus", Key::Minus },
|
||||
{ "MINUS", Key::Minus },
|
||||
{ "Period", Key::Period },
|
||||
{ "PERIOD", Key::Period },
|
||||
{ "Slash", Key::Slash },
|
||||
{ "SLASH", Key::Slash },
|
||||
{ "Semicolon", Key::SemiColon },
|
||||
{ "SEMICOLON", Key::SemiColon },
|
||||
{ "SEMI COLON", Key::SemiColon },
|
||||
{ "Equal", Key::Equal },
|
||||
{ "EQUAL", Key::Equal },
|
||||
|
||||
{ "World1", Key::World1 },
|
||||
{ "WORLD1", Key::World1 },
|
||||
{ "WORLD_1", Key::World1 },
|
||||
{ "World2", Key::World2 },
|
||||
{ "WORLD2", Key::World2 },
|
||||
{ "WORLD_2", Key::World2 },
|
||||
{ "Esc", Key::Escape },
|
||||
{ "ESC", Key::Escape },
|
||||
{ "ESCAPE", Key::Escape},
|
||||
{ "Enter", Key::Enter },
|
||||
{ "ENTER", Key::Enter },
|
||||
{ "Tab", Key::Tab },
|
||||
{ "TAB", Key::Tab },
|
||||
{ "Backspace", Key::BackSpace },
|
||||
{ "BACKSPACE", Key::BackSpace },
|
||||
{ "Insert", Key::Insert },
|
||||
{ "INSERT", Key::Insert },
|
||||
{ "DEL", Key::Delete },
|
||||
{ "Delete", Key::Delete },
|
||||
{ "DELETE", Key::Delete },
|
||||
{ "Right", Key::Right },
|
||||
{ "RIGHT", Key::Right },
|
||||
{ "Left", Key::Left },
|
||||
{ "LEFT", Key::Left },
|
||||
{ "Down", Key::Down },
|
||||
{ "DOWN", Key::Down },
|
||||
{ "Up", Key::Up },
|
||||
{ "UP", Key::Up },
|
||||
{ "PageUp", Key::PageUp },
|
||||
{ "PAGEUP", Key::PageUp },
|
||||
{ "PAGE_UP", Key::PageUp },
|
||||
{ "PageDown", Key::PageDown },
|
||||
{ "PAGEDOWN", Key::PageDown },
|
||||
{ "PAGE_DOWN", Key::PageDown },
|
||||
{ "Home", Key::Home },
|
||||
{ "HOME", Key::Home },
|
||||
{ "End", Key::End },
|
||||
{ "END", Key::End },
|
||||
{ "CapsLock", Key::CapsLock },
|
||||
{ "CAPSLOCK", Key::CapsLock },
|
||||
{ "CAPS_LOCK", Key::CapsLock },
|
||||
{ "ScrollLock", Key::ScrollLock },
|
||||
{ "SCROLLLOCK", Key::ScrollLock },
|
||||
{ "SCROLL_LOCK", Key::ScrollLock },
|
||||
{ "NumLock", Key::NumLock },
|
||||
{ "NUMLOCK", Key::NumLock },
|
||||
{ "NUM_LOCK", Key::NumLock },
|
||||
{ "PrintScreen", Key::PrintScreen },
|
||||
{ "PRINTSCREEN", Key::PrintScreen },
|
||||
{ "PRINT_SCREEN", Key::PrintScreen },
|
||||
{ "Pause", Key::Pause },
|
||||
{ "PAUSE", Key::Pause },
|
||||
{ "F1", Key::F1 },
|
||||
{ "F2", Key::F2 },
|
||||
{ "F3", Key::F3 },
|
||||
{ "F4", Key::F4 },
|
||||
{ "F5", Key::F5 },
|
||||
{ "F6", Key::F6 },
|
||||
{ "F7", Key::F7 },
|
||||
{ "F8", Key::F8 },
|
||||
{ "F9", Key::F9 },
|
||||
{ "F10", Key::F10 },
|
||||
{ "F11", Key::F11 },
|
||||
{ "F12", Key::F12 },
|
||||
{ "F13", Key::F13 },
|
||||
{ "F14", Key::F14 },
|
||||
{ "F15", Key::F15 },
|
||||
{ "F16", Key::F16 },
|
||||
{ "F17", Key::F17 },
|
||||
{ "F18", Key::F18 },
|
||||
{ "F19", Key::F19 },
|
||||
{ "F20", Key::F20 },
|
||||
{ "F21", Key::F21 },
|
||||
{ "F22", Key::F22 },
|
||||
{ "F23", Key::F23 },
|
||||
{ "F24", Key::F24 },
|
||||
{ "F25", Key::F25 },
|
||||
{ "Keypad0", Key::Keypad0 },
|
||||
{ "KP0", Key::Keypad0 },
|
||||
{ "KP_0", Key::Keypad0 },
|
||||
{ "Keypad1", Key::Keypad1 },
|
||||
{ "KP1", Key::Keypad1 },
|
||||
{ "KP_1", Key::Keypad1 },
|
||||
{ "Keypad2", Key::Keypad2 },
|
||||
{ "KP2", Key::Keypad2 },
|
||||
{ "KP_2", Key::Keypad2 },
|
||||
{ "Keypad3", Key::Keypad3 },
|
||||
{ "KP3", Key::Keypad3 },
|
||||
{ "KP_3", Key::Keypad3 },
|
||||
{ "Keypad4", Key::Keypad4 },
|
||||
{ "KP4", Key::Keypad4 },
|
||||
{ "KP_4", Key::Keypad4 },
|
||||
{ "Keypad5", Key::Keypad5 },
|
||||
{ "KP5", Key::Keypad5 },
|
||||
{ "KP_5", Key::Keypad5 },
|
||||
{ "Keypad6", Key::Keypad6 },
|
||||
{ "KP6", Key::Keypad6 },
|
||||
{ "KP_6", Key::Keypad6 },
|
||||
{ "Keypad7", Key::Keypad7 },
|
||||
{ "KP7", Key::Keypad7 },
|
||||
{ "KP_7", Key::Keypad7 },
|
||||
{ "Keypad8", Key::Keypad8 },
|
||||
{ "KP8", Key::Keypad8 },
|
||||
{ "KP_8", Key::Keypad8 },
|
||||
{ "Keypad9", Key::Keypad9 },
|
||||
{ "KP9", Key::Keypad9 },
|
||||
{ "KP_9", Key::Keypad9 },
|
||||
{ "KeypadDecimal", Key::KeypadDecimal },
|
||||
{ "KPDECIMAL", Key::KeypadDecimal },
|
||||
{ "KP_DECIMAL", Key::KeypadDecimal },
|
||||
{ "KeypadDivide", Key::KeypadDivide },
|
||||
{ "KPDIVIDE", Key::KeypadDivide },
|
||||
{ "KP_DIVIDE", Key::KeypadDivide },
|
||||
{ "KeypadMultiply", Key::KeypadMultiply },
|
||||
{ "KPMULTIPLY", Key::KeypadMultiply },
|
||||
{ "KP_MULTIPLY", Key::KeypadMultiply },
|
||||
{ "KeypadSubtract", Key::KeypadSubtract },
|
||||
{ "KPSUBTRACT", Key::KeypadSubtract },
|
||||
{ "KP_SUBTRACT", Key::KeypadSubtract },
|
||||
{ "KeypadAdd", Key::KeypadAdd },
|
||||
{ "KPADD", Key::KeypadAdd },
|
||||
{ "KP_ADD", Key::KeypadAdd },
|
||||
{ "KeypadEnter", Key::KeypadEnter },
|
||||
{ "KPENTER", Key::KeypadEnter },
|
||||
{ "KP_ENTER", Key::KeypadEnter },
|
||||
{ "KeypadEqual", Key::KeypadEnter },
|
||||
{ "KPEQUAL", Key::KeypadEnter },
|
||||
{ "KP_EQUAL", Key::KeypadEnter },
|
||||
{ "LeftShift", Key::LeftShift },
|
||||
{ "LSHIFT", Key::LeftShift },
|
||||
{ "LEFTSHIFT", Key::LeftShift },
|
||||
{ "LEFT_SHIFT", Key::LeftShift },
|
||||
{ "LeftControl", Key::LeftControl },
|
||||
{ "LCTRL", Key::LeftControl },
|
||||
{ "LEFTCONTROL", Key::LeftControl },
|
||||
{ "LEFT_CONTROL", Key::LeftControl },
|
||||
{ "LeftAlt", Key::LeftAlt },
|
||||
{ "LALT", Key::LeftAlt },
|
||||
{ "LEFTALT", Key::LeftAlt },
|
||||
{ "LEFT_ALT", Key::LeftAlt },
|
||||
{ "LeftSuper", Key::LeftSuper },
|
||||
{ "LEFTSUPER", Key::LeftSuper },
|
||||
{ "LEFT_SUPER", Key::LeftSuper },
|
||||
{ "RightShift", Key::RightShift },
|
||||
{ "RSHIFT", Key::RightShift },
|
||||
{ "RIGHTSHIFT", Key::RightShift },
|
||||
{ "RIGHT_SHIFT", Key::RightShift },
|
||||
{ "RightControl", Key::RightControl },
|
||||
{ "RCTRL", Key::RightControl },
|
||||
{ "RIGHTCONTROL", Key::RightControl },
|
||||
{ "RIGHT_CONTROL", Key::RightControl },
|
||||
{ "RightAlt", Key::RightAlt },
|
||||
{ "RALT", Key::RightAlt },
|
||||
{ "RIGHTALT", Key::RightAlt },
|
||||
{ "RIGHT_ALT", Key::RightAlt },
|
||||
{ "RightSuper", Key::RightSuper },
|
||||
{ "RIGHTSUPER", Key::RightSuper },
|
||||
{ "RIGHT_SUPER", Key::RightSuper },
|
||||
{ "Menu", Key::Menu },
|
||||
{ "MENU", Key::Menu }
|
||||
};
|
||||
constexpr bool operator==(const KeyWithModifier& lhs, const KeyWithModifier& rhs) noexcept
|
||||
{
|
||||
return (lhs.key == rhs.key) && (lhs.modifier == rhs.modifier);
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake)
|
||||
|
||||
set(HEADER_FILES
|
||||
include/gui.h
|
||||
include/guiactioncomponent.h
|
||||
include/guiassetcomponent.h
|
||||
include/guicomponent.h
|
||||
include/guifilepathcomponent.h
|
||||
@@ -37,7 +38,6 @@ set(HEADER_FILES
|
||||
include/guimissioncomponent.h
|
||||
include/guiparallelcomponent.h
|
||||
include/guipropertycomponent.h
|
||||
include/guishortcutscomponent.h
|
||||
include/guispacetimecomponent.h
|
||||
include/guiiswacomponent.h
|
||||
include/imgui_include.h
|
||||
@@ -47,6 +47,7 @@ source_group("Header Files" FILES ${HEADER_FILES})
|
||||
|
||||
set(SOURCE_FILES
|
||||
src/gui.cpp
|
||||
src/guiactioncomponent.cpp
|
||||
src/guiassetcomponent.cpp
|
||||
src/guicomponent.cpp
|
||||
src/guifilepathcomponent.cpp
|
||||
@@ -58,7 +59,6 @@ set(SOURCE_FILES
|
||||
src/guimissioncomponent.cpp
|
||||
src/guiparallelcomponent.cpp
|
||||
src/guipropertycomponent.cpp
|
||||
src/guishortcutscomponent.cpp
|
||||
src/guispacetimecomponent.cpp
|
||||
src/guiiswacomponent.cpp
|
||||
src/renderproperties.cpp
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
#include <modules/imgui/include/guicomponent.h>
|
||||
|
||||
#include <modules/imgui/include/guiactioncomponent.h>
|
||||
#include <modules/imgui/include/guiassetcomponent.h>
|
||||
#include <modules/imgui/include/guifilepathcomponent.h>
|
||||
#include <modules/imgui/include/guigibscomponent.h>
|
||||
@@ -38,7 +39,6 @@
|
||||
#include <modules/imgui/include/guimissioncomponent.h>
|
||||
#include <modules/imgui/include/guiparallelcomponent.h>
|
||||
#include <modules/imgui/include/guipropertycomponent.h>
|
||||
#include <modules/imgui/include/guishortcutscomponent.h>
|
||||
#include <modules/imgui/include/guispacetimecomponent.h>
|
||||
#include <openspace/properties/property.h>
|
||||
#include <openspace/properties/scalar/boolproperty.h>
|
||||
@@ -121,7 +121,7 @@ public:
|
||||
#ifdef OPENSPACE_MODULE_ISWA_ENABLED
|
||||
GuiIswaComponent _iswa;
|
||||
#endif // OPENSPACE_MODULE_ISWA_ENABLED
|
||||
GuiShortcutsComponent _shortcuts;
|
||||
GuiActionComponent _actions;
|
||||
GuiJoystickComponent _joystick;
|
||||
GuiParallelComponent _parallel;
|
||||
GuiPropertyComponent _featuredProperties;
|
||||
@@ -153,7 +153,7 @@ private:
|
||||
#endif
|
||||
|
||||
&_asset,
|
||||
&_shortcuts,
|
||||
&_actions,
|
||||
&_joystick,
|
||||
&_filePath,
|
||||
|
||||
|
||||
@@ -29,9 +29,9 @@
|
||||
|
||||
namespace openspace::gui {
|
||||
|
||||
class GuiShortcutsComponent : public GuiComponent {
|
||||
class GuiActionComponent : public GuiComponent {
|
||||
public:
|
||||
GuiShortcutsComponent();
|
||||
GuiActionComponent();
|
||||
|
||||
void render() override;
|
||||
};
|
||||
@@ -22,12 +22,12 @@
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <modules/imgui/include/guishortcutscomponent.h>
|
||||
#include <modules/imgui/include/guiactioncomponent.h>
|
||||
|
||||
#include <modules/imgui/include/gui.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/interaction/actionmanager.h>
|
||||
#include <openspace/interaction/keybindingmanager.h>
|
||||
#include <openspace/interaction/shortcutmanager.h>
|
||||
#include <openspace/scripting/scriptengine.h>
|
||||
#include <openspace/util/keys.h>
|
||||
|
||||
@@ -35,11 +35,11 @@
|
||||
|
||||
namespace openspace::gui {
|
||||
|
||||
GuiShortcutsComponent::GuiShortcutsComponent()
|
||||
GuiActionComponent::GuiActionComponent()
|
||||
: GuiComponent("Shortcuts", "Shortcuts")
|
||||
{}
|
||||
|
||||
void GuiShortcutsComponent::render() {
|
||||
void GuiActionComponent::render() {
|
||||
ImGui::SetNextWindowCollapsed(_isCollapsed);
|
||||
|
||||
bool v = _isEnabled;
|
||||
@@ -47,62 +47,50 @@ void GuiShortcutsComponent::render() {
|
||||
_isEnabled = v;
|
||||
_isCollapsed = ImGui::IsWindowCollapsed();
|
||||
|
||||
using K = KeyWithModifier;
|
||||
using V = std::string;
|
||||
const std::multimap<K, V>& binds = global::keybindingManager->keyBindings();
|
||||
|
||||
|
||||
// First the actual shortcuts
|
||||
CaptionText("Shortcuts");
|
||||
const std::vector<interaction::ShortcutManager::ShortcutInformation>& shortcuts =
|
||||
global::shortcutManager->shortcuts();
|
||||
|
||||
for (size_t i = 0; i < shortcuts.size(); ++i) {
|
||||
const interaction::ShortcutManager::ShortcutInformation& info = shortcuts[i];
|
||||
|
||||
if (ImGui::Button(info.name.c_str())) {
|
||||
global::scriptEngine->queueScript(
|
||||
info.script,
|
||||
scripting::ScriptEngine::RemoteScripting(info.synchronization)
|
||||
);
|
||||
std::set<std::string> boundActions;
|
||||
CaptionText("Keybindings");
|
||||
for (const std::pair<const K, V>& p : binds) {
|
||||
boundActions.insert(p.second);
|
||||
if (ImGui::Button(ghoul::to_string(p.first).c_str())) {
|
||||
global::actionManager->triggerAction(p.second, ghoul::Dictionary());
|
||||
}
|
||||
ImGui::SameLine();
|
||||
|
||||
// Poor mans table layout
|
||||
ImGui::SetCursorPosX(125.f);
|
||||
|
||||
ImGui::Text("%s", info.documentation.c_str());
|
||||
if (!info.synchronization) {
|
||||
const interaction::Action& a = global::actionManager->action(p.second);
|
||||
ImGui::Text("%s", a.documentation.c_str());
|
||||
if (!a.synchronization) {
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("(%s)", "local");
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 25.f);
|
||||
CaptionText("Other Actions");
|
||||
for (const interaction::Action& action : global::actionManager->actions()) {
|
||||
// We only show all of the other actions that are not currently bound to keys here
|
||||
if (boundActions.find(action.identifier) != boundActions.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Then display all the keybinds as buttons as well, for good measure
|
||||
CaptionText("Keybindings");
|
||||
using K = KeyWithModifier;
|
||||
using V = interaction::KeybindingManager::KeyInformation;
|
||||
const std::multimap<K, V>& binds = global::keybindingManager->keyBindings();
|
||||
|
||||
for (const std::pair<const K, V>& p : binds) {
|
||||
if (ImGui::Button(ghoul::to_string(p.first).c_str())) {
|
||||
global::scriptEngine->queueScript(
|
||||
p.second.command,
|
||||
scripting::ScriptEngine::RemoteScripting(p.second.synchronization)
|
||||
);
|
||||
if (ImGui::Button(action.identifier.c_str())) {
|
||||
global::actionManager->triggerAction(action.command, ghoul::Dictionary());
|
||||
}
|
||||
ImGui::SameLine();
|
||||
|
||||
// Poor mans table layout
|
||||
ImGui::SetCursorPosX(125.f);
|
||||
ImGui::SetCursorPosX(350.f);
|
||||
|
||||
ImGui::Text("%s", p.second.documentation.c_str());
|
||||
if (!p.second.synchronization) {
|
||||
ImGui::Text("%s", action.documentation.c_str());
|
||||
if (!action.synchronization) {
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("(%s)", "local");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
#include <modules/server/include/connection.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/interaction/shortcutmanager.h>
|
||||
#include <openspace/interaction/actionmanager.h>
|
||||
#include <openspace/interaction/keybindingmanager.h>
|
||||
|
||||
namespace {
|
||||
@@ -44,32 +44,28 @@ bool ShortcutTopic::isDone() const {
|
||||
}
|
||||
|
||||
std::vector<nlohmann::json> ShortcutTopic::shortcutsJson() const {
|
||||
using ShortcutInformation = interaction::ShortcutManager::ShortcutInformation;
|
||||
|
||||
const std::vector<ShortcutInformation>& shortcuts =
|
||||
global::shortcutManager->shortcuts();
|
||||
|
||||
std::vector<nlohmann::json> json;
|
||||
for (const ShortcutInformation& shortcut : shortcuts) {
|
||||
for (const interaction::Action& action : global::actionManager->actions()) {
|
||||
nlohmann::json shortcutJson = {
|
||||
{ "name", shortcut.name },
|
||||
{ "script", shortcut.script },
|
||||
{ "synchronization", static_cast<bool>(shortcut.synchronization) },
|
||||
{ "documentation", shortcut.documentation },
|
||||
{ "guiPath", shortcut.guiPath },
|
||||
{ "name", action.name },
|
||||
{ "script", action.command },
|
||||
{ "synchronization", static_cast<bool>(action.synchronization) },
|
||||
{ "documentation", action.documentation },
|
||||
{ "guiPath", action.guiPath },
|
||||
};
|
||||
json.push_back(shortcutJson);
|
||||
}
|
||||
|
||||
using KeyInformation = interaction::KeybindingManager::KeyInformation;
|
||||
|
||||
const std::multimap<KeyWithModifier, KeyInformation>& keyBindings =
|
||||
const std::multimap<KeyWithModifier, std::string>& keyBindings =
|
||||
global::keybindingManager->keyBindings();
|
||||
|
||||
for (const std::pair<const KeyWithModifier, KeyInformation>& keyBinding : keyBindings)
|
||||
{
|
||||
for (const std::pair<const KeyWithModifier, std::string>& keyBinding : keyBindings) {
|
||||
const KeyWithModifier& k = keyBinding.first;
|
||||
const KeyInformation& info = keyBinding.second;
|
||||
// @TODO (abock, 2021-08-05) Probably this should be rewritten to better account
|
||||
// for the new action mechanism
|
||||
const interaction::Action& action = global::actionManager->action(
|
||||
keyBinding.second
|
||||
);
|
||||
|
||||
nlohmann::json shortcutJson = {
|
||||
{ "key", ghoul::to_string(k.key) },
|
||||
@@ -81,11 +77,11 @@ std::vector<nlohmann::json> ShortcutTopic::shortcutsJson() const {
|
||||
{ "super" , hasKeyModifier(k.modifier, KeyModifier::Super) }
|
||||
}
|
||||
},
|
||||
{ "name", info.name },
|
||||
{ "script", info.command },
|
||||
{ "synchronization", static_cast<bool>(info.synchronization) },
|
||||
{ "documentation", info.documentation },
|
||||
{ "guiPath", info.guiPath },
|
||||
{ "name", action.name },
|
||||
{ "script", action.command },
|
||||
{ "synchronization", static_cast<bool>(action.synchronization) },
|
||||
{ "documentation", action.documentation },
|
||||
{ "guiPath", action.guiPath },
|
||||
};
|
||||
json.push_back(shortcutJson);
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ private:
|
||||
/**
|
||||
* Create a mouse event on the current cursor position.
|
||||
*/
|
||||
CefMouseEvent mouseEvent(KeyModifier mods = KeyModifier::NoModifier);
|
||||
CefMouseEvent mouseEvent(KeyModifier mods = KeyModifier::None);
|
||||
|
||||
#ifdef WIN32
|
||||
/**
|
||||
|
||||
@@ -79,10 +79,6 @@ openspace.rebindKey = function(oldKey, newKey)
|
||||
local t = openspace.getKeyBinding(oldKey)
|
||||
openspace.clearKey(oldKey)
|
||||
for _, v in pairs(t) do
|
||||
if v["Remote"] then
|
||||
openspace.bindKey(newKey, v["Command"])
|
||||
else
|
||||
openspace.bindKeyLocal(newKey, v["Command"])
|
||||
end
|
||||
openspace.bindKey(newKey, v)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -43,6 +43,8 @@ set(OPENSPACE_SOURCE
|
||||
${OPENSPACE_BASE_DIR}/src/engine/openspaceengine_lua.inl
|
||||
${OPENSPACE_BASE_DIR}/src/engine/syncengine.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/engine/virtualpropertymanager.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/actionmanager.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/actionmanager_lua.inl
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/camerainteractionstates.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/interactionmonitor.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/inputstate.cpp
|
||||
@@ -55,8 +57,6 @@ set(OPENSPACE_SOURCE
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/externinteraction.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/sessionrecording.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/sessionrecording_lua.inl
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/shortcutmanager.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/shortcutmanager_lua.inl
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/websocketinputstate.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/websocketcamerastates.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/tasks/convertrecfileversiontask.cpp
|
||||
@@ -223,6 +223,8 @@ set(OPENSPACE_HEADER
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/engine/syncengine.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/engine/virtualpropertymanager.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/engine/windowdelegate.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/action.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/actionmanager.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/delayedvariable.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/delayedvariable.inl
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/camerainteractionstates.h
|
||||
@@ -238,7 +240,6 @@ set(OPENSPACE_HEADER
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/scriptcamerastates.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/sessionrecording.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/sessionrecording.inl
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/shortcutmanager.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/websocketinputstate.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/websocketcamerastates.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/tasks/convertrecfileversiontask.h
|
||||
|
||||
@@ -28,9 +28,9 @@
|
||||
#include <openspace/engine/logfactory.h>
|
||||
#include <openspace/engine/moduleengine.h>
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/interaction/actionmanager.h>
|
||||
#include <openspace/interaction/keybindingmanager.h>
|
||||
#include <openspace/interaction/sessionrecording.h>
|
||||
#include <openspace/interaction/shortcutmanager.h>
|
||||
#include <openspace/mission/mission.h>
|
||||
#include <openspace/mission/missionmanager.h>
|
||||
#include <openspace/navigation/navigationhandler.h>
|
||||
@@ -86,11 +86,11 @@ void registerCoreClasses(scripting::ScriptEngine& engine) {
|
||||
engine.addLibrary(Profile::luaLibrary());
|
||||
engine.addLibrary(Scene::luaLibrary());
|
||||
engine.addLibrary(Time::luaLibrary());
|
||||
engine.addLibrary(interaction::ActionManager::luaLibrary());
|
||||
engine.addLibrary(interaction::KeybindingManager::luaLibrary());
|
||||
engine.addLibrary(interaction::NavigationHandler::luaLibrary());
|
||||
engine.addLibrary(interaction::PathNavigator::luaLibrary());
|
||||
engine.addLibrary(interaction::SessionRecording::luaLibrary());
|
||||
engine.addLibrary(interaction::ShortcutManager::luaLibrary());
|
||||
engine.addLibrary(scripting::ScriptScheduler::luaLibrary());
|
||||
engine.addLibrary(scripting::generalSystemCapabilities());
|
||||
engine.addLibrary(scripting::openglSystemCapabilities());
|
||||
|
||||
@@ -32,12 +32,12 @@
|
||||
#include <openspace/engine/syncengine.h>
|
||||
#include <openspace/engine/virtualpropertymanager.h>
|
||||
#include <openspace/engine/windowdelegate.h>
|
||||
#include <openspace/interaction/actionmanager.h>
|
||||
#include <openspace/interaction/interactionmonitor.h>
|
||||
#include <openspace/interaction/keybindingmanager.h>
|
||||
#include <openspace/interaction/joystickinputstate.h>
|
||||
#include <openspace/interaction/websocketinputstate.h>
|
||||
#include <openspace/interaction/sessionrecording.h>
|
||||
#include <openspace/interaction/shortcutmanager.h>
|
||||
#include <openspace/mission/missionmanager.h>
|
||||
#include <openspace/navigation/navigationhandler.h>
|
||||
#include <openspace/network/parallelpeer.h>
|
||||
@@ -90,12 +90,12 @@ namespace {
|
||||
sizeof(VirtualPropertyManager) +
|
||||
sizeof(WindowDelegate) +
|
||||
sizeof(configuration::Configuration) +
|
||||
sizeof(interaction::ActionManager) +
|
||||
sizeof(interaction::InteractionMonitor) +
|
||||
sizeof(interaction::WebsocketInputStates) +
|
||||
sizeof(interaction::KeybindingManager) +
|
||||
sizeof(interaction::NavigationHandler) +
|
||||
sizeof(interaction::SessionRecording) +
|
||||
sizeof(interaction::ShortcutManager) +
|
||||
sizeof(properties::PropertyOwner) +
|
||||
sizeof(properties::PropertyOwner) +
|
||||
sizeof(scripting::ScriptEngine) +
|
||||
@@ -272,6 +272,14 @@ void create() {
|
||||
configuration = new configuration::Configuration;
|
||||
#endif // WIN32
|
||||
|
||||
#ifdef WIN32
|
||||
actionManager = new (currentPos) interaction::ActionManager;
|
||||
ghoul_assert(actionManager, "No action manager");
|
||||
currentPos += sizeof(interaction::ActionManager);
|
||||
#else ^^^ WIN32 / !WIN32 vvv
|
||||
actionManager = new interaction::ActionManager;
|
||||
#endif // WIN32
|
||||
|
||||
#ifdef WIN32
|
||||
interactionMonitor = new (currentPos) interaction::InteractionMonitor;
|
||||
ghoul_assert(interactionMonitor, "No interactionMonitor");
|
||||
@@ -320,14 +328,6 @@ void create() {
|
||||
sessionRecording = new interaction::SessionRecording(true);
|
||||
#endif // WIN32
|
||||
|
||||
#ifdef WIN32
|
||||
shortcutManager = new (currentPos) interaction::ShortcutManager;
|
||||
ghoul_assert(shortcutManager, "No shortcutManager");
|
||||
currentPos += sizeof(interaction::ShortcutManager);
|
||||
#else // ^^^ WIN32 / !WIN32 vvv
|
||||
shortcutManager = new interaction::ShortcutManager;
|
||||
#endif // WIN32
|
||||
|
||||
#ifdef WIN32
|
||||
rootPropertyOwner = new (currentPos) properties::PropertyOwner({ "" });
|
||||
ghoul_assert(rootPropertyOwner, "No rootPropertyOwner");
|
||||
@@ -433,13 +433,6 @@ void destroy() {
|
||||
delete rootPropertyOwner;
|
||||
#endif // WIN32
|
||||
|
||||
LDEBUGC("Globals", "Destroying 'ShortcutManager'");
|
||||
#ifdef WIN32
|
||||
shortcutManager->~ShortcutManager();
|
||||
#else // ^^^ WIN32 / !WIN32 vvv
|
||||
delete shortcutManager;
|
||||
#endif // WIN32
|
||||
|
||||
LDEBUGC("Globals", "Destroying 'SessionRecording'");
|
||||
#ifdef WIN32
|
||||
sessionRecording->~SessionRecording();
|
||||
@@ -482,6 +475,13 @@ void destroy() {
|
||||
delete interactionMonitor;
|
||||
#endif // WIN32
|
||||
|
||||
LDEBUGC("Globals", "Destorying 'ActionManager'");
|
||||
#ifdef WIN32
|
||||
actionManager->~ActionManager();
|
||||
#else // ^^^ WIN32 / !WIN32 vvv
|
||||
delete actionManager;
|
||||
#endif // WIN32
|
||||
|
||||
LDEBUGC("Globals", "Destroying 'Configuration'");
|
||||
#ifdef WIN32
|
||||
configuration->~Configuration();
|
||||
|
||||
@@ -334,7 +334,7 @@ void OpenSpaceEngine::initialize() {
|
||||
// Then save the profile to a scene so that we can load it with the
|
||||
// existing infrastructure
|
||||
std::ofstream scene(outputAsset);
|
||||
std::string sceneContent = global::profile->convertToScene();
|
||||
std::string sceneContent = convertToScene(*global::profile);
|
||||
scene << sceneContent;
|
||||
|
||||
// Set asset name to that of the profile because a new scene file will be
|
||||
@@ -1103,9 +1103,9 @@ void OpenSpaceEngine::preSynchronization() {
|
||||
|
||||
if (_hasScheduledAssetLoading) {
|
||||
LINFO(fmt::format("Loading asset: {}", absPath(_scheduledAssetPathToLoad)));
|
||||
global::profile->setIgnoreUpdates(true);
|
||||
global::profile->ignoreUpdates = true;
|
||||
loadSingleAsset(_scheduledAssetPathToLoad);
|
||||
global::profile->setIgnoreUpdates(false);
|
||||
global::profile->ignoreUpdates = false;
|
||||
resetPropertyChangeFlagsOfSubowners(global::rootPropertyOwner);
|
||||
_hasScheduledAssetLoading = false;
|
||||
_scheduledAssetPathToLoad.clear();
|
||||
|
||||
162
src/interaction/actionmanager.cpp
Normal file
162
src/interaction/actionmanager.cpp
Normal file
@@ -0,0 +1,162 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2021 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <openspace/interaction/actionmanager.h>
|
||||
|
||||
#include <openspace/scripting/lualibrary.h>
|
||||
#include <openspace/scripting/scriptengine.h>
|
||||
#include <ghoul/misc/crc32.h>
|
||||
#include <ghoul/misc/dictionaryluaformatter.h>
|
||||
#include <algorithm>
|
||||
|
||||
#include "actionmanager_lua.inl"
|
||||
|
||||
namespace openspace::interaction {
|
||||
|
||||
bool ActionManager::hasAction(const std::string& identifier) const {
|
||||
ghoul_assert(!identifier.empty(), "Identifier must not be empty");
|
||||
|
||||
const unsigned int hash = ghoul::hashCRC32(identifier);
|
||||
const auto it = _actions.find(hash);
|
||||
return it != _actions.end();
|
||||
}
|
||||
|
||||
void ActionManager::registerAction(Action action) {
|
||||
ghoul_assert(!action.identifier.empty(), "Action must have an identifier");
|
||||
ghoul_assert(!hasAction(action.identifier), "Identifier already existed");
|
||||
|
||||
const unsigned int hash = ghoul::hashCRC32(action.identifier);
|
||||
_actions[hash] = std::move(action);
|
||||
}
|
||||
|
||||
void ActionManager::removeAction(const std::string& identifier) {
|
||||
ghoul_assert(!identifier.empty(), "Identifier must not be empty");
|
||||
ghoul_assert(hasAction(identifier), "Action was not found in the list");
|
||||
|
||||
const unsigned int hash = ghoul::hashCRC32(identifier);
|
||||
const auto it = _actions.find(hash);
|
||||
_actions.erase(it);
|
||||
}
|
||||
|
||||
const Action& ActionManager::action(const std::string& identifier) const {
|
||||
ghoul_assert(!identifier.empty(), "Identifier must not be empty");
|
||||
ghoul_assert(hasAction(identifier), "Action was not found in the list");
|
||||
|
||||
const unsigned int hash = ghoul::hashCRC32(identifier);
|
||||
const auto it = _actions.find(hash);
|
||||
return it->second;
|
||||
}
|
||||
|
||||
std::vector<Action> ActionManager::actions() const {
|
||||
std::vector<Action> result;
|
||||
result.reserve(_actions.size());
|
||||
for (const std::pair<unsigned int, Action>& p : _actions) {
|
||||
result.push_back(p.second);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void ActionManager::triggerAction(const std::string& identifier,
|
||||
const ghoul::Dictionary& arguments) const
|
||||
{
|
||||
ghoul_assert(!identifier.empty(), "Identifier must not be empty");
|
||||
ghoul_assert(hasAction(identifier), "Action was not found in the list");
|
||||
|
||||
const Action& a = action(identifier);
|
||||
if (arguments.isEmpty()) {
|
||||
global::scriptEngine->queueScript(
|
||||
a.command,
|
||||
scripting::ScriptEngine::RemoteScripting(a.synchronization)
|
||||
);
|
||||
}
|
||||
else {
|
||||
global::scriptEngine->queueScript(
|
||||
fmt::format("local args = {}\n{}", ghoul::formatLua(arguments), a.command),
|
||||
scripting::ScriptEngine::RemoteScripting(a.synchronization)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
scripting::LuaLibrary ActionManager::luaLibrary() {
|
||||
return {
|
||||
"action",
|
||||
{
|
||||
{
|
||||
"hasAction",
|
||||
&luascriptfunctions::hasAction,
|
||||
{},
|
||||
"string",
|
||||
"Checks if the passed identifier corresponds to an action"
|
||||
},
|
||||
{
|
||||
"removeAction",
|
||||
&luascriptfunctions::removeAction,
|
||||
{},
|
||||
"string",
|
||||
"Removes an existing action from the list of possible actions"
|
||||
},
|
||||
{
|
||||
"registerAction",
|
||||
&luascriptfunctions::registerAction,
|
||||
{},
|
||||
"table",
|
||||
"Registers a new action. The table must at least contain the keys "
|
||||
"'Identifier' and 'Command' represeting the unique identifier and the "
|
||||
"Lua script that belong to this new action. Optional keys are 'Name' for "
|
||||
"a human-readable name, 'Documentation' for a description of what the "
|
||||
"action does, 'GuiPath' for a path used for grouping a user interface. "
|
||||
"All of these parameters must be strings. The last parameter is "
|
||||
"'IsLocal' and represents whether the action should be executed locally "
|
||||
"(= false) or remotely (= true, the default)"
|
||||
},
|
||||
{
|
||||
"action",
|
||||
&luascriptfunctions::action,
|
||||
{},
|
||||
"string",
|
||||
"Returns information about the action as a table with the keys "
|
||||
"'Identifier', 'Command', 'Name', 'Documentation', 'GuiPath', and "
|
||||
"'Synchronization'"
|
||||
},
|
||||
{
|
||||
"actions",
|
||||
&luascriptfunctions::actions,
|
||||
{},
|
||||
"",
|
||||
"Returns all registered actions in the system as a table of tables each "
|
||||
"containing the keys 'Identifier', 'Command', 'Name', 'Documentation', "
|
||||
"'GuiPath', and 'Synchronization'"
|
||||
},
|
||||
{
|
||||
"triggerAction",
|
||||
&luascriptfunctions::triggerAction,
|
||||
{},
|
||||
"string",
|
||||
"Triggers the action given by the specified identifier"
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace openspace::interaction
|
||||
241
src/interaction/actionmanager_lua.inl
Normal file
241
src/interaction/actionmanager_lua.inl
Normal file
@@ -0,0 +1,241 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2021 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <openspace/engine/globals.h>
|
||||
|
||||
namespace openspace::luascriptfunctions {
|
||||
|
||||
/**
|
||||
* \ingroup LuaScripts
|
||||
* hasAction():
|
||||
* Checks if the passed identifier corresponds to an action.
|
||||
*/
|
||||
int hasAction(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::hasAction");
|
||||
|
||||
const std::string& identifier = ghoul::lua::value<std::string>(L, 1);
|
||||
if (identifier.empty()) {
|
||||
return ghoul::lua::luaError(L, "Identifier must not be empty");
|
||||
}
|
||||
|
||||
const bool res = global::actionManager->hasAction(identifier);
|
||||
ghoul::lua::push(L, res);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup LuaScripts
|
||||
* removeAction():
|
||||
* Removes an existing action from the list of possible actions.
|
||||
*/
|
||||
int removeAction(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeAction");
|
||||
|
||||
const std::string& identifier = ghoul::lua::value<std::string>(L, 1);
|
||||
if (identifier.empty()) {
|
||||
return ghoul::lua::luaError(L, "Identifier must not be empty");
|
||||
}
|
||||
if (!global::actionManager->hasAction(identifier)) {
|
||||
return ghoul::lua::luaError(
|
||||
L,
|
||||
fmt::format("Identifier '{}' for action not found", identifier)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
global::actionManager->removeAction(identifier);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup LuaScripts
|
||||
* registerAction():
|
||||
* Registers a new action. The first argument is the identifier which cannot have been
|
||||
* used to register a previous action before, the second argument is the Lua command that
|
||||
* is to be executed, and the optional third argument is the name used in a user-interface
|
||||
* to refer to this action. The fourth is a human readable description of the command for
|
||||
* documentation purposes. The fifth is the GUI path and the last parameter determines
|
||||
* whether the action should be executed locally (= false) or remotely (= true, the
|
||||
* default).
|
||||
*/
|
||||
int registerAction(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::registerAction");
|
||||
|
||||
ghoul::Dictionary d = ghoul::lua::value<ghoul::Dictionary>(L, 1);
|
||||
|
||||
if (!d.hasValue<std::string>("Identifier")) {
|
||||
return ghoul::lua::luaError(L, "Identifier must to provided to register action");
|
||||
}
|
||||
std::string identifier = d.value<std::string>("Identifier");
|
||||
if (global::actionManager->hasAction(identifier)) {
|
||||
return ghoul::lua::luaError(
|
||||
L,
|
||||
fmt::format("Action for identifier '{}' already existed", identifier)
|
||||
);
|
||||
}
|
||||
if (global::actionManager->hasAction(identifier)) {
|
||||
return ghoul::lua::luaError(
|
||||
L,
|
||||
fmt::format("Identifier '{}' for action already registered", identifier)
|
||||
);
|
||||
}
|
||||
|
||||
if (!d.hasValue<std::string>("Command")) {
|
||||
return ghoul::lua::luaError(
|
||||
L,
|
||||
fmt::format(
|
||||
"Identifier '{}' does not provide a Lua command to execute", identifier
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
interaction::Action action;
|
||||
action.identifier = std::move(identifier);
|
||||
action.command = d.value<std::string>("Command");
|
||||
if (d.hasValue<std::string>("Name")) {
|
||||
action.name = d.value<std::string>("Name");
|
||||
}
|
||||
if (d.hasValue<std::string>("Documentation")) {
|
||||
action.documentation = d.value<std::string>("Documentation");
|
||||
}
|
||||
if (d.hasValue<std::string>("GuiPath")) {
|
||||
action.guiPath = d.value<std::string>("GuiPath");
|
||||
}
|
||||
if (d.hasValue<bool>("IsLocal")) {
|
||||
bool value = d.value<bool>("IsLocal");
|
||||
action.synchronization = interaction::Action::IsSynchronized(value);
|
||||
}
|
||||
global::actionManager->registerAction(std::move(action));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup LuaScripts
|
||||
* action():
|
||||
* Returns information about the action with the identifier equal to the provided
|
||||
* identifier.
|
||||
*/
|
||||
int action(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::action");
|
||||
|
||||
const std::string& identifier = ghoul::lua::value<std::string>(L, 1);
|
||||
if (identifier.empty()) {
|
||||
return ghoul::lua::luaError(L, "Identifier must not be empty");
|
||||
}
|
||||
if (!global::actionManager->hasAction(identifier)) {
|
||||
return ghoul::lua::luaError(
|
||||
L,
|
||||
fmt::format("Identifier '{}' for action not found", identifier)
|
||||
);
|
||||
}
|
||||
|
||||
const interaction::Action& action = global::actionManager->action(identifier);
|
||||
lua_newtable(L);
|
||||
ghoul::lua::push(L, "Identifier", action.identifier);
|
||||
lua_settable(L, -3);
|
||||
ghoul::lua::push(L, "Command", action.command);
|
||||
lua_settable(L, -3);
|
||||
ghoul::lua::push(L, "Name", action.name);
|
||||
lua_settable(L, -3);
|
||||
ghoul::lua::push(L, "Documentation", action.documentation);
|
||||
lua_settable(L, -3);
|
||||
ghoul::lua::push(L, "GuiPath", action.guiPath);
|
||||
lua_settable(L, -3);
|
||||
ghoul::lua::push(
|
||||
L,
|
||||
"Synchronization",
|
||||
action.synchronization == interaction::Action::IsSynchronized::Yes
|
||||
);
|
||||
lua_settable(L, -3);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup LuaScripts
|
||||
* actions():
|
||||
* Returns all registered actions in the system.
|
||||
*/
|
||||
int actions(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::actions");
|
||||
|
||||
lua_newtable(L);
|
||||
const std::vector<interaction::Action>& actions = global::actionManager->actions();
|
||||
for (size_t i = 0; i < actions.size(); ++i) {
|
||||
const interaction::Action& action = actions[i];
|
||||
|
||||
ghoul::lua::push(L, i + 1);
|
||||
lua_newtable(L);
|
||||
ghoul::lua::push(L, "Identifier", action.identifier);
|
||||
lua_settable(L, -3);
|
||||
ghoul::lua::push(L, "Command", action.command);
|
||||
lua_settable(L, -3);
|
||||
ghoul::lua::push(L, "Name", action.name);
|
||||
lua_settable(L, -3);
|
||||
ghoul::lua::push(L, "Documentation", action.documentation);
|
||||
lua_settable(L, -3);
|
||||
ghoul::lua::push(L, "GuiPath", action.guiPath);
|
||||
lua_settable(L, -3);
|
||||
ghoul::lua::push(
|
||||
L,
|
||||
"Synchronization",
|
||||
action.synchronization == interaction::Action::IsSynchronized::Yes
|
||||
);
|
||||
lua_settable(L, -3);
|
||||
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup LuaScripts
|
||||
* triggerAction():
|
||||
* Triggers the action given by the specified identifier.
|
||||
*/
|
||||
int triggerAction(lua_State* L) {
|
||||
int n = ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::triggerAction");
|
||||
|
||||
const std::string& identifier = ghoul::lua::value<std::string>(L, 1);
|
||||
if (identifier.empty()) {
|
||||
return ghoul::lua::luaError(L, "Identifier must not be empty");
|
||||
}
|
||||
if (!global::actionManager->hasAction(identifier)) {
|
||||
return ghoul::lua::luaError(
|
||||
L,
|
||||
fmt::format("Identifier '{}' for action not found", identifier)
|
||||
);
|
||||
}
|
||||
|
||||
ghoul::Dictionary arguments;
|
||||
if (n == 2) {
|
||||
ghoul::lua::luaDictionaryFromState(L, arguments, 2);
|
||||
}
|
||||
|
||||
global::actionManager->triggerAction(identifier, arguments);
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace openspace::luascriptfunctions
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <openspace/interaction/keybindingmanager.h>
|
||||
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/interaction/actionmanager.h>
|
||||
#include <openspace/scripting/lualibrary.h>
|
||||
#include <openspace/scripting/scriptengine.h>
|
||||
#include <openspace/util/json_helper.h>
|
||||
@@ -52,12 +53,12 @@ void KeybindingManager::keyboardCallback(Key key, KeyModifier modifier, KeyActio
|
||||
// iterate over key bindings
|
||||
auto ret = _keyLua.equal_range({ key, modifier });
|
||||
for (auto it = ret.first; it != ret.second; ++it) {
|
||||
using RS = scripting::ScriptEngine::RemoteScripting;
|
||||
|
||||
global::scriptEngine->queueScript(
|
||||
it->second.command,
|
||||
it->second.synchronization ? RS::Yes : RS::No
|
||||
ghoul_assert(!it->second.empty(), "Action must not be empty");
|
||||
ghoul_assert(
|
||||
global::actionManager->hasAction(it->second),
|
||||
"Action must be registered"
|
||||
);
|
||||
global::actionManager->triggerAction(it->second, ghoul::Dictionary());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,54 +67,10 @@ void KeybindingManager::resetKeyBindings() {
|
||||
_keyLua.clear();
|
||||
}
|
||||
|
||||
void KeybindingManager::bindKeyLocal(Key key, KeyModifier modifier,
|
||||
std::string luaCommand, std::string documentation,
|
||||
std::string name, std::string guiPath)
|
||||
{
|
||||
void KeybindingManager::bindKey(Key key, KeyModifier modifier, std::string action) {
|
||||
#ifdef WIN32
|
||||
const bool isShift = hasKeyModifier(modifier, KeyModifier::Shift);
|
||||
const bool isKeypad = key == Key::Keypad0 || key == Key::Keypad1 ||
|
||||
key == Key::Keypad2 || key == Key::Keypad3 || key == Key::Keypad4 ||
|
||||
key == Key::Keypad5 || key == Key::Keypad6 || key == Key::Keypad7 ||
|
||||
key == Key::Keypad8 || key == Key::Keypad9 || key == Key::KeypadEnter ||
|
||||
key == Key::KeypadAdd || key == Key::KeypadSubtract ||
|
||||
key == Key::KeypadMultiply || key == Key::KeypadDivide;
|
||||
|
||||
if (isShift && isKeypad) {
|
||||
LWARNINGC(
|
||||
"bindKey",
|
||||
"Windows does not support binding keys to Shift + Keyboard as it will "
|
||||
"internally convert these into Home, End, etc, keys."
|
||||
);
|
||||
}
|
||||
#endif // WIN32
|
||||
|
||||
_keyLua.insert({
|
||||
{ key, modifier },
|
||||
{
|
||||
std::move(luaCommand),
|
||||
IsSynchronized::No,
|
||||
std::move(documentation),
|
||||
std::move(name),
|
||||
std::move(guiPath)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void KeybindingManager::bindKey(Key key, KeyModifier modifier, std::string luaCommand,
|
||||
std::string documentation, std::string name,
|
||||
std::string guiPath)
|
||||
{
|
||||
#ifdef WIN32
|
||||
const bool isShift = hasKeyModifier(modifier, KeyModifier::Shift);
|
||||
const bool isKeypad = key == Key::Keypad0 || key == Key::Keypad1 ||
|
||||
key == Key::Keypad2 || key == Key::Keypad3 || key == Key::Keypad4 ||
|
||||
key == Key::Keypad5 || key == Key::Keypad6 || key == Key::Keypad7 ||
|
||||
key == Key::Keypad8 || key == Key::Keypad9 || key == Key::KeypadEnter ||
|
||||
key == Key::KeypadAdd || key == Key::KeypadSubtract ||
|
||||
key == Key::KeypadMultiply || key == Key::KeypadDivide;
|
||||
|
||||
if (isShift && isKeypad) {
|
||||
if (isShift && isKeypadKey(key)) {
|
||||
LWARNINGC(
|
||||
"bindKey",
|
||||
"Windows does not support binding keys to Shift + Keypad as it will "
|
||||
@@ -121,22 +78,10 @@ void KeybindingManager::bindKey(Key key, KeyModifier modifier, std::string luaCo
|
||||
);
|
||||
}
|
||||
#endif // WIN32
|
||||
ghoul_assert(!action.empty(), "Action must not be empty");
|
||||
|
||||
_keyLua.insert({
|
||||
{ key, modifier },
|
||||
{
|
||||
std::move(luaCommand),
|
||||
IsSynchronized::Yes,
|
||||
std::move(documentation),
|
||||
std::move(name),
|
||||
std::move(guiPath)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void KeybindingManager::removeKeyBinding(const std::string& key) {
|
||||
KeyWithModifier k = stringToKey(key);
|
||||
removeKeyBinding(k);
|
||||
KeyWithModifier km = { key, modifier };
|
||||
_keyLua.insert({ km, std::move(action) });
|
||||
}
|
||||
|
||||
void KeybindingManager::removeKeyBinding(const KeyWithModifier& key) {
|
||||
@@ -155,17 +100,10 @@ void KeybindingManager::removeKeyBinding(const KeyWithModifier& key) {
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::pair<KeyWithModifier, KeybindingManager::KeyInformation>>
|
||||
KeybindingManager::keyBinding(const std::string& key) const
|
||||
std::vector<std::pair<KeyWithModifier, std::string>> KeybindingManager::keyBinding(
|
||||
const KeyWithModifier& key) const
|
||||
{
|
||||
KeyWithModifier k = stringToKey(key);
|
||||
return keyBinding(k);
|
||||
}
|
||||
|
||||
std::vector<std::pair<KeyWithModifier, KeybindingManager::KeyInformation>>
|
||||
KeybindingManager::keyBinding(const KeyWithModifier& key) const
|
||||
{
|
||||
std::vector<std::pair<KeyWithModifier, KeyInformation>> result;
|
||||
std::vector<std::pair<KeyWithModifier, std::string>> result;
|
||||
|
||||
auto itRange = _keyLua.equal_range(key);
|
||||
for (auto it = itRange.first; it != itRange.second; ++it) {
|
||||
@@ -174,8 +112,7 @@ KeybindingManager::keyBinding(const KeyWithModifier& key) const
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::multimap<KeyWithModifier, KeybindingManager::KeyInformation>&
|
||||
KeybindingManager::keyBindings() const
|
||||
const std::multimap<KeyWithModifier, std::string>& KeybindingManager::keyBindings() const
|
||||
{
|
||||
return _keyLua;
|
||||
}
|
||||
@@ -186,19 +123,14 @@ std::string KeybindingManager::generateJson() const {
|
||||
std::stringstream json;
|
||||
json << "[";
|
||||
bool first = true;
|
||||
for (const std::pair<const KeyWithModifier, KeyInformation>& p : _keyLua) {
|
||||
for (const std::pair<const KeyWithModifier, std::string>& p : _keyLua) {
|
||||
if (!first) {
|
||||
json << ",";
|
||||
}
|
||||
first = false;
|
||||
json << "{";
|
||||
json << R"("key": ")" << ghoul::to_string(p.first) << "\",";
|
||||
json << R"("script": ")" << escapedJson(p.second.command) << "\",";
|
||||
json << R"("remoteScripting": )"
|
||||
<< (p.second.synchronization ? "true," : "false,");
|
||||
json << R"("documentation": ")"
|
||||
<< escapedJson(p.second.documentation) << "\",";
|
||||
json << R"("name": ")" << escapedJson(p.second.name) << "\"";
|
||||
json << R"("action": ")" << p.second << "\"";
|
||||
json << "}";
|
||||
}
|
||||
json << "]";
|
||||
@@ -230,32 +162,15 @@ scripting::LuaLibrary KeybindingManager::luaLibrary() {
|
||||
"bindKey",
|
||||
&luascriptfunctions::bindKey,
|
||||
{},
|
||||
"string, string [, string, string, string]",
|
||||
"Binds a key by name to a lua string command to execute both locally "
|
||||
"and to broadcast to clients if this is the host of a parallel session. "
|
||||
"The first argument is the key, the second argument is the Lua command "
|
||||
"that is to be executed, and the optional third argument is a human "
|
||||
"readable description of the command for documentation purposes. The"
|
||||
"fourth is the GUI name and fifth is the GUI path, both optional."
|
||||
},
|
||||
{
|
||||
"bindKeyLocal",
|
||||
&luascriptfunctions::bindKeyLocal,
|
||||
{},
|
||||
"string, string [, string]",
|
||||
"Binds a key by name to a lua string command to execute only locally. "
|
||||
"The first argument is the key, the second argument is the Lua command "
|
||||
"that is to be executed, and the optional third argument is a human "
|
||||
"readable description of the command for documentation purposes."
|
||||
"string, string",
|
||||
"Binds a key by name to the action identified by the second argument"
|
||||
},
|
||||
{
|
||||
"getKeyBinding",
|
||||
&luascriptfunctions::getKeyBindings,
|
||||
{},
|
||||
"string",
|
||||
"Returns a list of information about the keybindings for the provided "
|
||||
"key. Each element in the list is a table describing the 'Command' that "
|
||||
"was bound and whether it was a 'Remote' script or not."
|
||||
"Returns a list of information about the keybindings for the provided key"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -30,21 +30,24 @@ namespace openspace::luascriptfunctions {
|
||||
/**
|
||||
* \ingroup LuaScripts
|
||||
* bindKey():
|
||||
* Binds a key to Lua command to both execute locally
|
||||
* and broadcast to all clients if this node is hosting
|
||||
* a parallel connection.
|
||||
* Binds a key to Lua command to both execute locally and broadcast to all clients if this
|
||||
* node is hosting a parallel connection.
|
||||
*/
|
||||
int bindKey(lua_State* L) {
|
||||
using ghoul::lua::luaTypeToString;
|
||||
|
||||
int nArguments = ghoul::lua::checkArgumentsAndThrow(L, { 2, 5 }, "lua::bindKey");
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::bindKey");
|
||||
|
||||
const std::string& key = ghoul::lua::value<std::string>(L, 1);
|
||||
std::string command = ghoul::lua::value<std::string>(L, 2);
|
||||
std::string key = ghoul::lua::value<std::string>(L, 1);
|
||||
std::string action = ghoul::lua::value<std::string>(L, 2);
|
||||
|
||||
if (command.empty()) {
|
||||
if (action.empty()) {
|
||||
lua_settop(L, 0);
|
||||
return ghoul::lua::luaError(L, "Command string is empty");
|
||||
return ghoul::lua::luaError(L, "Action must not be empty");
|
||||
}
|
||||
if (!global::actionManager->hasAction(action)) {
|
||||
lua_settop(L, 0);
|
||||
return ghoul::lua::luaError(L, fmt::format("Action '{}' does not exist", action));
|
||||
}
|
||||
|
||||
openspace::KeyWithModifier iKey = openspace::stringToKey(key);
|
||||
@@ -56,65 +59,7 @@ int bindKey(lua_State* L) {
|
||||
return ghoul::lua::luaError(L, error);
|
||||
}
|
||||
|
||||
std::string doc = (nArguments >= 3) ? ghoul::lua::value<std::string>(L, 3) : "";
|
||||
std::string name = (nArguments >= 4) ? ghoul::lua::value<std::string>(L, 4) : "";
|
||||
std::string guiPath = (nArguments == 5) ? ghoul::lua::value<std::string>(L, 5) : "";
|
||||
|
||||
global::keybindingManager->bindKey(
|
||||
iKey.key,
|
||||
iKey.modifier,
|
||||
std::move(command),
|
||||
std::move(doc),
|
||||
std::move(name),
|
||||
std::move(guiPath)
|
||||
);
|
||||
|
||||
lua_settop(L, 0);
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup LuaScripts
|
||||
* bindKey():
|
||||
* Binds a key to Lua command to execute only locally
|
||||
*/
|
||||
int bindKeyLocal(lua_State* L) {
|
||||
using ghoul::lua::luaTypeToString;
|
||||
|
||||
int nArguments = ghoul::lua::checkArgumentsAndThrow(L, { 2, 5 }, "lua::bindKeyLocal");
|
||||
|
||||
const std::string& key = ghoul::lua::value<std::string>(L, 1);
|
||||
std::string command = ghoul::lua::value<std::string>(L, 2);
|
||||
|
||||
if (command.empty()) {
|
||||
return ghoul::lua::luaError(L, "Command string is empty");
|
||||
}
|
||||
|
||||
openspace::KeyWithModifier iKey = openspace::stringToKey(key);
|
||||
|
||||
if (iKey.key == openspace::Key::Unknown) {
|
||||
std::string error = fmt::format("Could not find key '{}'", key);
|
||||
LERRORC("lua.bindKey", error);
|
||||
return ghoul::lua::luaError(L, error);
|
||||
}
|
||||
|
||||
std::string doc = nArguments >= 3 ? ghoul::lua::value<std::string>(L, 3) : "";
|
||||
std::string name = (nArguments >= 4) ?
|
||||
ghoul::lua::value<std::string>(L, 4) :
|
||||
"";
|
||||
std::string guiPath = (nArguments == 5) ?
|
||||
ghoul::lua::value<std::string>(L, 5) :
|
||||
"";
|
||||
|
||||
global::keybindingManager->bindKeyLocal(
|
||||
iKey.key,
|
||||
iKey.modifier,
|
||||
std::move(command),
|
||||
std::move(doc),
|
||||
std::move(name),
|
||||
std::move(guiPath)
|
||||
);
|
||||
global::keybindingManager->bindKey(iKey.key, iKey.modifier, std::move(action));
|
||||
|
||||
lua_settop(L, 0);
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
@@ -137,23 +82,17 @@ int getKeyBindings(lua_State* L) {
|
||||
);
|
||||
|
||||
using K = KeyWithModifier;
|
||||
using V = interaction::KeybindingManager::KeyInformation;
|
||||
using V = std::string;
|
||||
|
||||
const std::vector<std::pair<K, V>>& info = global::keybindingManager->keyBinding(key);
|
||||
const std::vector<std::pair<K, V>>& info = global::keybindingManager->keyBinding(
|
||||
stringToKey(key)
|
||||
);
|
||||
|
||||
lua_createtable(L, static_cast<int>(info.size()), 0);
|
||||
int i = 1;
|
||||
for (const std::pair<K, V>& it : info) {
|
||||
lua_pushnumber(L, i);
|
||||
|
||||
lua_createtable(L, 2, 0);
|
||||
ghoul::lua::push(L, "Command");
|
||||
ghoul::lua::push(L, it.second.command);
|
||||
lua_settable(L, -3);
|
||||
ghoul::lua::push(L, "Remote");
|
||||
ghoul::lua::push(L, static_cast<bool>(it.second.synchronization));
|
||||
lua_settable(L, -3);
|
||||
|
||||
ghoul::lua::push(L, it.second);
|
||||
lua_settable(L, -3);
|
||||
++i;
|
||||
}
|
||||
@@ -174,7 +113,7 @@ int clearKey(lua_State* L) {
|
||||
if (t == LUA_TSTRING) {
|
||||
// The user provided a single key
|
||||
const std::string& key = ghoul::lua::value<std::string>(L, 1);
|
||||
global::keybindingManager->removeKeyBinding(key);
|
||||
global::keybindingManager->removeKeyBinding(stringToKey(key));
|
||||
}
|
||||
else {
|
||||
// The user provided a list of keys
|
||||
@@ -182,7 +121,7 @@ int clearKey(lua_State* L) {
|
||||
ghoul::lua::luaDictionaryFromState(L, d);
|
||||
for (size_t i = 1; i <= d.size(); ++i) {
|
||||
const std::string& k = d.value<std::string>(std::to_string(i));
|
||||
global::keybindingManager->removeKeyBinding(k);
|
||||
global::keybindingManager->removeKeyBinding(stringToKey(k));
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2021 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <openspace/interaction/shortcutmanager.h>
|
||||
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/scripting/lualibrary.h>
|
||||
#include <openspace/scripting/scriptengine.h>
|
||||
#include <ghoul/glm.h>
|
||||
#include <sstream>
|
||||
|
||||
#include "shortcutmanager_lua.inl"
|
||||
|
||||
namespace openspace::interaction {
|
||||
|
||||
void ShortcutManager::resetShortcuts() {
|
||||
_shortcuts.clear();
|
||||
}
|
||||
|
||||
void ShortcutManager::addShortcut(ShortcutInformation info) {
|
||||
_shortcuts.push_back(std::move(info));
|
||||
}
|
||||
|
||||
const std::vector<ShortcutManager::ShortcutInformation>&
|
||||
ShortcutManager::shortcuts() const
|
||||
{
|
||||
return _shortcuts;
|
||||
}
|
||||
|
||||
scripting::LuaLibrary ShortcutManager::luaLibrary() {
|
||||
return {
|
||||
"",
|
||||
{
|
||||
{
|
||||
"clearShortcuts",
|
||||
&luascriptfunctions::clearShortcuts,
|
||||
{},
|
||||
"",
|
||||
"Clear all shortcuts in this scene"
|
||||
},
|
||||
{
|
||||
"bindShortcut",
|
||||
&luascriptfunctions::bindShortcut,
|
||||
{},
|
||||
"string, string [, string]",
|
||||
"Binds a Lua script to a new shortcut that is executed both locally and "
|
||||
"to be broadcast to clients if this is the host of a parallel session. "
|
||||
"The first argument is a human-readable name for this shortcut, the "
|
||||
"second argument is the Lua script that will be executed and the last "
|
||||
"argument is a describtive text for the shortcut for tooltips, etc."
|
||||
},
|
||||
{
|
||||
"bindShortcutLocal",
|
||||
&luascriptfunctions::bindShortcutLocal,
|
||||
{},
|
||||
"string, string [, string]",
|
||||
"Binds a Lua script to a new shortcut that is executed onlylocally. The "
|
||||
"first argument is a human-readable name for this shortcut, the second "
|
||||
"argument is the Lua script that will be executed and the last argument "
|
||||
"is a describtive text for the shortcut for tooltips, etc."
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace openspace::interaction
|
||||
@@ -33,8 +33,8 @@
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/misc/misc.h>
|
||||
#include <ghoul/misc/profiling.h>
|
||||
#include <json/json.hpp>
|
||||
#include <set>
|
||||
#include <json/json.hpp>
|
||||
|
||||
#include "profile_lua.inl"
|
||||
|
||||
@@ -62,8 +62,8 @@ namespace {
|
||||
}
|
||||
|
||||
void checkValue(const nlohmann::json& j, const std::string& key,
|
||||
bool (nlohmann::json::*checkFunc)() const, std::string_view keyPrefix,
|
||||
bool isOptional)
|
||||
bool (nlohmann::json::*checkFunc)() const,
|
||||
std::string_view keyPrefix, bool isOptional)
|
||||
{
|
||||
if (j.find(key) == j.end()) {
|
||||
if (!isOptional) {
|
||||
@@ -109,6 +109,11 @@ namespace {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
||||
//
|
||||
// Current version:
|
||||
//
|
||||
|
||||
void to_json(nlohmann::json& j, const Profile::Version& v) {
|
||||
j["major"] = v.major;
|
||||
j["minor"] = v.minor;
|
||||
@@ -169,7 +174,6 @@ void to_json(nlohmann::json& j, const Profile::Meta& v) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void from_json(const nlohmann::json& j, Profile::Meta& v) {
|
||||
checkValue(j, "name", &nlohmann::json::is_string, "meta", true);
|
||||
checkValue(j, "version", &nlohmann::json::is_string, "meta", true);
|
||||
@@ -203,7 +207,6 @@ void from_json(const nlohmann::json& j, Profile::Meta& v) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void to_json(nlohmann::json& j, const Profile::Property::SetType& v) {
|
||||
j = [](Profile::Property::SetType t) {
|
||||
switch (t) {
|
||||
@@ -249,8 +252,8 @@ void from_json(const nlohmann::json& j, Profile::Property& v) {
|
||||
j["value"].get_to(v.value);
|
||||
}
|
||||
|
||||
void to_json(nlohmann::json& j, const Profile::Keybinding& v) {
|
||||
j["key"] = ghoul::to_string(v.key);
|
||||
void to_json(nlohmann::json& j, const Profile::Action& v) {
|
||||
j["identifier"] = v.identifier;
|
||||
j["documentation"] = v.documentation;
|
||||
j["name"] = v.name;
|
||||
j["gui_path"] = v.guiPath;
|
||||
@@ -258,20 +261,20 @@ void to_json(nlohmann::json& j, const Profile::Keybinding& v) {
|
||||
j["script"] = v.script;
|
||||
}
|
||||
|
||||
void from_json(const nlohmann::json& j, Profile::Keybinding& v) {
|
||||
checkValue(j, "key", &nlohmann::json::is_string, "keybinding", false);
|
||||
checkValue(j, "documentation", &nlohmann::json::is_string, "keybinding", false);
|
||||
checkValue(j, "name", &nlohmann::json::is_string, "keybinding", false);
|
||||
checkValue(j, "gui_path", &nlohmann::json::is_string, "keybinding", false);
|
||||
checkValue(j, "is_local", &nlohmann::json::is_boolean, "keybinding", false);
|
||||
checkValue(j, "script", &nlohmann::json::is_string, "keybinding", false);
|
||||
void from_json(const nlohmann::json& j, Profile::Action& v) {
|
||||
checkValue(j, "identifier", &nlohmann::json::is_string, "action", false);
|
||||
checkValue(j, "documentation", &nlohmann::json::is_string, "action", false);
|
||||
checkValue(j, "name", &nlohmann::json::is_string, "action", false);
|
||||
checkValue(j, "gui_path", &nlohmann::json::is_string, "action", false);
|
||||
checkValue(j, "is_local", &nlohmann::json::is_boolean, "action", false);
|
||||
checkValue(j, "script", &nlohmann::json::is_string, "action", false);
|
||||
checkExtraKeys(
|
||||
j,
|
||||
"keybinding",
|
||||
{ "key", "documentation", "name", "gui_path", "is_local", "script" }
|
||||
"action",
|
||||
{ "identifier", "documentation", "name", "gui_path", "is_local", "script" }
|
||||
);
|
||||
|
||||
v.key = stringToKey(j.at("key").get<std::string>());
|
||||
j["identifier"].get_to(v.identifier);
|
||||
j["documentation"].get_to(v.documentation);
|
||||
j["name"].get_to(v.name);
|
||||
j["gui_path"].get_to(v.guiPath);
|
||||
@@ -279,6 +282,20 @@ void from_json(const nlohmann::json& j, Profile::Keybinding& v) {
|
||||
j["script"].get_to(v.script);
|
||||
}
|
||||
|
||||
void to_json(nlohmann::json& j, const Profile::Keybinding& v) {
|
||||
j["key"] = keyToString(v.key);
|
||||
j["action"] = v.action;
|
||||
}
|
||||
|
||||
void from_json(const nlohmann::json& j, Profile::Keybinding& v) {
|
||||
checkValue(j, "key", &nlohmann::json::is_string, "keybinding", false);
|
||||
checkValue(j, "action", &nlohmann::json::is_string, "keybinding", false);
|
||||
checkExtraKeys(j, "keybinding", { "key", "action" });
|
||||
|
||||
v.key = stringToKey(j.at("key").get<std::string>());
|
||||
j["action"].get_to(v.action);
|
||||
}
|
||||
|
||||
void to_json(nlohmann::json& j, const Profile::Time::Type& v) {
|
||||
j = [](Profile::Time::Type t) {
|
||||
switch (t) {
|
||||
@@ -439,8 +456,88 @@ void from_json(const nlohmann::json& j, Profile::CameraGoToGeo& v) {
|
||||
}
|
||||
}
|
||||
|
||||
// In these namespaces we defined the structs as they used to be defined in the older
|
||||
// versions. That way, we can keep the from_json files as they were originally written too
|
||||
namespace version10 {
|
||||
|
||||
struct Keybinding {
|
||||
KeyWithModifier key;
|
||||
std::string documentation;
|
||||
std::string name;
|
||||
std::string guiPath;
|
||||
bool isLocal;
|
||||
std::string script;
|
||||
};
|
||||
|
||||
void from_json(const nlohmann::json& j, version10::Keybinding& v) {
|
||||
checkValue(j, "key", &nlohmann::json::is_string, "keybinding", false);
|
||||
checkValue(j, "documentation", &nlohmann::json::is_string, "keybinding", false);
|
||||
checkValue(j, "name", &nlohmann::json::is_string, "keybinding", false);
|
||||
checkValue(j, "gui_path", &nlohmann::json::is_string, "keybinding", false);
|
||||
checkValue(j, "is_local", &nlohmann::json::is_boolean, "keybinding", false);
|
||||
checkValue(j, "script", &nlohmann::json::is_string, "keybinding", false);
|
||||
checkExtraKeys(
|
||||
j,
|
||||
"keybinding",
|
||||
{ "key", "documentation", "name", "gui_path", "is_local", "script" }
|
||||
);
|
||||
|
||||
v.key = stringToKey(j.at("key").get<std::string>());
|
||||
j["documentation"].get_to(v.documentation);
|
||||
j["name"].get_to(v.name);
|
||||
j["gui_path"].get_to(v.guiPath);
|
||||
j["is_local"].get_to(v.isLocal);
|
||||
j["script"].get_to(v.script);
|
||||
}
|
||||
|
||||
void convertVersion10to11(nlohmann::json& profile) {
|
||||
// Version 1.1 introduced actions and remove Lua function calling from keybindings
|
||||
|
||||
if (profile.find("keybindings") == profile.end()) {
|
||||
// We didn't find any keybindings, so there is nothing to do
|
||||
return;
|
||||
}
|
||||
|
||||
// This needs to be changed if there is another version for any of these types later
|
||||
using Action = Profile::Action;
|
||||
using Keybinding = Profile::Keybinding;
|
||||
|
||||
std::vector<Action> actions;
|
||||
std::vector<Keybinding> keybindings;
|
||||
|
||||
std::vector<version10::Keybinding> kbs =
|
||||
profile.at("keybindings").get<std::vector<version10::Keybinding>>();
|
||||
for (size_t i = 0; i < kbs.size(); ++i) {
|
||||
version10::Keybinding& kb = kbs[i];
|
||||
std::string identifier = fmt::format("profile.keybind.{}", i);
|
||||
|
||||
Action action;
|
||||
action.identifier = identifier;
|
||||
action.documentation = std::move(kb.documentation);
|
||||
action.name = std::move(kb.name);
|
||||
action.guiPath = std::move(kb.guiPath);
|
||||
action.isLocal = std::move(kb.isLocal);
|
||||
action.script = std::move(kb.script);
|
||||
actions.push_back(std::move(action));
|
||||
|
||||
Keybinding keybinding;
|
||||
keybinding.key = kb.key;
|
||||
keybinding.action = identifier;
|
||||
keybindings.push_back(keybinding);
|
||||
}
|
||||
|
||||
profile["actions"] = actions;
|
||||
profile["keybindings"] = keybindings;
|
||||
|
||||
profile["version"] = Profile::Version{ 1, 1 };
|
||||
}
|
||||
|
||||
} // namespace version10
|
||||
|
||||
|
||||
|
||||
Profile::ParsingError::ParsingError(Severity severity_, std::string msg)
|
||||
: ghoul::RuntimeError(std::move(msg), "profileFile")
|
||||
: ghoul::RuntimeError(std::move(msg), "profile")
|
||||
, severity(severity_)
|
||||
{}
|
||||
|
||||
@@ -448,11 +545,9 @@ void Profile::saveCurrentSettingsToProfile(const properties::PropertyOwner& root
|
||||
std::string currentTime,
|
||||
interaction::NavigationState navState)
|
||||
{
|
||||
_version = Profile::CurrentVersion;
|
||||
version = Profile::CurrentVersion;
|
||||
|
||||
//
|
||||
// Update properties
|
||||
//
|
||||
std::vector<properties::Property*> ps = changedProperties(rootOwner);
|
||||
|
||||
for (properties::Property* prop : ps) {
|
||||
@@ -460,23 +555,20 @@ void Profile::saveCurrentSettingsToProfile(const properties::PropertyOwner& root
|
||||
p.setType = Property::SetType::SetPropertyValueSingle;
|
||||
p.name = prop->fullyQualifiedIdentifier();
|
||||
p.value = prop->getStringValue();
|
||||
_properties.push_back(std::move(p));
|
||||
properties.push_back(std::move(p));
|
||||
}
|
||||
|
||||
//
|
||||
// add current time to profile file
|
||||
//
|
||||
// Add current time to profile file
|
||||
Time t;
|
||||
t.value = std::move(currentTime);
|
||||
t.type = Time::Type::Absolute;
|
||||
_time = t;
|
||||
time = t;
|
||||
|
||||
// Delta times
|
||||
std::vector<double> dts = global::timeManager->deltaTimeSteps();
|
||||
_deltaTimes = std::move(dts);
|
||||
deltaTimes = std::move(dts);
|
||||
|
||||
// Camera
|
||||
|
||||
CameraNavState c;
|
||||
c.anchor = navState.anchor;
|
||||
c.aim = navState.aim;
|
||||
@@ -485,50 +577,145 @@ void Profile::saveCurrentSettingsToProfile(const properties::PropertyOwner& root
|
||||
c.up = navState.up;
|
||||
c.yaw = navState.yaw;
|
||||
c.pitch = navState.pitch;
|
||||
_camera = std::move(c);
|
||||
}
|
||||
|
||||
void Profile::setIgnoreUpdates(bool ignoreUpdates) {
|
||||
_ignoreUpdates = ignoreUpdates;
|
||||
camera = std::move(c);
|
||||
}
|
||||
|
||||
void Profile::addAsset(const std::string& path) {
|
||||
ZoneScoped
|
||||
|
||||
if (_ignoreUpdates) {
|
||||
if (ignoreUpdates) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto it = std::find(_assets.cbegin(), _assets.cend(), path);
|
||||
|
||||
if (it != _assets.end()) {
|
||||
// Asset already existed, so nothing to do here
|
||||
return;
|
||||
const auto it = std::find(assets.cbegin(), assets.cend(), path);
|
||||
if (it == assets.end()) {
|
||||
assets.push_back(path);
|
||||
}
|
||||
|
||||
_assets.push_back(path);
|
||||
}
|
||||
|
||||
void Profile::removeAsset(const std::string& path) {
|
||||
ZoneScoped
|
||||
|
||||
if (_ignoreUpdates) {
|
||||
if (ignoreUpdates) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto it = std::find(_assets.cbegin(), _assets.cend(), path);
|
||||
|
||||
if (it == _assets.end()) {
|
||||
const auto it = std::find(assets.cbegin(), assets.cend(), path);
|
||||
if (it == assets.end()) {
|
||||
throw ghoul::RuntimeError(fmt::format(
|
||||
"Tried to remove non-existing asset '{}'", path
|
||||
));
|
||||
}
|
||||
|
||||
_assets.erase(it);
|
||||
assets.erase(it);
|
||||
}
|
||||
|
||||
void Profile::clearAssets() {
|
||||
_assets.clear();
|
||||
std::string Profile::serialize() const {
|
||||
nlohmann::json r;
|
||||
r["version"] = version;
|
||||
if (!modules.empty()) {
|
||||
r["modules"] = modules;
|
||||
}
|
||||
if (meta.has_value()) {
|
||||
r["meta"] = *meta;
|
||||
}
|
||||
if (!assets.empty()) {
|
||||
r["assets"] = assets;
|
||||
}
|
||||
if (!properties.empty()) {
|
||||
r["properties"] = properties;
|
||||
}
|
||||
if (!actions.empty()) {
|
||||
r["actions"] = actions;
|
||||
}
|
||||
if (!keybindings.empty()) {
|
||||
r["keybindings"] = keybindings;
|
||||
}
|
||||
if (time.has_value()) {
|
||||
r["time"] = *time;
|
||||
}
|
||||
if (!deltaTimes.empty()) {
|
||||
r["delta_times"] = deltaTimes;
|
||||
}
|
||||
if (camera.has_value()) {
|
||||
r["camera"] = std::visit(
|
||||
overloaded {
|
||||
[](const CameraNavState& c) { return nlohmann::json(c); },
|
||||
[](const Profile::CameraGoToGeo& c) { return nlohmann::json(c); }
|
||||
},
|
||||
*camera
|
||||
);
|
||||
}
|
||||
|
||||
if (!markNodes.empty()) {
|
||||
r["mark_nodes"] = markNodes;
|
||||
}
|
||||
if (!additionalScripts.empty()) {
|
||||
r["additional_scripts"] = additionalScripts;
|
||||
}
|
||||
|
||||
return r.dump(2);
|
||||
}
|
||||
|
||||
Profile::Profile(const std::string& content) {
|
||||
try {
|
||||
nlohmann::json profile = nlohmann::json::parse(content);
|
||||
profile.at("version").get_to(version);
|
||||
|
||||
// Update the file format in steps
|
||||
if (version.major == 1 && version.minor == 0) {
|
||||
version10::convertVersion10to11(profile);
|
||||
profile.at("version").get_to(version);
|
||||
}
|
||||
|
||||
|
||||
if (profile.find("modules") != profile.end()) {
|
||||
profile["modules"].get_to(modules);
|
||||
}
|
||||
if (profile.find("meta") != profile.end()) {
|
||||
meta = profile["meta"].get<Meta>();
|
||||
}
|
||||
if (profile.find("assets") != profile.end()) {
|
||||
profile["assets"].get_to(assets);
|
||||
}
|
||||
if (profile.find("properties") != profile.end()) {
|
||||
profile["properties"].get_to(properties);
|
||||
}
|
||||
if (profile.find("actions") != profile.end()) {
|
||||
profile["actions"].get_to(actions);
|
||||
}
|
||||
if (profile.find("keybindings") != profile.end()) {
|
||||
profile["keybindings"].get_to(keybindings);
|
||||
}
|
||||
if (profile.find("time") != profile.end()) {
|
||||
time = profile["time"].get<Time>();
|
||||
}
|
||||
if (profile.find("delta_times") != profile.end()) {
|
||||
profile["delta_times"].get_to(deltaTimes);
|
||||
}
|
||||
if (profile.find("camera") != profile.end()) {
|
||||
nlohmann::json c = profile.at("camera");
|
||||
if (c["type"] == CameraNavState::Type) {
|
||||
camera = c.get<CameraNavState>();
|
||||
}
|
||||
else if (c["type"] == CameraGoToGeo::Type) {
|
||||
camera = c.get<CameraGoToGeo>();
|
||||
}
|
||||
else {
|
||||
throw ParsingError(ParsingError::Severity::Error, "Unknown camera type");
|
||||
}
|
||||
}
|
||||
if (profile.find("mark_nodes") != profile.end()) {
|
||||
profile["mark_nodes"].get_to(markNodes);
|
||||
}
|
||||
if (profile.find("additional_scripts") != profile.end()) {
|
||||
profile["additional_scripts"].get_to(additionalScripts);
|
||||
}
|
||||
}
|
||||
catch (const nlohmann::json::exception& e) {
|
||||
std::string err = e.what();
|
||||
throw ParsingError(ParsingError::Severity::Error, err);
|
||||
}
|
||||
}
|
||||
|
||||
scripting::LuaLibrary Profile::luaLibrary() {
|
||||
@@ -554,143 +741,38 @@ scripting::LuaLibrary Profile::luaLibrary() {
|
||||
};
|
||||
}
|
||||
|
||||
std::string Profile::serialize() const {
|
||||
nlohmann::json r;
|
||||
r["version"] = _version;
|
||||
if (!_modules.empty()) {
|
||||
r["modules"] = _modules;
|
||||
}
|
||||
if (_meta.has_value()) {
|
||||
r["meta"] = *_meta;
|
||||
}
|
||||
if (!_assets.empty()) {
|
||||
r["assets"] = _assets;
|
||||
}
|
||||
if (!_properties.empty()) {
|
||||
r["properties"] = _properties;
|
||||
}
|
||||
if (!_keybindings.empty()) {
|
||||
r["keybindings"] = _keybindings;
|
||||
}
|
||||
if (_time.has_value()) {
|
||||
r["time"] = *_time;
|
||||
}
|
||||
if (!_deltaTimes.empty()) {
|
||||
r["delta_times"] = _deltaTimes;
|
||||
}
|
||||
if (_camera.has_value()) {
|
||||
r["camera"] = std::visit(
|
||||
overloaded {
|
||||
[](const CameraNavState& camera) {
|
||||
return nlohmann::json(camera);
|
||||
},
|
||||
[](const Profile::CameraGoToGeo& camera) {
|
||||
return nlohmann::json(camera);
|
||||
}
|
||||
},
|
||||
*_camera
|
||||
);
|
||||
}
|
||||
|
||||
if (!_markNodes.empty()) {
|
||||
r["mark_nodes"] = _markNodes;
|
||||
}
|
||||
if (!_additionalScripts.empty()) {
|
||||
r["additional_scripts"] = _additionalScripts;
|
||||
}
|
||||
|
||||
return r.dump(2);
|
||||
}
|
||||
|
||||
Profile::Profile(const std::string& content) {
|
||||
try {
|
||||
nlohmann::json profile = nlohmann::json::parse(content);
|
||||
|
||||
profile.at("version").get_to(_version);
|
||||
if (profile.find("modules") != profile.end()) {
|
||||
profile["modules"].get_to(_modules);
|
||||
}
|
||||
if (profile.find("meta") != profile.end()) {
|
||||
_meta = profile.at("meta").get<Meta>();
|
||||
}
|
||||
if (profile.find("assets") != profile.end()) {
|
||||
profile.at("assets").get_to(_assets);
|
||||
}
|
||||
if (profile.find("properties") != profile.end()) {
|
||||
profile.at("properties").get_to(_properties);
|
||||
}
|
||||
if (profile.find("keybindings") != profile.end()) {
|
||||
profile.at("keybindings").get_to(_keybindings);
|
||||
}
|
||||
if (profile.find("time") != profile.end()) {
|
||||
_time = profile.at("time").get<Time>();
|
||||
}
|
||||
if (profile.find("delta_times") != profile.end()) {
|
||||
profile.at("delta_times").get_to(_deltaTimes);
|
||||
}
|
||||
if (profile.find("camera") != profile.end()) {
|
||||
nlohmann::json c = profile.at("camera");
|
||||
if (c.at("type") == CameraNavState::Type) {
|
||||
_camera = c.get<CameraNavState>();
|
||||
}
|
||||
else if (c.at("type") == CameraGoToGeo::Type) {
|
||||
_camera = c.get<CameraGoToGeo>();
|
||||
}
|
||||
else {
|
||||
throw Profile::ParsingError(
|
||||
Profile::ParsingError::Severity::Error,
|
||||
"Unknown camera type"
|
||||
);
|
||||
}
|
||||
}
|
||||
if (profile.find("mark_nodes") != profile.end()) {
|
||||
profile.at("mark_nodes").get_to(_markNodes);
|
||||
}
|
||||
if (profile.find("additional_scripts") != profile.end()) {
|
||||
profile.at("additional_scripts").get_to(_additionalScripts);
|
||||
}
|
||||
}
|
||||
catch (const nlohmann::json::exception& e) {
|
||||
std::string err = e.what();
|
||||
throw Profile::ParsingError(
|
||||
Profile::ParsingError::Severity::Error,
|
||||
err
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
std::string Profile::convertToScene() const {
|
||||
std::string convertToScene(const Profile& p) {
|
||||
ZoneScoped
|
||||
|
||||
std::string output;
|
||||
|
||||
if (_meta.has_value()) {
|
||||
output += "asset.meta = {";
|
||||
if (p.meta.has_value()) {
|
||||
output += "asset.meta = {\n";
|
||||
|
||||
if (_meta->name.has_value()) {
|
||||
output += fmt::format(" Name = [[{}]],", *_meta->name);
|
||||
if (p.meta->name.has_value()) {
|
||||
output += fmt::format(" Name = [[{}]],\n", *p.meta->name);
|
||||
}
|
||||
if (_meta->version.has_value()) {
|
||||
output += fmt::format(" Version = [[{}]],", *_meta->version);
|
||||
if (p.meta->version.has_value()) {
|
||||
output += fmt::format(" Version = [[{}]],\n", *p.meta->version);
|
||||
}
|
||||
if (_meta->description.has_value()) {
|
||||
output += fmt::format(" Description = [[{}]],", *_meta->description);
|
||||
if (p.meta->description.has_value()) {
|
||||
output += fmt::format(" Description = [[{}]],\n", *p.meta->description);
|
||||
}
|
||||
if (_meta->author.has_value()) {
|
||||
output += fmt::format(" Author = [[{}]],", *_meta->author);
|
||||
if (p.meta->author.has_value()) {
|
||||
output += fmt::format(" Author = [[{}]],\n", *p.meta->author);
|
||||
}
|
||||
if (_meta->url.has_value()) {
|
||||
output += fmt::format(" URL = [[{}]],", *_meta->url);
|
||||
if (p.meta->url.has_value()) {
|
||||
output += fmt::format(" URL = [[{}]],\n", *p.meta->url);
|
||||
}
|
||||
if (_meta->license.has_value()) {
|
||||
output += fmt::format(" License = [[{}]],", *_meta->license);
|
||||
if (p.meta->license.has_value()) {
|
||||
output += fmt::format(" License = [[{}]]\n", *p.meta->license);
|
||||
}
|
||||
|
||||
output += "}";
|
||||
output += "}\n\n";
|
||||
}
|
||||
|
||||
// Modules
|
||||
for (const Module& m : _modules) {
|
||||
for (const Profile::Module& m : p.modules) {
|
||||
output += fmt::format(
|
||||
"if openspace.modules.isLoaded(\"{}\") then {} else {} end\n",
|
||||
m.name, *m.loadedInstruction, *m.notLoadedInstruction
|
||||
@@ -698,34 +780,45 @@ std::string Profile::convertToScene() const {
|
||||
}
|
||||
|
||||
// Assets
|
||||
for (const std::string& asset : _assets) {
|
||||
for (const std::string& asset : p.assets) {
|
||||
output += fmt::format("asset.require(\"{}\");\n", asset);
|
||||
}
|
||||
|
||||
output += "asset.onInitialize(function()\n";
|
||||
// Keybindings
|
||||
for (const Keybinding& k : _keybindings) {
|
||||
const std::string key = ghoul::to_string(k.key);
|
||||
const std::string name = k.name.empty() ? key : k.name;
|
||||
output += "\n\nasset.onInitialize(function()\n";
|
||||
// Actions
|
||||
output += " -- Actions\n";
|
||||
for (const Profile::Action& action : p.actions) {
|
||||
const std::string name = action.name.empty() ? action.identifier : action.name;
|
||||
output += fmt::format(
|
||||
k.isLocal ?
|
||||
"openspace.bindKeyLocal(\"{}\",\"{}\", [[{}]], [[{}]], [[{}]]);\n" :
|
||||
"openspace.bindKey(\"{}\", [[{}]], [[{}]], [[{}]], [[{}]]);\n",
|
||||
key, k.script, k.documentation, name, k.guiPath
|
||||
" openspace.action.registerAction({{"
|
||||
"Identifier=[[{}]], Command=[[{}]], Name=[[{}]], Documentation=[[{}]], "
|
||||
"GuiPath=[[{}]], IsLocal={}"
|
||||
"}})\n",
|
||||
action.identifier, action.script, name, action.documentation, action.guiPath,
|
||||
action.isLocal ? "true" : "false"
|
||||
);
|
||||
}
|
||||
|
||||
// Keybindings
|
||||
output += "\n -- Keybindings\n";
|
||||
for (size_t i = 0; i < p.keybindings.size(); ++i) {
|
||||
const Profile::Keybinding& k = p.keybindings[i];
|
||||
const std::string key = keyToString(k.key);
|
||||
output += fmt::format(" openspace.bindKey([[{}]], [[{}]])\n", key, k.action);
|
||||
}
|
||||
|
||||
// Time
|
||||
switch (_time->type) {
|
||||
case Time::Type::Absolute:
|
||||
output += fmt::format("openspace.time.setTime(\"{}\")\n", _time->value);
|
||||
output += "\n -- Time\n";
|
||||
switch (p.time->type) {
|
||||
case Profile::Time::Type::Absolute:
|
||||
output += fmt::format(" openspace.time.setTime(\"{}\")\n", p.time->value);
|
||||
break;
|
||||
case Time::Type::Relative:
|
||||
output += "local now = openspace.time.currentWallTime();\n";
|
||||
case Profile::Time::Type::Relative:
|
||||
output += " local now = openspace.time.currentWallTime();\n";
|
||||
output += fmt::format(
|
||||
"local prev = openspace.time.advancedTime(now, \"{}\");\n", _time->value
|
||||
" local prev = openspace.time.advancedTime(now, \"{}\");\n", p.time->value
|
||||
);
|
||||
output += "openspace.time.setTime(prev);\n";
|
||||
output += " openspace.time.setTime(prev);\n";
|
||||
break;
|
||||
default:
|
||||
throw ghoul::MissingCaseException();
|
||||
@@ -733,35 +826,37 @@ std::string Profile::convertToScene() const {
|
||||
|
||||
// Delta Times
|
||||
{
|
||||
output += "\n -- Delta Times\n";
|
||||
std::string times;
|
||||
for (const double d : _deltaTimes) {
|
||||
times += fmt::format("{} ,", d);
|
||||
for (double d : p.deltaTimes) {
|
||||
times += fmt::format("{}, ", d);
|
||||
}
|
||||
output += fmt::format("openspace.time.setDeltaTimeSteps({{ {} }});\n", times);
|
||||
output += fmt::format(" openspace.time.setDeltaTimeSteps({{ {} }});\n", times);
|
||||
}
|
||||
|
||||
// Mark Nodes
|
||||
{
|
||||
output += "\n -- Mark Nodes\n";
|
||||
std::string nodes;
|
||||
for (const std::string& n : _markNodes) {
|
||||
for (const std::string& n : p.markNodes) {
|
||||
nodes += fmt::format("[[{}]],", n);
|
||||
}
|
||||
output += fmt::format("openspace.markInterestingNodes({{ {} }});\n", nodes);
|
||||
output += fmt::format(" openspace.markInterestingNodes({{ {} }});\n", nodes);
|
||||
}
|
||||
|
||||
// Properties
|
||||
for (const Property& p : _properties) {
|
||||
switch (p.setType) {
|
||||
case Property::SetType::SetPropertyValue:
|
||||
output += "\n -- Properties\n";
|
||||
for (const Profile::Property& prop : p.properties) {
|
||||
switch (prop.setType) {
|
||||
case Profile::Property::SetType::SetPropertyValue:
|
||||
output += fmt::format(
|
||||
"openspace.setPropertyValue(\"{}\", {});\n",
|
||||
p.name, p.value
|
||||
" openspace.setPropertyValue(\"{}\", {});\n", prop.name, prop.value
|
||||
);
|
||||
break;
|
||||
case Property::SetType::SetPropertyValueSingle:
|
||||
case Profile::Property::SetType::SetPropertyValueSingle:
|
||||
output += fmt::format(
|
||||
"openspace.setPropertyValueSingle(\"{}\", {});\n",
|
||||
p.name, p.value
|
||||
" openspace.setPropertyValueSingle(\"{}\", {});\n",
|
||||
prop.name, prop.value
|
||||
);
|
||||
break;
|
||||
default:
|
||||
@@ -770,169 +865,67 @@ std::string Profile::convertToScene() const {
|
||||
}
|
||||
|
||||
// Camera
|
||||
if (_camera.has_value()) {
|
||||
output += "\n -- Camera\n";
|
||||
if (p.camera.has_value()) {
|
||||
output += std::visit(
|
||||
overloaded {
|
||||
[](const CameraNavState& camera) {
|
||||
[](const Profile::CameraNavState& c) {
|
||||
std::string result;
|
||||
result += "openspace.navigation.setNavigationState({";
|
||||
result += fmt::format("Anchor = [[{}]], ", camera.anchor);
|
||||
if (camera.aim.has_value()) {
|
||||
result += fmt::format("Aim = [[{}]], ", *camera.aim);
|
||||
result += " openspace.navigation.setNavigationState({";
|
||||
result += fmt::format("Anchor = [[{}]], ", c.anchor);
|
||||
if (c.aim.has_value()) {
|
||||
result += fmt::format("Aim = [[{}]], ", *c.aim);
|
||||
}
|
||||
if (!camera.referenceFrame.empty()) {
|
||||
if (!c.referenceFrame.empty()) {
|
||||
result += fmt::format(
|
||||
"ReferenceFrame = [[{}]], ", camera.referenceFrame
|
||||
"ReferenceFrame = [[{}]], ", c.referenceFrame
|
||||
);
|
||||
}
|
||||
result += fmt::format(
|
||||
"Position = {{ {}, {}, {} }}, ",
|
||||
camera.position.x, camera.position.y, camera.position.z
|
||||
c.position.x, c.position.y, c.position.z
|
||||
);
|
||||
if (camera.up.has_value()) {
|
||||
if (c.up.has_value()) {
|
||||
result += fmt::format(
|
||||
"Up = {{ {}, {}, {} }}, ",
|
||||
camera.up->x, camera.up->y, camera.up->z
|
||||
"Up = {{ {}, {}, {} }}, ", c.up->x, c.up->y, c.up->z
|
||||
);
|
||||
}
|
||||
if (camera.yaw.has_value()) {
|
||||
result += fmt::format("Yaw = {}, ", *camera.yaw);
|
||||
if (c.yaw.has_value()) {
|
||||
result += fmt::format("Yaw = {}, ", *c.yaw);
|
||||
}
|
||||
if (camera.pitch.has_value()) {
|
||||
result += fmt::format("Pitch = {} ", *camera.pitch);
|
||||
if (c.pitch.has_value()) {
|
||||
result += fmt::format("Pitch = {} ", *c.pitch);
|
||||
}
|
||||
result += "})\n";
|
||||
return result;
|
||||
},
|
||||
[](const CameraGoToGeo& camera) {
|
||||
if (camera.altitude.has_value()) {
|
||||
[](const Profile::CameraGoToGeo& c) {
|
||||
if (c.altitude.has_value()) {
|
||||
return fmt::format(
|
||||
"openspace.globebrowsing.goToGeo([[{}]], {}, {}, {});\n",
|
||||
camera.anchor,
|
||||
camera.latitude, camera.longitude, *camera.altitude
|
||||
" openspace.globebrowsing.goToGeo([[{}]], {}, {}, {});\n",
|
||||
c.anchor, c.latitude, c.longitude, *c.altitude
|
||||
);
|
||||
}
|
||||
else {
|
||||
return fmt::format(
|
||||
"openspace.globebrowsing.goToGeo([[{}]], {}, {});\n",
|
||||
camera.anchor, camera.latitude, camera.longitude
|
||||
" openspace.globebrowsing.goToGeo([[{}]], {}, {});\n",
|
||||
c.anchor, c.latitude, c.longitude
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
*_camera
|
||||
*p.camera
|
||||
);
|
||||
}
|
||||
|
||||
for (const std::string& a : _additionalScripts) {
|
||||
output += fmt::format("{}\n", a);
|
||||
output += "\n -- Additional Scripts begin\n";
|
||||
for (const std::string& a : p.additionalScripts) {
|
||||
output += fmt::format(" {}\n", a);
|
||||
}
|
||||
|
||||
output += " -- Additional Scripts end\n";
|
||||
output += "end)\n";
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
Profile::Version Profile::version() const {
|
||||
return _version;
|
||||
}
|
||||
|
||||
std::vector<Profile::Module> Profile::modules() const {
|
||||
return _modules;
|
||||
}
|
||||
|
||||
std::optional<Profile::Meta> Profile::meta() const {
|
||||
return _meta;
|
||||
}
|
||||
|
||||
std::vector<std::string> Profile::assets() const {
|
||||
return _assets;
|
||||
}
|
||||
|
||||
std::vector<Profile::Property> Profile::properties() const {
|
||||
return _properties;
|
||||
}
|
||||
|
||||
std::vector<Profile::Keybinding> Profile::keybindings() const {
|
||||
return _keybindings;
|
||||
}
|
||||
|
||||
std::optional<Profile::Time> Profile::time() const {
|
||||
return _time;
|
||||
}
|
||||
|
||||
std::vector<double> Profile::deltaTimes() const {
|
||||
return _deltaTimes;
|
||||
}
|
||||
|
||||
std::optional<Profile::CameraType> Profile::camera() const {
|
||||
return _camera;
|
||||
}
|
||||
|
||||
std::vector<std::string> Profile::markNodes() const {
|
||||
return _markNodes;
|
||||
}
|
||||
|
||||
std::vector<std::string> Profile::additionalScripts() const {
|
||||
return _additionalScripts;
|
||||
}
|
||||
|
||||
void Profile::setVersion(Version v) {
|
||||
_version = v;
|
||||
}
|
||||
|
||||
void Profile::setModules(std::vector<Module>& m) {
|
||||
_modules.clear();
|
||||
copy(m.begin(), m.end(), back_inserter(_modules));
|
||||
}
|
||||
|
||||
void Profile::setMeta(Meta m) {
|
||||
_meta = m;
|
||||
}
|
||||
|
||||
void Profile::setProperties(std::vector<Property>& p) {
|
||||
_properties.clear();
|
||||
copy(p.begin(), p.end(), back_inserter(_properties));
|
||||
}
|
||||
|
||||
void Profile::setKeybindings(std::vector<Keybinding>& k) {
|
||||
_keybindings.clear();
|
||||
copy(k.begin(), k.end(), back_inserter(_keybindings));
|
||||
}
|
||||
|
||||
void Profile::setTime(Time t) {
|
||||
_time = t;
|
||||
}
|
||||
|
||||
void Profile::setDeltaTimes(std::vector<double> dt) {
|
||||
_deltaTimes = dt;
|
||||
}
|
||||
|
||||
void Profile::setCamera(CameraType c) {
|
||||
_camera = c;
|
||||
}
|
||||
|
||||
void Profile::setMarkNodes(std::vector<std::string>& n) {
|
||||
_markNodes.clear();
|
||||
copy(n.begin(), n.end(), back_inserter(_markNodes));
|
||||
}
|
||||
|
||||
void Profile::setAdditionalScripts(std::vector<std::string>& s) {
|
||||
_additionalScripts.clear();
|
||||
copy(s.begin(), s.end(), back_inserter(_additionalScripts));
|
||||
}
|
||||
|
||||
void Profile::clearMeta() {
|
||||
_meta = std::nullopt;
|
||||
}
|
||||
|
||||
void Profile::clearTime() {
|
||||
_time = std::nullopt;
|
||||
}
|
||||
|
||||
void Profile::clearCamera() {
|
||||
_camera = std::nullopt;
|
||||
}
|
||||
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
@@ -34,90 +34,85 @@
|
||||
|
||||
namespace openspace {
|
||||
|
||||
bool hasKeyModifier(KeyAction lhs, KeyAction rhs) {
|
||||
return static_cast<std::underlying_type_t<KeyAction>>(lhs) &
|
||||
static_cast<std::underlying_type_t<KeyAction>>(rhs);
|
||||
}
|
||||
|
||||
KeyAction operator|(KeyAction lhs, KeyAction rhs) {
|
||||
return static_cast<KeyAction>(
|
||||
static_cast<std::underlying_type_t<KeyAction>>(lhs) |
|
||||
static_cast<std::underlying_type_t<KeyAction>>(rhs)
|
||||
);
|
||||
}
|
||||
|
||||
KeyAction operator|=(KeyAction lhs, KeyAction rhs) {
|
||||
return (lhs | rhs);
|
||||
}
|
||||
|
||||
bool hasKeyModifier(KeyModifier lhs, KeyModifier rhs) {
|
||||
return static_cast<std::underlying_type_t<KeyModifier>>(lhs) &
|
||||
static_cast<std::underlying_type_t<KeyModifier>>(rhs);
|
||||
}
|
||||
|
||||
KeyModifier operator|(KeyModifier lhs, KeyModifier rhs) {
|
||||
return static_cast<KeyModifier>(
|
||||
static_cast<std::underlying_type_t<KeyModifier>>(lhs) |
|
||||
static_cast<std::underlying_type_t<KeyModifier>>(rhs)
|
||||
);
|
||||
}
|
||||
|
||||
KeyModifier operator|=(KeyModifier lhs, KeyModifier rhs) {
|
||||
return (lhs | rhs);
|
||||
}
|
||||
|
||||
KeyWithModifier stringToKey(std::string str) {
|
||||
// key only uppercase
|
||||
std::transform(
|
||||
str.begin(),
|
||||
str.end(),
|
||||
str.begin(),
|
||||
[](char v) { return static_cast<char>(toupper(v)); }
|
||||
);
|
||||
|
||||
std::vector<std::string> tokens = ghoul::tokenizeString(str, '+');
|
||||
std::vector<std::string> originalTokens = tokens;
|
||||
for (std::string& t : tokens) {
|
||||
std::transform(
|
||||
t.begin(), t.end(),
|
||||
t.begin(),
|
||||
[](char v) { return static_cast<char>(toupper(v)); }
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
// default is unknown
|
||||
const auto itKey = KeyMapping.find(tokens.back());
|
||||
if (itKey == KeyMapping.cend()) {
|
||||
throw ghoul::RuntimeError(
|
||||
fmt::format("Could not find key for '{}'", tokens.back())
|
||||
);
|
||||
Key key = Key::Unknown;
|
||||
std::string keyName = tokens.back();
|
||||
std::string keyNameOriginal = originalTokens.back();
|
||||
for (const KeyInfo& ki : KeyInfos) {
|
||||
if (ki.identifier == keyName || ki.name == keyName ||
|
||||
ki.identifier == keyNameOriginal || ki.name == keyNameOriginal)
|
||||
{
|
||||
key = ki.key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (key == Key::Unknown) {
|
||||
throw ghoul::RuntimeError(fmt::format("Could not find key for '{}'", keyName));
|
||||
}
|
||||
Key k = itKey->second;
|
||||
|
||||
KeyModifier m = KeyModifier::NoModifier;
|
||||
KeyModifier m = KeyModifier::None;
|
||||
|
||||
std::for_each(
|
||||
tokens.begin(),
|
||||
tokens.end() - 1,
|
||||
[&m](const std::string& s) {
|
||||
const auto itMod = KeyModifierMapping.find(s);
|
||||
if (itMod != KeyModifierMapping.end()) {
|
||||
m = static_cast<KeyModifier>(
|
||||
static_cast<std::underlying_type_t<KeyModifier>>(m) |
|
||||
static_cast<std::underlying_type_t<KeyModifier>>(itMod->second)
|
||||
);
|
||||
bool found = false;
|
||||
for (const KeyModifierInfo& kmi : KeyModifierInfos) {
|
||||
if (kmi.identifier == s || kmi.name == s) {
|
||||
m |= kmi.modifier;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!found) {
|
||||
throw ghoul::RuntimeError(fmt::format("Unknown modifier key '{}'", s));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return { k, m };
|
||||
return { key, m };
|
||||
}
|
||||
|
||||
bool operator<(const KeyWithModifier& lhs, const KeyWithModifier& rhs) {
|
||||
if (lhs.modifier == rhs.modifier) {
|
||||
return lhs.key < rhs.key;
|
||||
}
|
||||
else {
|
||||
return lhs.modifier < rhs.modifier;
|
||||
}
|
||||
}
|
||||
// Returns the 'identifier' of the key (compared to the ghoul::to_string which returns the
|
||||
// 'name' of the key
|
||||
std::string keyToString(KeyWithModifier keyWithModifier) {
|
||||
using namespace openspace;
|
||||
|
||||
bool operator==(const KeyWithModifier& lhs, const KeyWithModifier& rhs) {
|
||||
return (lhs.key == rhs.key) && (lhs.modifier == rhs.modifier);
|
||||
std::string modifier;
|
||||
if (keyWithModifier.modifier != KeyModifier::None) {
|
||||
for (const openspace::KeyModifierInfo& kmi : openspace::KeyModifierInfos) {
|
||||
// No need for an extra check for the empty modifier since that is mapped to 0,
|
||||
// meaning that the `hasKeyModifier` will always fail for it since it checks
|
||||
// internally against != 0
|
||||
|
||||
if (hasKeyModifier(keyWithModifier.modifier, kmi.modifier)) {
|
||||
modifier += fmt::format("{}+", kmi.identifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string key;
|
||||
for (const openspace::KeyInfo& ki : openspace::KeyInfos) {
|
||||
if (ki.key == keyWithModifier.key) {
|
||||
key = std::string(ki.identifier);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// The modifier has a residual + at the end that we use here
|
||||
return modifier + key;
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
@@ -126,11 +121,12 @@ namespace ghoul {
|
||||
|
||||
template <>
|
||||
std::string to_string(const openspace::Key& key) {
|
||||
for (const std::pair<const std::string, openspace::Key>& p : openspace::KeyMapping) {
|
||||
if (p.second == key) {
|
||||
return p.first;
|
||||
for (const openspace::KeyInfo& ki : openspace::KeyInfos) {
|
||||
if (ki.key == key) {
|
||||
return std::string(ki.name);
|
||||
}
|
||||
}
|
||||
|
||||
throw ghoul::MissingCaseException();
|
||||
}
|
||||
|
||||
@@ -138,30 +134,34 @@ template <>
|
||||
std::string to_string(const openspace::KeyModifier& mod) {
|
||||
using namespace openspace;
|
||||
|
||||
if (mod == KeyModifier::NoModifier) {
|
||||
if (mod == KeyModifier::None) {
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string result;
|
||||
using K = const std::string;
|
||||
using V = openspace::KeyModifier;
|
||||
for (const std::pair<K, V>& p : KeyModifierMapping) {
|
||||
if (hasKeyModifier(mod, p.second)) {
|
||||
result += p.first + "+";
|
||||
for (const openspace::KeyModifierInfo& kmi : openspace::KeyModifierInfos) {
|
||||
// No need for an extra check for the empty modifier since that is mapped to 0,
|
||||
// meaning that the `hasKeyModifier` will always fail for it since it checks
|
||||
// internally against != 0
|
||||
|
||||
if (hasKeyModifier(mod, kmi.modifier)) {
|
||||
result += fmt::format("{}+", kmi.name);
|
||||
}
|
||||
|
||||
}
|
||||
// The last addition has added an additional '+' that we
|
||||
// should remove
|
||||
return result.substr(0, result.size() - 1);
|
||||
result.pop_back();
|
||||
return result;
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string to_string(const openspace::KeyWithModifier& key) {
|
||||
if (key.modifier == openspace::KeyModifier::NoModifier) {
|
||||
if (key.modifier == openspace::KeyModifier::None) {
|
||||
return to_string(key.key);
|
||||
}
|
||||
else {
|
||||
return to_string(key.modifier) + "+" + to_string(key.key);
|
||||
return fmt::format("{}+{}", to_string(key.modifier), to_string(key.key));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/engine/windowdelegate.h>
|
||||
#include <openspace/interaction/actionmanager.h>
|
||||
#include <openspace/interaction/keybindingmanager.h>
|
||||
#include <openspace/interaction/sessionrecording.h>
|
||||
#include <openspace/network/parallelpeer.h>
|
||||
@@ -464,16 +465,19 @@ void TimeManager::addDeltaTimesKeybindings() {
|
||||
|
||||
auto addDeltaTimeKeybind = [this](Key key, KeyModifier mod, double step) {
|
||||
const std::string s = fmt::format("{:.0f}", step);
|
||||
global::keybindingManager->bindKeyLocal(
|
||||
key,
|
||||
mod,
|
||||
fmt::format("openspace.time.interpolateDeltaTime({})", s),
|
||||
fmt::format(
|
||||
"Setting the simulation speed to {} seconds per realtime second", s
|
||||
),
|
||||
fmt::format("Set Simulation Speed: {}", s),
|
||||
DeltaTimeStepsKeybindsGuiPath
|
||||
|
||||
std::string identifier = fmt::format("core.time.delta_time.{}", s);
|
||||
interaction::Action action;
|
||||
action.identifier = identifier;
|
||||
action.command = fmt::format("openspace.time.interpolateDeltaTime({})", s);
|
||||
action.documentation = fmt::format(
|
||||
"Setting the simulation speed to {} seconds per realtime second", s
|
||||
);
|
||||
action.name = fmt::format("Set Simulation Speed: {}", s);
|
||||
action.guiPath = DeltaTimeStepsKeybindsGuiPath;
|
||||
action.synchronization = interaction::Action::IsSynchronized::No;
|
||||
global::actionManager->registerAction(std::move(action));
|
||||
global::keybindingManager->bindKey(key, mod, std::move(identifier));
|
||||
_deltaTimeStepKeybindings.push_back(KeyWithModifier{ key, mod });
|
||||
};
|
||||
|
||||
@@ -486,7 +490,7 @@ void TimeManager::addDeltaTimesKeybindings() {
|
||||
const Key key = Keys[i % nKeys];
|
||||
const double deltaTimeStep = steps[i];
|
||||
|
||||
KeyModifier modifier = KeyModifier::NoModifier;
|
||||
KeyModifier modifier = KeyModifier::None;
|
||||
if (i > nKeys - 1) {
|
||||
modifier = KeyModifier::Shift;
|
||||
}
|
||||
@@ -519,11 +523,11 @@ void TimeManager::clearDeltaTimesKeybindings() {
|
||||
if (bindings.size() > 1) {
|
||||
std::string names;
|
||||
for (auto& b : bindings) {
|
||||
names += fmt::format("'{}' ", b.second.name);
|
||||
names += fmt::format("'{}' ", b.second);
|
||||
}
|
||||
LWARNING(fmt::format(
|
||||
"Updating keybindings for new delta time steps: More than one action "
|
||||
"was bound to key '{}'. The following keybindings are removed: {}",
|
||||
"was bound to key '{}'. The following actions are removed: {}",
|
||||
ghoul::to_string(kb), names
|
||||
));
|
||||
}
|
||||
|
||||
@@ -366,7 +366,7 @@ TEST_CASE("Add asset to empty Profile (ignored)", "[profile]") {
|
||||
source["version"]["minor"] = 11;
|
||||
|
||||
Profile p(source.dump());
|
||||
p.setIgnoreUpdates(true);
|
||||
p.ignoreUpdates = true;
|
||||
p.addAsset("new-asset");
|
||||
std::string originalSerialized = p.serialize();
|
||||
|
||||
@@ -403,7 +403,7 @@ TEST_CASE("Add asset to not-empty Profile (ignored)", "[profile]") {
|
||||
source["assets"].push_back("old-asset");
|
||||
|
||||
Profile p(source.dump());
|
||||
p.setIgnoreUpdates(true);
|
||||
p.ignoreUpdates = true;
|
||||
p.addAsset("new-asset");
|
||||
std::string originalSerialized = p.serialize();
|
||||
|
||||
@@ -468,7 +468,7 @@ TEST_CASE("Remove asset (ignored)", "[profile]") {
|
||||
|
||||
|
||||
Profile p(source.dump());
|
||||
p.setIgnoreUpdates(true);
|
||||
p.ignoreUpdates = true;
|
||||
p.removeAsset("asset2");
|
||||
std::string originalSerialized = p.serialize();
|
||||
|
||||
@@ -503,7 +503,7 @@ TEST_CASE("Removing non-exisiting asset (ignored)", "[profile]") {
|
||||
source["assets"].push_back("asset3");
|
||||
|
||||
Profile p(source.dump());
|
||||
p.setIgnoreUpdates(true);
|
||||
p.ignoreUpdates = true;
|
||||
REQUIRE_NOTHROW(p.removeAsset("unknown-asset"));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user