Feature/keybindings (#1708)

* Add action manager to handle actions in replacement of keyboard shortcuts
* Implement new Action concept
* Remove the shortcutscomponent as it is no longer needed
* Update profile version from 1.0 to 1.1
* Add action dialog
* Restructure of key specification in keys.h
* Remove solid field-of-view keybind from the newhorizons profile as the setting no longer exists
This commit is contained in:
Alexander Bock
2021-08-18 10:58:20 +02:00
committed by GitHub
parent b651170565
commit 34985f64a6
72 changed files with 3443 additions and 3157 deletions

View File

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

View File

@@ -0,0 +1,103 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_UI_LAUNCHER___ACTIONDIALOG___H__
#define __OPENSPACE_UI_LAUNCHER___ACTIONDIALOG___H__
#include <QDialog>
#include <openspace/scene/profile.h>
class QCheckBox;
class QComboBox;
class QDialogButtonBox;
class QGridLayout;
class QLineEdit;
class QListWidget;
class QPushButton;
class QTextEdit;
class ActionDialog : public QDialog {
Q_OBJECT
public:
ActionDialog(QWidget* parent,
std::vector<openspace::Profile::Action>* actions,
std::vector<openspace::Profile::Keybinding>* keybindings);
private:
void createWidgets();
void createActionWidgets(QGridLayout* layout);
void createKeyboardWidgets(QGridLayout* layout);
void applyChanges();
openspace::Profile::Action* selectedAction();
void actionAdd();
void actionRemove();
void actionSelected();
void actionSaved();
void clearActionFields();
void actionRejected();
openspace::Profile::Keybinding* selectedKeybinding();
void keybindingAdd();
void keybindingRemove();
void keybindingSelected();
void keybindingActionSelected(int);
void keybindingSaved();
void clearKeybindingFields();
void keybindingRejected();
std::vector<openspace::Profile::Action>* _actions = nullptr;
std::vector<openspace::Profile::Action> _actionData;
std::vector<openspace::Profile::Keybinding>* _keybindings = nullptr;
std::vector<openspace::Profile::Keybinding> _keybindingsData;
struct {
QListWidget* list = nullptr;
QLineEdit* identifier = nullptr;
QLineEdit* name = nullptr;
QLineEdit* guiPath = nullptr;
QLineEdit* documentation = nullptr;
QCheckBox* isLocal = nullptr;
QTextEdit* script = nullptr;
QPushButton* addButton = nullptr;
QPushButton* removeButton = nullptr;
QDialogButtonBox* saveButtons = nullptr;
} _actionWidgets;
struct {
QListWidget* list = nullptr;
QCheckBox* shiftModifier = nullptr;
QCheckBox* ctrlModifier = nullptr;
QCheckBox* altModifier = nullptr;
QComboBox* key = nullptr;
QComboBox* action = nullptr;
QLineEdit* actionText = nullptr;
QPushButton* addButton = nullptr;
QPushButton* removeButton = nullptr;
QDialogButtonBox* saveButtons = nullptr;
} _keybindingWidgets;
};
#endif // __OPENSPACE_UI_LAUNCHER___ACTIONDIALOG___H__

View File

@@ -27,8 +27,6 @@
#include <QDialog>
namespace openspace { class Profile; }
class QTextEdit;
class AdditionalScriptsDialog : public QDialog {
@@ -41,7 +39,7 @@ public:
* new or imported profile.
* \param parent Pointer to parent Qt widget
*/
AdditionalScriptsDialog(openspace::Profile& profile, QWidget* parent);
AdditionalScriptsDialog(QWidget* parent, std::vector<std::string>* scripts);
private slots:
void parseScript();
@@ -57,7 +55,8 @@ private slots:
private:
void createWidgets();
openspace::Profile& _profile;
std::vector<std::string>* _scripts = nullptr;
std::vector<std::string> _scriptsData;
QTextEdit* _textScripts = nullptr;
QPushButton* _chooseScriptsButton = nullptr;
};

View File

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

View File

@@ -27,7 +27,8 @@
#include <QDialog>
namespace openspace { class Profile; }
#include <openspace/scene/profile.h>
#include <optional>
class QLabel;
class QLineEdit;
@@ -43,7 +44,7 @@ public:
* new or imported profile.
* \param parent Pointer to parent Qt widget (optional)
*/
CameraDialog(openspace::Profile& profile, QWidget* parent);
CameraDialog(QWidget* parent, std::optional<openspace::Profile::CameraType>* camera);
private slots:
void approved();
@@ -57,7 +58,7 @@ private:
void addErrorMsg(QString errorDescription);
bool areRequiredFormsFilledAndValid();
openspace::Profile& _profile;
std::optional<openspace::Profile::CameraType>* _camera = nullptr;
QTabWidget* _tabWidget = nullptr;
struct {
QLineEdit* anchor = nullptr;

View File

@@ -27,8 +27,6 @@
#include <QDialog>
namespace openspace { class Profile; }
class QDialogButtonBox;
class QLabel;
class QListWidget;
@@ -45,7 +43,7 @@ public:
* new or imported profile.
* \param parent Pointer to parent Qt widget
*/
DeltaTimesDialog(openspace::Profile& profile, QWidget* parent);
DeltaTimesDialog(QWidget* parent, std::vector<double>* deltaTimes);
/**
* Returns a text summary of the delta time list for display purposes
@@ -87,8 +85,8 @@ private:
void setLabelForKey(int index, bool editMode, std::string color);
bool isLineEmpty(int index);
openspace::Profile& _profile;
std::vector<double> _data;
std::vector<double>* _deltaTimes = nullptr;
std::vector<double> _deltaTimesData;
bool _editModeNewItem = false;
QListWidget* _listWidget = nullptr;

View File

@@ -1,124 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_UI_LAUNCHER___KEYBINDINGS___H__
#define __OPENSPACE_UI_LAUNCHER___KEYBINDINGS___H__
#include <QDialog>
#include <openspace/scene/profile.h>
#include <openspace/util/keys.h>
#include <QWidget>
#include <QListWidgetItem>
class QComboBox;
class QCheckBox;
class QTextEdit;
class QDialogButtonBox;
class QListWidget;
class QLabel;
class QPushButton;
class KeybindingsDialog : public QDialog {
Q_OBJECT
public:
/**
* Constructor for keybindings class
*
* \param profile The #openspace::Profile object containing all data of the
* new or imported profile.
* \param parent Pointer to parent Qt widget (optional)
*/
KeybindingsDialog(openspace::Profile& profile, QWidget* parent);
/**
* Handles keypress while the Qt dialog window is open
*
* \param evt #QKeyEvent object for the key press event
*/
virtual void keyPressEvent(QKeyEvent* evt) override;
private slots:
void listItemSelected();
void listItemAdded();
void listItemRemove();
void listItemSave();
void listItemCancelSave();
void transitionToEditMode();
void parseSelections();
void chooseScripts();
void keySelected(int index);
void keyModSelected(int index);
/**
* Adds scripts to the _scriptEdit from outside dialogs
*
* \param scripts #std::string scripts to be appended
*/
void appendScriptsToKeybind(std::string scripts);
private:
void createWidgets();
void transitionFromEditMode();
void editBoxDisabled(bool disabled);
int indexInKeyMapping(std::vector<int>& mapVector, int keyInt);
bool areRequiredFormsFilled();
bool isLineEmpty(int index);
void addStringToErrorDisplay(const QString& newString);
void checkForNumberKeyConflict(int key);
void checkForBindingConflict(int selectedModKey, int selectedKey);
openspace::Profile& _profile;
std::vector<openspace::Profile::Keybinding> _data;
std::vector<int> _mapModKeyComboBoxIndexToKeyValue;
std::vector<int> _mapKeyComboBoxIndexToKeyValue;
bool _editModeNewItem = false;
int _currentKeybindingSelection = 0;
QListWidget* _list = nullptr;
QLabel* _keyModLabel = nullptr;
QComboBox* _keyModCombo = nullptr;
QLabel* _keyLabel = nullptr;
QComboBox* _keyCombo = nullptr;
QLabel* _nameLabel = nullptr;
QLineEdit* _nameEdit = nullptr;
QLabel* _guiPathLabel = nullptr;
QLineEdit* _guiPathEdit = nullptr;
QLabel* _documentationLabel = nullptr;
QLineEdit* _documentationEdit = nullptr;
QCheckBox* _localCheck = nullptr;
QLabel* _scriptLabel = nullptr;
QTextEdit* _scriptEdit = nullptr;
QPushButton* _addButton = nullptr;
QPushButton* _removeButton = nullptr;
QPushButton* _chooseScriptsButton = nullptr;
QPushButton* _saveButton = nullptr;
QPushButton* _cancelButton = nullptr;
QDialogButtonBox* _buttonBox = nullptr;
QLabel* _errorMsg = nullptr;
};
#endif // __OPENSPACE_UI_LAUNCHER___KEYBINDINGS___H__

View File

@@ -27,8 +27,6 @@
#include <QDialog>
namespace openspace { class Profile; }
class QLineEdit;
class QListWidget;
class QListWidgetItem;
@@ -44,7 +42,7 @@ public:
* new or imported profile.
* \param parent Pointer to parent Qt widget
*/
MarkNodesDialog(openspace::Profile& profile, QWidget* parent);
MarkNodesDialog(QWidget* parent, std::vector<std::string>* markedNodes);
/**
* Handles keypress while the Qt dialog window is open
@@ -63,8 +61,8 @@ private:
void createWidgets();
std::vector<QListWidgetItem*> _markedNodesListItems;
openspace::Profile& _profile;
std::vector<std::string> _data;
std::vector<std::string>* _markedNodes;
std::vector<std::string> _markedNodesData;
QListWidget* _list = nullptr;
QPushButton* _removeButton = nullptr;

View File

@@ -27,7 +27,8 @@
#include <QDialog>
namespace openspace { class Profile; }
#include <openspace/scene/profile.h>
#include <optional>
class QLineEdit;
class QTextEdit;
@@ -42,7 +43,7 @@ public:
* new or imported profile.
* \param parent Pointer to parent Qt widget
*/
MetaDialog(openspace::Profile& profile, QWidget* parent);
MetaDialog(QWidget* parent, std::optional<openspace::Profile::Meta>* meta);
private slots:
void save();
@@ -50,7 +51,7 @@ private slots:
private:
void createWidgets();
openspace::Profile& _profile;
std::optional<openspace::Profile::Meta>* _meta = nullptr;
QLineEdit* _nameEdit = nullptr;
QLineEdit* _versionEdit = nullptr;

View File

@@ -45,7 +45,7 @@ public:
* new or imported profile.
* \param parent Pointer to parent Qt widget
*/
ModulesDialog(openspace::Profile& profile, QWidget* parent);
ModulesDialog(QWidget* parent, std::vector<openspace::Profile::Module>* modules);
/**
* Handles keypress while the Qt dialog window is open
@@ -71,8 +71,8 @@ private:
void editBoxDisabled(bool disabled);
bool isLineEmpty(int index) const;
openspace::Profile& _profile;
std::vector<openspace::Profile::Module> _data;
std::vector<openspace::Profile::Module>* _modules = nullptr;
std::vector<openspace::Profile::Module> _moduleData;
bool _editModeNewItem = false;
QListWidget* _list = nullptr;

View File

@@ -46,7 +46,8 @@ public:
* new or imported profile.
* \param parent Pointer to parent Qt widget
*/
PropertiesDialog(openspace::Profile& profile, QWidget* parent);
PropertiesDialog(QWidget* parent,
std::vector<openspace::Profile::Property>* properties);
/**
* Handles keypress while the Qt dialog window is open
@@ -73,8 +74,8 @@ private:
bool areRequiredFormsFilled();
bool isLineEmpty(int index);
openspace::Profile& _profile;
std::vector<openspace::Profile::Property> _data;
std::vector<openspace::Profile::Property>* _properties = nullptr;
std::vector<openspace::Profile::Property> _propertyData;
bool _editModeNewItem = false;
QListWidget* _list = nullptr;

View File

@@ -25,7 +25,6 @@
#ifndef __OPENSPACE_UI_LAUNCHER___SCRIPTLOG___H__
#define __OPENSPACE_UI_LAUNCHER___SCRIPTLOG___H__
#include "profile/keybindingsdialog.h"
#include <QDialog>
#include <QListWidget>

View File

@@ -44,7 +44,7 @@ public:
* new or imported profile.
* \param parent Pointer to parent Qt widget
*/
TimeDialog(openspace::Profile& profile, QWidget* parent);
TimeDialog(QWidget* parent, std::optional<openspace::Profile::Time>* time);
private slots:
void enableAccordingToType(int);
@@ -54,8 +54,8 @@ private:
void createWidgets();
void enableFormatForAbsolute(bool enableAbs);
openspace::Profile& _profile;
openspace::Profile::Time _data;
std::optional<openspace::Profile::Time>* _time = nullptr;
openspace::Profile::Time _timeData;
bool _initializedAsAbsolute = true;
QComboBox* _typeCombo = nullptr;

View File

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

View File

@@ -0,0 +1,700 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include "profile/actiondialog.h"
#include "profile/line.h"
#include <openspace/util/keys.h>
#include <ghoul/fmt.h>
#include <ghoul/misc/assert.h>
#include <QCheckBox>
#include <QComboBox>
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QListWidget>
#include <QMessageBox>
#include <QPushButton>
#include <QTextEdit>
#include <QVBoxLayout>
using namespace openspace;
namespace {
void updateListItem(QListWidgetItem* item, const Profile::Action& action) {
ghoul_assert(item, "Item must exist at this point");
item->setText(
action.name.empty() ?
QString::fromStdString(action.identifier) :
QString::fromStdString(action.name)
);
}
void updateListItem(QListWidgetItem* item, const Profile::Keybinding& kb) {
ghoul_assert(item, "Item must exist at this point");
std::string name = fmt::format("{}\t{}", ghoul::to_string(kb.key), kb.action);
item->setText(QString::fromStdString(name));
}
} // namespace
ActionDialog::ActionDialog(QWidget* parent,
std::vector<openspace::Profile::Action>* actions,
std::vector<openspace::Profile::Keybinding>* keybindings)
: QDialog(parent)
, _actions(actions)
, _keybindings(keybindings)
, _actionData(*_actions)
, _keybindingsData(*_keybindings)
{
setWindowTitle("Actions and Keybindings");
createWidgets();
}
void ActionDialog::createWidgets() {
// Column 0 Column 1 Column 2
// *----------------------*---------------*----------------*
// | Actions | Row 0
// | | Identifier | [oooooooooooo] | Row 1
// | | Name | [oooooooooooo] | Row 2
// | | GUI Path | [oooooooooooo] | Row 3
// | | Documentation | [oooooooooooo] | Row 4
// | | Is Local | [] | Row 5
// | | Script | [oooooooooooo] | Row 6
// *----------------------*---------------*----------------*
// | [+] [-] | | [Save] [Cancel]| Row 7
// *----------------------*---------------*----------------*
// |=======================================================| Row 8
// | Keybindings | Row 9
// *----------------------*---------------*----------------|
// | | Modifier | []S []C []A | Row 10
// | | Key | DDDDDDDDDDDD> | Row 11
// | | Add actions | DDDDDDDDDDDD> | Row 12
// | | Action | [oooooooooooo] | Row 13
// *----------------------*---------------*----------------*
// | [+] [-] | | [Save] [Cancel]| Row 14
// *----------------------*---------------*----------------*
// |=======================================================| Row 14
// *----------------------*---------------*----------------*
// | | [Save] [Cancel]| Row 15
// *----------------------*---------------*----------------*
QGridLayout* layout = new QGridLayout(this);
createActionWidgets(layout);
clearActionFields();
layout->addWidget(new Line, 8, 0, 1, 3);
createKeyboardWidgets(layout);
clearKeybindingFields();
layout->addWidget(new Line, 16, 0, 1, 3);
QDialogButtonBox* buttonBox = new QDialogButtonBox;
buttonBox->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel);
QObject::connect(
buttonBox, &QDialogButtonBox::accepted,
this, &ActionDialog::applyChanges
);
QObject::connect(
buttonBox, &QDialogButtonBox::rejected,
this, &ActionDialog::reject
);
layout->addWidget(buttonBox, 17, 2, Qt::AlignRight);
}
void ActionDialog::createActionWidgets(QGridLayout* layout) {
QLabel* title = new QLabel("Actions");
title->setObjectName("heading");
layout->addWidget(title, 0, 0, 1, 3);
_actionWidgets.list = new QListWidget;
_actionWidgets.list->setToolTip(
"The list of all actions currently defined in the profile. Select one to edit it "
"or use the + button below to create a new action"
);
_actionWidgets.list->setAlternatingRowColors(true);
_actionWidgets.list->setResizeMode(QListView::Adjust);
connect(
_actionWidgets.list, &QListWidget::itemSelectionChanged,
this, &ActionDialog::actionSelected
);
for (size_t i = 0; i < _actionData.size(); ++i) {
const Profile::Action& action = _actionData[i];
std::string name = action.name.empty() ? action.identifier : action.name;
_actionWidgets.list->addItem(new QListWidgetItem(QString::fromStdString(name)));
}
layout->addWidget(_actionWidgets.list, 1, 0, 6, 1);
layout->addWidget(new QLabel("Identifier"), 1, 1);
_actionWidgets.identifier = new QLineEdit;
_actionWidgets.identifier->setToolTip(
"The unique identifier for this action. The identifier name cannot be reused "
"between different actions and will lead to a failure to load the profile if it "
"happens. There are no restrictions on the name of the identifier, but a dot "
"separated hierarchical structure is suggested to prevent name clashes"
);
_actionWidgets.identifier->setEnabled(false);
layout->addWidget(_actionWidgets.identifier, 1, 2);
layout->addWidget(new QLabel("Name"), 2, 1);
_actionWidgets.name = new QLineEdit;
_actionWidgets.name->setToolTip(
"The user-facing name of this action. As it is displayed in user interfaces, the "
"name should be as concise and informative as possible"
);
_actionWidgets.name->setEnabled(false);
layout->addWidget(_actionWidgets.name, 2, 2);
layout->addWidget(new QLabel("GUI Path"), 3, 1);
_actionWidgets.guiPath = new QLineEdit;
_actionWidgets.guiPath->setToolTip(
"The path under which this action will be shown in user interfaces. The path "
"must use the '/' character as separators between folders and start with a '/' "
"character that denotes the root folder"
);
_actionWidgets.guiPath->setEnabled(false);
layout->addWidget(_actionWidgets.guiPath, 3, 2);
layout->addWidget(new QLabel("Documentation"), 4, 1);
_actionWidgets.documentation = new QLineEdit;
_actionWidgets.documentation->setToolTip(
"A longer user-facing documentation that describes the action in more detail. "
"The user can request the documentation on demand, so it might be longer and "
"more descriptive than the name itself and might also explain some optional "
"parameters that that action can consume"
);
_actionWidgets.documentation->setEnabled(false);
layout->addWidget(_actionWidgets.documentation, 4, 2);
layout->addWidget(new QLabel("Is Local"), 5, 1);
_actionWidgets.isLocal = new QCheckBox;
_actionWidgets.isLocal->setToolTip(
"If this value is checked, the action will only ever affect the OpenSpace "
"instance that is executing it. If running a 'regular' OpenSpace instance, this "
"setting will not make any difference, but it is necessary in a clustered "
"environment or when using a parallel connection, in which case it determines "
"whether a command should be executed only locally or send to all remote "
"instances as well"
);
_actionWidgets.isLocal->setEnabled(false);
layout->addWidget(_actionWidgets.isLocal, 5, 2);
layout->addWidget(new QLabel("Script"), 6, 1);
_actionWidgets.script = new QTextEdit;
_actionWidgets.script->setToolTip(
"This is the Lua script that gets executed when this action is triggered. "
"Actions can make use of optional arguments which are already defined as the "
"`args` variable when this script executes. If no arguments are passed, this "
"variable does not exist"
);
_actionWidgets.script->setEnabled(false);
layout->addWidget(_actionWidgets.script, 6, 2);
// + / - buttons
QWidget* container = new QWidget;
QBoxLayout* containerLayout = new QHBoxLayout(container);
_actionWidgets.addButton = new QPushButton("+");
_actionWidgets.addButton->setObjectName("add-button");
_actionWidgets.addButton->setToolTip("Adds a new action to the list of all actions");
QObject::connect(
_actionWidgets.addButton, &QPushButton::clicked,
this, &ActionDialog::actionAdd
);
containerLayout->addWidget(_actionWidgets.addButton);
_actionWidgets.removeButton = new QPushButton("-");
_actionWidgets.removeButton->setObjectName("remove-button");
_actionWidgets.removeButton->setToolTip("Removes the currently selected action");
_actionWidgets.removeButton->setEnabled(false);
QObject::connect(
_actionWidgets.removeButton, &QPushButton::clicked,
this, &ActionDialog::actionRemove
);
containerLayout->addWidget(_actionWidgets.removeButton);
layout->addWidget(container, 7, 0, Qt::AlignLeft);
// Save / Cancel buttons
_actionWidgets.saveButtons = new QDialogButtonBox;
_actionWidgets.saveButtons->setToolTip(
"Saves or discards all changes to the currently selected action"
);
_actionWidgets.saveButtons->setEnabled(false);
_actionWidgets.saveButtons->setStandardButtons(
QDialogButtonBox::Save | QDialogButtonBox::Cancel
);
QObject::connect(
_actionWidgets.saveButtons, &QDialogButtonBox::accepted,
this, &ActionDialog::actionSaved
);
QObject::connect(
_actionWidgets.saveButtons, &QDialogButtonBox::rejected,
this, &ActionDialog::actionRejected
);
layout->addWidget(_actionWidgets.saveButtons, 7, 2, Qt::AlignRight);
}
void ActionDialog::createKeyboardWidgets(QGridLayout* layout) {
QLabel* title = new QLabel("Keybindings");
title->setObjectName("heading");
layout->addWidget(title);
_keybindingWidgets.list = new QListWidget;
_keybindingWidgets.list->setToolTip(
"The list of all keybindings currently assigned in this profile"
);
_keybindingWidgets.list->setAlternatingRowColors(true);
_keybindingWidgets.list->setResizeMode(QListView::Adjust);
connect(
_keybindingWidgets.list, &QListWidget::itemSelectionChanged,
this, &ActionDialog::keybindingSelected
);
for (size_t i = 0; i < _keybindingsData.size(); ++i) {
const Profile::Keybinding& kv = _keybindingsData[i];
QListWidgetItem* item = new QListWidgetItem;
updateListItem(item, kv);
_keybindingWidgets.list->addItem(item);
}
layout->addWidget(_keybindingWidgets.list, 10, 0, 4, 1);
layout->addWidget(new QLabel("Modifier"), 10, 1);
{
QWidget* container = new QWidget;
QBoxLayout* containerLayout = new QHBoxLayout(container);
_keybindingWidgets.shiftModifier = new QCheckBox("Shift");
_keybindingWidgets.shiftModifier->setEnabled(false);
containerLayout->addWidget(_keybindingWidgets.shiftModifier);
_keybindingWidgets.ctrlModifier = new QCheckBox("Control");
_keybindingWidgets.ctrlModifier->setEnabled(false);
containerLayout->addWidget(_keybindingWidgets.ctrlModifier);
_keybindingWidgets.altModifier = new QCheckBox("Alt");
_keybindingWidgets.altModifier->setEnabled(false);
containerLayout->addWidget(_keybindingWidgets.altModifier);
layout->addWidget(container, 10, 2);
}
layout->addWidget(new QLabel("Key"), 11, 1);
_keybindingWidgets.key = new QComboBox;
QStringList keyList;
for (const KeyInfo& ki : KeyInfos) {
keyList += QString::fromStdString(std::string(ki.name));
}
_keybindingWidgets.key->addItems(keyList);
_keybindingWidgets.key->setCurrentIndex(-1);
_keybindingWidgets.key->setEnabled(false);
layout->addWidget(_keybindingWidgets.key, 11, 2);
layout->addWidget(new QLabel("Action chooser"), 12, 1);
_keybindingWidgets.action = new QComboBox;
_keybindingWidgets.action->setToolTip(
"You can select any of the actions defined above here to be associated with the "
"selected keybind. Selecting an action from this dropdown menu will "
"automatically enter it into the text field below and overwrite any value that "
"already is entered in there"
);
for (const Profile::Action& action : _actionData) {
_keybindingWidgets.action->addItem(QString::fromStdString(action.identifier));
}
connect(
_keybindingWidgets.action, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &ActionDialog::keybindingActionSelected
);
_keybindingWidgets.action->setEnabled(false);
layout->addWidget(_keybindingWidgets.action, 12, 2);
layout->addWidget(new QLabel("Action"), 13, 1);
_keybindingWidgets.actionText = new QLineEdit;
_keybindingWidgets.actionText->setToolTip(
"This is the action that will be triggered when the keybind is pressed. In the "
"majority of cases, you do not need to enter something here manually, but "
"instead select the action from the dropdown list above. However, if you know "
"that an action with a specific identifier will exist at runtime, for example if "
"it is defined in an asset included in this profile, you can enter the "
"identifier of that action manually here to associate a key with it. If the "
"identifer does not exist, an error will be logged when trying to bind the key "
"at startup."
);
_keybindingWidgets.actionText->setEnabled(false);
layout->addWidget(_keybindingWidgets.actionText, 13, 2);
// +/- buttons
QWidget* container = new QWidget;
QBoxLayout* containerLayout = new QHBoxLayout(container);
_keybindingWidgets.addButton = new QPushButton("+");
_keybindingWidgets.addButton->setObjectName("add-button");
_keybindingWidgets.addButton->setToolTip(
"Adds a new keybinding to the list of all keybindings"
);
QObject::connect(
_keybindingWidgets.addButton, &QPushButton::clicked,
this, &ActionDialog::keybindingAdd
);
containerLayout->addWidget(_keybindingWidgets.addButton);
_keybindingWidgets.removeButton = new QPushButton("-");
_keybindingWidgets.removeButton->setObjectName("remove-button");
_keybindingWidgets.removeButton->setToolTip(
"Removes the currently selected keybinding"
);
_keybindingWidgets.removeButton->setEnabled(false);
QObject::connect(
_keybindingWidgets.removeButton, &QPushButton::clicked,
this, &ActionDialog::keybindingRemove
);
containerLayout->addWidget(_keybindingWidgets.removeButton);
layout->addWidget(container, 14, 0, Qt::AlignLeft);
// Save/Cancel
_keybindingWidgets.saveButtons = new QDialogButtonBox;
_keybindingWidgets.saveButtons->setToolTip(
"Saves or discards all changes to the currently selected keybinding"
);
_keybindingWidgets.saveButtons->setEnabled(false);
_keybindingWidgets.saveButtons->setStandardButtons(
QDialogButtonBox::Save | QDialogButtonBox::Cancel
);
QObject::connect(
_keybindingWidgets.saveButtons, &QDialogButtonBox::accepted,
this, &ActionDialog::keybindingSaved
);
QObject::connect(
_keybindingWidgets.saveButtons, &QDialogButtonBox::rejected,
this, &ActionDialog::keybindingRejected
);
layout->addWidget(_keybindingWidgets.saveButtons, 14, 2, Qt::AlignRight);
}
void ActionDialog::applyChanges() {
*_actions = std::move(_actionData);
*_keybindings = std::move(_keybindingsData);
accept();
}
Profile::Action* ActionDialog::selectedAction() {
QListWidgetItem* item = _actionWidgets.list->currentItem();
const int idx = _actionWidgets.list->row(item);
return idx != -1 ? &_actionData[idx] : nullptr;
}
void ActionDialog::actionAdd() {
_actionWidgets.list->addItem("");
_actionData.push_back(Profile::Action());
_actionWidgets.list->setCurrentRow(_actionWidgets.list->count() - 1);
}
void ActionDialog::actionRemove() {
const openspace::Profile::Action* action = selectedAction();
ghoul_assert(action, "An action must exist at this point");
ghoul_assert(
_actionWidgets.list->count() == static_cast<int>(_actionData.size()),
"Action list and data has desynced"
);
// We can't remove an action if it has a keyboard shortcut attached to it
for (size_t i = 0; i < _keybindingsData.size(); ++i) {
const Profile::Keybinding& kb = _keybindingsData[i];
if (kb.action != action->identifier) {
continue;
}
QMessageBox::StandardButton button = QMessageBox::information(
this,
"Remove action",
QString::fromStdString(fmt::format(
"Action '{}' is used in the keybind '{}' and cannot be removed unless "
"the keybind is removed as well. Do you want to remove the keybind as "
"well?",
action->identifier, ghoul::to_string(kb.key)
)),
QMessageBox::StandardButton::Yes,
QMessageBox::StandardButton::No
);
if (button == QMessageBox::StandardButton::Yes) {
_keybindingsData.erase(_keybindingsData.begin() + i);
delete _keybindingWidgets.list->takeItem(static_cast<int>(i));
i--;
}
else {
// If the user chooses 'No' at least once, we have to bail
return;
}
}
for (size_t i = 0; i < _actionData.size(); ++i) {
if (_actionData[i].identifier == action->identifier) {
_actionData.erase(_actionData.begin() + i);
delete _actionWidgets.list->takeItem(static_cast<int>(i));
clearActionFields();
return;
}
}
ghoul_assert(false, "We shouldn't be able to get here");
}
void ActionDialog::actionSelected() {
const Profile::Action* action = selectedAction();
if (action) {
// Action selected
_actionWidgets.identifier->setText(QString::fromStdString(action->identifier));
_actionWidgets.identifier->setEnabled(true);
_actionWidgets.name->setText(QString::fromStdString(action->name));
_actionWidgets.name->setEnabled(true);
_actionWidgets.guiPath->setText(QString::fromStdString(action->guiPath));
_actionWidgets.guiPath->setEnabled(true);
_actionWidgets.documentation->setText(
QString::fromStdString(action->documentation)
);
_actionWidgets.documentation->setEnabled(true);
_actionWidgets.isLocal->setChecked(action->isLocal);
_actionWidgets.isLocal->setEnabled(true);
_actionWidgets.script->setText(QString::fromStdString(action->script));
_actionWidgets.script->setEnabled(true);
_actionWidgets.addButton->setEnabled(false);
_actionWidgets.removeButton->setEnabled(true);
_actionWidgets.saveButtons->setEnabled(true);
}
else {
// No action selected
_actionWidgets.addButton->setEnabled(true);
_actionWidgets.removeButton->setEnabled(false);
_actionWidgets.saveButtons->setEnabled(false);
}
}
void ActionDialog::actionSaved() {
std::string newIdentifier = _actionWidgets.identifier->text().toStdString();
if (newIdentifier.empty()) {
QMessageBox::critical(this, "Empty identifier", "Identifier must not be empty");
return;
}
Profile::Action* action = selectedAction();
std::string oldIdentifier = action->identifier;
if (oldIdentifier != newIdentifier) {
// The identifier is a bit special as we need to make sure that we didn't
// accidentally create a duplicate while renaming the currently selected action.
// Also if we didn't create a duplicate, meaning that we renamed an action to a
// new valid identifier, we need to make sure that we update all keybinds that
// referenced the old value are updated to use the new name instead
const auto it = std::find_if(
_actionData.begin(), _actionData.end(),
[id = newIdentifier](const Profile::Action& action) {
return action.identifier == id;
}
);
if (it != _actionData.end()) {
QMessageBox::critical(
this,
"Duplicate identifier",
"The chosen identifier was already used in another action. Identifiers "
"have to be unique. Please choose a different identfier."
);
return;
}
// If we got this far, we have a new identifier and it is a new one, so we need to
// update other keybinds now
ghoul_assert(
_keybindingWidgets.list->count() == _keybindingsData.size(),
"The list and data got out of sync"
);
for (int i = 0; i < _keybindingWidgets.list->count(); ++i) {
if (_keybindingsData[i].action == oldIdentifier) {
_keybindingsData[i].action = newIdentifier;
updateListItem(_keybindingWidgets.list->item(i), _keybindingsData[i]);
}
}
for (int i = 0; i < _keybindingWidgets.action->count(); ++i) {
if (_keybindingWidgets.action->itemText(i).toStdString() == oldIdentifier) {
_keybindingWidgets.action->setItemText(
i,
QString::fromStdString(newIdentifier)
);
}
}
action->identifier = newIdentifier;
}
action->name = _actionWidgets.name->text().toStdString();
action->guiPath = _actionWidgets.guiPath->text().toStdString();
action->documentation = _actionWidgets.documentation->text().toStdString();
action->isLocal = _actionWidgets.isLocal->isChecked();
action->script = _actionWidgets.script->toPlainText().toStdString();
updateListItem(_actionWidgets.list->currentItem(), *action);
clearActionFields();
}
void ActionDialog::clearActionFields() {
_actionWidgets.list->setCurrentRow(-1);
_actionWidgets.identifier->clear();
_actionWidgets.identifier->setEnabled(false);
_actionWidgets.name->clear();
_actionWidgets.name->setEnabled(false);
_actionWidgets.guiPath->clear();
_actionWidgets.guiPath->setEnabled(false);
_actionWidgets.documentation->clear();
_actionWidgets.documentation->setEnabled(false);
_actionWidgets.isLocal->setChecked(false);
_actionWidgets.isLocal->setEnabled(false);
_actionWidgets.script->clear();
_actionWidgets.script->setEnabled(false);
_actionWidgets.saveButtons->setEnabled(false);
}
void ActionDialog::actionRejected() {
if (_actionData.back().identifier.empty()) {
// This happens if someone creates a new action and never gave an identifier
delete _actionWidgets.list->takeItem(_actionWidgets.list->count() - 1);
_actionData.erase(_actionData.begin() + _actionData.size() - 1);
}
clearActionFields();
}
Profile::Keybinding* ActionDialog::selectedKeybinding() {
QListWidgetItem* item = _keybindingWidgets.list->currentItem();
const int idx = _keybindingWidgets.list->row(item);
return idx != -1 ? &_keybindingsData[idx] : nullptr;
}
void ActionDialog::keybindingAdd() {
_keybindingWidgets.list->addItem("");
_keybindingsData.push_back(Profile::Keybinding());
_keybindingWidgets.list->setCurrentRow(_keybindingWidgets.list->count() - 1);
}
void ActionDialog::keybindingRemove() {
const Profile::Keybinding* keybinding = selectedKeybinding();
ghoul_assert(keybinding, "A keybinding must be selected at this point");
for (size_t i = 0; i < _keybindingsData.size(); ++i) {
if (_keybindingsData[i].key == keybinding->key &&
_keybindingsData[i].action == keybinding->action)
{
_keybindingsData.erase(_keybindingsData.begin() + i);
delete _keybindingWidgets.list->takeItem(static_cast<int>(i));
clearKeybindingFields();
return;
}
}
}
void ActionDialog::keybindingSelected() {
const Profile::Keybinding* keybinding = selectedKeybinding();
if (keybinding) {
_keybindingWidgets.shiftModifier->setEnabled(true);
_keybindingWidgets.shiftModifier->setChecked(
hasKeyModifier(keybinding->key.modifier, KeyModifier::Shift)
);
_keybindingWidgets.ctrlModifier->setEnabled(true);
_keybindingWidgets.ctrlModifier->setChecked(
hasKeyModifier(keybinding->key.modifier, KeyModifier::Control)
);
_keybindingWidgets.altModifier->setEnabled(true);
_keybindingWidgets.altModifier->setChecked(
hasKeyModifier(keybinding->key.modifier, KeyModifier::Alt)
);
std::string key = ghoul::to_string(keybinding->key.key);
_keybindingWidgets.key->setCurrentText(QString::fromStdString(key));
_keybindingWidgets.key->setEnabled(true);
_keybindingWidgets.action->setCurrentText(QString::fromStdString(keybinding->action));
_keybindingWidgets.action->setEnabled(true);
_keybindingWidgets.actionText->setText(
QString::fromStdString(keybinding->action)
);
_keybindingWidgets.actionText->setEnabled(true);
_keybindingWidgets.addButton->setEnabled(false);
_keybindingWidgets.removeButton->setEnabled(true);
_keybindingWidgets.saveButtons->setEnabled(true);
}
else {
// No keybinding selected
_keybindingWidgets.addButton->setEnabled(true);
_keybindingWidgets.removeButton->setEnabled(false);
_keybindingWidgets.saveButtons->setEnabled(false);
}
}
void ActionDialog::keybindingActionSelected(int) {
_keybindingWidgets.actionText->setText(_keybindingWidgets.action->currentText());
}
void ActionDialog::keybindingSaved() {
Profile::Keybinding* keybinding = selectedKeybinding();
ghoul_assert(keybinding, "There must be a selected action at this point");
KeyModifier km = KeyModifier::None;
if (_keybindingWidgets.shiftModifier->isChecked()) {
km |= KeyModifier::Shift;
}
if (_keybindingWidgets.altModifier->isChecked()) {
km |= KeyModifier::Alt;
}
if (_keybindingWidgets.ctrlModifier->isChecked()) {
km |= KeyModifier::Control;
}
keybinding->key = stringToKey(_keybindingWidgets.key->currentText().toStdString());
keybinding->key.modifier = km;
keybinding->action = _keybindingWidgets.actionText->text().toStdString();
updateListItem(_keybindingWidgets.list->currentItem(), *keybinding);
clearKeybindingFields();
}
void ActionDialog::clearKeybindingFields() {
_keybindingWidgets.list->setCurrentRow(-1);
_keybindingWidgets.shiftModifier->setChecked(false);
_keybindingWidgets.shiftModifier->setEnabled(false);
_keybindingWidgets.ctrlModifier->setChecked(false);
_keybindingWidgets.ctrlModifier->setEnabled(false);
_keybindingWidgets.altModifier->setChecked(false);
_keybindingWidgets.altModifier->setEnabled(false);
_keybindingWidgets.key->setCurrentIndex(-1);
_keybindingWidgets.key->setEnabled(false);
_keybindingWidgets.action->setCurrentIndex(-1);
_keybindingWidgets.action->setEnabled(false);
_keybindingWidgets.actionText->clear();
_keybindingWidgets.actionText->setEnabled(false);
}
void ActionDialog::keybindingRejected() {
clearKeybindingFields();
}

View File

@@ -35,17 +35,17 @@
#include <QVBoxLayout>
#include <sstream>
AdditionalScriptsDialog::AdditionalScriptsDialog(openspace::Profile& profile,
QWidget* parent)
AdditionalScriptsDialog::AdditionalScriptsDialog(QWidget* parent,
std::vector<std::string>* scripts)
: QDialog(parent)
, _profile(profile)
, _scripts(scripts)
, _scriptsData(*_scripts)
{
setWindowTitle("Additional Scripts");
createWidgets();
std::vector<std::string> scripts = _profile.additionalScripts();
std::string scriptText = std::accumulate(
scripts.begin(), scripts.end(),
_scriptsData.begin(), _scriptsData.end(),
std::string(), [](std::string lhs, std::string rhs) { return lhs + rhs + '\n'; }
);
_textScripts->setText(QString::fromStdString(std::move(scriptText)));
@@ -96,7 +96,7 @@ void AdditionalScriptsDialog::parseScript() {
std::getline(iss, s);
additionalScripts.push_back(std::move(s));
}
_profile.setAdditionalScripts(additionalScripts);
*_scripts = std::move(additionalScripts);
accept();
}

View File

@@ -123,8 +123,9 @@ namespace {
}
} // namespace
AssetsDialog::AssetsDialog(openspace::Profile& profile, const std::string& assetBasePath,
const std::string& userAssetBasePath, QWidget* parent)
AssetsDialog::AssetsDialog(QWidget* parent, openspace::Profile* profile,
const std::string& assetBasePath,
const std::string& userAssetBasePath)
: QDialog(parent)
, _profile(profile)
{
@@ -158,10 +159,10 @@ AssetsDialog::AssetsDialog(openspace::Profile& profile, const std::string& asset
connect(_assetTree, &QTreeView::clicked, this, &AssetsDialog::selected);
for (const std::string& a : _profile.assets()) {
QModelIndex parent = _assetTreeModel.index(-1, 0);
int nRows = _assetTreeModel.rowCount(parent);
traverseToFindFilesystemMatch(_assetTreeModel, parent, nRows, a);
for (const std::string& a : _profile->assets) {
QModelIndex p = _assetTreeModel.index(-1, 0);
int nRows = _assetTreeModel.rowCount(p);
traverseToFindFilesystemMatch(_assetTreeModel, p, nRows, a);
}
int nRows = _assetTreeModel.rowCount(_assetTreeModel.index(-1, 0));
@@ -224,13 +225,13 @@ QString AssetsDialog::createTextSummary() {
}
void AssetsDialog::parseSelections() {
_profile.clearAssets();
_profile->assets.clear();
std::vector<std::string> summaryPaths;
std::vector<AssetTreeItem*> summaryItems;
_assetTreeModel.getSelectedAssets(summaryPaths, summaryItems);
for (const std::string& sel : summaryPaths) {
_profile.addAsset(sel);
_profile->addAsset(sel);
}
accept();
}

View File

@@ -25,7 +25,6 @@
#include "profile/cameradialog.h"
#include "profile/line.h"
#include <openspace/scene/profile.h>
#include <QDialogButtonBox>
#include <QDoubleValidator>
#include <QFrame>
@@ -56,15 +55,16 @@ namespace {
}
} // namespace
CameraDialog::CameraDialog(openspace::Profile& profile, QWidget *parent)
CameraDialog::CameraDialog(QWidget* parent,
std::optional<openspace::Profile::CameraType>* camera)
: QDialog(parent)
, _profile(profile)
, _camera(camera)
{
setWindowTitle("Set Camera Position");
createWidgets();
if (_profile.camera().has_value()) {
openspace::Profile::CameraType type = *_profile.camera();
if (_camera->has_value()) {
const openspace::Profile::CameraType& type = **_camera;
std::visit(overloaded {
[this](const openspace::Profile::CameraNavState& nav) {
_tabWidget->setCurrentIndex(CameraTypeNav);
@@ -406,7 +406,7 @@ void CameraDialog::approved() {
else {
nav.pitch = std::nullopt;
}
_profile.setCamera(nav);
*_camera = std::move(nav);
}
else if (_tabWidget->currentIndex() == CameraTypeGeo) {
openspace::Profile::CameraGoToGeo geo;
@@ -416,7 +416,7 @@ void CameraDialog::approved() {
if (!_geoState.altitude->text().isEmpty()) {
geo.altitude = _geoState.altitude->text().toDouble();
}
_profile.setCamera(geo);
*_camera = std::move(geo);
}
accept();

View File

@@ -80,16 +80,15 @@ namespace {
}
} // namespace
DeltaTimesDialog::DeltaTimesDialog(openspace::Profile& profile, QWidget *parent)
DeltaTimesDialog::DeltaTimesDialog(QWidget* parent, std::vector<double>* deltaTimes)
: QDialog(parent)
, _profile(profile)
, _deltaTimes(deltaTimes)
, _deltaTimesData(*_deltaTimes)
{
setWindowTitle("Simulation Time Increments");
createWidgets();
_data = _profile.deltaTimes();
for (size_t d = 0; d < _data.size(); ++d) {
for (size_t d = 0; d < _deltaTimesData.size(); ++d) {
std::string summary = createSummaryForDeltaTime(d, true);
_listWidget->addItem(new QListWidgetItem(QString::fromStdString(summary)));
}
@@ -204,7 +203,11 @@ std::string DeltaTimesDialog::createSummaryForDeltaTime(size_t idx, bool forList
}
if (forListView) {
s += '\t' + std::to_string(_data.at(idx)) + '\t' + timeDescription(_data.at(idx));
s += fmt::format(
"\t{}\t{}",
std::to_string(_deltaTimesData.at(idx)),
timeDescription(_deltaTimesData.at(idx))
);
}
return s;
}
@@ -213,16 +216,16 @@ void DeltaTimesDialog::listItemSelected() {
QListWidgetItem *item = _listWidget->currentItem();
int index = _listWidget->row(item);
if (index < (static_cast<int>(_data.size()) - 1)) {
if (index < (static_cast<int>(_deltaTimesData.size()) - 1)) {
_listWidget->setCurrentRow(index);
}
if (!_data.empty()) {
if (_data.at(index) == 0) {
if (!_deltaTimesData.empty()) {
if (_deltaTimesData.at(index) == 0) {
_seconds->clear();
}
else {
_seconds->setText(QString::number(_data.at(index)));
_seconds->setText(QString::number(_deltaTimesData.at(index)));
}
}
_editModeNewItem = true;
@@ -231,8 +234,8 @@ void DeltaTimesDialog::listItemSelected() {
void DeltaTimesDialog::setLabelForKey(int index, bool editMode, std::string color) {
std::string labelS = "Set Simulation Time Increment for key";
if (index >= static_cast<int>(_data.size())) {
index = static_cast<int>(_data.size()) - 1;
if (index >= static_cast<int>(_deltaTimesData.size())) {
index = static_cast<int>(_deltaTimesData.size()) - 1;
}
if (editMode) {
labelS += " '" + createSummaryForDeltaTime(index, false) + "':";
@@ -262,7 +265,7 @@ bool DeltaTimesDialog::isLineEmpty(int index) {
if (!_listWidget->item(index)->text().isEmpty()) {
isEmpty = false;
}
if (!_data.empty() && (_data.at(0) != 0)) {
if (!_deltaTimesData.empty() && (_deltaTimesData.at(0) != 0)) {
isEmpty = false;
}
return isEmpty;
@@ -276,11 +279,11 @@ void DeltaTimesDialog::addDeltaTimeValue() {
// Special case where list is "empty" but really has one line that is blank.
// This is done because QListWidget does not seem to like having its sole
// remaining item being removed.
_data.at(0) = 0;
_deltaTimesData.at(0) = 0;
_listWidget->item(0)->setText(messageAddValue);
}
else if (_data.size() < MaxNumberOfKeys) {
_data.push_back(0);
else if (_deltaTimesData.size() < MaxNumberOfKeys) {
_deltaTimesData.push_back(0);
_listWidget->addItem(new QListWidgetItem(messageAddValue));
}
else {
@@ -295,8 +298,8 @@ void DeltaTimesDialog::saveDeltaTimeValue() {
QListWidgetItem* item = _listWidget->currentItem();
if (item != nullptr) {
int index = _listWidget->row(item);
if (_data.size() > 0) {
_data.at(index) = _seconds->text().toDouble();
if (_deltaTimesData.size() > 0) {
_deltaTimesData.at(index) = _seconds->text().toDouble();
std::string summary = createSummaryForDeltaTime(index, true);
_listWidget->item(index)->setText(QString::fromStdString(summary));
transitionEditMode(index, false);
@@ -308,7 +311,7 @@ void DeltaTimesDialog::saveDeltaTimeValue() {
void DeltaTimesDialog::discardDeltaTimeValue() {
listItemSelected();
transitionEditMode(_listWidget->count() - 1, false);
if (_editModeNewItem && !_data.empty() && _data.back() == 0) {
if (_editModeNewItem && !_deltaTimesData.empty() && _deltaTimesData.back() == 0) {
removeDeltaTimeValue();
}
_editModeNewItem = false;
@@ -317,13 +320,13 @@ void DeltaTimesDialog::discardDeltaTimeValue() {
void DeltaTimesDialog::removeDeltaTimeValue() {
if (_listWidget->count() > 0) {
if (_listWidget->count() == 1) {
_data.at(0) = 0;
_deltaTimesData.at(0) = 0;
_listWidget->item(0)->setText("");
}
else {
delete _listWidget->takeItem(_listWidget->count() - 1);
if (!_data.empty()) {
_data.pop_back();
if (!_deltaTimesData.empty()) {
_deltaTimesData.pop_back();
}
}
}
@@ -356,20 +359,20 @@ void DeltaTimesDialog::transitionEditMode(int index, bool state) {
}
void DeltaTimesDialog::parseSelections() {
if ((_data.size() == 1) && (_data.at(0) == 0)) {
_data.clear();
if ((_deltaTimesData.size() == 1) && (_deltaTimesData.at(0) == 0)) {
_deltaTimesData.clear();
}
int finalNonzeroIndex = static_cast<int>(_data.size()) - 1;
int finalNonzeroIndex = static_cast<int>(_deltaTimesData.size()) - 1;
for (; finalNonzeroIndex >= 0; --finalNonzeroIndex) {
if (_data.at(finalNonzeroIndex) != 0) {
if (_deltaTimesData.at(finalNonzeroIndex) != 0) {
break;
}
}
std::vector<double> tempDt;
for (int i = 0; i < (finalNonzeroIndex + 1); ++i) {
tempDt.push_back(_data[i]);
tempDt.push_back(_deltaTimesData[i]);
}
_profile.setDeltaTimes(tempDt);
*_deltaTimes = std::move(_deltaTimesData);
accept();
}

View File

@@ -1,577 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include "profile/keybindingsdialog.h"
#include "profile/line.h"
#include "profile/scriptlogdialog.h"
#include <openspace/scene/profile.h>
#include <qevent.h>
#include <algorithm>
#include <QKeyEvent>
#include <QCheckBox>
#include <QVBoxLayout>
#include <QPushButton>
#include <QLabel>
#include <QComboBox>
#include <QLineEdit>
#include <QTextEdit>
#include <QDialogButtonBox>
using namespace openspace;
namespace {
const Profile::Keybinding BlankKey= {
{ Key::Unknown, KeyModifier::NoModifier },
"",
"",
"",
true,
""
};
void replaceChars(std::string& src, const std::string& from, const std::string& to) {
std::string newString;
std::string::size_type found, last = 0;
while ((found = src.find(from, last)) != std::string::npos) {
newString.append(src, last, (found - last));
newString += to;
last = found + from.length();
}
newString += src.substr(last);
src.swap(newString);
}
std::string truncateString(std::string& s) {
const size_t maxLength = 50;
replaceChars(s, "\n", ";");
if (s.length() > maxLength) {
s.resize(maxLength);
s += "...";
}
return s;
}
std::string createOneLineSummary(Profile::Keybinding k) {
std::string summary;
int keymod = static_cast<int>(k.key.modifier);
if (keymod != static_cast<int>(KeyModifier::NoModifier)) {
summary += KeyModifierNames.at(keymod) + " ";
}
int keyname = static_cast<int>(k.key.key);
summary += KeyNames.at(keyname) + " ";
summary += truncateString(k.name) + " (";
summary += truncateString(k.documentation) + ") @ ";
summary += truncateString(k.guiPath) + " ";
summary += (k.isLocal) ? "local" : "remote";
summary += " `" + truncateString(k.script) + "`";
return summary;
}
} // namespace
KeybindingsDialog::KeybindingsDialog(Profile& profile, QWidget *parent)
: QDialog(parent)
, _profile(profile)
, _data(_profile.keybindings())
{
setWindowTitle("Assign Keybindings");
createWidgets();
transitionFromEditMode();
}
void KeybindingsDialog::appendScriptsToKeybind(std::string scripts) {
_scriptEdit->append(QString::fromStdString(std::move(scripts)));
}
void KeybindingsDialog::createWidgets() {
QBoxLayout* layout = new QVBoxLayout(this);
{
_list = new QListWidget;
connect(
_list, &QListWidget::itemSelectionChanged,
this, &KeybindingsDialog::listItemSelected
);
_list->setAlternatingRowColors(true);
_list->setMovement(QListView::Free);
_list->setResizeMode(QListView::Adjust);
for (size_t i = 0; i < _data.size(); ++i) {
std::string summary = createOneLineSummary(_data[i]);
_list->addItem(new QListWidgetItem(QString::fromStdString(summary)));
}
layout->addWidget(_list);
}
{
QBoxLayout* box = new QHBoxLayout;
_addButton = new QPushButton("Add new");
connect(
_addButton, &QPushButton::clicked,
this, &KeybindingsDialog::listItemAdded
);
box->addWidget(_addButton);
_removeButton = new QPushButton("Remove");
connect(
_removeButton, &QPushButton::clicked,
this, &KeybindingsDialog::listItemRemove
);
box->addWidget(_removeButton);
box->addStretch();
layout->addLayout(box);
}
layout->addWidget(new Line);
{
QGridLayout* box = new QGridLayout;
_keyModLabel = new QLabel("Key Modifier");
box->addWidget(_keyModLabel, 0, 0);
_keyModCombo = new QComboBox;
_keyModCombo->setToolTip(
"Modifier keys to hold while key is pressed (blank means none)"
);
QStringList comboModKeysStringList;
int modIdx = 0;
for (const std::pair<const int, std::string>& m : KeyModifierNames) {
comboModKeysStringList += QString::fromStdString(m.second);
_mapModKeyComboBoxIndexToKeyValue.push_back(modIdx++);
}
_keyModCombo->addItems(comboModKeysStringList);
connect(
_keyModCombo, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &KeybindingsDialog::keyModSelected
);
box->addWidget(_keyModCombo, 0, 1);
_keyLabel = new QLabel("Key");
box->addWidget(_keyLabel, 1, 0);
_keyCombo = new QComboBox;
_keyCombo->setToolTip("Key to press for this keybinding");
QStringList comboKeysStringList;
for (int i = 0; i < static_cast<int>(Key::Last); ++i) {
if (KeyNames.find(i) != KeyNames.end()) {
comboKeysStringList += QString::fromStdString(KeyNames.at(i));
// Create map to relate key combo box to integer value defined in Key
_mapKeyComboBoxIndexToKeyValue.push_back(i);
}
}
_keyCombo->addItems(comboKeysStringList);
connect(
_keyCombo, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &KeybindingsDialog::keySelected
);
box->addWidget(_keyCombo, 1, 1);
_nameLabel = new QLabel("Name:");
box->addWidget(_nameLabel, 2, 0);
_nameEdit = new QLineEdit;
_nameEdit->setToolTip("Name assigned to this keybinding");
box->addWidget(_nameEdit, 2, 1);
_guiPathLabel = new QLabel("GUI Path:");
box->addWidget(_guiPathLabel, 3, 0);
_guiPathEdit = new QLineEdit;
_guiPathEdit->setToolTip(
"[OPTIONAL] Path for where this keybinding appears in GUI menu"
);
box->addWidget(_guiPathEdit, 3, 1);
_documentationLabel = new QLabel("Documentation:");
box->addWidget(_documentationLabel, 4, 0);
_documentationEdit = new QLineEdit;
_documentationEdit->setToolTip(
"[OPTIONAL] Documentation entry for keybinding"
);
box->addWidget(_documentationEdit, 4, 1);
_localCheck = new QCheckBox("Local");
_localCheck->setToolTip(
"Determines whether the command, when executed, should be shared with "
"connected instances or only executed locally"
);
box->addWidget(_localCheck, 5, 0, 1, 2);
_scriptLabel = new QLabel("Script");
box->addWidget(_scriptLabel, 6, 0, 1, 2);
_chooseScriptsButton = new QPushButton("Choose Scripts");
connect(
_chooseScriptsButton, &QPushButton::clicked,
this, &KeybindingsDialog::chooseScripts
);
box->addWidget(_chooseScriptsButton, 6, 1, 1, 1);
_scriptEdit = new QTextEdit;
_scriptEdit->setAcceptRichText(false);
_scriptEdit->setToolTip("Command(s) to execute at keypress event");
_scriptEdit->setTabChangesFocus(true);
box->addWidget(_scriptEdit, 7, 0, 1, 2);
box->setRowStretch(7, 1);
QBoxLayout* buttonBox = new QHBoxLayout;
_saveButton = new QPushButton("Save");
connect(
_saveButton, &QPushButton::clicked,
this, &KeybindingsDialog::listItemSave
);
buttonBox->addWidget(_saveButton);
_cancelButton = new QPushButton("Cancel");
connect(
_cancelButton, &QPushButton::clicked,
this, &KeybindingsDialog::listItemCancelSave
);
buttonBox->addWidget(_cancelButton);
buttonBox->addStretch();
box->addLayout(buttonBox, 8, 1, 1, 2);
layout->addLayout(box);
}
layout->addWidget(new Line);
{
QBoxLayout* footerLayout = new QHBoxLayout;
_errorMsg = new QLabel;
_errorMsg->setObjectName("error-message");
_errorMsg->setWordWrap(true);
footerLayout->addWidget(_errorMsg);
_buttonBox = new QDialogButtonBox;
_buttonBox->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel);
QObject::connect(
_buttonBox, &QDialogButtonBox::accepted,
this, &KeybindingsDialog::parseSelections
);
QObject::connect(
_buttonBox, &QDialogButtonBox::rejected,
this, &KeybindingsDialog::reject
);
footerLayout->addWidget(_buttonBox);
layout->addLayout(footerLayout);
}
}
void KeybindingsDialog::listItemSelected() {
QListWidgetItem *item = _list->currentItem();
int index = _list->row(item);
_currentKeybindingSelection = index;
if (_data.size() > 0) {
Profile::Keybinding& k = _data[index];
const int modifierKey = indexInKeyMapping(
_mapModKeyComboBoxIndexToKeyValue,
static_cast<int>(k.key.modifier)
);
_keyModCombo->setCurrentIndex(modifierKey);
if (k.key.key == Key::Unknown) {
_keyCombo->setCurrentIndex(0);
}
else {
const int key = indexInKeyMapping(
_mapKeyComboBoxIndexToKeyValue,
static_cast<int>(k.key.key)
);
_keyCombo->setCurrentIndex(key);
}
// Do key here
_nameEdit->setText(QString::fromStdString(k.name));
_guiPathEdit->setText(QString::fromStdString(k.guiPath));
_documentationEdit->setText(QString::fromStdString(k.documentation));
_localCheck->setChecked(k.isLocal);
_scriptEdit->setText(QString::fromStdString(k.script));
}
transitionToEditMode();
}
void KeybindingsDialog::keySelected(int index) {
_errorMsg->clear();
int selectedKey = _mapKeyComboBoxIndexToKeyValue[index];
checkForNumberKeyConflict(selectedKey);
checkForBindingConflict(_keyModCombo->currentIndex(), selectedKey);
}
void KeybindingsDialog::keyModSelected(int index) {
_errorMsg->clear();
int selectedKey = _mapModKeyComboBoxIndexToKeyValue[index];
checkForBindingConflict(selectedKey,
_mapKeyComboBoxIndexToKeyValue.at(_keyCombo->currentIndex()));
}
void KeybindingsDialog::addStringToErrorDisplay(const QString& newString) {
QString errorContents = _errorMsg->text();
bool alreadyContainsString = (errorContents.indexOf(newString, 0) != -1);
if (!alreadyContainsString) {
errorContents = newString + errorContents;
_errorMsg->setText(errorContents);
}
}
int KeybindingsDialog::indexInKeyMapping(std::vector<int>& mapVector, int keyInt) {
const auto it = std::find(mapVector.cbegin(), mapVector.cend(), keyInt);
return static_cast<int>(std::distance(mapVector.cbegin(), it));
}
bool KeybindingsDialog::isLineEmpty(int index) {
bool isEmpty = true;
if (!_list->item(index)->text().isEmpty()) {
isEmpty = false;
}
if (!_data.empty() && !_data.at(0).name.empty()) {
isEmpty = false;
}
return isEmpty;
}
void KeybindingsDialog::listItemAdded() {
_data.push_back(BlankKey);
_list->addItem(new QListWidgetItem(" (Enter details below & click 'Save')"));
// Scroll down to that blank line highlighted
_list->setCurrentRow(_list->count() - 1);
// Blank-out the 2 text fields, set combo box to index 0
_keyModCombo->setCurrentIndex(static_cast<int>(_data.back().key.modifier));
if (_data.back().key.key == Key::Unknown) {
_keyCombo->setCurrentIndex(0);
}
else {
_keyCombo->setCurrentIndex(static_cast<int>(_data.back().key.key));
}
_keyModCombo->setFocus(Qt::OtherFocusReason);
_nameEdit->setText(QString::fromStdString(_data.back().name));
_guiPathEdit->setText("/");
_documentationEdit->setText(QString::fromStdString(_data.back().documentation));
_localCheck->setChecked(false);
_scriptEdit->setText(QString::fromStdString(_data.back().script));
_currentKeybindingSelection = static_cast<int>(_data.size() - 1);
_editModeNewItem = true;
}
void KeybindingsDialog::checkForNumberKeyConflict(int key) {
const QString numKeyWarning = "Warning: Using a number key may conflict with the "
"keybindings for simulation time increments.\n";
if (key >= static_cast<int>(Key::Num0) && key <= static_cast<int>(Key::Num9)) {
addStringToErrorDisplay(numKeyWarning);
}
}
void KeybindingsDialog::checkForBindingConflict(int selectedModKey, int selectedKey) {
const QString localWarn = "Warning: New selection conflicts with binding '";
if (_currentKeybindingSelection >= static_cast<int>(_data.size())) {
return;
}
KeyModifier newModifier = static_cast<KeyModifier>(selectedModKey);
Key newKey = static_cast<Key>(selectedKey);
for (int i = 0; i < static_cast<int>(_data.size()); ++i) {
if (i == _currentKeybindingSelection) {
continue;
}
openspace::Profile::Keybinding k = _data[i];
if ((k.key.key == newKey) && (k.key.modifier == newModifier)) {
addStringToErrorDisplay(localWarn + QString::fromStdString(k.name) + "'.\n");
break;
}
}
}
void KeybindingsDialog::listItemSave() {
if (!areRequiredFormsFilled()) {
return;
}
QListWidgetItem* item = _list->currentItem();
int index = _list->row(item);
if (!_data.empty()) {
int keyModIdx = _mapModKeyComboBoxIndexToKeyValue.at(
_keyModCombo->currentIndex());
_data[index].key.modifier = static_cast<KeyModifier>(keyModIdx);
int keyIdx = _mapKeyComboBoxIndexToKeyValue.at(_keyCombo->currentIndex());
_data[index].key.key = static_cast<Key>(keyIdx);
_data[index].name = _nameEdit->text().toStdString();
_data[index].guiPath = _guiPathEdit->text().toStdString();
_data[index].documentation = _documentationEdit->text().toStdString();
_data[index].script = _scriptEdit->toPlainText().toStdString();
_data[index].isLocal = (_localCheck->isChecked());
std::string summary = createOneLineSummary(_data[index]);
_list->item(index)->setText(QString::fromStdString(summary));
}
transitionFromEditMode();
}
bool KeybindingsDialog::areRequiredFormsFilled() {
bool requiredFormsFilled = true;
std::string errors;
if (_keyCombo->currentIndex() < 0) {
errors += "Missing key";
requiredFormsFilled = false;
}
if (_nameEdit->text().length() == 0) {
if (!errors.empty()) {
errors += ", ";
}
errors += "Missing keybinding name";
requiredFormsFilled = false;
}
if (_scriptEdit->toPlainText().isEmpty()) {
if (!errors.empty()) {
errors += ", ";
}
errors += "Missing script";
requiredFormsFilled = false;
}
_errorMsg->setText(QString::fromStdString(errors));
return requiredFormsFilled;
}
void KeybindingsDialog::listItemCancelSave() {
listItemSelected();
transitionFromEditMode();
if (_editModeNewItem && !_data.empty() &&
(_data.back().name.length() == 0 || _data.back().script.length() == 0 ||
_data.back().key.key == Key::Unknown))
{
listItemRemove();
}
_editModeNewItem = false;
}
void KeybindingsDialog::listItemRemove() {
if (_list->count() > 0) {
if (_list->count() == 1) {
// Special case where last remaining item is being removed (QListWidget does
// not like the final item being removed so instead clear it & leave it)
_data.at(0) = BlankKey;
_list->item(0)->setText("");
}
else {
int index = _list->currentRow();
if (index >= 0 && index < _list->count()) {
_list->takeItem(index);
if (!_data.empty()) {
_data.erase(_data.begin() + index);
}
}
}
}
_list->clearSelection();
transitionFromEditMode();
}
void KeybindingsDialog::transitionToEditMode() {
_saveButton->setDisabled(true);
_cancelButton->setDisabled(true);
_buttonBox->setDisabled(true);
_keyLabel->setText("<font color='black'>Key</font>");
_keyModLabel->setText("<font color='black'>Key Modifier</font>");
_nameLabel->setText("<font color='black'>Name</font>");
_scriptLabel->setText("<font color='black'>Script</font>");
_guiPathLabel->setText("<font color='black'>GUI Path</font>");
_documentationLabel->setText("<font color='black'>Documentation</font>");
editBoxDisabled(false);
_errorMsg->setText("");
}
void KeybindingsDialog::transitionFromEditMode() {
_list->setDisabled(false);
_addButton->setDisabled(false);
_removeButton->setDisabled(false);
_saveButton->setDisabled(false);
_cancelButton->setDisabled(false);
_buttonBox->setDisabled(false);
_keyLabel->setText("<font color='light gray'>Key</font>");
_keyModLabel->setText("<font color='light gray'>Key Modifier</font>");
_nameLabel->setText("<font color='light gray'>Name</font>");
_scriptLabel->setText("<font color='light gray'>Script</font>");
_guiPathLabel->setText("<font color='light gray'>GUI Path</font>");
_documentationLabel->setText("<font color='light gray'>Documentation</font>");
editBoxDisabled(true);
_errorMsg->setText("");
}
void KeybindingsDialog::editBoxDisabled(bool disabled) {
_keyLabel->setDisabled(disabled);
_keyCombo->setDisabled(disabled);
_keyModLabel->setDisabled(disabled);
_keyModCombo->setDisabled(disabled);
_nameLabel->setDisabled(disabled);
_nameEdit->setDisabled(disabled);
_guiPathLabel->setDisabled(disabled);
_guiPathEdit->setDisabled(disabled);
_documentationLabel->setDisabled(disabled);
_documentationEdit->setDisabled(disabled);
_localCheck->setDisabled(disabled);
_scriptLabel->setDisabled(disabled);
_scriptEdit->setDisabled(disabled);
_cancelButton->setDisabled(disabled);
_saveButton->setDisabled(disabled);
_chooseScriptsButton->setDisabled(disabled);
}
void KeybindingsDialog::parseSelections() {
// Handle case with only one remaining but empty line
if ((_data.size() == 1) && (_data.at(0).name.empty())) {
_data.clear();
}
_profile.setKeybindings(_data);
accept();
}
void KeybindingsDialog::chooseScripts() {
_errorMsg->clear();
ScriptlogDialog d(this);
connect(&d, &ScriptlogDialog::scriptsSelected, this, &KeybindingsDialog::appendScriptsToKeybind);
d.exec();
}
void KeybindingsDialog::keyPressEvent(QKeyEvent* evt) {
if (evt->key() == Qt::Key_Enter || evt->key() == Qt::Key_Return) {
return;
}
else if (evt->key() == Qt::Key_Escape) {
if (_editModeNewItem) {
listItemCancelSave();
return;
}
}
QDialog::keyPressEvent(evt);
}

View File

@@ -35,10 +35,10 @@
#include <QPushButton>
#include <QVBoxLayout>
MarkNodesDialog::MarkNodesDialog(openspace::Profile& profile, QWidget* parent)
MarkNodesDialog::MarkNodesDialog(QWidget* parent, std::vector<std::string>* markedNodes)
: QDialog(parent)
, _profile(profile)
, _data(_profile.markNodes())
, _markedNodes(markedNodes)
, _markedNodesData(*_markedNodes)
{
setWindowTitle("Mark Interesting Nodes");
createWidgets();
@@ -55,9 +55,9 @@ void MarkNodesDialog::createWidgets() {
_list->setMovement(QListView::Free);
_list->setResizeMode(QListView::Adjust);
for (size_t i = 0; i < _data.size(); ++i) {
for (size_t i = 0; i < _markedNodesData.size(); ++i) {
_markedNodesListItems.push_back(
new QListWidgetItem(QString::fromStdString(_data[i]))
new QListWidgetItem(QString::fromStdString(_markedNodesData[i]))
);
_list->addItem(_markedNodesListItems[i]);
}
@@ -110,12 +110,17 @@ void MarkNodesDialog::listItemAdded() {
}
std::string itemToAdd = _newNode->text().toStdString();
const auto it = std::find(_data.cbegin(), _data.cend(), itemToAdd);
if (it != _data.end()) {
_list->setCurrentRow(static_cast<int>(std::distance(_data.cbegin(), it)));
const auto it = std::find(
_markedNodesData.cbegin(), _markedNodesData.cend(),
itemToAdd
);
if (it != _markedNodesData.end()) {
_list->setCurrentRow(
static_cast<int>(std::distance(_markedNodesData.cbegin(), it))
);
}
else {
_data.push_back(itemToAdd);
_markedNodesData.push_back(itemToAdd);
_markedNodesListItems.push_back(new QListWidgetItem(_newNode->text()));
_list->addItem(_markedNodesListItems.back());
@@ -136,12 +141,12 @@ void MarkNodesDialog::listItemRemove() {
}
_list->takeItem(index);
_data.erase(_data.begin() + index);
_markedNodesData.erase(_markedNodesData.begin() + index);
_markedNodesListItems.erase(_markedNodesListItems.begin() + index);
}
void MarkNodesDialog::parseSelections() {
_profile.setMarkNodes(_data);
*_markedNodes = std::move(_markedNodesData);
accept();
}

View File

@@ -34,32 +34,32 @@
#include <QVBoxLayout>
#include <algorithm>
MetaDialog::MetaDialog(openspace::Profile& profile, QWidget *parent)
MetaDialog::MetaDialog(QWidget* parent, std::optional<openspace::Profile::Meta>* meta)
: QDialog(parent)
, _profile(profile)
, _meta(meta)
{
setWindowTitle("Meta");
createWidgets();
if (_profile.meta().has_value()) {
openspace::Profile::Meta meta = *_profile.meta();
if (meta.name.has_value()) {
_nameEdit->setText(QString::fromStdString(*meta.name));
if (_meta->has_value()) {
const openspace::Profile::Meta& m = **_meta;
if (m.name.has_value()) {
_nameEdit->setText(QString::fromStdString(*m.name));
}
if (meta.version.has_value()) {
_versionEdit->setText(QString::fromStdString(*meta.version));
if (m.version.has_value()) {
_versionEdit->setText(QString::fromStdString(*m.version));
}
if (meta.description.has_value()) {
_descriptionEdit->setText(QString::fromStdString(*meta.description));
if (m.description.has_value()) {
_descriptionEdit->setText(QString::fromStdString(*m.description));
}
if (meta.author.has_value()) {
_authorEdit->setText(QString::fromStdString(*meta.author));
if (m.author.has_value()) {
_authorEdit->setText(QString::fromStdString(*m.author));
}
if (meta.url.has_value()) {
_urlEdit->setText(QString::fromStdString(*meta.url));
if (m.url.has_value()) {
_urlEdit->setText(QString::fromStdString(*m.url));
}
if (meta.license.has_value()) {
_licenseEdit->setText(QString::fromStdString(*meta.license));
if (m.license.has_value()) {
_licenseEdit->setText(QString::fromStdString(*m.license));
}
}
}
@@ -127,10 +127,10 @@ void MetaDialog::save() {
if (!_licenseEdit->text().isEmpty()) {
m.license = _licenseEdit->text().toStdString();
}
_profile.setMeta(m);
*_meta = std::move(m);
}
else {
_profile.clearMeta();
*_meta = std::nullopt;
}
accept();
}

View File

@@ -40,10 +40,11 @@ namespace {
const Profile::Module Blank = { "", "", "" };
} // namespace
ModulesDialog::ModulesDialog(Profile& profile, QWidget *parent)
ModulesDialog::ModulesDialog(QWidget* parent,
std::vector<openspace::Profile::Module>* modules)
: QDialog(parent)
, _profile(profile)
, _data(_profile.modules())
, _modules(modules)
, _moduleData(*_modules)
{
setWindowTitle("Modules");
createWidgets();
@@ -63,7 +64,7 @@ void ModulesDialog::createWidgets() {
_list->setMovement(QListView::Free);
_list->setResizeMode(QListView::Adjust);
for (const Profile::Module& m : _data) {
for (const Profile::Module& m : _moduleData) {
_list->addItem(new QListWidgetItem(createOneLineSummary(m)));
}
layout->addWidget(_list);
@@ -176,8 +177,8 @@ void ModulesDialog::listItemSelected() {
QListWidgetItem* item = _list->currentItem();
int index = _list->row(item);
if (!_data.empty()) {
const Profile::Module& m = _data[index];
if (!_moduleData.empty()) {
const Profile::Module& m = _moduleData[index];
_moduleEdit->setText(QString::fromStdString(m.name));
if (m.loadedInstruction.has_value()) {
_loadedEdit->setText(QString::fromStdString(*m.loadedInstruction));
@@ -200,7 +201,7 @@ bool ModulesDialog::isLineEmpty(int index) const {
if (!_list->item(index)->text().isEmpty()) {
isEmpty = false;
}
if (!_data.empty() && !_data.at(0).name.empty()) {
if (!_moduleData.empty() && !_moduleData.at(0).name.empty()) {
isEmpty = false;
}
return isEmpty;
@@ -213,13 +214,13 @@ void ModulesDialog::listItemAdded() {
// Special case where list is "empty" but really has one line that is blank.
// This is done because QListWidget does not seem to like having its sole
// remaining item being removed.
_data.at(0) = Blank;
_moduleData.at(0) = Blank;
_list->item(0)->setText(" (Enter details below & click 'Save')");
_list->setCurrentRow(0);
transitionToEditMode();
}
else {
_data.push_back(Blank);
_moduleData.push_back(Blank);
_list->addItem(new QListWidgetItem(" (Enter details below & click 'Save')"));
//Scroll down to that blank line highlighted
_list->setCurrentRow(_list->count() - 1);
@@ -227,16 +228,18 @@ void ModulesDialog::listItemAdded() {
}
// Blank-out the 2 text fields, set combo box to index 0
_moduleEdit->setText(QString::fromStdString(_data.back().name));
if (_data.back().loadedInstruction.has_value()) {
_loadedEdit->setText(QString::fromStdString(*_data.back().loadedInstruction));
_moduleEdit->setText(QString::fromStdString(_moduleData.back().name));
if (_moduleData.back().loadedInstruction.has_value()) {
_loadedEdit->setText(QString::fromStdString(
*_moduleData.back().loadedInstruction
));
}
else {
_loadedEdit->clear();
}
if (_data.back().notLoadedInstruction.has_value()) {
if (_moduleData.back().notLoadedInstruction.has_value()) {
_notLoadedEdit->setText(
QString::fromStdString(*_data.back().notLoadedInstruction)
QString::fromStdString(*_moduleData.back().notLoadedInstruction)
);
}
else {
@@ -255,11 +258,11 @@ void ModulesDialog::listItemSave() {
QListWidgetItem* item = _list->currentItem();
int index = _list->row(item);
if ( _data.size() > 0) {
_data[index].name = _moduleEdit->text().toStdString();
_data[index].loadedInstruction = _loadedEdit->text().toStdString();
_data[index].notLoadedInstruction = _notLoadedEdit->text().toStdString();
_list->item(index)->setText(createOneLineSummary(_data[index]));
if (_moduleData.size() > 0) {
_moduleData[index].name = _moduleEdit->text().toStdString();
_moduleData[index].loadedInstruction = _loadedEdit->text().toStdString();
_moduleData[index].notLoadedInstruction = _notLoadedEdit->text().toStdString();
_list->item(index)->setText(createOneLineSummary(_moduleData[index]));
}
transitionFromEditMode();
_editModeNewItem = false;
@@ -267,7 +270,7 @@ void ModulesDialog::listItemSave() {
void ModulesDialog::listItemCancelSave() {
transitionFromEditMode();
if (_editModeNewItem && !_data.empty() && _data.back().name.empty()) {
if (_editModeNewItem && !_moduleData.empty() && _moduleData.back().name.empty()) {
listItemRemove();
}
_editModeNewItem = false;
@@ -279,15 +282,15 @@ void ModulesDialog::listItemRemove() {
if (_list->count() == 1) {
// Special case where last remaining item is being removed (QListWidget
// doesn't like the final item being removed so instead clear it)
_data.at(0) = Blank;
_moduleData.at(0) = Blank;
_list->item(0)->setText("");
}
else {
int index = _list->currentRow();
if (index >= 0 && index < _list->count()) {
delete _list->takeItem(index);
if (!_data.empty()) {
_data.erase(_data.begin() + index);
if (!_moduleData.empty()) {
_moduleData.erase(_moduleData.begin() + index);
}
}
}
@@ -336,10 +339,10 @@ void ModulesDialog::editBoxDisabled(bool disabled) {
void ModulesDialog::parseSelections() {
// Handle case with only one remaining but empty line
if ((_data.size() == 1) && (_data.at(0).name.empty())) {
_data.clear();
if ((_moduleData.size() == 1) && (_moduleData.at(0).name.empty())) {
_moduleData.clear();
}
_profile.setModules(_data);
*_modules = std::move(_moduleData);
accept();
}

View File

@@ -24,11 +24,11 @@
#include "profile/profileedit.h"
#include "profile/actiondialog.h"
#include "profile/additionalscriptsdialog.h"
#include "profile/assetsdialog.h"
#include "profile/cameradialog.h"
#include "profile/deltatimesdialog.h"
#include "profile/keybindingsdialog.h"
#include "profile/line.h"
#include "profile/marknodesdialog.h"
#include "profile/metadialog.h"
@@ -36,6 +36,7 @@
#include "profile/propertiesdialog.h"
#include "profile/timedialog.h"
#include <openspace/scene/profile.h>
#include <ghoul/fmt.h>
#include <QDialogButtonBox>
#include <QKeyEvent>
#include <QLabel>
@@ -69,17 +70,18 @@ namespace {
return results;
}
std::string summarizeKeybindings(const std::vector<Profile::Keybinding>& keybindings)
std::string summarizeKeybindings(const std::vector<Profile::Keybinding>& keybindings,
const std::vector<Profile::Action>& actions)
{
std::string results;
for (Profile::Keybinding k : keybindings) {
results += k.name + " (";
int keymod = static_cast<int>(k.key.modifier);
if (keymod != static_cast<int>(openspace::KeyModifier::NoModifier)) {
results += openspace::KeyModifierNames.at(keymod) + "+";
}
results += openspace::KeyNames.at(static_cast<int>(k.key.key));
results += ")\n";
const auto it = std::find_if(
actions.cbegin(), actions.cend(),
[id = k.action](const Profile::Action& a) { return a.identifier == id; }
);
std::string name = it != actions.end() ? it->name : "Unknown action";
results += fmt::format("{} ({})\n", name, ghoul::to_string(k.key));
}
return results;
}
@@ -87,7 +89,7 @@ namespace {
std::string summarizeProperties(const std::vector<Profile::Property>& properties) {
std::string results;
for (openspace::Profile::Property p : properties) {
results += p.name + " = " + p.value + '\n';
results += fmt::format("{} = {}\n", p.name, p.value);
}
return results;
}
@@ -333,26 +335,26 @@ void ProfileEdit::createWidgets(const std::string& profileName) {
}
void ProfileEdit::initSummaryTextForEachCategory() {
_modulesLabel->setText(labelText(_profile.modules().size(), "Modules"));
_modulesLabel->setText(labelText(_profile.modules.size(), "Modules"));
_assetsLabel->setText(labelText(_profile.assets().size(), "Assets"));
_assetsEdit->setText(QString::fromStdString(summarizeAssets(_profile.assets())));
_assetsLabel->setText(labelText(_profile.assets.size(), "Assets"));
_assetsEdit->setText(QString::fromStdString(summarizeAssets(_profile.assets)));
_propertiesLabel->setText(labelText(_profile.properties().size(), "Properties"));
_propertiesLabel->setText(labelText(_profile.properties.size(), "Properties"));
_propertiesEdit->setText(
QString::fromStdString(summarizeProperties(_profile.properties()))
QString::fromStdString(summarizeProperties(_profile.properties))
);
_keybindingsLabel->setText(labelText(_profile.keybindings().size(), "Keybindings"));
_keybindingsEdit->setText(
QString::fromStdString(summarizeKeybindings(_profile.keybindings()))
);
_keybindingsLabel->setText(labelText(_profile.keybindings.size(), "Keybindings"));
_keybindingsEdit->setText(QString::fromStdString(
summarizeKeybindings(_profile.keybindings, _profile.actions)
));
_deltaTimesLabel->setText(
labelText(_profile.deltaTimes().size(), "Simulation Time Increments")
labelText(_profile.deltaTimes.size(), "Simulation Time Increments")
);
_interestingNodesLabel->setText(
labelText(_profile.markNodes().size(), "Mark Interesting Nodes")
labelText(_profile.markNodes.size(), "Mark Interesting Nodes")
);
}
@@ -401,68 +403,68 @@ void ProfileEdit::duplicateProfile() {
void ProfileEdit::openMeta() {
_errorMsg->clear();
MetaDialog(_profile, this).exec();
MetaDialog(this, &_profile.meta).exec();
}
void ProfileEdit::openModules() {
_errorMsg->clear();
ModulesDialog(_profile, this).exec();
_modulesLabel->setText(labelText(_profile.modules().size(), "Modules"));
ModulesDialog(this, &_profile.modules).exec();
_modulesLabel->setText(labelText(_profile.modules.size(), "Modules"));
}
void ProfileEdit::openProperties() {
_errorMsg->clear();
PropertiesDialog(_profile, this).exec();
_propertiesLabel->setText(labelText(_profile.properties().size(), "Properties"));
PropertiesDialog(this, &_profile.properties).exec();
_propertiesLabel->setText(labelText(_profile.properties.size(), "Properties"));
_propertiesEdit->setText(
QString::fromStdString(summarizeProperties(_profile.properties()))
QString::fromStdString(summarizeProperties(_profile.properties))
);
}
void ProfileEdit::openKeybindings() {
_errorMsg->clear();
KeybindingsDialog(_profile, this).exec();
_keybindingsLabel->setText(labelText(_profile.keybindings().size(), "Keybindings"));
_keybindingsEdit->setText(
QString::fromStdString(summarizeKeybindings(_profile.keybindings()))
);
ActionDialog(this, &_profile.actions, &_profile.keybindings).exec();
_keybindingsLabel->setText(labelText(_profile.keybindings.size(), "Keybindings"));
_keybindingsEdit->setText(QString::fromStdString(
summarizeKeybindings(_profile.keybindings, _profile.actions)
));
}
void ProfileEdit::openAssets() {
_errorMsg->clear();
AssetsDialog(_profile, _assetBasePath, _userAssetBasePath, this).exec();
_assetsLabel->setText(labelText(_profile.assets().size(), "Assets"));
_assetsEdit->setText(QString::fromStdString(summarizeAssets(_profile.assets())));
AssetsDialog(this, &_profile, _assetBasePath, _userAssetBasePath).exec();
_assetsLabel->setText(labelText(_profile.assets.size(), "Assets"));
_assetsEdit->setText(QString::fromStdString(summarizeAssets(_profile.assets)));
}
void ProfileEdit::openTime() {
_errorMsg->clear();
TimeDialog(_profile, this).exec();
TimeDialog(this, &_profile.time).exec();
}
void ProfileEdit::openDeltaTimes() {
_errorMsg->clear();
DeltaTimesDialog(_profile, this).exec();
DeltaTimesDialog(this, &_profile.deltaTimes).exec();
_deltaTimesLabel->setText(
labelText(_profile.deltaTimes().size(), "Simulation Time Increments")
labelText(_profile.deltaTimes.size(), "Simulation Time Increments")
);
}
void ProfileEdit::openAddedScripts() {
_errorMsg->clear();
AdditionalScriptsDialog(_profile, this).exec();
AdditionalScriptsDialog(this, &_profile.additionalScripts).exec();
}
void ProfileEdit::openCamera() {
_errorMsg->clear();
CameraDialog(_profile, this).exec();
CameraDialog(this, &_profile.camera).exec();
}
void ProfileEdit::openMarkNodes() {
_errorMsg->clear();
MarkNodesDialog(_profile, this).exec();
MarkNodesDialog(this, &_profile.markNodes).exec();
_interestingNodesLabel->setText(
labelText(_profile.markNodes().size(), "Mark Interesting Nodes")
labelText(_profile.markNodes.size(), "Mark Interesting Nodes")
);
}

View File

@@ -46,10 +46,11 @@ namespace {
};
} // namespace
PropertiesDialog::PropertiesDialog(Profile& profile, QWidget *parent)
PropertiesDialog::PropertiesDialog(QWidget* parent,
std::vector<openspace::Profile::Property>* properties)
: QDialog(parent)
, _profile(profile)
, _data(_profile.properties())
, _properties(properties)
, _propertyData(*_properties)
{
setWindowTitle("Set Property Values");
createWidgets();
@@ -65,8 +66,8 @@ void PropertiesDialog::createWidgets() {
_list, &QListWidget::itemSelectionChanged,
this, &PropertiesDialog::listItemSelected
);
for (size_t i = 0; i < _data.size(); ++i) {
_list->addItem(new QListWidgetItem(createOneLineSummary(_data[i])));
for (size_t i = 0; i < _propertyData.size(); ++i) {
_list->addItem(new QListWidgetItem(createOneLineSummary(_propertyData[i])));
}
layout->addWidget(_list);
}
@@ -172,8 +173,8 @@ void PropertiesDialog::listItemSelected() {
QListWidgetItem* item = _list->currentItem();
int index = _list->row(item);
if (_data.size() > 0) {
Profile::Property& p = _data[index];
if (_propertyData.size() > 0) {
Profile::Property& p = _propertyData[index];
if (p.setType == Profile::Property::SetType::SetPropertyValueSingle) {
_commandCombo->setCurrentIndex(0);
}
@@ -191,7 +192,7 @@ bool PropertiesDialog::isLineEmpty(int index) {
if (!_list->item(index)->text().isEmpty()) {
isEmpty = false;
}
if (!_data.empty() && !_data.at(0).name.empty()) {
if (!_propertyData.empty() && !_propertyData.at(0).name.empty()) {
isEmpty = false;
}
return isEmpty;
@@ -204,13 +205,13 @@ void PropertiesDialog::listItemAdded() {
// Special case where list is "empty" but really has one line that is blank.
// This is done because QListWidget does not seem to like having its sole
// remaining item being removed.
_data.at(0) = Blank;
_propertyData.at(0) = Blank;
_list->item(0)->setText(" (Enter details below & click 'Save')");
_list->setCurrentRow(0);
transitionToEditMode();
}
else {
_data.push_back(Blank);
_propertyData.push_back(Blank);
_list->addItem(new QListWidgetItem(" (Enter details below & click 'Save')"));
//Scroll down to that blank line highlighted
_list->setCurrentRow(_list->count() - 1);
@@ -218,8 +219,8 @@ void PropertiesDialog::listItemAdded() {
// Blank-out the 2 text fields, set combo box to index 0
_commandCombo->setCurrentIndex(0);
_propertyEdit->setText(QString::fromStdString(_data.back().name));
_valueEdit->setText(QString::fromStdString(_data.back().value));
_propertyEdit->setText(QString::fromStdString(_propertyData.back().name));
_valueEdit->setText(QString::fromStdString(_propertyData.back().value));
_commandCombo->setFocus(Qt::OtherFocusReason);
_editModeNewItem = true;
}
@@ -232,16 +233,17 @@ void PropertiesDialog::listItemSave() {
QListWidgetItem* item = _list->currentItem();
int index = _list->row(item);
if ( _data.size() > 0) {
if (_propertyData.size() > 0) {
if (_commandCombo->currentIndex() == 0) {
_data[index].setType = Profile::Property::SetType::SetPropertyValueSingle;
_propertyData[index].setType =
Profile::Property::SetType::SetPropertyValueSingle;
}
else {
_data[index].setType = Profile::Property::SetType::SetPropertyValue;
_propertyData[index].setType = Profile::Property::SetType::SetPropertyValue;
}
_data[index].name = _propertyEdit->text().toStdString();
_data[index].value = _valueEdit->text().toStdString();
_list->item(index)->setText(createOneLineSummary(_data[index]));
_propertyData[index].name = _propertyEdit->text().toStdString();
_propertyData[index].value = _valueEdit->text().toStdString();
_list->item(index)->setText(createOneLineSummary(_propertyData[index]));
}
transitionFromEditMode();
_editModeNewItem = false;
@@ -269,8 +271,10 @@ void PropertiesDialog::listItemCancelSave() {
listItemSelected();
transitionFromEditMode();
if (_editModeNewItem) {
if (_data.size() > 0) {
if (_data.back().name.length() == 0 || _data.back().value.length() == 0) {
if (_propertyData.size() > 0) {
if (_propertyData.back().name.length() == 0 ||
_propertyData.back().value.length() == 0)
{
listItemRemove();
}
}
@@ -284,15 +288,15 @@ void PropertiesDialog::listItemRemove() {
if (_list->count() == 1) {
//Special case where last remaining item is being removed (QListWidget
// doesn't like the final item being removed so instead clear it)
_data.at(0) = Blank;
_propertyData.at(0) = Blank;
_list->item(0)->setText("");
}
else {
int index = _list->currentRow();
if (index >= 0 && index < _list->count()) {
delete _list->takeItem(index);
if (_data.size() > 0) {
_data.erase(_data.begin() + index);
if (_propertyData.size() > 0) {
_propertyData.erase(_propertyData.begin() + index);
}
}
}
@@ -341,10 +345,10 @@ void PropertiesDialog::editBoxDisabled(bool disabled) {
void PropertiesDialog::parseSelections() {
// Handle case with only one remaining but empty line
if ((_data.size() == 1) && (_data.at(0).name.compare("") == 0)) {
_data.clear();
if ((_propertyData.size() == 1) && (_propertyData.at(0).name.compare("") == 0)) {
_propertyData.clear();
}
_profile.setProperties(_data);
*_properties = std::move(_propertyData);
accept();
}

View File

@@ -37,20 +37,20 @@
using namespace openspace;
TimeDialog::TimeDialog(openspace::Profile& profile, QWidget* parent)
TimeDialog::TimeDialog(QWidget* parent, std::optional<openspace::Profile::Time>* time)
: QDialog(parent)
, _profile(profile)
, _time(time)
{
setWindowTitle("Time");
createWidgets();
QStringList types = { "Absolute", "Relative" };
_typeCombo->addItems(types);
if (_profile.time().has_value()) {
_data = *_profile.time();
if (_data.type == Profile::Time::Type::Relative) {
if (_data.value == "") {
_data.value = "now";
if (_time->has_value()) {
_timeData = **_time;
if (_timeData.type == Profile::Time::Type::Relative) {
if (_timeData.value == "") {
_timeData.value = "now";
}
_relativeEdit->setSelection(0, _relativeEdit->text().length());
}
@@ -59,11 +59,11 @@ TimeDialog::TimeDialog(openspace::Profile& profile, QWidget* parent)
}
}
else {
_data.type = Profile::Time::Type::Relative;
_data.value = "now";
_timeData.type = Profile::Time::Type::Relative;
_timeData.value = "now";
}
_initializedAsAbsolute = (_data.type == Profile::Time::Type::Absolute);
enableAccordingToType(static_cast<int>(_data.type));
_initializedAsAbsolute = (_timeData.type == Profile::Time::Type::Absolute);
enableAccordingToType(static_cast<int>(_timeData.type));
}
void TimeDialog::createWidgets() {
@@ -117,15 +117,15 @@ void TimeDialog::enableAccordingToType(int idx) {
_relativeEdit->setText("now");
}
else {
_relativeEdit->setText(QString::fromStdString(_data.value));
_relativeEdit->setText(QString::fromStdString(_timeData.value));
}
_relativeEdit->setFocus(Qt::OtherFocusReason);
}
else {
_relativeEdit->setText("<font color='gray'>Relative Time:</font>");
size_t tIdx = _data.value.find_first_of('T', 0);
QString importDate = QString::fromStdString(_data.value.substr(0, tIdx));
QString importTime = QString::fromStdString(_data.value.substr(tIdx + 1));
size_t tIdx = _timeData.value.find_first_of('T', 0);
QString importDate = QString::fromStdString(_timeData.value.substr(0, tIdx));
QString importTime = QString::fromStdString(_timeData.value.substr(tIdx + 1));
_absoluteEdit->setDate(QDate::fromString(importDate, Qt::DateFormat::ISODate));
_absoluteEdit->setTime(QTime::fromString(importTime));
_relativeEdit->clear();
@@ -144,13 +144,13 @@ void TimeDialog::approved() {
constexpr const int Relative = static_cast<int>(Profile::Time::Type::Relative);
if (_typeCombo->currentIndex() == Relative) {
if (_relativeEdit->text().isEmpty()) {
_profile.clearTime();
*_time = std::nullopt;
}
else {
Profile::Time t;
t.type = Profile::Time::Type::Relative;
t.value = _relativeEdit->text().toStdString();
_profile.setTime(t);
*_time = t;
}
}
else {
@@ -161,7 +161,7 @@ void TimeDialog::approved() {
_absoluteEdit->date().toString("yyyy-MM-dd").toStdString(),
_absoluteEdit->time().toString().toStdString()
);
_profile.setTime(t);
*_time = t;
}
accept();
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -22,58 +22,49 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/engine/globals.h>
#include <ghoul/logging/logmanager.h>
#ifndef __OPENSPACE_CORE___ACTION___H__
#define __OPENSPACE_CORE___ACTION___H__
namespace {
#include <ghoul/misc/boolean.h>
#include <string>
openspace::interaction::ShortcutManager::ShortcutInformation extractInfo(lua_State* L,
int nArguments,
bool isSync)
{
openspace::interaction::ShortcutManager::ShortcutInformation i = {
ghoul::lua::value<std::string>(L, 1, ghoul::lua::PopValue::No),
ghoul::lua::value<std::string>(L, 2, ghoul::lua::PopValue::No),
openspace::interaction::ShortcutManager::IsSynchronized(isSync),
nArguments >= 3 ?
ghoul::lua::value<std::string>(L, 3, ghoul::lua::PopValue::No) :
"",
nArguments == 4 ?
ghoul::lua::value<std::string>(L, 4, ghoul::lua::PopValue::No) :
""
};
lua_pop(L, nArguments);
return i;
}
namespace openspace::interaction {
} // namespace
struct Action {
BooleanType(IsSynchronized);
namespace openspace::luascriptfunctions {
/// Unique identifier that identifies this action. There is no special naming scheme
/// that we enforce, we are trying to stick to the same . separated structure that
/// hopefully provides some protection against accidentally reusing identifiers
std::string identifier;
int clearShortcuts(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::clearShortcuts");
global::shortcutManager->resetShortcuts();
return 0;
}
/// The Lua script that gets executed whenever this action is triggered. Optional
/// parameters can be passed to actions which are accessible through an `args`
/// variable that contains all of the arguments passed into the action. This means
/// that the provided script must not use this variable name itself or the script will
/// not successfully execute
std::string command;
int bindShortcut(lua_State* L) {
int n = ghoul::lua::checkArgumentsAndThrow(L, { 2, 4 }, "lua::bindShortcut");
/// The human-readable name of this action. This name must not be unique, but it is
/// recommended that the combination of GuiPath + name should be unique to prevent
/// user confusion
std::string name;
interaction::ShortcutManager::ShortcutInformation info = extractInfo(L, n, true);
global::shortcutManager->addShortcut(std::move(info));
/// A user-facing description of what the action does when it gets triggered. If the
/// action uses optional arguments, they should be described in here, too
std::string documentation;
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
return 0;
}
/// This variable defines a subdivision of where this action is placed in a user
/// interface. The individual path components are separated by '/' with a leading '/'
/// for the root path
std::string guiPath;
int bindShortcutLocal(lua_State* L) {
int n = ghoul::lua::checkArgumentsAndThrow(L, { 2, 4 }, "lua::bindShortcutLocal");
/// If this value is set to `Yes`, the execution of this action is synchronized to
/// other OpenSpace instances, for example other nodes in a cluster environment, or
/// to other OpenSpace instances using a parallel connection
IsSynchronized synchronization = IsSynchronized::Yes;
};
interaction::ShortcutManager::ShortcutInformation info = extractInfo(L, n, false);
global::shortcutManager->addShortcut(std::move(info));
} // namespace openspace::interaction
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
return 0;
}
} // namespace openspace::luascriptfunctions
#endif // __OPENSPACE_CORE___ACTION___H__

View File

@@ -22,39 +22,34 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_CORE___SHORTCUTMANAGER___H__
#define __OPENSPACE_CORE___SHORTCUTMANAGER___H__
#ifndef __OPENSPACE_CORE___ACTIONMANAGER___H__
#define __OPENSPACE_CORE___ACTIONMANAGER___H__
#include <ghoul/misc/boolean.h>
#include <string>
#include <vector>
#include <openspace/interaction/action.h>
#include <unordered_map>
namespace ghoul { class Dictionary; }
namespace openspace::scripting { struct LuaLibrary; }
namespace openspace::interaction {
class ShortcutManager {
class ActionManager {
public:
BooleanType(IsSynchronized);
bool hasAction(const std::string& identifier) const;
void registerAction(Action action);
void removeAction(const std::string& identifier);
const Action& action(const std::string& identifier) const;
std::vector<Action> actions() const;
struct ShortcutInformation {
std::string name;
std::string script;
IsSynchronized synchronization;
std::string documentation;
std::string guiPath;
};
void resetShortcuts();
void addShortcut(ShortcutInformation info);
const std::vector<ShortcutInformation>& shortcuts() const;
void triggerAction(const std::string& identifier,
const ghoul::Dictionary& arguments) const;
static scripting::LuaLibrary luaLibrary();
private:
std::vector<ShortcutInformation> _shortcuts;
std::unordered_map<unsigned int, Action> _actions;
};
} // namespace openspace::interaction
#endif // __OPENSPACE_CORE___SHORTCUTMANAGER___H__
#endif // __OPENSPACE_CORE___ACTIONMANAGER___H__

View File

@@ -28,7 +28,6 @@
#include <openspace/documentation/documentationgenerator.h>
#include <openspace/util/keys.h>
#include <ghoul/misc/boolean.h>
namespace openspace {
class Camera;
@@ -41,33 +40,15 @@ namespace openspace::interaction {
class KeybindingManager : public DocumentationGenerator {
public:
BooleanType(IsSynchronized);
struct KeyInformation {
std::string command;
IsSynchronized synchronization;
std::string documentation;
std::string name;
std::string guiPath;
};
KeybindingManager();
void resetKeyBindings();
void bindKeyLocal(Key key, KeyModifier modifier, std::string luaCommand,
std::string documentation = "", std::string name = "", std::string guiPath = "");
void bindKey(Key key, KeyModifier modifier, std::string action);
void bindKey(Key key, KeyModifier modifier, std::string luaCommand,
std::string documentation = "", std::string name = "", std::string guiPath = "");
void removeKeyBinding(const std::string& key);
void removeKeyBinding(const KeyWithModifier& key);
std::vector<std::pair<KeyWithModifier, KeyInformation>> keyBinding(
const std::string& key) const;
std::vector<std::pair<KeyWithModifier, KeyInformation>> keyBinding(
std::vector<std::pair<KeyWithModifier, std::string>> keyBinding(
const KeyWithModifier& key) const;
static scripting::LuaLibrary luaLibrary();
@@ -76,10 +57,10 @@ public:
std::string generateJson() const override;
const std::multimap<KeyWithModifier, KeyInformation>& keyBindings() const;
const std::multimap<KeyWithModifier, std::string>& keyBindings() const;
private:
std::multimap<KeyWithModifier, KeyInformation> _keyLua;
std::multimap<KeyWithModifier, std::string> _keyLua;
};
} // namespace openspace::interaction

View File

@@ -79,15 +79,20 @@ public:
SetType setType;
std::string name;
std::string value;
};
struct Keybinding {
KeyWithModifier key;
struct Action {
std::string identifier;
std::string documentation;
std::string name;
std::string guiPath;
bool isLocal;
std::string script;
};
struct Keybinding {
KeyWithModifier key;
std::string action;
};
struct Time {
enum class Type {
Absolute,
@@ -122,8 +127,6 @@ public:
explicit Profile(const std::string& content);
std::string serialize() const;
std::string convertToScene() const;
/**
* Saves all current settings, starting from the profile that was loaded at startup,
* and all of the property & asset changes that were made since startup.
@@ -131,46 +134,29 @@ public:
void saveCurrentSettingsToProfile(const properties::PropertyOwner& rootOwner,
std::string currentTime, interaction::NavigationState navState);
/// If the value passed to this function is 'true', the addAsset and removeAsset
/// functions will be no-ops instead
void setIgnoreUpdates(bool ignoreUpdates);
/// Adds a new asset and checks for duplicates
/// Adds a new asset and checks for duplicates unless the `ignoreUpdates` member is
/// set to `true`
void addAsset(const std::string& path);
/// Removes an asset
/// Removes an asset unless the `ignoreUpdates` member is set to `true`
void removeAsset(const std::string& path);
/// Removes all assets
void clearAssets();
static constexpr const Version CurrentVersion = Version{ 1, 1 };
Version version() const;
std::vector<Module> modules() const;
std::optional<Meta> meta() const;
std::vector<std::string> assets() const;
std::vector<Property> properties() const;
std::vector<Keybinding> keybindings() const;
std::optional<Time> time() const;
std::vector<double> deltaTimes() const;
std::optional<CameraType> camera() const;
std::vector<std::string> markNodes() const;
std::vector<std::string> additionalScripts() const;
void clearMeta();
void clearTime();
void clearCamera();
void setVersion(Version v);
void setModules(std::vector<Module>& m);
void setMeta(Meta m);
void setProperties(std::vector<Property>& p);
void setKeybindings(std::vector<Keybinding>& k);
void setTime(Time t);
void setDeltaTimes(std::vector<double> dt);
void setCamera(CameraType c);
void setMarkNodes(std::vector<std::string>& n);
void setAdditionalScripts(std::vector<std::string>& s);
Version version = CurrentVersion;
std::vector<Module> modules;
std::optional<Meta> meta;
std::vector<std::string> assets;
std::vector<Property> properties;
std::vector<Action> actions;
std::vector<Keybinding> keybindings;
std::optional<Time> time;
std::vector<double> deltaTimes;
std::optional<CameraType> camera;
std::vector<std::string> markNodes;
std::vector<std::string> additionalScripts;
bool ignoreUpdates = false;
/**
* Returns the Lua library that contains all Lua functions available to provide
@@ -178,25 +164,21 @@ public:
* \return The Lua library that contains all Lua functions available for profiles
*/
static scripting::LuaLibrary luaLibrary();
private:
static constexpr const Version CurrentVersion = Version { 1, 0 };
Version _version = CurrentVersion;
std::vector<Module> _modules;
std::optional<Meta> _meta;
std::vector<std::string> _assets;
std::vector<Property> _properties;
std::vector<Keybinding> _keybindings;
std::optional<Time> _time;
std::vector<double> _deltaTimes;
std::optional<CameraType> _camera;
std::vector<std::string> _markNodes;
std::vector<std::string> _additionalScripts;
bool _ignoreUpdates = false;
};
/**
* This function takes a profile and returns its asset-ifyied version as a string. This
* is the format that is saved as a scene file that, in turn, is provided to OpenSpace as
* the root asset to load. This function is a key step to be able to load a Profile in
* OpenSpace (at the moment).
*
* \param profile The profile that should be converted to the asset-file format
*
* \return The string representation of the provided profile, ready to be loaded as an
* asset
*/
std::string convertToScene(const Profile& profile);
} // namespace openspace
#endif // __OPENSPACE_CORE___PROFILE___H__

View File

@@ -58,545 +58,366 @@
// definitions GLFW v3.1
#include <ghoul/misc/stringconversion.h>
#include <array>
#include <map>
#include <string>
#include <unordered_map>
namespace openspace {
enum class KeyAction : int {
//////////////////////////////////////////////////////////////////////////////////////////
enum class KeyAction : uint8_t {
Release = 0,
Press = 1,
Repeat = 2
};
bool hasKeyAction(KeyAction lhs, KeyAction rhs);
constexpr bool hasKeyAction(KeyAction lhs, KeyAction rhs) {
return static_cast<std::underlying_type_t<KeyAction>>(lhs) &
static_cast<std::underlying_type_t<KeyAction>>(rhs);
}
KeyAction operator|(KeyAction lhs, KeyAction rhs);
KeyAction operator|=(KeyAction& lhs, KeyAction rhs);
constexpr KeyAction operator|(KeyAction lhs, KeyAction rhs) {
return static_cast<KeyAction>(
static_cast<std::underlying_type_t<KeyAction>>(lhs) |
static_cast<std::underlying_type_t<KeyAction>>(rhs)
);
}
enum class KeyModifier : int {
NoModifier = 0,
Shift = 0x0001,
Control = 0x0002,
Alt = 0x0004,
Super = 0x0008
constexpr KeyAction operator|=(KeyAction& lhs, KeyAction rhs) {
return (lhs | rhs);
}
//////////////////////////////////////////////////////////////////////////////////////////
enum class KeyModifier : uint8_t {
None = 0,
Shift = 0x01,
Control = 0x02,
Alt = 0x04,
Super = 0x08
};
static const std::map<int, std::string> KeyModifierNames = {
{0, ""},
{0x0001, "Shift"},
{0x0002, "Control"},
{0x0004, "Alt"},
{0x0008, "Super"},
{0x0003, "Shift+Control"},
{0x0005, "Shift+Alt"},
{0x0009, "Shift+Super"},
{0x0006, "Control+Alt"},
{0x000A, "Control+Super"},
{0x000C, "Alt+Super"},
{0x0007, "Shift+Control+Alt"},
{0x000B, "Shift+Control+Super"},
{0x000D, "Shift+Alt+Super"},
{0x000E, "Control+Alt+Super"},
{0x000F, "Shift+Control+Alt+Super"}
constexpr KeyModifier operator|(KeyModifier lhs, KeyModifier rhs) {
return static_cast<KeyModifier>(
static_cast<std::underlying_type_t<KeyModifier>>(lhs) |
static_cast<std::underlying_type_t<KeyModifier>>(rhs)
);
}
constexpr KeyModifier operator|=(KeyModifier& lhs, KeyModifier rhs) {
return lhs = (lhs | rhs);
}
struct KeyModifierInfo {
KeyModifier modifier;
std::string_view name;
std::string_view identifier;
};
bool hasKeyModifier(KeyModifier lhs, KeyModifier rhs);
KeyModifier operator|(KeyModifier lhs, KeyModifier rhs);
KeyModifier operator|=(KeyModifier& lhs, KeyModifier rhs);
enum class Key {
Unknown = -1,
Space = 32,
Apostrophe = 39,
Comma = 44,
Minus = 45,
Period = 46,
Slash = 47,
Num0 = 48,
Num1 = 49,
Num2 = 50,
Num3 = 51,
Num4 = 52,
Num5 = 53,
Num6 = 54,
Num7 = 55,
Num8 = 56,
Num9 = 57,
SemiColon = 59,
Equal = 61,
A = 65,
B = 66,
C = 67,
D = 68,
E = 69,
F = 70,
G = 71,
H = 72,
I = 73,
J = 74,
K = 75,
L = 76,
M = 77,
N = 78,
O = 79,
P = 80,
Q = 81,
R = 82,
S = 83,
T = 84,
U = 85,
V = 86,
W = 87,
X = 88,
Y = 89,
Z = 90,
LeftBracket = 91,
BackSlash = 92,
RightBracket = 93,
GraveAccent = 96,
World1 = 161,
World2 = 162,
Escape = 256,
Enter = 257,
Tab = 258,
BackSpace = 259,
Insert = 260,
Delete = 261,
Right = 262,
Left = 263,
Down = 264,
Up = 265,
PageUp = 266,
PageDown = 267,
Home = 268,
End = 269,
CapsLock = 280,
ScrollLock = 281,
NumLock = 282,
PrintScreen = 283,
Pause = 284,
F1 = 290,
F2 = 291,
F3 = 292,
F4 = 293,
F5 = 294,
F6 = 295,
F7 = 296,
F8 = 297,
F9 = 298,
F10 = 299,
F11 = 300,
F12 = 301,
F13 = 302,
F14 = 303,
F15 = 304,
F16 = 305,
F17 = 306,
F18 = 307,
F19 = 308,
F20 = 309,
F21 = 310,
F22 = 311,
F23 = 312,
F24 = 313,
F25 = 314,
Keypad0 = 320,
Keypad1 = 321,
Keypad2 = 322,
Keypad3 = 323,
Keypad4 = 324,
Keypad5 = 325,
Keypad6 = 326,
Keypad7 = 327,
Keypad8 = 328,
Keypad9 = 329,
KeypadDecimal = 330,
KeypadDivide = 331,
KeypadMultiply = 332,
KeypadSubtract = 333,
KeypadAdd = 334,
KeypadEnter = 335,
LeftShift = 340,
LeftControl = 341,
LeftAlt = 342,
LeftSuper = 343,
RightShift = 344,
RightControl = 345,
RightAlt = 346,
RightSuper = 347,
Menu = 348,
Last = Menu
constexpr std::array<KeyModifierInfo, 5> KeyModifierInfos = {
KeyModifierInfo{ KeyModifier::None, "", "" },
KeyModifierInfo{ KeyModifier::Shift, "Shift", "SHIFT" },
KeyModifierInfo{ KeyModifier::Control, "Control", "CTRL" },
KeyModifierInfo{ KeyModifier::Alt, "Alt", "ALT" },
KeyModifierInfo{ KeyModifier::Super, "Super", "SUPER" },
};
static const std::map<int, std::string> KeyNames = {
{32, "Space"},
{39, "'"},
{44, ","},
{45, "-"},
{46, "."},
{47, "/"},
{48, "0"},
{49, "1"},
{50, "2"},
{51, "3"},
{52, "4"},
{53, "5"},
{54, "6"},
{55, "7"},
{56, "8"},
{57, "9"},
{59, ";"},
{61, "="},
{65, "A"},
{66, "B"},
{67, "C"},
{68, "D"},
{69, "E"},
{70, "F"},
{71, "G"},
{72, "H"},
{73, "I"},
{74, "J"},
{75, "K"},
{76, "L"},
{77, "M"},
{78, "N"},
{79, "O"},
{80, "P"},
{81, "Q"},
{82, "R"},
{83, "S"},
{84, "T"},
{85, "U"},
{86, "V"},
{87, "W"},
{88, "X"},
{89, "Y"},
{90, "Z"},
{91, "["},
{92, "\\"},
{93, "]"},
{96, "`"},
{161, "World1"},
{162, "World2"},
{256, "Escape"},
{257, "Enter"},
{258, "Tab"},
{259, "BackSpace"},
{260, "Insert"},
{261, "Delete"},
{262, "Right"},
{263, "Left"},
{264, "Down"},
{265, "Up"},
{266, "PageUp"},
{267, "PageDown"},
{268, "Home"},
{269, "End"},
{280, "CapsLock"},
{281, "ScrollLock"},
{282, "NumLock"},
{283, "PrintScreen"},
{284, "Pause"},
{290, "F1"},
{291, "F2"},
{292, "F3"},
{293, "F4"},
{294, "F5"},
{295, "F6"},
{296, "F7"},
{297, "F8"},
{298, "F9"},
{299, "F10"},
{300, "F11"},
{301, "F12"},
{302, "F13"},
{303, "F14"},
{304, "F15"},
{305, "F16"},
{306, "F17"},
{307, "F18"},
{308, "F19"},
{309, "F20"},
{310, "F21"},
{311, "F22"},
{312, "F23"},
{313, "F24"},
{314, "F25"},
{320, "Keypad 0"},
{321, "Keypad 1"},
{322, "Keypad 2"},
{323, "Keypad 3"},
{324, "Keypad 4"},
{325, "Keypad 5"},
{326, "Keypad 6"},
{327, "Keypad 7"},
{328, "Keypad 8"},
{329, "Keypad 9"},
{330, "Keypad ."},
{331, "Keypad /"},
{332, "Keypad *"},
{333, "Keypad -"},
{334, "Keypad +"},
{335, "Keypad Enter"},
{340, "Left Shift"},
{341, "Left Control"},
{342, "Left Alt"},
{343, "Left Super"},
{344, "Right Shift"},
{345, "Right Control"},
{346, "Right Alt"},
{347, "Right Super"},
{348, "Menu"}
constexpr bool hasKeyModifier(KeyModifier lhs, KeyModifier rhs) {
return static_cast<std::underlying_type_t<KeyModifier>>(lhs) &
static_cast<std::underlying_type_t<KeyModifier>>(rhs);
}
//////////////////////////////////////////////////////////////////////////////////////////
enum class Key : uint16_t {
Unknown = uint16_t(-1),
Space = 32,
Apostrophe = 39,
Comma = 44,
Minus = 45,
Period = 46,
Slash = 47,
Num0 = 48,
Num1 = 49,
Num2 = 50,
Num3 = 51,
Num4 = 52,
Num5 = 53,
Num6 = 54,
Num7 = 55,
Num8 = 56,
Num9 = 57,
SemiColon = 59,
Equal = 61,
A = 65,
B = 66,
C = 67,
D = 68,
E = 69,
F = 70,
G = 71,
H = 72,
I = 73,
J = 74,
K = 75,
L = 76,
M = 77,
N = 78,
O = 79,
P = 80,
Q = 81,
R = 82,
S = 83,
T = 84,
U = 85,
V = 86,
W = 87,
X = 88,
Y = 89,
Z = 90,
LeftBracket = 91,
BackSlash = 92,
RightBracket = 93,
GraveAccent = 96,
World1 = 161,
World2 = 162,
Escape = 256,
Enter = 257,
Tab = 258,
BackSpace = 259,
Insert = 260,
Delete = 261,
Right = 262,
Left = 263,
Down = 264,
Up = 265,
PageUp = 266,
PageDown = 267,
Home = 268,
End = 269,
CapsLock = 280,
ScrollLock = 281,
NumLock = 282,
PrintScreen = 283,
Pause = 284,
F1 = 290,
F2 = 291,
F3 = 292,
F4 = 293,
F5 = 294,
F6 = 295,
F7 = 296,
F8 = 297,
F9 = 298,
F10 = 299,
F11 = 300,
F12 = 301,
F13 = 302,
F14 = 303,
F15 = 304,
F16 = 305,
F17 = 306,
F18 = 307,
F19 = 308,
F20 = 309,
F21 = 310,
F22 = 311,
F23 = 312,
F24 = 313,
F25 = 314,
Keypad0 = 320,
Keypad1 = 321,
Keypad2 = 322,
Keypad3 = 323,
Keypad4 = 324,
Keypad5 = 325,
Keypad6 = 326,
Keypad7 = 327,
Keypad8 = 328,
Keypad9 = 329,
KeypadDecimal = 330,
KeypadDivide = 331,
KeypadMultiply = 332,
KeypadSubtract = 333,
KeypadAdd = 334,
KeypadEnter = 335,
LeftShift = 340,
LeftControl = 341,
LeftAlt = 342,
LeftSuper = 343,
RightShift = 344,
RightControl = 345,
RightAlt = 346,
RightSuper = 347,
Menu = 348,
Last = Menu
};
struct KeyInfo {
Key key;
std::string_view name;
std::string_view identifier;
};
constexpr const std::array<KeyInfo, 120> KeyInfos = {
KeyInfo { Key::Unknown, "", "" },
KeyInfo { Key::Space, "Space", "SPACE" },
KeyInfo { Key::Apostrophe, "'", "APOSTROPHE" },
KeyInfo { Key::Comma, ",", "COMMA" },
KeyInfo { Key::Minus, "-", "MINUS" },
KeyInfo { Key::Period, ".", "PERIOD" },
KeyInfo { Key::Slash, "/", "SLASH" },
KeyInfo { Key::Num0, "0", "0" },
KeyInfo { Key::Num1, "1", "1" },
KeyInfo { Key::Num2, "2", "2" },
KeyInfo { Key::Num3, "3", "3" },
KeyInfo { Key::Num4, "4", "4" },
KeyInfo { Key::Num5, "5", "5" },
KeyInfo { Key::Num6, "6", "6" },
KeyInfo { Key::Num7, "7", "7" },
KeyInfo { Key::Num8, "8", "8" },
KeyInfo { Key::Num9, "9", "9" },
KeyInfo { Key::SemiColon, ";", "SEMICOLON" },
KeyInfo { Key::Equal, "=", "EQUAL" },
KeyInfo { Key::A, "A", "A" },
KeyInfo { Key::B, "B", "B" },
KeyInfo { Key::C, "C", "C" },
KeyInfo { Key::D, "D", "D" },
KeyInfo { Key::E, "E", "E" },
KeyInfo { Key::F, "F", "F" },
KeyInfo { Key::G, "G", "G" },
KeyInfo { Key::H, "H", "H" },
KeyInfo { Key::I, "I", "I" },
KeyInfo { Key::J, "J", "J" },
KeyInfo { Key::K, "K", "K" },
KeyInfo { Key::L, "L", "L" },
KeyInfo { Key::M, "M", "M" },
KeyInfo { Key::N, "N", "N" },
KeyInfo { Key::O, "O", "O" },
KeyInfo { Key::P, "P", "P" },
KeyInfo { Key::Q, "Q", "Q" },
KeyInfo { Key::R, "R", "R" },
KeyInfo { Key::S, "S", "S" },
KeyInfo { Key::T, "T", "T" },
KeyInfo { Key::U, "U", "U" },
KeyInfo { Key::V, "V", "V" },
KeyInfo { Key::W, "W", "W" },
KeyInfo { Key::X, "X", "X" },
KeyInfo { Key::Y, "Y", "Y" },
KeyInfo { Key::Z, "Z", "Z" },
KeyInfo { Key::LeftBracket, "[", "LEFTBRACKET" },
KeyInfo { Key::BackSlash, "\\", "BACKSLASH" },
KeyInfo { Key::RightBracket, "]", "RIGHTBRACKET" },
KeyInfo { Key::GraveAccent, "`", "GRAVEACCENT" },
KeyInfo { Key::World1, "World1", "WORLD1" },
KeyInfo { Key::World2, "World2", "WORLD2" },
KeyInfo { Key::Escape, "Escape", "ESC" },
KeyInfo { Key::Enter, "Enter", "ENTER" },
KeyInfo { Key::Tab, "Tab", "TAB" },
KeyInfo { Key::BackSpace, "Backspace", "BACKSPACE" },
KeyInfo { Key::Insert, "Insert", "INSERT" },
KeyInfo { Key::Delete, "Delete", "DELETE" },
KeyInfo { Key::Right, "Right", "RIGHT" },
KeyInfo { Key::Left, "Left", "LEFT" },
KeyInfo { Key::Down, "Down", "DOWN" },
KeyInfo { Key::Up, "Up", "UP" },
KeyInfo { Key::PageUp, "PageUp", "PAGEUP" },
KeyInfo { Key::PageDown, "PageDown", "PAGEDOWN" },
KeyInfo { Key::Home, "Home", "HOME" },
KeyInfo { Key::End, "End", "END" },
KeyInfo { Key::CapsLock, "CapsLock", "CAPS_LOCK" },
KeyInfo { Key::ScrollLock, "ScrollLock", "SCROLL_LOCK" },
KeyInfo { Key::NumLock, "NumLock", "NUM_LOCK" },
KeyInfo { Key::PrintScreen, "PrintScreen", "PRINT_SCREEN" },
KeyInfo { Key::Pause, "Pause", "PAUSE" },
KeyInfo { Key::F1, "F1", "F1" },
KeyInfo { Key::F2, "F2", "F2" },
KeyInfo { Key::F3, "F3", "F3" },
KeyInfo { Key::F4, "F4", "F4" },
KeyInfo { Key::F5, "F5", "F5" },
KeyInfo { Key::F6, "F6", "F6" },
KeyInfo { Key::F7, "F7", "F7" },
KeyInfo { Key::F8, "F8", "F8" },
KeyInfo { Key::F9, "F9", "F9" },
KeyInfo { Key::F10, "F10", "F10" },
KeyInfo { Key::F11, "F11", "F11" },
KeyInfo { Key::F12, "F12", "F12" },
KeyInfo { Key::F13, "F13", "F13" },
KeyInfo { Key::F14, "F14", "F14" },
KeyInfo { Key::F15, "F15", "F15" },
KeyInfo { Key::F16, "F16", "F16" },
KeyInfo { Key::F17, "F17", "F17" },
KeyInfo { Key::F18, "F18", "F18" },
KeyInfo { Key::F19, "F19", "F19" },
KeyInfo { Key::F20, "F20", "F20" },
KeyInfo { Key::F21, "F21", "F21" },
KeyInfo { Key::F22, "F22", "F22" },
KeyInfo { Key::F23, "F23", "F23" },
KeyInfo { Key::F24, "F24", "F24" },
KeyInfo { Key::F25, "F25", "F25" },
KeyInfo { Key::Keypad0, "Keypad 0", "KP_0" },
KeyInfo { Key::Keypad1, "Keypad 1", "KP_1" },
KeyInfo { Key::Keypad2, "Keypad 2", "KP_2" },
KeyInfo { Key::Keypad3, "Keypad 3", "KP_3" },
KeyInfo { Key::Keypad4, "Keypad 4", "KP_4" },
KeyInfo { Key::Keypad5, "Keypad 5", "KP_5" },
KeyInfo { Key::Keypad6, "Keypad 6", "KP_6" },
KeyInfo { Key::Keypad7, "Keypad 7", "KP_7" },
KeyInfo { Key::Keypad8, "Keypad 8", "KP_8" },
KeyInfo { Key::Keypad9, "Keypad 9", "KP_9" },
KeyInfo { Key::KeypadDecimal, "Keypad .", "KP_DECIMAL" },
KeyInfo { Key::KeypadDivide, "Keypad /", "KP_DIVIDE" },
KeyInfo { Key::KeypadMultiply, "Keypad *", "KP_MULTIPLY" },
KeyInfo { Key::KeypadSubtract, "Keypad -", "KP_SUBTRACT" },
KeyInfo { Key::KeypadAdd, "Keypad +", "KP_ADD" },
KeyInfo { Key::KeypadEnter, "Keypad Enter", "KP_ENTER" },
KeyInfo { Key::LeftShift, "Left Shift", "LEFT_SHIFT" },
KeyInfo { Key::LeftControl, "Left Control", "LEFT_CONTROL" },
KeyInfo { Key::LeftAlt, "Left Alt", "LEFT_ALT" },
KeyInfo { Key::LeftSuper, "Left Super", "LEFT_SUPER" },
KeyInfo { Key::RightShift, "Right Shift", "RIGHT_SHIFT" },
KeyInfo { Key::RightControl, "Right Control", "RIGHT_CONTROL" },
KeyInfo { Key::RightAlt, "Right Alt", "RIGHT_ALT" },
KeyInfo { Key::RightSuper, "Right Super", "RIGHT_SUPER" },
KeyInfo { Key::Menu, "Menu", "MENU" }
};
//////////////////////////////////////////////////////////////////////////////////////////
struct KeyWithModifier {
Key key;
KeyModifier modifier;
Key key = Key::Unknown;
KeyModifier modifier = KeyModifier::None;
};
constexpr inline bool isKeypadKey(Key key) noexcept {
return key == Key::Keypad0 || key == Key::Keypad1 || key == Key::Keypad2 ||
key == Key::Keypad3 || key == Key::Keypad4 || key == Key::Keypad5 ||
key == Key::Keypad6 || key == Key::Keypad7 || key == Key::Keypad8 ||
key == Key::Keypad9 || key == Key::KeypadEnter || key == Key::KeypadAdd ||
key == Key::KeypadSubtract || key == Key::KeypadMultiply ||
key == Key::KeypadDivide;
}
KeyWithModifier stringToKey(std::string str);
bool operator<(const KeyWithModifier& lhs, const KeyWithModifier& rhs);
bool operator==(const KeyWithModifier& lhs, const KeyWithModifier& rhs);
std::string keyToString(KeyWithModifier keyWithModifier);
static const std::map<std::string, KeyModifier> KeyModifierMapping = {
{ "SHIFT", KeyModifier::Shift },
{ "ALT", KeyModifier::Alt },
{ "CTRL", KeyModifier::Control },
{ "SUPER", KeyModifier::Super }
};
// @TODO (abock, 2021-08-12) This function should die
constexpr bool operator<(const KeyWithModifier& lhs, const KeyWithModifier& rhs) noexcept
{
if (lhs.modifier == rhs.modifier) {
return lhs.key < rhs.key;
}
else {
return lhs.modifier < rhs.modifier;
}
}
static const std::map<std::string, Key> KeyMapping = {
{ "0", Key::Num0 },
{ "1", Key::Num1 },
{ "2", Key::Num2 },
{ "3", Key::Num3 },
{ "4", Key::Num4 },
{ "5", Key::Num5 },
{ "6", Key::Num6 },
{ "7", Key::Num7 },
{ "8", Key::Num8 },
{ "9", Key::Num9 },
{ "A", Key::A },
{ "B", Key::B },
{ "C", Key::C },
{ "D", Key::D },
{ "E", Key::E },
{ "F", Key::F },
{ "G", Key::G },
{ "H", Key::H },
{ "I", Key::I },
{ "J", Key::J },
{ "K", Key::K },
{ "L", Key::L },
{ "M", Key::M },
{ "N", Key::N },
{ "O", Key::O },
{ "P", Key::P },
{ "Q", Key::Q },
{ "R", Key::R },
{ "S", Key::S },
{ "T", Key::T },
{ "U", Key::U },
{ "V", Key::V },
{ "W", Key::W },
{ "X", Key::X },
{ "Y", Key::Y },
{ "Z", Key::Z },
{ "LeftBracket", Key::LeftBracket },
{ "LEFTBRACKET", Key::LeftBracket },
{ "LEFT_BRACKET", Key::LeftBracket },
{ "Backslash", Key::BackSlash },
{ "BACKSLASH", Key::BackSlash },
{ "RightBracket", Key::RightBracket },
{ "RIGHTBRACKET", Key::RightBracket },
{ "RIGHT_BRACKET", Key::RightBracket },
{ "GraveAccent", Key::GraveAccent },
{ "GRAVEACCENT", Key::GraveAccent },
{ "GRAVE_ACCENT", Key::GraveAccent },
{ "Space", Key::Space },
{ "SPACE", Key::Space },
{ "Apostrophe", Key::Apostrophe },
{ "APOSTROPHE", Key::Apostrophe },
{ "Comma", Key::Comma },
{ "COMMA", Key::Comma },
{ "Minus", Key::Minus },
{ "MINUS", Key::Minus },
{ "Period", Key::Period },
{ "PERIOD", Key::Period },
{ "Slash", Key::Slash },
{ "SLASH", Key::Slash },
{ "Semicolon", Key::SemiColon },
{ "SEMICOLON", Key::SemiColon },
{ "SEMI COLON", Key::SemiColon },
{ "Equal", Key::Equal },
{ "EQUAL", Key::Equal },
{ "World1", Key::World1 },
{ "WORLD1", Key::World1 },
{ "WORLD_1", Key::World1 },
{ "World2", Key::World2 },
{ "WORLD2", Key::World2 },
{ "WORLD_2", Key::World2 },
{ "Esc", Key::Escape },
{ "ESC", Key::Escape },
{ "ESCAPE", Key::Escape},
{ "Enter", Key::Enter },
{ "ENTER", Key::Enter },
{ "Tab", Key::Tab },
{ "TAB", Key::Tab },
{ "Backspace", Key::BackSpace },
{ "BACKSPACE", Key::BackSpace },
{ "Insert", Key::Insert },
{ "INSERT", Key::Insert },
{ "DEL", Key::Delete },
{ "Delete", Key::Delete },
{ "DELETE", Key::Delete },
{ "Right", Key::Right },
{ "RIGHT", Key::Right },
{ "Left", Key::Left },
{ "LEFT", Key::Left },
{ "Down", Key::Down },
{ "DOWN", Key::Down },
{ "Up", Key::Up },
{ "UP", Key::Up },
{ "PageUp", Key::PageUp },
{ "PAGEUP", Key::PageUp },
{ "PAGE_UP", Key::PageUp },
{ "PageDown", Key::PageDown },
{ "PAGEDOWN", Key::PageDown },
{ "PAGE_DOWN", Key::PageDown },
{ "Home", Key::Home },
{ "HOME", Key::Home },
{ "End", Key::End },
{ "END", Key::End },
{ "CapsLock", Key::CapsLock },
{ "CAPSLOCK", Key::CapsLock },
{ "CAPS_LOCK", Key::CapsLock },
{ "ScrollLock", Key::ScrollLock },
{ "SCROLLLOCK", Key::ScrollLock },
{ "SCROLL_LOCK", Key::ScrollLock },
{ "NumLock", Key::NumLock },
{ "NUMLOCK", Key::NumLock },
{ "NUM_LOCK", Key::NumLock },
{ "PrintScreen", Key::PrintScreen },
{ "PRINTSCREEN", Key::PrintScreen },
{ "PRINT_SCREEN", Key::PrintScreen },
{ "Pause", Key::Pause },
{ "PAUSE", Key::Pause },
{ "F1", Key::F1 },
{ "F2", Key::F2 },
{ "F3", Key::F3 },
{ "F4", Key::F4 },
{ "F5", Key::F5 },
{ "F6", Key::F6 },
{ "F7", Key::F7 },
{ "F8", Key::F8 },
{ "F9", Key::F9 },
{ "F10", Key::F10 },
{ "F11", Key::F11 },
{ "F12", Key::F12 },
{ "F13", Key::F13 },
{ "F14", Key::F14 },
{ "F15", Key::F15 },
{ "F16", Key::F16 },
{ "F17", Key::F17 },
{ "F18", Key::F18 },
{ "F19", Key::F19 },
{ "F20", Key::F20 },
{ "F21", Key::F21 },
{ "F22", Key::F22 },
{ "F23", Key::F23 },
{ "F24", Key::F24 },
{ "F25", Key::F25 },
{ "Keypad0", Key::Keypad0 },
{ "KP0", Key::Keypad0 },
{ "KP_0", Key::Keypad0 },
{ "Keypad1", Key::Keypad1 },
{ "KP1", Key::Keypad1 },
{ "KP_1", Key::Keypad1 },
{ "Keypad2", Key::Keypad2 },
{ "KP2", Key::Keypad2 },
{ "KP_2", Key::Keypad2 },
{ "Keypad3", Key::Keypad3 },
{ "KP3", Key::Keypad3 },
{ "KP_3", Key::Keypad3 },
{ "Keypad4", Key::Keypad4 },
{ "KP4", Key::Keypad4 },
{ "KP_4", Key::Keypad4 },
{ "Keypad5", Key::Keypad5 },
{ "KP5", Key::Keypad5 },
{ "KP_5", Key::Keypad5 },
{ "Keypad6", Key::Keypad6 },
{ "KP6", Key::Keypad6 },
{ "KP_6", Key::Keypad6 },
{ "Keypad7", Key::Keypad7 },
{ "KP7", Key::Keypad7 },
{ "KP_7", Key::Keypad7 },
{ "Keypad8", Key::Keypad8 },
{ "KP8", Key::Keypad8 },
{ "KP_8", Key::Keypad8 },
{ "Keypad9", Key::Keypad9 },
{ "KP9", Key::Keypad9 },
{ "KP_9", Key::Keypad9 },
{ "KeypadDecimal", Key::KeypadDecimal },
{ "KPDECIMAL", Key::KeypadDecimal },
{ "KP_DECIMAL", Key::KeypadDecimal },
{ "KeypadDivide", Key::KeypadDivide },
{ "KPDIVIDE", Key::KeypadDivide },
{ "KP_DIVIDE", Key::KeypadDivide },
{ "KeypadMultiply", Key::KeypadMultiply },
{ "KPMULTIPLY", Key::KeypadMultiply },
{ "KP_MULTIPLY", Key::KeypadMultiply },
{ "KeypadSubtract", Key::KeypadSubtract },
{ "KPSUBTRACT", Key::KeypadSubtract },
{ "KP_SUBTRACT", Key::KeypadSubtract },
{ "KeypadAdd", Key::KeypadAdd },
{ "KPADD", Key::KeypadAdd },
{ "KP_ADD", Key::KeypadAdd },
{ "KeypadEnter", Key::KeypadEnter },
{ "KPENTER", Key::KeypadEnter },
{ "KP_ENTER", Key::KeypadEnter },
{ "KeypadEqual", Key::KeypadEnter },
{ "KPEQUAL", Key::KeypadEnter },
{ "KP_EQUAL", Key::KeypadEnter },
{ "LeftShift", Key::LeftShift },
{ "LSHIFT", Key::LeftShift },
{ "LEFTSHIFT", Key::LeftShift },
{ "LEFT_SHIFT", Key::LeftShift },
{ "LeftControl", Key::LeftControl },
{ "LCTRL", Key::LeftControl },
{ "LEFTCONTROL", Key::LeftControl },
{ "LEFT_CONTROL", Key::LeftControl },
{ "LeftAlt", Key::LeftAlt },
{ "LALT", Key::LeftAlt },
{ "LEFTALT", Key::LeftAlt },
{ "LEFT_ALT", Key::LeftAlt },
{ "LeftSuper", Key::LeftSuper },
{ "LEFTSUPER", Key::LeftSuper },
{ "LEFT_SUPER", Key::LeftSuper },
{ "RightShift", Key::RightShift },
{ "RSHIFT", Key::RightShift },
{ "RIGHTSHIFT", Key::RightShift },
{ "RIGHT_SHIFT", Key::RightShift },
{ "RightControl", Key::RightControl },
{ "RCTRL", Key::RightControl },
{ "RIGHTCONTROL", Key::RightControl },
{ "RIGHT_CONTROL", Key::RightControl },
{ "RightAlt", Key::RightAlt },
{ "RALT", Key::RightAlt },
{ "RIGHTALT", Key::RightAlt },
{ "RIGHT_ALT", Key::RightAlt },
{ "RightSuper", Key::RightSuper },
{ "RIGHTSUPER", Key::RightSuper },
{ "RIGHT_SUPER", Key::RightSuper },
{ "Menu", Key::Menu },
{ "MENU", Key::Menu }
};
constexpr bool operator==(const KeyWithModifier& lhs, const KeyWithModifier& rhs) noexcept
{
return (lhs.key == rhs.key) && (lhs.modifier == rhs.modifier);
}
} // namespace openspace

View File

@@ -26,6 +26,7 @@ include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake)
set(HEADER_FILES
include/gui.h
include/guiactioncomponent.h
include/guiassetcomponent.h
include/guicomponent.h
include/guifilepathcomponent.h
@@ -37,7 +38,6 @@ set(HEADER_FILES
include/guimissioncomponent.h
include/guiparallelcomponent.h
include/guipropertycomponent.h
include/guishortcutscomponent.h
include/guispacetimecomponent.h
include/guiiswacomponent.h
include/imgui_include.h
@@ -47,6 +47,7 @@ source_group("Header Files" FILES ${HEADER_FILES})
set(SOURCE_FILES
src/gui.cpp
src/guiactioncomponent.cpp
src/guiassetcomponent.cpp
src/guicomponent.cpp
src/guifilepathcomponent.cpp
@@ -58,7 +59,6 @@ set(SOURCE_FILES
src/guimissioncomponent.cpp
src/guiparallelcomponent.cpp
src/guipropertycomponent.cpp
src/guishortcutscomponent.cpp
src/guispacetimecomponent.cpp
src/guiiswacomponent.cpp
src/renderproperties.cpp

View File

@@ -27,6 +27,7 @@
#include <modules/imgui/include/guicomponent.h>
#include <modules/imgui/include/guiactioncomponent.h>
#include <modules/imgui/include/guiassetcomponent.h>
#include <modules/imgui/include/guifilepathcomponent.h>
#include <modules/imgui/include/guigibscomponent.h>
@@ -38,7 +39,6 @@
#include <modules/imgui/include/guimissioncomponent.h>
#include <modules/imgui/include/guiparallelcomponent.h>
#include <modules/imgui/include/guipropertycomponent.h>
#include <modules/imgui/include/guishortcutscomponent.h>
#include <modules/imgui/include/guispacetimecomponent.h>
#include <openspace/properties/property.h>
#include <openspace/properties/scalar/boolproperty.h>
@@ -121,7 +121,7 @@ public:
#ifdef OPENSPACE_MODULE_ISWA_ENABLED
GuiIswaComponent _iswa;
#endif // OPENSPACE_MODULE_ISWA_ENABLED
GuiShortcutsComponent _shortcuts;
GuiActionComponent _actions;
GuiJoystickComponent _joystick;
GuiParallelComponent _parallel;
GuiPropertyComponent _featuredProperties;
@@ -153,7 +153,7 @@ private:
#endif
&_asset,
&_shortcuts,
&_actions,
&_joystick,
&_filePath,

View File

@@ -29,9 +29,9 @@
namespace openspace::gui {
class GuiShortcutsComponent : public GuiComponent {
class GuiActionComponent : public GuiComponent {
public:
GuiShortcutsComponent();
GuiActionComponent();
void render() override;
};

View File

@@ -22,12 +22,12 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <modules/imgui/include/guishortcutscomponent.h>
#include <modules/imgui/include/guiactioncomponent.h>
#include <modules/imgui/include/gui.h>
#include <openspace/engine/globals.h>
#include <openspace/interaction/actionmanager.h>
#include <openspace/interaction/keybindingmanager.h>
#include <openspace/interaction/shortcutmanager.h>
#include <openspace/scripting/scriptengine.h>
#include <openspace/util/keys.h>
@@ -35,11 +35,11 @@
namespace openspace::gui {
GuiShortcutsComponent::GuiShortcutsComponent()
GuiActionComponent::GuiActionComponent()
: GuiComponent("Shortcuts", "Shortcuts")
{}
void GuiShortcutsComponent::render() {
void GuiActionComponent::render() {
ImGui::SetNextWindowCollapsed(_isCollapsed);
bool v = _isEnabled;
@@ -47,62 +47,50 @@ void GuiShortcutsComponent::render() {
_isEnabled = v;
_isCollapsed = ImGui::IsWindowCollapsed();
using K = KeyWithModifier;
using V = std::string;
const std::multimap<K, V>& binds = global::keybindingManager->keyBindings();
// First the actual shortcuts
CaptionText("Shortcuts");
const std::vector<interaction::ShortcutManager::ShortcutInformation>& shortcuts =
global::shortcutManager->shortcuts();
for (size_t i = 0; i < shortcuts.size(); ++i) {
const interaction::ShortcutManager::ShortcutInformation& info = shortcuts[i];
if (ImGui::Button(info.name.c_str())) {
global::scriptEngine->queueScript(
info.script,
scripting::ScriptEngine::RemoteScripting(info.synchronization)
);
std::set<std::string> boundActions;
CaptionText("Keybindings");
for (const std::pair<const K, V>& p : binds) {
boundActions.insert(p.second);
if (ImGui::Button(ghoul::to_string(p.first).c_str())) {
global::actionManager->triggerAction(p.second, ghoul::Dictionary());
}
ImGui::SameLine();
// Poor mans table layout
ImGui::SetCursorPosX(125.f);
ImGui::Text("%s", info.documentation.c_str());
if (!info.synchronization) {
const interaction::Action& a = global::actionManager->action(p.second);
ImGui::Text("%s", a.documentation.c_str());
if (!a.synchronization) {
ImGui::SameLine();
ImGui::Text("(%s)", "local");
}
}
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 25.f);
CaptionText("Other Actions");
for (const interaction::Action& action : global::actionManager->actions()) {
// We only show all of the other actions that are not currently bound to keys here
if (boundActions.find(action.identifier) != boundActions.end()) {
continue;
}
// Then display all the keybinds as buttons as well, for good measure
CaptionText("Keybindings");
using K = KeyWithModifier;
using V = interaction::KeybindingManager::KeyInformation;
const std::multimap<K, V>& binds = global::keybindingManager->keyBindings();
for (const std::pair<const K, V>& p : binds) {
if (ImGui::Button(ghoul::to_string(p.first).c_str())) {
global::scriptEngine->queueScript(
p.second.command,
scripting::ScriptEngine::RemoteScripting(p.second.synchronization)
);
if (ImGui::Button(action.identifier.c_str())) {
global::actionManager->triggerAction(action.command, ghoul::Dictionary());
}
ImGui::SameLine();
// Poor mans table layout
ImGui::SetCursorPosX(125.f);
ImGui::SetCursorPosX(350.f);
ImGui::Text("%s", p.second.documentation.c_str());
if (!p.second.synchronization) {
ImGui::Text("%s", action.documentation.c_str());
if (!action.synchronization) {
ImGui::SameLine();
ImGui::Text("(%s)", "local");
}
}
}

View File

@@ -26,7 +26,7 @@
#include <modules/server/include/connection.h>
#include <openspace/engine/globals.h>
#include <openspace/interaction/shortcutmanager.h>
#include <openspace/interaction/actionmanager.h>
#include <openspace/interaction/keybindingmanager.h>
namespace {
@@ -44,32 +44,28 @@ bool ShortcutTopic::isDone() const {
}
std::vector<nlohmann::json> ShortcutTopic::shortcutsJson() const {
using ShortcutInformation = interaction::ShortcutManager::ShortcutInformation;
const std::vector<ShortcutInformation>& shortcuts =
global::shortcutManager->shortcuts();
std::vector<nlohmann::json> json;
for (const ShortcutInformation& shortcut : shortcuts) {
for (const interaction::Action& action : global::actionManager->actions()) {
nlohmann::json shortcutJson = {
{ "name", shortcut.name },
{ "script", shortcut.script },
{ "synchronization", static_cast<bool>(shortcut.synchronization) },
{ "documentation", shortcut.documentation },
{ "guiPath", shortcut.guiPath },
{ "name", action.name },
{ "script", action.command },
{ "synchronization", static_cast<bool>(action.synchronization) },
{ "documentation", action.documentation },
{ "guiPath", action.guiPath },
};
json.push_back(shortcutJson);
}
using KeyInformation = interaction::KeybindingManager::KeyInformation;
const std::multimap<KeyWithModifier, KeyInformation>& keyBindings =
const std::multimap<KeyWithModifier, std::string>& keyBindings =
global::keybindingManager->keyBindings();
for (const std::pair<const KeyWithModifier, KeyInformation>& keyBinding : keyBindings)
{
for (const std::pair<const KeyWithModifier, std::string>& keyBinding : keyBindings) {
const KeyWithModifier& k = keyBinding.first;
const KeyInformation& info = keyBinding.second;
// @TODO (abock, 2021-08-05) Probably this should be rewritten to better account
// for the new action mechanism
const interaction::Action& action = global::actionManager->action(
keyBinding.second
);
nlohmann::json shortcutJson = {
{ "key", ghoul::to_string(k.key) },
@@ -81,11 +77,11 @@ std::vector<nlohmann::json> ShortcutTopic::shortcutsJson() const {
{ "super" , hasKeyModifier(k.modifier, KeyModifier::Super) }
}
},
{ "name", info.name },
{ "script", info.command },
{ "synchronization", static_cast<bool>(info.synchronization) },
{ "documentation", info.documentation },
{ "guiPath", info.guiPath },
{ "name", action.name },
{ "script", action.command },
{ "synchronization", static_cast<bool>(action.synchronization) },
{ "documentation", action.documentation },
{ "guiPath", action.guiPath },
};
json.push_back(shortcutJson);
}

View File

@@ -80,7 +80,7 @@ private:
/**
* Create a mouse event on the current cursor position.
*/
CefMouseEvent mouseEvent(KeyModifier mods = KeyModifier::NoModifier);
CefMouseEvent mouseEvent(KeyModifier mods = KeyModifier::None);
#ifdef WIN32
/**

View File

@@ -79,10 +79,6 @@ openspace.rebindKey = function(oldKey, newKey)
local t = openspace.getKeyBinding(oldKey)
openspace.clearKey(oldKey)
for _, v in pairs(t) do
if v["Remote"] then
openspace.bindKey(newKey, v["Command"])
else
openspace.bindKeyLocal(newKey, v["Command"])
end
openspace.bindKey(newKey, v)
end
end

View File

@@ -43,6 +43,8 @@ set(OPENSPACE_SOURCE
${OPENSPACE_BASE_DIR}/src/engine/openspaceengine_lua.inl
${OPENSPACE_BASE_DIR}/src/engine/syncengine.cpp
${OPENSPACE_BASE_DIR}/src/engine/virtualpropertymanager.cpp
${OPENSPACE_BASE_DIR}/src/interaction/actionmanager.cpp
${OPENSPACE_BASE_DIR}/src/interaction/actionmanager_lua.inl
${OPENSPACE_BASE_DIR}/src/interaction/camerainteractionstates.cpp
${OPENSPACE_BASE_DIR}/src/interaction/interactionmonitor.cpp
${OPENSPACE_BASE_DIR}/src/interaction/inputstate.cpp
@@ -55,8 +57,6 @@ set(OPENSPACE_SOURCE
${OPENSPACE_BASE_DIR}/src/interaction/externinteraction.cpp
${OPENSPACE_BASE_DIR}/src/interaction/sessionrecording.cpp
${OPENSPACE_BASE_DIR}/src/interaction/sessionrecording_lua.inl
${OPENSPACE_BASE_DIR}/src/interaction/shortcutmanager.cpp
${OPENSPACE_BASE_DIR}/src/interaction/shortcutmanager_lua.inl
${OPENSPACE_BASE_DIR}/src/interaction/websocketinputstate.cpp
${OPENSPACE_BASE_DIR}/src/interaction/websocketcamerastates.cpp
${OPENSPACE_BASE_DIR}/src/interaction/tasks/convertrecfileversiontask.cpp
@@ -223,6 +223,8 @@ set(OPENSPACE_HEADER
${OPENSPACE_BASE_DIR}/include/openspace/engine/syncengine.h
${OPENSPACE_BASE_DIR}/include/openspace/engine/virtualpropertymanager.h
${OPENSPACE_BASE_DIR}/include/openspace/engine/windowdelegate.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/action.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/actionmanager.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/delayedvariable.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/delayedvariable.inl
${OPENSPACE_BASE_DIR}/include/openspace/interaction/camerainteractionstates.h
@@ -238,7 +240,6 @@ set(OPENSPACE_HEADER
${OPENSPACE_BASE_DIR}/include/openspace/interaction/scriptcamerastates.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/sessionrecording.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/sessionrecording.inl
${OPENSPACE_BASE_DIR}/include/openspace/interaction/shortcutmanager.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/websocketinputstate.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/websocketcamerastates.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/tasks/convertrecfileversiontask.h

View File

@@ -28,9 +28,9 @@
#include <openspace/engine/logfactory.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/interaction/actionmanager.h>
#include <openspace/interaction/keybindingmanager.h>
#include <openspace/interaction/sessionrecording.h>
#include <openspace/interaction/shortcutmanager.h>
#include <openspace/mission/mission.h>
#include <openspace/mission/missionmanager.h>
#include <openspace/navigation/navigationhandler.h>
@@ -86,11 +86,11 @@ void registerCoreClasses(scripting::ScriptEngine& engine) {
engine.addLibrary(Profile::luaLibrary());
engine.addLibrary(Scene::luaLibrary());
engine.addLibrary(Time::luaLibrary());
engine.addLibrary(interaction::ActionManager::luaLibrary());
engine.addLibrary(interaction::KeybindingManager::luaLibrary());
engine.addLibrary(interaction::NavigationHandler::luaLibrary());
engine.addLibrary(interaction::PathNavigator::luaLibrary());
engine.addLibrary(interaction::SessionRecording::luaLibrary());
engine.addLibrary(interaction::ShortcutManager::luaLibrary());
engine.addLibrary(scripting::ScriptScheduler::luaLibrary());
engine.addLibrary(scripting::generalSystemCapabilities());
engine.addLibrary(scripting::openglSystemCapabilities());

View File

@@ -32,12 +32,12 @@
#include <openspace/engine/syncengine.h>
#include <openspace/engine/virtualpropertymanager.h>
#include <openspace/engine/windowdelegate.h>
#include <openspace/interaction/actionmanager.h>
#include <openspace/interaction/interactionmonitor.h>
#include <openspace/interaction/keybindingmanager.h>
#include <openspace/interaction/joystickinputstate.h>
#include <openspace/interaction/websocketinputstate.h>
#include <openspace/interaction/sessionrecording.h>
#include <openspace/interaction/shortcutmanager.h>
#include <openspace/mission/missionmanager.h>
#include <openspace/navigation/navigationhandler.h>
#include <openspace/network/parallelpeer.h>
@@ -90,12 +90,12 @@ namespace {
sizeof(VirtualPropertyManager) +
sizeof(WindowDelegate) +
sizeof(configuration::Configuration) +
sizeof(interaction::ActionManager) +
sizeof(interaction::InteractionMonitor) +
sizeof(interaction::WebsocketInputStates) +
sizeof(interaction::KeybindingManager) +
sizeof(interaction::NavigationHandler) +
sizeof(interaction::SessionRecording) +
sizeof(interaction::ShortcutManager) +
sizeof(properties::PropertyOwner) +
sizeof(properties::PropertyOwner) +
sizeof(scripting::ScriptEngine) +
@@ -272,6 +272,14 @@ void create() {
configuration = new configuration::Configuration;
#endif // WIN32
#ifdef WIN32
actionManager = new (currentPos) interaction::ActionManager;
ghoul_assert(actionManager, "No action manager");
currentPos += sizeof(interaction::ActionManager);
#else ^^^ WIN32 / !WIN32 vvv
actionManager = new interaction::ActionManager;
#endif // WIN32
#ifdef WIN32
interactionMonitor = new (currentPos) interaction::InteractionMonitor;
ghoul_assert(interactionMonitor, "No interactionMonitor");
@@ -320,14 +328,6 @@ void create() {
sessionRecording = new interaction::SessionRecording(true);
#endif // WIN32
#ifdef WIN32
shortcutManager = new (currentPos) interaction::ShortcutManager;
ghoul_assert(shortcutManager, "No shortcutManager");
currentPos += sizeof(interaction::ShortcutManager);
#else // ^^^ WIN32 / !WIN32 vvv
shortcutManager = new interaction::ShortcutManager;
#endif // WIN32
#ifdef WIN32
rootPropertyOwner = new (currentPos) properties::PropertyOwner({ "" });
ghoul_assert(rootPropertyOwner, "No rootPropertyOwner");
@@ -433,13 +433,6 @@ void destroy() {
delete rootPropertyOwner;
#endif // WIN32
LDEBUGC("Globals", "Destroying 'ShortcutManager'");
#ifdef WIN32
shortcutManager->~ShortcutManager();
#else // ^^^ WIN32 / !WIN32 vvv
delete shortcutManager;
#endif // WIN32
LDEBUGC("Globals", "Destroying 'SessionRecording'");
#ifdef WIN32
sessionRecording->~SessionRecording();
@@ -482,6 +475,13 @@ void destroy() {
delete interactionMonitor;
#endif // WIN32
LDEBUGC("Globals", "Destorying 'ActionManager'");
#ifdef WIN32
actionManager->~ActionManager();
#else // ^^^ WIN32 / !WIN32 vvv
delete actionManager;
#endif // WIN32
LDEBUGC("Globals", "Destroying 'Configuration'");
#ifdef WIN32
configuration->~Configuration();

View File

@@ -334,7 +334,7 @@ void OpenSpaceEngine::initialize() {
// Then save the profile to a scene so that we can load it with the
// existing infrastructure
std::ofstream scene(outputAsset);
std::string sceneContent = global::profile->convertToScene();
std::string sceneContent = convertToScene(*global::profile);
scene << sceneContent;
// Set asset name to that of the profile because a new scene file will be
@@ -1103,9 +1103,9 @@ void OpenSpaceEngine::preSynchronization() {
if (_hasScheduledAssetLoading) {
LINFO(fmt::format("Loading asset: {}", absPath(_scheduledAssetPathToLoad)));
global::profile->setIgnoreUpdates(true);
global::profile->ignoreUpdates = true;
loadSingleAsset(_scheduledAssetPathToLoad);
global::profile->setIgnoreUpdates(false);
global::profile->ignoreUpdates = false;
resetPropertyChangeFlagsOfSubowners(global::rootPropertyOwner);
_hasScheduledAssetLoading = false;
_scheduledAssetPathToLoad.clear();

View File

@@ -0,0 +1,162 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/interaction/actionmanager.h>
#include <openspace/scripting/lualibrary.h>
#include <openspace/scripting/scriptengine.h>
#include <ghoul/misc/crc32.h>
#include <ghoul/misc/dictionaryluaformatter.h>
#include <algorithm>
#include "actionmanager_lua.inl"
namespace openspace::interaction {
bool ActionManager::hasAction(const std::string& identifier) const {
ghoul_assert(!identifier.empty(), "Identifier must not be empty");
const unsigned int hash = ghoul::hashCRC32(identifier);
const auto it = _actions.find(hash);
return it != _actions.end();
}
void ActionManager::registerAction(Action action) {
ghoul_assert(!action.identifier.empty(), "Action must have an identifier");
ghoul_assert(!hasAction(action.identifier), "Identifier already existed");
const unsigned int hash = ghoul::hashCRC32(action.identifier);
_actions[hash] = std::move(action);
}
void ActionManager::removeAction(const std::string& identifier) {
ghoul_assert(!identifier.empty(), "Identifier must not be empty");
ghoul_assert(hasAction(identifier), "Action was not found in the list");
const unsigned int hash = ghoul::hashCRC32(identifier);
const auto it = _actions.find(hash);
_actions.erase(it);
}
const Action& ActionManager::action(const std::string& identifier) const {
ghoul_assert(!identifier.empty(), "Identifier must not be empty");
ghoul_assert(hasAction(identifier), "Action was not found in the list");
const unsigned int hash = ghoul::hashCRC32(identifier);
const auto it = _actions.find(hash);
return it->second;
}
std::vector<Action> ActionManager::actions() const {
std::vector<Action> result;
result.reserve(_actions.size());
for (const std::pair<unsigned int, Action>& p : _actions) {
result.push_back(p.second);
}
return result;
}
void ActionManager::triggerAction(const std::string& identifier,
const ghoul::Dictionary& arguments) const
{
ghoul_assert(!identifier.empty(), "Identifier must not be empty");
ghoul_assert(hasAction(identifier), "Action was not found in the list");
const Action& a = action(identifier);
if (arguments.isEmpty()) {
global::scriptEngine->queueScript(
a.command,
scripting::ScriptEngine::RemoteScripting(a.synchronization)
);
}
else {
global::scriptEngine->queueScript(
fmt::format("local args = {}\n{}", ghoul::formatLua(arguments), a.command),
scripting::ScriptEngine::RemoteScripting(a.synchronization)
);
}
}
scripting::LuaLibrary ActionManager::luaLibrary() {
return {
"action",
{
{
"hasAction",
&luascriptfunctions::hasAction,
{},
"string",
"Checks if the passed identifier corresponds to an action"
},
{
"removeAction",
&luascriptfunctions::removeAction,
{},
"string",
"Removes an existing action from the list of possible actions"
},
{
"registerAction",
&luascriptfunctions::registerAction,
{},
"table",
"Registers a new action. The table must at least contain the keys "
"'Identifier' and 'Command' represeting the unique identifier and the "
"Lua script that belong to this new action. Optional keys are 'Name' for "
"a human-readable name, 'Documentation' for a description of what the "
"action does, 'GuiPath' for a path used for grouping a user interface. "
"All of these parameters must be strings. The last parameter is "
"'IsLocal' and represents whether the action should be executed locally "
"(= false) or remotely (= true, the default)"
},
{
"action",
&luascriptfunctions::action,
{},
"string",
"Returns information about the action as a table with the keys "
"'Identifier', 'Command', 'Name', 'Documentation', 'GuiPath', and "
"'Synchronization'"
},
{
"actions",
&luascriptfunctions::actions,
{},
"",
"Returns all registered actions in the system as a table of tables each "
"containing the keys 'Identifier', 'Command', 'Name', 'Documentation', "
"'GuiPath', and 'Synchronization'"
},
{
"triggerAction",
&luascriptfunctions::triggerAction,
{},
"string",
"Triggers the action given by the specified identifier"
}
}
};
}
} // namespace openspace::interaction

View File

@@ -0,0 +1,241 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/engine/globals.h>
namespace openspace::luascriptfunctions {
/**
* \ingroup LuaScripts
* hasAction():
* Checks if the passed identifier corresponds to an action.
*/
int hasAction(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::hasAction");
const std::string& identifier = ghoul::lua::value<std::string>(L, 1);
if (identifier.empty()) {
return ghoul::lua::luaError(L, "Identifier must not be empty");
}
const bool res = global::actionManager->hasAction(identifier);
ghoul::lua::push(L, res);
return 1;
}
/**
* \ingroup LuaScripts
* removeAction():
* Removes an existing action from the list of possible actions.
*/
int removeAction(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeAction");
const std::string& identifier = ghoul::lua::value<std::string>(L, 1);
if (identifier.empty()) {
return ghoul::lua::luaError(L, "Identifier must not be empty");
}
if (!global::actionManager->hasAction(identifier)) {
return ghoul::lua::luaError(
L,
fmt::format("Identifier '{}' for action not found", identifier)
);
}
global::actionManager->removeAction(identifier);
return 0;
}
/**
* \ingroup LuaScripts
* registerAction():
* Registers a new action. The first argument is the identifier which cannot have been
* used to register a previous action before, the second argument is the Lua command that
* is to be executed, and the optional third argument is the name used in a user-interface
* to refer to this action. The fourth is a human readable description of the command for
* documentation purposes. The fifth is the GUI path and the last parameter determines
* whether the action should be executed locally (= false) or remotely (= true, the
* default).
*/
int registerAction(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::registerAction");
ghoul::Dictionary d = ghoul::lua::value<ghoul::Dictionary>(L, 1);
if (!d.hasValue<std::string>("Identifier")) {
return ghoul::lua::luaError(L, "Identifier must to provided to register action");
}
std::string identifier = d.value<std::string>("Identifier");
if (global::actionManager->hasAction(identifier)) {
return ghoul::lua::luaError(
L,
fmt::format("Action for identifier '{}' already existed", identifier)
);
}
if (global::actionManager->hasAction(identifier)) {
return ghoul::lua::luaError(
L,
fmt::format("Identifier '{}' for action already registered", identifier)
);
}
if (!d.hasValue<std::string>("Command")) {
return ghoul::lua::luaError(
L,
fmt::format(
"Identifier '{}' does not provide a Lua command to execute", identifier
)
);
}
interaction::Action action;
action.identifier = std::move(identifier);
action.command = d.value<std::string>("Command");
if (d.hasValue<std::string>("Name")) {
action.name = d.value<std::string>("Name");
}
if (d.hasValue<std::string>("Documentation")) {
action.documentation = d.value<std::string>("Documentation");
}
if (d.hasValue<std::string>("GuiPath")) {
action.guiPath = d.value<std::string>("GuiPath");
}
if (d.hasValue<bool>("IsLocal")) {
bool value = d.value<bool>("IsLocal");
action.synchronization = interaction::Action::IsSynchronized(value);
}
global::actionManager->registerAction(std::move(action));
return 0;
}
/**
* \ingroup LuaScripts
* action():
* Returns information about the action with the identifier equal to the provided
* identifier.
*/
int action(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::action");
const std::string& identifier = ghoul::lua::value<std::string>(L, 1);
if (identifier.empty()) {
return ghoul::lua::luaError(L, "Identifier must not be empty");
}
if (!global::actionManager->hasAction(identifier)) {
return ghoul::lua::luaError(
L,
fmt::format("Identifier '{}' for action not found", identifier)
);
}
const interaction::Action& action = global::actionManager->action(identifier);
lua_newtable(L);
ghoul::lua::push(L, "Identifier", action.identifier);
lua_settable(L, -3);
ghoul::lua::push(L, "Command", action.command);
lua_settable(L, -3);
ghoul::lua::push(L, "Name", action.name);
lua_settable(L, -3);
ghoul::lua::push(L, "Documentation", action.documentation);
lua_settable(L, -3);
ghoul::lua::push(L, "GuiPath", action.guiPath);
lua_settable(L, -3);
ghoul::lua::push(
L,
"Synchronization",
action.synchronization == interaction::Action::IsSynchronized::Yes
);
lua_settable(L, -3);
return 1;
}
/**
* \ingroup LuaScripts
* actions():
* Returns all registered actions in the system.
*/
int actions(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::actions");
lua_newtable(L);
const std::vector<interaction::Action>& actions = global::actionManager->actions();
for (size_t i = 0; i < actions.size(); ++i) {
const interaction::Action& action = actions[i];
ghoul::lua::push(L, i + 1);
lua_newtable(L);
ghoul::lua::push(L, "Identifier", action.identifier);
lua_settable(L, -3);
ghoul::lua::push(L, "Command", action.command);
lua_settable(L, -3);
ghoul::lua::push(L, "Name", action.name);
lua_settable(L, -3);
ghoul::lua::push(L, "Documentation", action.documentation);
lua_settable(L, -3);
ghoul::lua::push(L, "GuiPath", action.guiPath);
lua_settable(L, -3);
ghoul::lua::push(
L,
"Synchronization",
action.synchronization == interaction::Action::IsSynchronized::Yes
);
lua_settable(L, -3);
lua_settable(L, -3);
}
return 1;
}
/**
* \ingroup LuaScripts
* triggerAction():
* Triggers the action given by the specified identifier.
*/
int triggerAction(lua_State* L) {
int n = ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::triggerAction");
const std::string& identifier = ghoul::lua::value<std::string>(L, 1);
if (identifier.empty()) {
return ghoul::lua::luaError(L, "Identifier must not be empty");
}
if (!global::actionManager->hasAction(identifier)) {
return ghoul::lua::luaError(
L,
fmt::format("Identifier '{}' for action not found", identifier)
);
}
ghoul::Dictionary arguments;
if (n == 2) {
ghoul::lua::luaDictionaryFromState(L, arguments, 2);
}
global::actionManager->triggerAction(identifier, arguments);
return 0;
}
} // namespace openspace::luascriptfunctions

View File

@@ -25,6 +25,7 @@
#include <openspace/interaction/keybindingmanager.h>
#include <openspace/engine/globals.h>
#include <openspace/interaction/actionmanager.h>
#include <openspace/scripting/lualibrary.h>
#include <openspace/scripting/scriptengine.h>
#include <openspace/util/json_helper.h>
@@ -52,12 +53,12 @@ void KeybindingManager::keyboardCallback(Key key, KeyModifier modifier, KeyActio
// iterate over key bindings
auto ret = _keyLua.equal_range({ key, modifier });
for (auto it = ret.first; it != ret.second; ++it) {
using RS = scripting::ScriptEngine::RemoteScripting;
global::scriptEngine->queueScript(
it->second.command,
it->second.synchronization ? RS::Yes : RS::No
ghoul_assert(!it->second.empty(), "Action must not be empty");
ghoul_assert(
global::actionManager->hasAction(it->second),
"Action must be registered"
);
global::actionManager->triggerAction(it->second, ghoul::Dictionary());
}
}
}
@@ -66,54 +67,10 @@ void KeybindingManager::resetKeyBindings() {
_keyLua.clear();
}
void KeybindingManager::bindKeyLocal(Key key, KeyModifier modifier,
std::string luaCommand, std::string documentation,
std::string name, std::string guiPath)
{
void KeybindingManager::bindKey(Key key, KeyModifier modifier, std::string action) {
#ifdef WIN32
const bool isShift = hasKeyModifier(modifier, KeyModifier::Shift);
const bool isKeypad = key == Key::Keypad0 || key == Key::Keypad1 ||
key == Key::Keypad2 || key == Key::Keypad3 || key == Key::Keypad4 ||
key == Key::Keypad5 || key == Key::Keypad6 || key == Key::Keypad7 ||
key == Key::Keypad8 || key == Key::Keypad9 || key == Key::KeypadEnter ||
key == Key::KeypadAdd || key == Key::KeypadSubtract ||
key == Key::KeypadMultiply || key == Key::KeypadDivide;
if (isShift && isKeypad) {
LWARNINGC(
"bindKey",
"Windows does not support binding keys to Shift + Keyboard as it will "
"internally convert these into Home, End, etc, keys."
);
}
#endif // WIN32
_keyLua.insert({
{ key, modifier },
{
std::move(luaCommand),
IsSynchronized::No,
std::move(documentation),
std::move(name),
std::move(guiPath)
}
});
}
void KeybindingManager::bindKey(Key key, KeyModifier modifier, std::string luaCommand,
std::string documentation, std::string name,
std::string guiPath)
{
#ifdef WIN32
const bool isShift = hasKeyModifier(modifier, KeyModifier::Shift);
const bool isKeypad = key == Key::Keypad0 || key == Key::Keypad1 ||
key == Key::Keypad2 || key == Key::Keypad3 || key == Key::Keypad4 ||
key == Key::Keypad5 || key == Key::Keypad6 || key == Key::Keypad7 ||
key == Key::Keypad8 || key == Key::Keypad9 || key == Key::KeypadEnter ||
key == Key::KeypadAdd || key == Key::KeypadSubtract ||
key == Key::KeypadMultiply || key == Key::KeypadDivide;
if (isShift && isKeypad) {
if (isShift && isKeypadKey(key)) {
LWARNINGC(
"bindKey",
"Windows does not support binding keys to Shift + Keypad as it will "
@@ -121,22 +78,10 @@ void KeybindingManager::bindKey(Key key, KeyModifier modifier, std::string luaCo
);
}
#endif // WIN32
ghoul_assert(!action.empty(), "Action must not be empty");
_keyLua.insert({
{ key, modifier },
{
std::move(luaCommand),
IsSynchronized::Yes,
std::move(documentation),
std::move(name),
std::move(guiPath)
}
});
}
void KeybindingManager::removeKeyBinding(const std::string& key) {
KeyWithModifier k = stringToKey(key);
removeKeyBinding(k);
KeyWithModifier km = { key, modifier };
_keyLua.insert({ km, std::move(action) });
}
void KeybindingManager::removeKeyBinding(const KeyWithModifier& key) {
@@ -155,17 +100,10 @@ void KeybindingManager::removeKeyBinding(const KeyWithModifier& key) {
}
}
std::vector<std::pair<KeyWithModifier, KeybindingManager::KeyInformation>>
KeybindingManager::keyBinding(const std::string& key) const
std::vector<std::pair<KeyWithModifier, std::string>> KeybindingManager::keyBinding(
const KeyWithModifier& key) const
{
KeyWithModifier k = stringToKey(key);
return keyBinding(k);
}
std::vector<std::pair<KeyWithModifier, KeybindingManager::KeyInformation>>
KeybindingManager::keyBinding(const KeyWithModifier& key) const
{
std::vector<std::pair<KeyWithModifier, KeyInformation>> result;
std::vector<std::pair<KeyWithModifier, std::string>> result;
auto itRange = _keyLua.equal_range(key);
for (auto it = itRange.first; it != itRange.second; ++it) {
@@ -174,8 +112,7 @@ KeybindingManager::keyBinding(const KeyWithModifier& key) const
return result;
}
const std::multimap<KeyWithModifier, KeybindingManager::KeyInformation>&
KeybindingManager::keyBindings() const
const std::multimap<KeyWithModifier, std::string>& KeybindingManager::keyBindings() const
{
return _keyLua;
}
@@ -186,19 +123,14 @@ std::string KeybindingManager::generateJson() const {
std::stringstream json;
json << "[";
bool first = true;
for (const std::pair<const KeyWithModifier, KeyInformation>& p : _keyLua) {
for (const std::pair<const KeyWithModifier, std::string>& p : _keyLua) {
if (!first) {
json << ",";
}
first = false;
json << "{";
json << R"("key": ")" << ghoul::to_string(p.first) << "\",";
json << R"("script": ")" << escapedJson(p.second.command) << "\",";
json << R"("remoteScripting": )"
<< (p.second.synchronization ? "true," : "false,");
json << R"("documentation": ")"
<< escapedJson(p.second.documentation) << "\",";
json << R"("name": ")" << escapedJson(p.second.name) << "\"";
json << R"("action": ")" << p.second << "\"";
json << "}";
}
json << "]";
@@ -230,32 +162,15 @@ scripting::LuaLibrary KeybindingManager::luaLibrary() {
"bindKey",
&luascriptfunctions::bindKey,
{},
"string, string [, string, string, string]",
"Binds a key by name to a lua string command to execute both locally "
"and to broadcast to clients if this is the host of a parallel session. "
"The first argument is the key, the second argument is the Lua command "
"that is to be executed, and the optional third argument is a human "
"readable description of the command for documentation purposes. The"
"fourth is the GUI name and fifth is the GUI path, both optional."
},
{
"bindKeyLocal",
&luascriptfunctions::bindKeyLocal,
{},
"string, string [, string]",
"Binds a key by name to a lua string command to execute only locally. "
"The first argument is the key, the second argument is the Lua command "
"that is to be executed, and the optional third argument is a human "
"readable description of the command for documentation purposes."
"string, string",
"Binds a key by name to the action identified by the second argument"
},
{
"getKeyBinding",
&luascriptfunctions::getKeyBindings,
{},
"string",
"Returns a list of information about the keybindings for the provided "
"key. Each element in the list is a table describing the 'Command' that "
"was bound and whether it was a 'Remote' script or not."
"Returns a list of information about the keybindings for the provided key"
}
}
};

View File

@@ -30,21 +30,24 @@ namespace openspace::luascriptfunctions {
/**
* \ingroup LuaScripts
* bindKey():
* Binds a key to Lua command to both execute locally
* and broadcast to all clients if this node is hosting
* a parallel connection.
* Binds a key to Lua command to both execute locally and broadcast to all clients if this
* node is hosting a parallel connection.
*/
int bindKey(lua_State* L) {
using ghoul::lua::luaTypeToString;
int nArguments = ghoul::lua::checkArgumentsAndThrow(L, { 2, 5 }, "lua::bindKey");
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::bindKey");
const std::string& key = ghoul::lua::value<std::string>(L, 1);
std::string command = ghoul::lua::value<std::string>(L, 2);
std::string key = ghoul::lua::value<std::string>(L, 1);
std::string action = ghoul::lua::value<std::string>(L, 2);
if (command.empty()) {
if (action.empty()) {
lua_settop(L, 0);
return ghoul::lua::luaError(L, "Command string is empty");
return ghoul::lua::luaError(L, "Action must not be empty");
}
if (!global::actionManager->hasAction(action)) {
lua_settop(L, 0);
return ghoul::lua::luaError(L, fmt::format("Action '{}' does not exist", action));
}
openspace::KeyWithModifier iKey = openspace::stringToKey(key);
@@ -56,65 +59,7 @@ int bindKey(lua_State* L) {
return ghoul::lua::luaError(L, error);
}
std::string doc = (nArguments >= 3) ? ghoul::lua::value<std::string>(L, 3) : "";
std::string name = (nArguments >= 4) ? ghoul::lua::value<std::string>(L, 4) : "";
std::string guiPath = (nArguments == 5) ? ghoul::lua::value<std::string>(L, 5) : "";
global::keybindingManager->bindKey(
iKey.key,
iKey.modifier,
std::move(command),
std::move(doc),
std::move(name),
std::move(guiPath)
);
lua_settop(L, 0);
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
return 0;
}
/**
* \ingroup LuaScripts
* bindKey():
* Binds a key to Lua command to execute only locally
*/
int bindKeyLocal(lua_State* L) {
using ghoul::lua::luaTypeToString;
int nArguments = ghoul::lua::checkArgumentsAndThrow(L, { 2, 5 }, "lua::bindKeyLocal");
const std::string& key = ghoul::lua::value<std::string>(L, 1);
std::string command = ghoul::lua::value<std::string>(L, 2);
if (command.empty()) {
return ghoul::lua::luaError(L, "Command string is empty");
}
openspace::KeyWithModifier iKey = openspace::stringToKey(key);
if (iKey.key == openspace::Key::Unknown) {
std::string error = fmt::format("Could not find key '{}'", key);
LERRORC("lua.bindKey", error);
return ghoul::lua::luaError(L, error);
}
std::string doc = nArguments >= 3 ? ghoul::lua::value<std::string>(L, 3) : "";
std::string name = (nArguments >= 4) ?
ghoul::lua::value<std::string>(L, 4) :
"";
std::string guiPath = (nArguments == 5) ?
ghoul::lua::value<std::string>(L, 5) :
"";
global::keybindingManager->bindKeyLocal(
iKey.key,
iKey.modifier,
std::move(command),
std::move(doc),
std::move(name),
std::move(guiPath)
);
global::keybindingManager->bindKey(iKey.key, iKey.modifier, std::move(action));
lua_settop(L, 0);
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
@@ -137,23 +82,17 @@ int getKeyBindings(lua_State* L) {
);
using K = KeyWithModifier;
using V = interaction::KeybindingManager::KeyInformation;
using V = std::string;
const std::vector<std::pair<K, V>>& info = global::keybindingManager->keyBinding(key);
const std::vector<std::pair<K, V>>& info = global::keybindingManager->keyBinding(
stringToKey(key)
);
lua_createtable(L, static_cast<int>(info.size()), 0);
int i = 1;
for (const std::pair<K, V>& it : info) {
lua_pushnumber(L, i);
lua_createtable(L, 2, 0);
ghoul::lua::push(L, "Command");
ghoul::lua::push(L, it.second.command);
lua_settable(L, -3);
ghoul::lua::push(L, "Remote");
ghoul::lua::push(L, static_cast<bool>(it.second.synchronization));
lua_settable(L, -3);
ghoul::lua::push(L, it.second);
lua_settable(L, -3);
++i;
}
@@ -174,7 +113,7 @@ int clearKey(lua_State* L) {
if (t == LUA_TSTRING) {
// The user provided a single key
const std::string& key = ghoul::lua::value<std::string>(L, 1);
global::keybindingManager->removeKeyBinding(key);
global::keybindingManager->removeKeyBinding(stringToKey(key));
}
else {
// The user provided a list of keys
@@ -182,7 +121,7 @@ int clearKey(lua_State* L) {
ghoul::lua::luaDictionaryFromState(L, d);
for (size_t i = 1; i <= d.size(); ++i) {
const std::string& k = d.value<std::string>(std::to_string(i));
global::keybindingManager->removeKeyBinding(k);
global::keybindingManager->removeKeyBinding(stringToKey(k));
}
lua_pop(L, 1);
}

View File

@@ -1,87 +0,0 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2021 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/interaction/shortcutmanager.h>
#include <openspace/engine/globals.h>
#include <openspace/scripting/lualibrary.h>
#include <openspace/scripting/scriptengine.h>
#include <ghoul/glm.h>
#include <sstream>
#include "shortcutmanager_lua.inl"
namespace openspace::interaction {
void ShortcutManager::resetShortcuts() {
_shortcuts.clear();
}
void ShortcutManager::addShortcut(ShortcutInformation info) {
_shortcuts.push_back(std::move(info));
}
const std::vector<ShortcutManager::ShortcutInformation>&
ShortcutManager::shortcuts() const
{
return _shortcuts;
}
scripting::LuaLibrary ShortcutManager::luaLibrary() {
return {
"",
{
{
"clearShortcuts",
&luascriptfunctions::clearShortcuts,
{},
"",
"Clear all shortcuts in this scene"
},
{
"bindShortcut",
&luascriptfunctions::bindShortcut,
{},
"string, string [, string]",
"Binds a Lua script to a new shortcut that is executed both locally and "
"to be broadcast to clients if this is the host of a parallel session. "
"The first argument is a human-readable name for this shortcut, the "
"second argument is the Lua script that will be executed and the last "
"argument is a describtive text for the shortcut for tooltips, etc."
},
{
"bindShortcutLocal",
&luascriptfunctions::bindShortcutLocal,
{},
"string, string [, string]",
"Binds a Lua script to a new shortcut that is executed onlylocally. The "
"first argument is a human-readable name for this shortcut, the second "
"argument is the Lua script that will be executed and the last argument "
"is a describtive text for the shortcut for tooltips, etc."
}
}
};
}
} // namespace openspace::interaction

View File

@@ -33,8 +33,8 @@
#include <ghoul/logging/logmanager.h>
#include <ghoul/misc/misc.h>
#include <ghoul/misc/profiling.h>
#include <json/json.hpp>
#include <set>
#include <json/json.hpp>
#include "profile_lua.inl"
@@ -62,8 +62,8 @@ namespace {
}
void checkValue(const nlohmann::json& j, const std::string& key,
bool (nlohmann::json::*checkFunc)() const, std::string_view keyPrefix,
bool isOptional)
bool (nlohmann::json::*checkFunc)() const,
std::string_view keyPrefix, bool isOptional)
{
if (j.find(key) == j.end()) {
if (!isOptional) {
@@ -109,6 +109,11 @@ namespace {
}
} // namespace
//
// Current version:
//
void to_json(nlohmann::json& j, const Profile::Version& v) {
j["major"] = v.major;
j["minor"] = v.minor;
@@ -169,7 +174,6 @@ void to_json(nlohmann::json& j, const Profile::Meta& v) {
}
}
void from_json(const nlohmann::json& j, Profile::Meta& v) {
checkValue(j, "name", &nlohmann::json::is_string, "meta", true);
checkValue(j, "version", &nlohmann::json::is_string, "meta", true);
@@ -203,7 +207,6 @@ void from_json(const nlohmann::json& j, Profile::Meta& v) {
}
}
void to_json(nlohmann::json& j, const Profile::Property::SetType& v) {
j = [](Profile::Property::SetType t) {
switch (t) {
@@ -249,8 +252,8 @@ void from_json(const nlohmann::json& j, Profile::Property& v) {
j["value"].get_to(v.value);
}
void to_json(nlohmann::json& j, const Profile::Keybinding& v) {
j["key"] = ghoul::to_string(v.key);
void to_json(nlohmann::json& j, const Profile::Action& v) {
j["identifier"] = v.identifier;
j["documentation"] = v.documentation;
j["name"] = v.name;
j["gui_path"] = v.guiPath;
@@ -258,20 +261,20 @@ void to_json(nlohmann::json& j, const Profile::Keybinding& v) {
j["script"] = v.script;
}
void from_json(const nlohmann::json& j, Profile::Keybinding& v) {
checkValue(j, "key", &nlohmann::json::is_string, "keybinding", false);
checkValue(j, "documentation", &nlohmann::json::is_string, "keybinding", false);
checkValue(j, "name", &nlohmann::json::is_string, "keybinding", false);
checkValue(j, "gui_path", &nlohmann::json::is_string, "keybinding", false);
checkValue(j, "is_local", &nlohmann::json::is_boolean, "keybinding", false);
checkValue(j, "script", &nlohmann::json::is_string, "keybinding", false);
void from_json(const nlohmann::json& j, Profile::Action& v) {
checkValue(j, "identifier", &nlohmann::json::is_string, "action", false);
checkValue(j, "documentation", &nlohmann::json::is_string, "action", false);
checkValue(j, "name", &nlohmann::json::is_string, "action", false);
checkValue(j, "gui_path", &nlohmann::json::is_string, "action", false);
checkValue(j, "is_local", &nlohmann::json::is_boolean, "action", false);
checkValue(j, "script", &nlohmann::json::is_string, "action", false);
checkExtraKeys(
j,
"keybinding",
{ "key", "documentation", "name", "gui_path", "is_local", "script" }
"action",
{ "identifier", "documentation", "name", "gui_path", "is_local", "script" }
);
v.key = stringToKey(j.at("key").get<std::string>());
j["identifier"].get_to(v.identifier);
j["documentation"].get_to(v.documentation);
j["name"].get_to(v.name);
j["gui_path"].get_to(v.guiPath);
@@ -279,6 +282,20 @@ void from_json(const nlohmann::json& j, Profile::Keybinding& v) {
j["script"].get_to(v.script);
}
void to_json(nlohmann::json& j, const Profile::Keybinding& v) {
j["key"] = keyToString(v.key);
j["action"] = v.action;
}
void from_json(const nlohmann::json& j, Profile::Keybinding& v) {
checkValue(j, "key", &nlohmann::json::is_string, "keybinding", false);
checkValue(j, "action", &nlohmann::json::is_string, "keybinding", false);
checkExtraKeys(j, "keybinding", { "key", "action" });
v.key = stringToKey(j.at("key").get<std::string>());
j["action"].get_to(v.action);
}
void to_json(nlohmann::json& j, const Profile::Time::Type& v) {
j = [](Profile::Time::Type t) {
switch (t) {
@@ -439,8 +456,88 @@ void from_json(const nlohmann::json& j, Profile::CameraGoToGeo& v) {
}
}
// In these namespaces we defined the structs as they used to be defined in the older
// versions. That way, we can keep the from_json files as they were originally written too
namespace version10 {
struct Keybinding {
KeyWithModifier key;
std::string documentation;
std::string name;
std::string guiPath;
bool isLocal;
std::string script;
};
void from_json(const nlohmann::json& j, version10::Keybinding& v) {
checkValue(j, "key", &nlohmann::json::is_string, "keybinding", false);
checkValue(j, "documentation", &nlohmann::json::is_string, "keybinding", false);
checkValue(j, "name", &nlohmann::json::is_string, "keybinding", false);
checkValue(j, "gui_path", &nlohmann::json::is_string, "keybinding", false);
checkValue(j, "is_local", &nlohmann::json::is_boolean, "keybinding", false);
checkValue(j, "script", &nlohmann::json::is_string, "keybinding", false);
checkExtraKeys(
j,
"keybinding",
{ "key", "documentation", "name", "gui_path", "is_local", "script" }
);
v.key = stringToKey(j.at("key").get<std::string>());
j["documentation"].get_to(v.documentation);
j["name"].get_to(v.name);
j["gui_path"].get_to(v.guiPath);
j["is_local"].get_to(v.isLocal);
j["script"].get_to(v.script);
}
void convertVersion10to11(nlohmann::json& profile) {
// Version 1.1 introduced actions and remove Lua function calling from keybindings
if (profile.find("keybindings") == profile.end()) {
// We didn't find any keybindings, so there is nothing to do
return;
}
// This needs to be changed if there is another version for any of these types later
using Action = Profile::Action;
using Keybinding = Profile::Keybinding;
std::vector<Action> actions;
std::vector<Keybinding> keybindings;
std::vector<version10::Keybinding> kbs =
profile.at("keybindings").get<std::vector<version10::Keybinding>>();
for (size_t i = 0; i < kbs.size(); ++i) {
version10::Keybinding& kb = kbs[i];
std::string identifier = fmt::format("profile.keybind.{}", i);
Action action;
action.identifier = identifier;
action.documentation = std::move(kb.documentation);
action.name = std::move(kb.name);
action.guiPath = std::move(kb.guiPath);
action.isLocal = std::move(kb.isLocal);
action.script = std::move(kb.script);
actions.push_back(std::move(action));
Keybinding keybinding;
keybinding.key = kb.key;
keybinding.action = identifier;
keybindings.push_back(keybinding);
}
profile["actions"] = actions;
profile["keybindings"] = keybindings;
profile["version"] = Profile::Version{ 1, 1 };
}
} // namespace version10
Profile::ParsingError::ParsingError(Severity severity_, std::string msg)
: ghoul::RuntimeError(std::move(msg), "profileFile")
: ghoul::RuntimeError(std::move(msg), "profile")
, severity(severity_)
{}
@@ -448,11 +545,9 @@ void Profile::saveCurrentSettingsToProfile(const properties::PropertyOwner& root
std::string currentTime,
interaction::NavigationState navState)
{
_version = Profile::CurrentVersion;
version = Profile::CurrentVersion;
//
// Update properties
//
std::vector<properties::Property*> ps = changedProperties(rootOwner);
for (properties::Property* prop : ps) {
@@ -460,23 +555,20 @@ void Profile::saveCurrentSettingsToProfile(const properties::PropertyOwner& root
p.setType = Property::SetType::SetPropertyValueSingle;
p.name = prop->fullyQualifiedIdentifier();
p.value = prop->getStringValue();
_properties.push_back(std::move(p));
properties.push_back(std::move(p));
}
//
// add current time to profile file
//
// Add current time to profile file
Time t;
t.value = std::move(currentTime);
t.type = Time::Type::Absolute;
_time = t;
time = t;
// Delta times
std::vector<double> dts = global::timeManager->deltaTimeSteps();
_deltaTimes = std::move(dts);
deltaTimes = std::move(dts);
// Camera
CameraNavState c;
c.anchor = navState.anchor;
c.aim = navState.aim;
@@ -485,50 +577,145 @@ void Profile::saveCurrentSettingsToProfile(const properties::PropertyOwner& root
c.up = navState.up;
c.yaw = navState.yaw;
c.pitch = navState.pitch;
_camera = std::move(c);
}
void Profile::setIgnoreUpdates(bool ignoreUpdates) {
_ignoreUpdates = ignoreUpdates;
camera = std::move(c);
}
void Profile::addAsset(const std::string& path) {
ZoneScoped
if (_ignoreUpdates) {
if (ignoreUpdates) {
return;
}
const auto it = std::find(_assets.cbegin(), _assets.cend(), path);
if (it != _assets.end()) {
// Asset already existed, so nothing to do here
return;
const auto it = std::find(assets.cbegin(), assets.cend(), path);
if (it == assets.end()) {
assets.push_back(path);
}
_assets.push_back(path);
}
void Profile::removeAsset(const std::string& path) {
ZoneScoped
if (_ignoreUpdates) {
if (ignoreUpdates) {
return;
}
const auto it = std::find(_assets.cbegin(), _assets.cend(), path);
if (it == _assets.end()) {
const auto it = std::find(assets.cbegin(), assets.cend(), path);
if (it == assets.end()) {
throw ghoul::RuntimeError(fmt::format(
"Tried to remove non-existing asset '{}'", path
));
}
_assets.erase(it);
assets.erase(it);
}
void Profile::clearAssets() {
_assets.clear();
std::string Profile::serialize() const {
nlohmann::json r;
r["version"] = version;
if (!modules.empty()) {
r["modules"] = modules;
}
if (meta.has_value()) {
r["meta"] = *meta;
}
if (!assets.empty()) {
r["assets"] = assets;
}
if (!properties.empty()) {
r["properties"] = properties;
}
if (!actions.empty()) {
r["actions"] = actions;
}
if (!keybindings.empty()) {
r["keybindings"] = keybindings;
}
if (time.has_value()) {
r["time"] = *time;
}
if (!deltaTimes.empty()) {
r["delta_times"] = deltaTimes;
}
if (camera.has_value()) {
r["camera"] = std::visit(
overloaded {
[](const CameraNavState& c) { return nlohmann::json(c); },
[](const Profile::CameraGoToGeo& c) { return nlohmann::json(c); }
},
*camera
);
}
if (!markNodes.empty()) {
r["mark_nodes"] = markNodes;
}
if (!additionalScripts.empty()) {
r["additional_scripts"] = additionalScripts;
}
return r.dump(2);
}
Profile::Profile(const std::string& content) {
try {
nlohmann::json profile = nlohmann::json::parse(content);
profile.at("version").get_to(version);
// Update the file format in steps
if (version.major == 1 && version.minor == 0) {
version10::convertVersion10to11(profile);
profile.at("version").get_to(version);
}
if (profile.find("modules") != profile.end()) {
profile["modules"].get_to(modules);
}
if (profile.find("meta") != profile.end()) {
meta = profile["meta"].get<Meta>();
}
if (profile.find("assets") != profile.end()) {
profile["assets"].get_to(assets);
}
if (profile.find("properties") != profile.end()) {
profile["properties"].get_to(properties);
}
if (profile.find("actions") != profile.end()) {
profile["actions"].get_to(actions);
}
if (profile.find("keybindings") != profile.end()) {
profile["keybindings"].get_to(keybindings);
}
if (profile.find("time") != profile.end()) {
time = profile["time"].get<Time>();
}
if (profile.find("delta_times") != profile.end()) {
profile["delta_times"].get_to(deltaTimes);
}
if (profile.find("camera") != profile.end()) {
nlohmann::json c = profile.at("camera");
if (c["type"] == CameraNavState::Type) {
camera = c.get<CameraNavState>();
}
else if (c["type"] == CameraGoToGeo::Type) {
camera = c.get<CameraGoToGeo>();
}
else {
throw ParsingError(ParsingError::Severity::Error, "Unknown camera type");
}
}
if (profile.find("mark_nodes") != profile.end()) {
profile["mark_nodes"].get_to(markNodes);
}
if (profile.find("additional_scripts") != profile.end()) {
profile["additional_scripts"].get_to(additionalScripts);
}
}
catch (const nlohmann::json::exception& e) {
std::string err = e.what();
throw ParsingError(ParsingError::Severity::Error, err);
}
}
scripting::LuaLibrary Profile::luaLibrary() {
@@ -554,143 +741,38 @@ scripting::LuaLibrary Profile::luaLibrary() {
};
}
std::string Profile::serialize() const {
nlohmann::json r;
r["version"] = _version;
if (!_modules.empty()) {
r["modules"] = _modules;
}
if (_meta.has_value()) {
r["meta"] = *_meta;
}
if (!_assets.empty()) {
r["assets"] = _assets;
}
if (!_properties.empty()) {
r["properties"] = _properties;
}
if (!_keybindings.empty()) {
r["keybindings"] = _keybindings;
}
if (_time.has_value()) {
r["time"] = *_time;
}
if (!_deltaTimes.empty()) {
r["delta_times"] = _deltaTimes;
}
if (_camera.has_value()) {
r["camera"] = std::visit(
overloaded {
[](const CameraNavState& camera) {
return nlohmann::json(camera);
},
[](const Profile::CameraGoToGeo& camera) {
return nlohmann::json(camera);
}
},
*_camera
);
}
if (!_markNodes.empty()) {
r["mark_nodes"] = _markNodes;
}
if (!_additionalScripts.empty()) {
r["additional_scripts"] = _additionalScripts;
}
return r.dump(2);
}
Profile::Profile(const std::string& content) {
try {
nlohmann::json profile = nlohmann::json::parse(content);
profile.at("version").get_to(_version);
if (profile.find("modules") != profile.end()) {
profile["modules"].get_to(_modules);
}
if (profile.find("meta") != profile.end()) {
_meta = profile.at("meta").get<Meta>();
}
if (profile.find("assets") != profile.end()) {
profile.at("assets").get_to(_assets);
}
if (profile.find("properties") != profile.end()) {
profile.at("properties").get_to(_properties);
}
if (profile.find("keybindings") != profile.end()) {
profile.at("keybindings").get_to(_keybindings);
}
if (profile.find("time") != profile.end()) {
_time = profile.at("time").get<Time>();
}
if (profile.find("delta_times") != profile.end()) {
profile.at("delta_times").get_to(_deltaTimes);
}
if (profile.find("camera") != profile.end()) {
nlohmann::json c = profile.at("camera");
if (c.at("type") == CameraNavState::Type) {
_camera = c.get<CameraNavState>();
}
else if (c.at("type") == CameraGoToGeo::Type) {
_camera = c.get<CameraGoToGeo>();
}
else {
throw Profile::ParsingError(
Profile::ParsingError::Severity::Error,
"Unknown camera type"
);
}
}
if (profile.find("mark_nodes") != profile.end()) {
profile.at("mark_nodes").get_to(_markNodes);
}
if (profile.find("additional_scripts") != profile.end()) {
profile.at("additional_scripts").get_to(_additionalScripts);
}
}
catch (const nlohmann::json::exception& e) {
std::string err = e.what();
throw Profile::ParsingError(
Profile::ParsingError::Severity::Error,
err
);
}
}
std::string Profile::convertToScene() const {
std::string convertToScene(const Profile& p) {
ZoneScoped
std::string output;
if (_meta.has_value()) {
output += "asset.meta = {";
if (p.meta.has_value()) {
output += "asset.meta = {\n";
if (_meta->name.has_value()) {
output += fmt::format(" Name = [[{}]],", *_meta->name);
if (p.meta->name.has_value()) {
output += fmt::format(" Name = [[{}]],\n", *p.meta->name);
}
if (_meta->version.has_value()) {
output += fmt::format(" Version = [[{}]],", *_meta->version);
if (p.meta->version.has_value()) {
output += fmt::format(" Version = [[{}]],\n", *p.meta->version);
}
if (_meta->description.has_value()) {
output += fmt::format(" Description = [[{}]],", *_meta->description);
if (p.meta->description.has_value()) {
output += fmt::format(" Description = [[{}]],\n", *p.meta->description);
}
if (_meta->author.has_value()) {
output += fmt::format(" Author = [[{}]],", *_meta->author);
if (p.meta->author.has_value()) {
output += fmt::format(" Author = [[{}]],\n", *p.meta->author);
}
if (_meta->url.has_value()) {
output += fmt::format(" URL = [[{}]],", *_meta->url);
if (p.meta->url.has_value()) {
output += fmt::format(" URL = [[{}]],\n", *p.meta->url);
}
if (_meta->license.has_value()) {
output += fmt::format(" License = [[{}]],", *_meta->license);
if (p.meta->license.has_value()) {
output += fmt::format(" License = [[{}]]\n", *p.meta->license);
}
output += "}";
output += "}\n\n";
}
// Modules
for (const Module& m : _modules) {
for (const Profile::Module& m : p.modules) {
output += fmt::format(
"if openspace.modules.isLoaded(\"{}\") then {} else {} end\n",
m.name, *m.loadedInstruction, *m.notLoadedInstruction
@@ -698,34 +780,45 @@ std::string Profile::convertToScene() const {
}
// Assets
for (const std::string& asset : _assets) {
for (const std::string& asset : p.assets) {
output += fmt::format("asset.require(\"{}\");\n", asset);
}
output += "asset.onInitialize(function()\n";
// Keybindings
for (const Keybinding& k : _keybindings) {
const std::string key = ghoul::to_string(k.key);
const std::string name = k.name.empty() ? key : k.name;
output += "\n\nasset.onInitialize(function()\n";
// Actions
output += " -- Actions\n";
for (const Profile::Action& action : p.actions) {
const std::string name = action.name.empty() ? action.identifier : action.name;
output += fmt::format(
k.isLocal ?
"openspace.bindKeyLocal(\"{}\",\"{}\", [[{}]], [[{}]], [[{}]]);\n" :
"openspace.bindKey(\"{}\", [[{}]], [[{}]], [[{}]], [[{}]]);\n",
key, k.script, k.documentation, name, k.guiPath
" openspace.action.registerAction({{"
"Identifier=[[{}]], Command=[[{}]], Name=[[{}]], Documentation=[[{}]], "
"GuiPath=[[{}]], IsLocal={}"
"}})\n",
action.identifier, action.script, name, action.documentation, action.guiPath,
action.isLocal ? "true" : "false"
);
}
// Keybindings
output += "\n -- Keybindings\n";
for (size_t i = 0; i < p.keybindings.size(); ++i) {
const Profile::Keybinding& k = p.keybindings[i];
const std::string key = keyToString(k.key);
output += fmt::format(" openspace.bindKey([[{}]], [[{}]])\n", key, k.action);
}
// Time
switch (_time->type) {
case Time::Type::Absolute:
output += fmt::format("openspace.time.setTime(\"{}\")\n", _time->value);
output += "\n -- Time\n";
switch (p.time->type) {
case Profile::Time::Type::Absolute:
output += fmt::format(" openspace.time.setTime(\"{}\")\n", p.time->value);
break;
case Time::Type::Relative:
output += "local now = openspace.time.currentWallTime();\n";
case Profile::Time::Type::Relative:
output += " local now = openspace.time.currentWallTime();\n";
output += fmt::format(
"local prev = openspace.time.advancedTime(now, \"{}\");\n", _time->value
" local prev = openspace.time.advancedTime(now, \"{}\");\n", p.time->value
);
output += "openspace.time.setTime(prev);\n";
output += " openspace.time.setTime(prev);\n";
break;
default:
throw ghoul::MissingCaseException();
@@ -733,35 +826,37 @@ std::string Profile::convertToScene() const {
// Delta Times
{
output += "\n -- Delta Times\n";
std::string times;
for (const double d : _deltaTimes) {
times += fmt::format("{} ,", d);
for (double d : p.deltaTimes) {
times += fmt::format("{}, ", d);
}
output += fmt::format("openspace.time.setDeltaTimeSteps({{ {} }});\n", times);
output += fmt::format(" openspace.time.setDeltaTimeSteps({{ {} }});\n", times);
}
// Mark Nodes
{
output += "\n -- Mark Nodes\n";
std::string nodes;
for (const std::string& n : _markNodes) {
for (const std::string& n : p.markNodes) {
nodes += fmt::format("[[{}]],", n);
}
output += fmt::format("openspace.markInterestingNodes({{ {} }});\n", nodes);
output += fmt::format(" openspace.markInterestingNodes({{ {} }});\n", nodes);
}
// Properties
for (const Property& p : _properties) {
switch (p.setType) {
case Property::SetType::SetPropertyValue:
output += "\n -- Properties\n";
for (const Profile::Property& prop : p.properties) {
switch (prop.setType) {
case Profile::Property::SetType::SetPropertyValue:
output += fmt::format(
"openspace.setPropertyValue(\"{}\", {});\n",
p.name, p.value
" openspace.setPropertyValue(\"{}\", {});\n", prop.name, prop.value
);
break;
case Property::SetType::SetPropertyValueSingle:
case Profile::Property::SetType::SetPropertyValueSingle:
output += fmt::format(
"openspace.setPropertyValueSingle(\"{}\", {});\n",
p.name, p.value
" openspace.setPropertyValueSingle(\"{}\", {});\n",
prop.name, prop.value
);
break;
default:
@@ -770,169 +865,67 @@ std::string Profile::convertToScene() const {
}
// Camera
if (_camera.has_value()) {
output += "\n -- Camera\n";
if (p.camera.has_value()) {
output += std::visit(
overloaded {
[](const CameraNavState& camera) {
[](const Profile::CameraNavState& c) {
std::string result;
result += "openspace.navigation.setNavigationState({";
result += fmt::format("Anchor = [[{}]], ", camera.anchor);
if (camera.aim.has_value()) {
result += fmt::format("Aim = [[{}]], ", *camera.aim);
result += " openspace.navigation.setNavigationState({";
result += fmt::format("Anchor = [[{}]], ", c.anchor);
if (c.aim.has_value()) {
result += fmt::format("Aim = [[{}]], ", *c.aim);
}
if (!camera.referenceFrame.empty()) {
if (!c.referenceFrame.empty()) {
result += fmt::format(
"ReferenceFrame = [[{}]], ", camera.referenceFrame
"ReferenceFrame = [[{}]], ", c.referenceFrame
);
}
result += fmt::format(
"Position = {{ {}, {}, {} }}, ",
camera.position.x, camera.position.y, camera.position.z
c.position.x, c.position.y, c.position.z
);
if (camera.up.has_value()) {
if (c.up.has_value()) {
result += fmt::format(
"Up = {{ {}, {}, {} }}, ",
camera.up->x, camera.up->y, camera.up->z
"Up = {{ {}, {}, {} }}, ", c.up->x, c.up->y, c.up->z
);
}
if (camera.yaw.has_value()) {
result += fmt::format("Yaw = {}, ", *camera.yaw);
if (c.yaw.has_value()) {
result += fmt::format("Yaw = {}, ", *c.yaw);
}
if (camera.pitch.has_value()) {
result += fmt::format("Pitch = {} ", *camera.pitch);
if (c.pitch.has_value()) {
result += fmt::format("Pitch = {} ", *c.pitch);
}
result += "})\n";
return result;
},
[](const CameraGoToGeo& camera) {
if (camera.altitude.has_value()) {
[](const Profile::CameraGoToGeo& c) {
if (c.altitude.has_value()) {
return fmt::format(
"openspace.globebrowsing.goToGeo([[{}]], {}, {}, {});\n",
camera.anchor,
camera.latitude, camera.longitude, *camera.altitude
" openspace.globebrowsing.goToGeo([[{}]], {}, {}, {});\n",
c.anchor, c.latitude, c.longitude, *c.altitude
);
}
else {
return fmt::format(
"openspace.globebrowsing.goToGeo([[{}]], {}, {});\n",
camera.anchor, camera.latitude, camera.longitude
" openspace.globebrowsing.goToGeo([[{}]], {}, {});\n",
c.anchor, c.latitude, c.longitude
);
}
}
},
*_camera
*p.camera
);
}
for (const std::string& a : _additionalScripts) {
output += fmt::format("{}\n", a);
output += "\n -- Additional Scripts begin\n";
for (const std::string& a : p.additionalScripts) {
output += fmt::format(" {}\n", a);
}
output += " -- Additional Scripts end\n";
output += "end)\n";
return output;
}
Profile::Version Profile::version() const {
return _version;
}
std::vector<Profile::Module> Profile::modules() const {
return _modules;
}
std::optional<Profile::Meta> Profile::meta() const {
return _meta;
}
std::vector<std::string> Profile::assets() const {
return _assets;
}
std::vector<Profile::Property> Profile::properties() const {
return _properties;
}
std::vector<Profile::Keybinding> Profile::keybindings() const {
return _keybindings;
}
std::optional<Profile::Time> Profile::time() const {
return _time;
}
std::vector<double> Profile::deltaTimes() const {
return _deltaTimes;
}
std::optional<Profile::CameraType> Profile::camera() const {
return _camera;
}
std::vector<std::string> Profile::markNodes() const {
return _markNodes;
}
std::vector<std::string> Profile::additionalScripts() const {
return _additionalScripts;
}
void Profile::setVersion(Version v) {
_version = v;
}
void Profile::setModules(std::vector<Module>& m) {
_modules.clear();
copy(m.begin(), m.end(), back_inserter(_modules));
}
void Profile::setMeta(Meta m) {
_meta = m;
}
void Profile::setProperties(std::vector<Property>& p) {
_properties.clear();
copy(p.begin(), p.end(), back_inserter(_properties));
}
void Profile::setKeybindings(std::vector<Keybinding>& k) {
_keybindings.clear();
copy(k.begin(), k.end(), back_inserter(_keybindings));
}
void Profile::setTime(Time t) {
_time = t;
}
void Profile::setDeltaTimes(std::vector<double> dt) {
_deltaTimes = dt;
}
void Profile::setCamera(CameraType c) {
_camera = c;
}
void Profile::setMarkNodes(std::vector<std::string>& n) {
_markNodes.clear();
copy(n.begin(), n.end(), back_inserter(_markNodes));
}
void Profile::setAdditionalScripts(std::vector<std::string>& s) {
_additionalScripts.clear();
copy(s.begin(), s.end(), back_inserter(_additionalScripts));
}
void Profile::clearMeta() {
_meta = std::nullopt;
}
void Profile::clearTime() {
_time = std::nullopt;
}
void Profile::clearCamera() {
_camera = std::nullopt;
}
} // namespace openspace

View File

@@ -34,90 +34,85 @@
namespace openspace {
bool hasKeyModifier(KeyAction lhs, KeyAction rhs) {
return static_cast<std::underlying_type_t<KeyAction>>(lhs) &
static_cast<std::underlying_type_t<KeyAction>>(rhs);
}
KeyAction operator|(KeyAction lhs, KeyAction rhs) {
return static_cast<KeyAction>(
static_cast<std::underlying_type_t<KeyAction>>(lhs) |
static_cast<std::underlying_type_t<KeyAction>>(rhs)
);
}
KeyAction operator|=(KeyAction lhs, KeyAction rhs) {
return (lhs | rhs);
}
bool hasKeyModifier(KeyModifier lhs, KeyModifier rhs) {
return static_cast<std::underlying_type_t<KeyModifier>>(lhs) &
static_cast<std::underlying_type_t<KeyModifier>>(rhs);
}
KeyModifier operator|(KeyModifier lhs, KeyModifier rhs) {
return static_cast<KeyModifier>(
static_cast<std::underlying_type_t<KeyModifier>>(lhs) |
static_cast<std::underlying_type_t<KeyModifier>>(rhs)
);
}
KeyModifier operator|=(KeyModifier lhs, KeyModifier rhs) {
return (lhs | rhs);
}
KeyWithModifier stringToKey(std::string str) {
// key only uppercase
std::transform(
str.begin(),
str.end(),
str.begin(),
[](char v) { return static_cast<char>(toupper(v)); }
);
std::vector<std::string> tokens = ghoul::tokenizeString(str, '+');
std::vector<std::string> originalTokens = tokens;
for (std::string& t : tokens) {
std::transform(
t.begin(), t.end(),
t.begin(),
[](char v) { return static_cast<char>(toupper(v)); }
);
}
// default is unknown
const auto itKey = KeyMapping.find(tokens.back());
if (itKey == KeyMapping.cend()) {
throw ghoul::RuntimeError(
fmt::format("Could not find key for '{}'", tokens.back())
);
Key key = Key::Unknown;
std::string keyName = tokens.back();
std::string keyNameOriginal = originalTokens.back();
for (const KeyInfo& ki : KeyInfos) {
if (ki.identifier == keyName || ki.name == keyName ||
ki.identifier == keyNameOriginal || ki.name == keyNameOriginal)
{
key = ki.key;
break;
}
}
if (key == Key::Unknown) {
throw ghoul::RuntimeError(fmt::format("Could not find key for '{}'", keyName));
}
Key k = itKey->second;
KeyModifier m = KeyModifier::NoModifier;
KeyModifier m = KeyModifier::None;
std::for_each(
tokens.begin(),
tokens.end() - 1,
[&m](const std::string& s) {
const auto itMod = KeyModifierMapping.find(s);
if (itMod != KeyModifierMapping.end()) {
m = static_cast<KeyModifier>(
static_cast<std::underlying_type_t<KeyModifier>>(m) |
static_cast<std::underlying_type_t<KeyModifier>>(itMod->second)
);
bool found = false;
for (const KeyModifierInfo& kmi : KeyModifierInfos) {
if (kmi.identifier == s || kmi.name == s) {
m |= kmi.modifier;
found = true;
break;
}
}
else {
if (!found) {
throw ghoul::RuntimeError(fmt::format("Unknown modifier key '{}'", s));
}
}
);
return { k, m };
return { key, m };
}
bool operator<(const KeyWithModifier& lhs, const KeyWithModifier& rhs) {
if (lhs.modifier == rhs.modifier) {
return lhs.key < rhs.key;
}
else {
return lhs.modifier < rhs.modifier;
}
}
// Returns the 'identifier' of the key (compared to the ghoul::to_string which returns the
// 'name' of the key
std::string keyToString(KeyWithModifier keyWithModifier) {
using namespace openspace;
bool operator==(const KeyWithModifier& lhs, const KeyWithModifier& rhs) {
return (lhs.key == rhs.key) && (lhs.modifier == rhs.modifier);
std::string modifier;
if (keyWithModifier.modifier != KeyModifier::None) {
for (const openspace::KeyModifierInfo& kmi : openspace::KeyModifierInfos) {
// No need for an extra check for the empty modifier since that is mapped to 0,
// meaning that the `hasKeyModifier` will always fail for it since it checks
// internally against != 0
if (hasKeyModifier(keyWithModifier.modifier, kmi.modifier)) {
modifier += fmt::format("{}+", kmi.identifier);
}
}
}
std::string key;
for (const openspace::KeyInfo& ki : openspace::KeyInfos) {
if (ki.key == keyWithModifier.key) {
key = std::string(ki.identifier);
break;
}
}
// The modifier has a residual + at the end that we use here
return modifier + key;
}
} // namespace openspace
@@ -126,11 +121,12 @@ namespace ghoul {
template <>
std::string to_string(const openspace::Key& key) {
for (const std::pair<const std::string, openspace::Key>& p : openspace::KeyMapping) {
if (p.second == key) {
return p.first;
for (const openspace::KeyInfo& ki : openspace::KeyInfos) {
if (ki.key == key) {
return std::string(ki.name);
}
}
throw ghoul::MissingCaseException();
}
@@ -138,30 +134,34 @@ template <>
std::string to_string(const openspace::KeyModifier& mod) {
using namespace openspace;
if (mod == KeyModifier::NoModifier) {
if (mod == KeyModifier::None) {
return "";
}
std::string result;
using K = const std::string;
using V = openspace::KeyModifier;
for (const std::pair<K, V>& p : KeyModifierMapping) {
if (hasKeyModifier(mod, p.second)) {
result += p.first + "+";
for (const openspace::KeyModifierInfo& kmi : openspace::KeyModifierInfos) {
// No need for an extra check for the empty modifier since that is mapped to 0,
// meaning that the `hasKeyModifier` will always fail for it since it checks
// internally against != 0
if (hasKeyModifier(mod, kmi.modifier)) {
result += fmt::format("{}+", kmi.name);
}
}
// The last addition has added an additional '+' that we
// should remove
return result.substr(0, result.size() - 1);
result.pop_back();
return result;
}
template <>
std::string to_string(const openspace::KeyWithModifier& key) {
if (key.modifier == openspace::KeyModifier::NoModifier) {
if (key.modifier == openspace::KeyModifier::None) {
return to_string(key.key);
}
else {
return to_string(key.modifier) + "+" + to_string(key.key);
return fmt::format("{}+{}", to_string(key.modifier), to_string(key.key));
}
}

View File

@@ -26,6 +26,7 @@
#include <openspace/engine/globals.h>
#include <openspace/engine/windowdelegate.h>
#include <openspace/interaction/actionmanager.h>
#include <openspace/interaction/keybindingmanager.h>
#include <openspace/interaction/sessionrecording.h>
#include <openspace/network/parallelpeer.h>
@@ -464,16 +465,19 @@ void TimeManager::addDeltaTimesKeybindings() {
auto addDeltaTimeKeybind = [this](Key key, KeyModifier mod, double step) {
const std::string s = fmt::format("{:.0f}", step);
global::keybindingManager->bindKeyLocal(
key,
mod,
fmt::format("openspace.time.interpolateDeltaTime({})", s),
fmt::format(
"Setting the simulation speed to {} seconds per realtime second", s
),
fmt::format("Set Simulation Speed: {}", s),
DeltaTimeStepsKeybindsGuiPath
std::string identifier = fmt::format("core.time.delta_time.{}", s);
interaction::Action action;
action.identifier = identifier;
action.command = fmt::format("openspace.time.interpolateDeltaTime({})", s);
action.documentation = fmt::format(
"Setting the simulation speed to {} seconds per realtime second", s
);
action.name = fmt::format("Set Simulation Speed: {}", s);
action.guiPath = DeltaTimeStepsKeybindsGuiPath;
action.synchronization = interaction::Action::IsSynchronized::No;
global::actionManager->registerAction(std::move(action));
global::keybindingManager->bindKey(key, mod, std::move(identifier));
_deltaTimeStepKeybindings.push_back(KeyWithModifier{ key, mod });
};
@@ -486,7 +490,7 @@ void TimeManager::addDeltaTimesKeybindings() {
const Key key = Keys[i % nKeys];
const double deltaTimeStep = steps[i];
KeyModifier modifier = KeyModifier::NoModifier;
KeyModifier modifier = KeyModifier::None;
if (i > nKeys - 1) {
modifier = KeyModifier::Shift;
}
@@ -519,11 +523,11 @@ void TimeManager::clearDeltaTimesKeybindings() {
if (bindings.size() > 1) {
std::string names;
for (auto& b : bindings) {
names += fmt::format("'{}' ", b.second.name);
names += fmt::format("'{}' ", b.second);
}
LWARNING(fmt::format(
"Updating keybindings for new delta time steps: More than one action "
"was bound to key '{}'. The following keybindings are removed: {}",
"was bound to key '{}'. The following actions are removed: {}",
ghoul::to_string(kb), names
));
}

View File

@@ -366,7 +366,7 @@ TEST_CASE("Add asset to empty Profile (ignored)", "[profile]") {
source["version"]["minor"] = 11;
Profile p(source.dump());
p.setIgnoreUpdates(true);
p.ignoreUpdates = true;
p.addAsset("new-asset");
std::string originalSerialized = p.serialize();
@@ -403,7 +403,7 @@ TEST_CASE("Add asset to not-empty Profile (ignored)", "[profile]") {
source["assets"].push_back("old-asset");
Profile p(source.dump());
p.setIgnoreUpdates(true);
p.ignoreUpdates = true;
p.addAsset("new-asset");
std::string originalSerialized = p.serialize();
@@ -468,7 +468,7 @@ TEST_CASE("Remove asset (ignored)", "[profile]") {
Profile p(source.dump());
p.setIgnoreUpdates(true);
p.ignoreUpdates = true;
p.removeAsset("asset2");
std::string originalSerialized = p.serialize();
@@ -503,7 +503,7 @@ TEST_CASE("Removing non-exisiting asset (ignored)", "[profile]") {
source["assets"].push_back("asset3");
Profile p(source.dump());
p.setIgnoreUpdates(true);
p.ignoreUpdates = true;
REQUIRE_NOTHROW(p.removeAsset("unknown-asset"));
}