diff --git a/apps/OpenSpace/ext/launcher/CMakeLists.txt b/apps/OpenSpace/ext/launcher/CMakeLists.txt index f8cbd26db7..fde2d6d029 100644 --- a/apps/OpenSpace/ext/launcher/CMakeLists.txt +++ b/apps/OpenSpace/ext/launcher/CMakeLists.txt @@ -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 diff --git a/apps/OpenSpace/ext/launcher/include/profile/actiondialog.h b/apps/OpenSpace/ext/launcher/include/profile/actiondialog.h new file mode 100644 index 0000000000..2b840380c2 --- /dev/null +++ b/apps/OpenSpace/ext/launcher/include/profile/actiondialog.h @@ -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 + +#include + +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* actions, + std::vector* 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* _actions = nullptr; + std::vector _actionData; + std::vector* _keybindings = nullptr; + std::vector _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__ diff --git a/apps/OpenSpace/ext/launcher/include/profile/additionalscriptsdialog.h b/apps/OpenSpace/ext/launcher/include/profile/additionalscriptsdialog.h index 9ff82c4e8b..661a81496e 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/additionalscriptsdialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/additionalscriptsdialog.h @@ -27,8 +27,6 @@ #include -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* scripts); private slots: void parseScript(); @@ -57,7 +55,8 @@ private slots: private: void createWidgets(); - openspace::Profile& _profile; + std::vector* _scripts = nullptr; + std::vector _scriptsData; QTextEdit* _textScripts = nullptr; QPushButton* _chooseScriptsButton = nullptr; }; diff --git a/apps/OpenSpace/ext/launcher/include/profile/assetsdialog.h b/apps/OpenSpace/ext/launcher/include/profile/assetsdialog.h index 0d65333501..c3a06e6c12 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/assetsdialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/assetsdialog.h @@ -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; diff --git a/apps/OpenSpace/ext/launcher/include/profile/cameradialog.h b/apps/OpenSpace/ext/launcher/include/profile/cameradialog.h index eeb6a32c06..a82211e5f2 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/cameradialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/cameradialog.h @@ -27,7 +27,8 @@ #include -namespace openspace { class Profile; } +#include +#include 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* camera); private slots: void approved(); @@ -57,7 +58,7 @@ private: void addErrorMsg(QString errorDescription); bool areRequiredFormsFilledAndValid(); - openspace::Profile& _profile; + std::optional* _camera = nullptr; QTabWidget* _tabWidget = nullptr; struct { QLineEdit* anchor = nullptr; diff --git a/apps/OpenSpace/ext/launcher/include/profile/deltatimesdialog.h b/apps/OpenSpace/ext/launcher/include/profile/deltatimesdialog.h index 744a1db8ac..b366f1c57c 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/deltatimesdialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/deltatimesdialog.h @@ -27,8 +27,6 @@ #include -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* 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 _data; + std::vector* _deltaTimes = nullptr; + std::vector _deltaTimesData; bool _editModeNewItem = false; QListWidget* _listWidget = nullptr; diff --git a/apps/OpenSpace/ext/launcher/include/profile/keybindingsdialog.h b/apps/OpenSpace/ext/launcher/include/profile/keybindingsdialog.h deleted file mode 100644 index 91dd07972c..0000000000 --- a/apps/OpenSpace/ext/launcher/include/profile/keybindingsdialog.h +++ /dev/null @@ -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 - -#include -#include -#include -#include - -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& 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 _data; - std::vector _mapModKeyComboBoxIndexToKeyValue; - std::vector _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__ diff --git a/apps/OpenSpace/ext/launcher/include/profile/marknodesdialog.h b/apps/OpenSpace/ext/launcher/include/profile/marknodesdialog.h index f20d680f92..5524a807a3 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/marknodesdialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/marknodesdialog.h @@ -27,8 +27,6 @@ #include -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* markedNodes); /** * Handles keypress while the Qt dialog window is open @@ -63,8 +61,8 @@ private: void createWidgets(); std::vector _markedNodesListItems; - openspace::Profile& _profile; - std::vector _data; + std::vector* _markedNodes; + std::vector _markedNodesData; QListWidget* _list = nullptr; QPushButton* _removeButton = nullptr; diff --git a/apps/OpenSpace/ext/launcher/include/profile/metadialog.h b/apps/OpenSpace/ext/launcher/include/profile/metadialog.h index 51c500f972..e369054d7f 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/metadialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/metadialog.h @@ -27,7 +27,8 @@ #include -namespace openspace { class Profile; } +#include +#include 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* meta); private slots: void save(); @@ -50,7 +51,7 @@ private slots: private: void createWidgets(); - openspace::Profile& _profile; + std::optional* _meta = nullptr; QLineEdit* _nameEdit = nullptr; QLineEdit* _versionEdit = nullptr; diff --git a/apps/OpenSpace/ext/launcher/include/profile/modulesdialog.h b/apps/OpenSpace/ext/launcher/include/profile/modulesdialog.h index 6533eff4ba..f43867c891 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/modulesdialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/modulesdialog.h @@ -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* 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 _data; + std::vector* _modules = nullptr; + std::vector _moduleData; bool _editModeNewItem = false; QListWidget* _list = nullptr; diff --git a/apps/OpenSpace/ext/launcher/include/profile/propertiesdialog.h b/apps/OpenSpace/ext/launcher/include/profile/propertiesdialog.h index 0938bc8659..6e27c30b95 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/propertiesdialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/propertiesdialog.h @@ -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* 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 _data; + std::vector* _properties = nullptr; + std::vector _propertyData; bool _editModeNewItem = false; QListWidget* _list = nullptr; diff --git a/apps/OpenSpace/ext/launcher/include/profile/scriptlogdialog.h b/apps/OpenSpace/ext/launcher/include/profile/scriptlogdialog.h index 34a5a0e555..cec9bd3a52 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/scriptlogdialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/scriptlogdialog.h @@ -25,7 +25,6 @@ #ifndef __OPENSPACE_UI_LAUNCHER___SCRIPTLOG___H__ #define __OPENSPACE_UI_LAUNCHER___SCRIPTLOG___H__ -#include "profile/keybindingsdialog.h" #include #include diff --git a/apps/OpenSpace/ext/launcher/include/profile/timedialog.h b/apps/OpenSpace/ext/launcher/include/profile/timedialog.h index 394b477f0f..244b3cfd53 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/timedialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/timedialog.h @@ -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* 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* _time = nullptr; + openspace::Profile::Time _timeData; bool _initializedAsAbsolute = true; QComboBox* _typeCombo = nullptr; diff --git a/apps/OpenSpace/ext/launcher/resources/qss/launcher.qss b/apps/OpenSpace/ext/launcher/resources/qss/launcher.qss index 1b31494beb..fcf37934bb 100644 --- a/apps/OpenSpace/ext/launcher/resources/qss/launcher.qss +++ b/apps/OpenSpace/ext/launcher/resources/qss/launcher.qss @@ -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 */ diff --git a/apps/OpenSpace/ext/launcher/src/profile/actiondialog.cpp b/apps/OpenSpace/ext/launcher/src/profile/actiondialog.cpp new file mode 100644 index 0000000000..54ad1112a1 --- /dev/null +++ b/apps/OpenSpace/ext/launcher/src/profile/actiondialog.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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* actions, + std::vector* 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::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(_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(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(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(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(); +} diff --git a/apps/OpenSpace/ext/launcher/src/profile/additionalscriptsdialog.cpp b/apps/OpenSpace/ext/launcher/src/profile/additionalscriptsdialog.cpp index 70b3533670..60ea7b3513 100644 --- a/apps/OpenSpace/ext/launcher/src/profile/additionalscriptsdialog.cpp +++ b/apps/OpenSpace/ext/launcher/src/profile/additionalscriptsdialog.cpp @@ -35,17 +35,17 @@ #include #include -AdditionalScriptsDialog::AdditionalScriptsDialog(openspace::Profile& profile, - QWidget* parent) +AdditionalScriptsDialog::AdditionalScriptsDialog(QWidget* parent, + std::vector* scripts) : QDialog(parent) - , _profile(profile) + , _scripts(scripts) + , _scriptsData(*_scripts) { setWindowTitle("Additional Scripts"); createWidgets(); - std::vector 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(); } diff --git a/apps/OpenSpace/ext/launcher/src/profile/assetsdialog.cpp b/apps/OpenSpace/ext/launcher/src/profile/assetsdialog.cpp index 19671a9587..8c46bf58a6 100644 --- a/apps/OpenSpace/ext/launcher/src/profile/assetsdialog.cpp +++ b/apps/OpenSpace/ext/launcher/src/profile/assetsdialog.cpp @@ -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 summaryPaths; std::vector summaryItems; _assetTreeModel.getSelectedAssets(summaryPaths, summaryItems); for (const std::string& sel : summaryPaths) { - _profile.addAsset(sel); + _profile->addAsset(sel); } accept(); } diff --git a/apps/OpenSpace/ext/launcher/src/profile/cameradialog.cpp b/apps/OpenSpace/ext/launcher/src/profile/cameradialog.cpp index c5adbc8c6d..2b8d6f4aef 100644 --- a/apps/OpenSpace/ext/launcher/src/profile/cameradialog.cpp +++ b/apps/OpenSpace/ext/launcher/src/profile/cameradialog.cpp @@ -25,7 +25,6 @@ #include "profile/cameradialog.h" #include "profile/line.h" -#include #include #include #include @@ -56,15 +55,16 @@ namespace { } } // namespace -CameraDialog::CameraDialog(openspace::Profile& profile, QWidget *parent) +CameraDialog::CameraDialog(QWidget* parent, + std::optional* 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(); diff --git a/apps/OpenSpace/ext/launcher/src/profile/deltatimesdialog.cpp b/apps/OpenSpace/ext/launcher/src/profile/deltatimesdialog.cpp index 4fdcbabc3d..2c23da48ff 100644 --- a/apps/OpenSpace/ext/launcher/src/profile/deltatimesdialog.cpp +++ b/apps/OpenSpace/ext/launcher/src/profile/deltatimesdialog.cpp @@ -80,16 +80,15 @@ namespace { } } // namespace -DeltaTimesDialog::DeltaTimesDialog(openspace::Profile& profile, QWidget *parent) +DeltaTimesDialog::DeltaTimesDialog(QWidget* parent, std::vector* 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(_data.size()) - 1)) { + if (index < (static_cast(_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(_data.size())) { - index = static_cast(_data.size()) - 1; + if (index >= static_cast(_deltaTimesData.size())) { + index = static_cast(_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(_data.size()) - 1; + int finalNonzeroIndex = static_cast(_deltaTimesData.size()) - 1; for (; finalNonzeroIndex >= 0; --finalNonzeroIndex) { - if (_data.at(finalNonzeroIndex) != 0) { + if (_deltaTimesData.at(finalNonzeroIndex) != 0) { break; } } std::vector 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(); } diff --git a/apps/OpenSpace/ext/launcher/src/profile/keybindingsdialog.cpp b/apps/OpenSpace/ext/launcher/src/profile/keybindingsdialog.cpp deleted file mode 100644 index b4cb0c7cb6..0000000000 --- a/apps/OpenSpace/ext/launcher/src/profile/keybindingsdialog.cpp +++ /dev/null @@ -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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -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(k.key.modifier); - if (keymod != static_cast(KeyModifier::NoModifier)) { - summary += KeyModifierNames.at(keymod) + " "; - } - int keyname = static_cast(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& m : KeyModifierNames) { - comboModKeysStringList += QString::fromStdString(m.second); - _mapModKeyComboBoxIndexToKeyValue.push_back(modIdx++); - } - _keyModCombo->addItems(comboModKeysStringList); - connect( - _keyModCombo, QOverload::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(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::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(k.key.modifier) - ); - _keyModCombo->setCurrentIndex(modifierKey); - - if (k.key.key == Key::Unknown) { - _keyCombo->setCurrentIndex(0); - } - else { - const int key = indexInKeyMapping( - _mapKeyComboBoxIndexToKeyValue, - static_cast(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& mapVector, int keyInt) { - const auto it = std::find(mapVector.cbegin(), mapVector.cend(), keyInt); - return static_cast(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(_data.back().key.modifier)); - if (_data.back().key.key == Key::Unknown) { - _keyCombo->setCurrentIndex(0); - } - else { - _keyCombo->setCurrentIndex(static_cast(_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(_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(Key::Num0) && key <= static_cast(Key::Num9)) { - addStringToErrorDisplay(numKeyWarning); - } -} - -void KeybindingsDialog::checkForBindingConflict(int selectedModKey, int selectedKey) { - const QString localWarn = "Warning: New selection conflicts with binding '"; - if (_currentKeybindingSelection >= static_cast(_data.size())) { - return; - } - KeyModifier newModifier = static_cast(selectedModKey); - Key newKey = static_cast(selectedKey); - for (int i = 0; i < static_cast(_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(keyModIdx); - int keyIdx = _mapKeyComboBoxIndexToKeyValue.at(_keyCombo->currentIndex()); - _data[index].key.key = static_cast(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("Key"); - _keyModLabel->setText("Key Modifier"); - _nameLabel->setText("Name"); - _scriptLabel->setText("Script"); - _guiPathLabel->setText("GUI Path"); - _documentationLabel->setText("Documentation"); - - 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("Key"); - _keyModLabel->setText("Key Modifier"); - _nameLabel->setText("Name"); - _scriptLabel->setText("Script"); - _guiPathLabel->setText("GUI Path"); - _documentationLabel->setText("Documentation"); - 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); -} - diff --git a/apps/OpenSpace/ext/launcher/src/profile/marknodesdialog.cpp b/apps/OpenSpace/ext/launcher/src/profile/marknodesdialog.cpp index 9af27989c7..418c47a0d9 100644 --- a/apps/OpenSpace/ext/launcher/src/profile/marknodesdialog.cpp +++ b/apps/OpenSpace/ext/launcher/src/profile/marknodesdialog.cpp @@ -35,10 +35,10 @@ #include #include -MarkNodesDialog::MarkNodesDialog(openspace::Profile& profile, QWidget* parent) +MarkNodesDialog::MarkNodesDialog(QWidget* parent, std::vector* 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(std::distance(_data.cbegin(), it))); + const auto it = std::find( + _markedNodesData.cbegin(), _markedNodesData.cend(), + itemToAdd + ); + if (it != _markedNodesData.end()) { + _list->setCurrentRow( + static_cast(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(); } diff --git a/apps/OpenSpace/ext/launcher/src/profile/metadialog.cpp b/apps/OpenSpace/ext/launcher/src/profile/metadialog.cpp index 1edba2fdee..599307a729 100644 --- a/apps/OpenSpace/ext/launcher/src/profile/metadialog.cpp +++ b/apps/OpenSpace/ext/launcher/src/profile/metadialog.cpp @@ -34,32 +34,32 @@ #include #include -MetaDialog::MetaDialog(openspace::Profile& profile, QWidget *parent) +MetaDialog::MetaDialog(QWidget* parent, std::optional* 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(); } diff --git a/apps/OpenSpace/ext/launcher/src/profile/modulesdialog.cpp b/apps/OpenSpace/ext/launcher/src/profile/modulesdialog.cpp index 7359026d7e..871b9647fe 100644 --- a/apps/OpenSpace/ext/launcher/src/profile/modulesdialog.cpp +++ b/apps/OpenSpace/ext/launcher/src/profile/modulesdialog.cpp @@ -40,10 +40,11 @@ namespace { const Profile::Module Blank = { "", "", "" }; } // namespace -ModulesDialog::ModulesDialog(Profile& profile, QWidget *parent) +ModulesDialog::ModulesDialog(QWidget* parent, + std::vector* 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(); } diff --git a/apps/OpenSpace/ext/launcher/src/profile/profileedit.cpp b/apps/OpenSpace/ext/launcher/src/profile/profileedit.cpp index 6f6a9cea0c..04dc395b88 100644 --- a/apps/OpenSpace/ext/launcher/src/profile/profileedit.cpp +++ b/apps/OpenSpace/ext/launcher/src/profile/profileedit.cpp @@ -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 +#include #include #include #include @@ -69,17 +70,18 @@ namespace { return results; } - std::string summarizeKeybindings(const std::vector& keybindings) + std::string summarizeKeybindings(const std::vector& keybindings, + const std::vector& actions) { std::string results; for (Profile::Keybinding k : keybindings) { - results += k.name + " ("; - int keymod = static_cast(k.key.modifier); - if (keymod != static_cast(openspace::KeyModifier::NoModifier)) { - results += openspace::KeyModifierNames.at(keymod) + "+"; - } - results += openspace::KeyNames.at(static_cast(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& 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") ); } diff --git a/apps/OpenSpace/ext/launcher/src/profile/propertiesdialog.cpp b/apps/OpenSpace/ext/launcher/src/profile/propertiesdialog.cpp index 3a9441154e..a57548b5a2 100644 --- a/apps/OpenSpace/ext/launcher/src/profile/propertiesdialog.cpp +++ b/apps/OpenSpace/ext/launcher/src/profile/propertiesdialog.cpp @@ -46,10 +46,11 @@ namespace { }; } // namespace -PropertiesDialog::PropertiesDialog(Profile& profile, QWidget *parent) +PropertiesDialog::PropertiesDialog(QWidget* parent, + std::vector* 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(); } diff --git a/apps/OpenSpace/ext/launcher/src/profile/timedialog.cpp b/apps/OpenSpace/ext/launcher/src/profile/timedialog.cpp index 03d9526b82..e9f518bc81 100644 --- a/apps/OpenSpace/ext/launcher/src/profile/timedialog.cpp +++ b/apps/OpenSpace/ext/launcher/src/profile/timedialog.cpp @@ -37,20 +37,20 @@ using namespace openspace; -TimeDialog::TimeDialog(openspace::Profile& profile, QWidget* parent) +TimeDialog::TimeDialog(QWidget* parent, std::optional* 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(_data.type)); + _initializedAsAbsolute = (_timeData.type == Profile::Time::Type::Absolute); + enableAccordingToType(static_cast(_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("Relative Time:"); - 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(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(); } diff --git a/data/assets/base_blank.asset b/data/assets/base_blank.asset index b318dcf2fd..6c47bea5d9 100644 --- a/data/assets/base_blank.asset +++ b/data/assets/base_blank.asset @@ -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) diff --git a/data/assets/examples/basic.scene b/data/assets/examples/basic.scene index b8c3eba619..a4ca571d1b 100644 --- a/data/assets/examples/basic.scene +++ b/data/assets/examples/basic.scene @@ -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') diff --git a/data/assets/scene/digitaluniverse/stars.asset b/data/assets/scene/digitaluniverse/stars.asset index db0ac4adb7..77624e5725 100644 --- a/data/assets/scene/digitaluniverse/stars.asset +++ b/data/assets/scene/digitaluniverse/stars.asset @@ -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]] diff --git a/data/assets/scene/milkyway/constellations/constellation_art.asset b/data/assets/scene/milkyway/constellations/constellation_art.asset index 8df89c7658..1217742e88 100644 --- a/data/assets/scene/milkyway/constellations/constellation_art.asset +++ b/data/assets/scene/milkyway/constellations/constellation_art.asset @@ -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) diff --git a/data/assets/scene/milkyway/constellations/constellation_extrakeybinds.asset b/data/assets/scene/milkyway/constellations/constellation_extrakeybinds.asset index 383a82b0ea..33693141f8 100644 --- a/data/assets/scene/milkyway/constellations/constellation_extrakeybinds.asset +++ b/data/assets/scene/milkyway/constellations/constellation_extrakeybinds.asset @@ -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 = { diff --git a/data/assets/scene/milkyway/constellations/constellation_keybinds.asset b/data/assets/scene/milkyway/constellations/constellation_keybinds.asset index 08765add84..37b9f3e124 100644 --- a/data/assets/scene/milkyway/constellations/constellation_keybinds.asset +++ b/data/assets/scene/milkyway/constellations/constellation_keybinds.asset @@ -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) diff --git a/data/assets/scene/solarsystem/missions/apollo/11/lem_flipbook.asset b/data/assets/scene/solarsystem/missions/apollo/11/lem_flipbook.asset index d158311265..29972a0ab0 100644 --- a/data/assets/scene/solarsystem/missions/apollo/11/lem_flipbook.asset +++ b/data/assets/scene/solarsystem/missions/apollo/11/lem_flipbook.asset @@ -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) diff --git a/data/assets/scene/solarsystem/missions/apollo/insignias_map.asset b/data/assets/scene/solarsystem/missions/apollo/insignias_map.asset index acd33f0daa..b79b609c3c 100644 --- a/data/assets/scene/solarsystem/missions/apollo/insignias_map.asset +++ b/data/assets/scene/solarsystem/missions/apollo/insignias_map.asset @@ -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) diff --git a/data/assets/util/default_keybindings.asset b/data/assets/util/default_keybindings.asset index 05a5cdcc10..b3fdc7ca40 100644 --- a/data/assets/util/default_keybindings.asset +++ b/data/assets/util/default_keybindings.asset @@ -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) diff --git a/data/assets/util/scene_helper.asset b/data/assets/util/scene_helper.asset deleted file mode 100644 index 89f6c88a4c..0000000000 --- a/data/assets/util/scene_helper.asset +++ /dev/null @@ -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) diff --git a/data/assets/util/testing_keybindings.asset b/data/assets/util/testing_keybindings.asset index 53a94a0dc1..ce15e6687e 100644 --- a/data/assets/util/testing_keybindings.asset +++ b/data/assets/util/testing_keybindings.asset @@ -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) diff --git a/data/profiles/apollo.profile b/data/profiles/apollo.profile index e4d0d56f37..ce3e96b213 100644 --- a/data/profiles/apollo.profile +++ b/data/profiles/apollo.profile @@ -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 } } \ No newline at end of file diff --git a/data/profiles/default.profile b/data/profiles/default.profile index f3e5f95679..6d3077cc1b 100644 --- a/data/profiles/default.profile +++ b/data/profiles/default.profile @@ -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 } } \ No newline at end of file diff --git a/data/profiles/default_full.profile b/data/profiles/default_full.profile index 8d5113b15b..d2bbfc3a8c 100644 --- a/data/profiles/default_full.profile +++ b/data/profiles/default_full.profile @@ -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 } } \ No newline at end of file diff --git a/data/profiles/jwst.profile b/data/profiles/jwst.profile index d273706c84..ee9269fa65 100644 --- a/data/profiles/jwst.profile +++ b/data/profiles/jwst.profile @@ -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 } -} +} \ No newline at end of file diff --git a/data/profiles/mars.profile b/data/profiles/mars.profile index eb730ff151..b63767b8bd 100644 --- a/data/profiles/mars.profile +++ b/data/profiles/mars.profile @@ -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 } } \ No newline at end of file diff --git a/data/profiles/newhorizons.profile b/data/profiles/newhorizons.profile index f66c34681d..60bb04c35d 100644 --- a/data/profiles/newhorizons.profile +++ b/data/profiles/newhorizons.profile @@ -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 } -} +} \ No newline at end of file diff --git a/data/profiles/osirisrex.profile b/data/profiles/osirisrex.profile index a6b9399bcb..8f3a080085 100644 --- a/data/profiles/osirisrex.profile +++ b/data/profiles/osirisrex.profile @@ -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 } } \ No newline at end of file diff --git a/data/profiles/rosetta.profile b/data/profiles/rosetta.profile index 3f344c3893..9004efd649 100644 --- a/data/profiles/rosetta.profile +++ b/data/profiles/rosetta.profile @@ -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 } } \ No newline at end of file diff --git a/data/profiles/voyager.profile b/data/profiles/voyager.profile index d56b6f1fba..894f46ca4f 100644 --- a/data/profiles/voyager.profile +++ b/data/profiles/voyager.profile @@ -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 } } \ No newline at end of file diff --git a/include/openspace/engine/globals.h b/include/openspace/engine/globals.h index c308a08bf7..0055117b3d 100644 --- a/include/openspace/engine/globals.h +++ b/include/openspace/engine/globals.h @@ -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; diff --git a/src/interaction/shortcutmanager_lua.inl b/include/openspace/interaction/action.h similarity index 52% rename from src/interaction/shortcutmanager_lua.inl rename to include/openspace/interaction/action.h index 90021969bd..05150d2b5b 100644 --- a/src/interaction/shortcutmanager_lua.inl +++ b/include/openspace/interaction/action.h @@ -22,58 +22,49 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include -#include +#ifndef __OPENSPACE_CORE___ACTION___H__ +#define __OPENSPACE_CORE___ACTION___H__ -namespace { +#include +#include -openspace::interaction::ShortcutManager::ShortcutInformation extractInfo(lua_State* L, - int nArguments, - bool isSync) -{ - openspace::interaction::ShortcutManager::ShortcutInformation i = { - ghoul::lua::value(L, 1, ghoul::lua::PopValue::No), - ghoul::lua::value(L, 2, ghoul::lua::PopValue::No), - openspace::interaction::ShortcutManager::IsSynchronized(isSync), - nArguments >= 3 ? - ghoul::lua::value(L, 3, ghoul::lua::PopValue::No) : - "", - nArguments == 4 ? - ghoul::lua::value(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__ diff --git a/include/openspace/interaction/shortcutmanager.h b/include/openspace/interaction/actionmanager.h similarity index 77% rename from include/openspace/interaction/shortcutmanager.h rename to include/openspace/interaction/actionmanager.h index d1043cf74b..b140fe1bd4 100644 --- a/include/openspace/interaction/shortcutmanager.h +++ b/include/openspace/interaction/actionmanager.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 -#include -#include +#include +#include +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 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& shortcuts() const; + void triggerAction(const std::string& identifier, + const ghoul::Dictionary& arguments) const; static scripting::LuaLibrary luaLibrary(); private: - std::vector _shortcuts; + std::unordered_map _actions; }; } // namespace openspace::interaction -#endif // __OPENSPACE_CORE___SHORTCUTMANAGER___H__ +#endif // __OPENSPACE_CORE___ACTIONMANAGER___H__ diff --git a/include/openspace/interaction/keybindingmanager.h b/include/openspace/interaction/keybindingmanager.h index e837da5c36..196848a939 100644 --- a/include/openspace/interaction/keybindingmanager.h +++ b/include/openspace/interaction/keybindingmanager.h @@ -28,7 +28,6 @@ #include #include -#include 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> keyBinding( - const std::string& key) const; - - std::vector> keyBinding( + std::vector> keyBinding( const KeyWithModifier& key) const; static scripting::LuaLibrary luaLibrary(); @@ -76,10 +57,10 @@ public: std::string generateJson() const override; - const std::multimap& keyBindings() const; + const std::multimap& keyBindings() const; private: - std::multimap _keyLua; + std::multimap _keyLua; }; } // namespace openspace::interaction diff --git a/include/openspace/scene/profile.h b/include/openspace/scene/profile.h index 347edd925f..0969c2e4f2 100644 --- a/include/openspace/scene/profile.h +++ b/include/openspace/scene/profile.h @@ -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 modules() const; - std::optional meta() const; - std::vector assets() const; - std::vector properties() const; - std::vector keybindings() const; - std::optional