From bf2ab4ed45fc87c97b46f3005ad096adc1c7af38 Mon Sep 17 00:00:00 2001 From: Aesylwinn Date: Sun, 31 Jul 2016 16:07:17 -0400 Subject: [PATCH] Change the way modifiers are handled so they can be shared. --- apps/opencs/model/prefs/modifiersetting.cpp | 13 ++-- apps/opencs/model/prefs/shortcut.cpp | 34 ++++++++- apps/opencs/model/prefs/shortcut.hpp | 6 +- apps/opencs/model/prefs/shortcutmanager.cpp | 74 +++++++++++++------- apps/opencs/model/prefs/shortcutmanager.hpp | 16 +++-- apps/opencs/model/prefs/shortcutsetting.cpp | 13 ++-- apps/opencs/model/prefs/state.cpp | 62 +++++++++------- apps/opencs/model/prefs/state.hpp | 4 +- apps/opencs/view/render/cameracontroller.cpp | 7 +- apps/opencs/view/render/worldspacewidget.cpp | 4 +- 10 files changed, 144 insertions(+), 89 deletions(-) diff --git a/apps/opencs/model/prefs/modifiersetting.cpp b/apps/opencs/model/prefs/modifiersetting.cpp index bbdad163d..d8bf84342 100644 --- a/apps/opencs/model/prefs/modifiersetting.cpp +++ b/apps/opencs/model/prefs/modifiersetting.cpp @@ -21,9 +21,8 @@ namespace CSMPrefs std::pair ModifierSetting::makeWidgets(QWidget* parent) { - QKeySequence sequence; int modifier = 0; - State::get().getShortcutManager().getSequence(getKey(), sequence, modifier); + State::get().getShortcutManager().getModifier(getKey(), modifier); QString text = QString::fromUtf8(State::get().getShortcutManager().convertToString(modifier).c_str()); @@ -111,13 +110,10 @@ namespace CSMPrefs void ModifierSetting::storeValue(int modifier) { - QKeySequence sequence; - int ignored; - State::get().getShortcutManager().getSequence(getKey(), sequence, ignored); - State::get().getShortcutManager().setSequence(getKey(), sequence, modifier); + State::get().getShortcutManager().setModifier(getKey(), modifier); // Convert to string and assign - std::string value = State::get().getShortcutManager().convertToString(sequence, modifier); + std::string value = State::get().getShortcutManager().convertToString(modifier); { QMutexLocker lock(getMutex()); @@ -133,9 +129,8 @@ namespace CSMPrefs mEditorActive = false; // Button text - QKeySequence sequence; int modifier = 0; - State::get().getShortcutManager().getSequence(getKey(), sequence, modifier); + State::get().getShortcutManager().getModifier(getKey(), modifier); QString text = QString::fromUtf8(State::get().getShortcutManager().convertToString(modifier).c_str()); mButton->setText(text); diff --git a/apps/opencs/model/prefs/shortcut.cpp b/apps/opencs/model/prefs/shortcut.cpp index 90ec987ff..27077ac83 100644 --- a/apps/opencs/model/prefs/shortcut.cpp +++ b/apps/opencs/model/prefs/shortcut.cpp @@ -14,6 +14,7 @@ namespace CSMPrefs : QObject(parent) , mEnabled(true) , mName(name) + , mModName("") , mSecondaryMode(SM_Ignore) , mModifier(0) , mCurrentPos(0) @@ -25,13 +26,34 @@ namespace CSMPrefs assert (parent); State::get().getShortcutManager().addShortcut(this); - State::get().getShortcutManager().getSequence(name, mSequence, mModifier); + State::get().getShortcutManager().getSequence(name, mSequence); } - Shortcut::Shortcut(const std::string& name, SecondaryMode secMode, QWidget* parent) + Shortcut::Shortcut(const std::string& name, const std::string& modName, QWidget* parent) : QObject(parent) , mEnabled(true) , mName(name) + , mModName(modName) + , mSecondaryMode(SM_Ignore) + , mModifier(0) + , mCurrentPos(0) + , mLastPos(0) + , mActivationStatus(AS_Inactive) + , mModifierStatus(false) + , mAction(0) + { + assert (parent); + + State::get().getShortcutManager().addShortcut(this); + State::get().getShortcutManager().getSequence(name, mSequence); + State::get().getShortcutManager().getModifier(modName, mModifier); + } + + Shortcut::Shortcut(const std::string& name, const std::string& modName, SecondaryMode secMode, QWidget* parent) + : QObject(parent) + , mEnabled(true) + , mName(name) + , mModName(modName) , mSecondaryMode(secMode) , mModifier(0) , mCurrentPos(0) @@ -43,7 +65,8 @@ namespace CSMPrefs assert (parent); State::get().getShortcutManager().addShortcut(this); - State::get().getShortcutManager().getSequence(name, mSequence, mModifier); + State::get().getShortcutManager().getSequence(name, mSequence); + State::get().getShortcutManager().getModifier(modName, mModifier); } Shortcut::~Shortcut() @@ -61,6 +84,11 @@ namespace CSMPrefs return mName; } + const std::string& Shortcut::getModifierName() const + { + return mModName; + } + Shortcut::SecondaryMode Shortcut::getSecondaryMode() const { return mSecondaryMode; diff --git a/apps/opencs/model/prefs/shortcut.hpp b/apps/opencs/model/prefs/shortcut.hpp index fa68e6f19..7a90a1d08 100644 --- a/apps/opencs/model/prefs/shortcut.hpp +++ b/apps/opencs/model/prefs/shortcut.hpp @@ -34,13 +34,16 @@ namespace CSMPrefs }; Shortcut(const std::string& name, QWidget* parent); - Shortcut(const std::string& name, SecondaryMode secMode, QWidget* parent); + Shortcut(const std::string& name, const std::string& modName, QWidget* parent); + Shortcut(const std::string& name, const std::string& modName, SecondaryMode secMode, QWidget* parent); ~Shortcut(); bool isEnabled() const; const std::string& getName() const; + const std::string& getModifierName() const; + SecondaryMode getSecondaryMode() const; const QKeySequence& getSequence() const; @@ -82,6 +85,7 @@ namespace CSMPrefs bool mEnabled; std::string mName; + std::string mModName; SecondaryMode mSecondaryMode; QKeySequence mSequence; int mModifier; diff --git a/apps/opencs/model/prefs/shortcutmanager.cpp b/apps/opencs/model/prefs/shortcutmanager.cpp index 5a3514a5e..6ae778fff 100644 --- a/apps/opencs/model/prefs/shortcutmanager.cpp +++ b/apps/opencs/model/prefs/shortcutmanager.cpp @@ -19,6 +19,7 @@ namespace CSMPrefs void ShortcutManager::addShortcut(Shortcut* shortcut) { mShortcuts.insert(std::make_pair(shortcut->getName(), shortcut)); + mShortcuts.insert(std::make_pair(shortcut->getModifierName(), shortcut)); mEventHandler->addShortcut(shortcut); } @@ -41,13 +42,12 @@ namespace CSMPrefs mEventHandler->removeShortcut(shortcut); } - bool ShortcutManager::getSequence(const std::string& name, QKeySequence& sequence, int& modifier) const + bool ShortcutManager::getSequence(const std::string& name, QKeySequence& sequence) const { SequenceMap::const_iterator item = mSequences.find(name); if (item != mSequences.end()) { - sequence = item->second.first; - modifier = item->second.second; + sequence = item->second; return true; } @@ -55,17 +55,17 @@ namespace CSMPrefs return false; } - void ShortcutManager::setSequence(const std::string& name, const QKeySequence& sequence, int modifier) + void ShortcutManager::setSequence(const std::string& name, const QKeySequence& sequence) { // Add to map/modify SequenceMap::iterator item = mSequences.find(name); if (item != mSequences.end()) { - item->second = std::make_pair(sequence, modifier); + item->second = sequence; } else { - mSequences.insert(std::make_pair(name, std::make_pair(sequence, modifier))); + mSequences.insert(std::make_pair(name, sequence)); } // Change active shortcuts @@ -74,6 +74,40 @@ namespace CSMPrefs for (ShortcutMap::iterator it = rangeS.first; it != rangeS.second; ++it) { it->second->setSequence(sequence); + } + } + + bool ShortcutManager::getModifier(const std::string& name, int& modifier) const + { + ModifierMap::const_iterator item = mModifiers.find(name); + if (item != mModifiers.end()) + { + modifier = item->second; + + return true; + } + else + return false; + } + + void ShortcutManager::setModifier(const std::string& name, int modifier) + { + // Add to map/modify + ModifierMap::iterator item = mModifiers.find(name); + if (item != mModifiers.end()) + { + item->second = modifier; + } + else + { + mModifiers.insert(std::make_pair(name, modifier)); + } + + // Change active shortcuts + std::pair rangeS = mShortcuts.equal_range(name); + + for (ShortcutMap::iterator it = rangeS.first; it != rangeS.second; ++it) + { it->second->setModifier(modifier); } } @@ -256,7 +290,6 @@ namespace CSMPrefs { const QChar SequenceStart = '{'; const QChar SequenceEnd = '}'; - const QString ModifierSequence = QString::fromUtf8(":mod"); QStringList substrings; @@ -278,30 +311,19 @@ namespace CSMPrefs count = endIndex - startIndex; if (count > 0) { - // Check if looking for modifier - int separatorIndex = toolTip.indexOf(ModifierSequence, startIndex); - if (separatorIndex != -1 && separatorIndex < endIndex) - { - count = separatorIndex - startIndex; + QString settingName = toolTip.mid(startIndex, count); - QString settingName = toolTip.mid(startIndex, count); + QKeySequence sequence; + int modifier; - QKeySequence ignored; - int modifier = 0; - getSequence(settingName.toUtf8().data(), ignored, modifier); - - QString value = QString::fromUtf8(convertToString(modifier).c_str()); + if (getSequence(settingName.toUtf8().data(), sequence)) + { + QString value = QString::fromUtf8(convertToString(sequence).c_str()); substrings.push_back(value); } - else + else if (getModifier(settingName.toUtf8().data(), modifier)) { - QString settingName = toolTip.mid(startIndex, count); - - QKeySequence sequence; - int ignored = 0; - getSequence(settingName.toUtf8().data(), sequence, ignored); - - QString value = QString::fromUtf8(convertToString(sequence).c_str()); + QString value = QString::fromUtf8(convertToString(modifier).c_str()); substrings.push_back(value); } diff --git a/apps/opencs/model/prefs/shortcutmanager.hpp b/apps/opencs/model/prefs/shortcutmanager.hpp index bb081a82a..99f01a5df 100644 --- a/apps/opencs/model/prefs/shortcutmanager.hpp +++ b/apps/opencs/model/prefs/shortcutmanager.hpp @@ -27,8 +27,11 @@ namespace CSMPrefs /// The shortcut class will do this automatically void removeShortcut(Shortcut* shortcut); - bool getSequence(const std::string& name, QKeySequence& sequence, int& modifier) const; - void setSequence(const std::string& name, const QKeySequence& sequence, int modifier); + bool getSequence(const std::string& name, QKeySequence& sequence) const; + void setSequence(const std::string& name, const QKeySequence& sequence); + + bool getModifier(const std::string& name, int& modifier) const; + void setModifier(const std::string& name, int modifier); std::string convertToString(const QKeySequence& sequence) const; std::string convertToString(int modifier) const; @@ -40,22 +43,21 @@ namespace CSMPrefs void convertFromString(const std::string& data, QKeySequence& sequence, int& modifier) const; - /// Replaces "{sequence-name}" or "{sequence-name:mod}" with the appropriate text + /// Replaces "{sequence-name}" or "{modifier-name}" with the appropriate text QString processToolTip(const QString& toolTip) const; private: - /// Key Sequence, Modifier (for secondary signal) - typedef std::pair SequenceData; - // Need a multimap in case multiple shortcuts share the same name typedef std::multimap ShortcutMap; - typedef std::map SequenceMap; + typedef std::map SequenceMap; + typedef std::map ModifierMap; typedef std::map NameMap; typedef std::map KeyMap; ShortcutMap mShortcuts; SequenceMap mSequences; + ModifierMap mModifiers; NameMap mNames; KeyMap mKeys; diff --git a/apps/opencs/model/prefs/shortcutsetting.cpp b/apps/opencs/model/prefs/shortcutsetting.cpp index 82ecd7c81..726566fdd 100644 --- a/apps/opencs/model/prefs/shortcutsetting.cpp +++ b/apps/opencs/model/prefs/shortcutsetting.cpp @@ -29,8 +29,7 @@ namespace CSMPrefs std::pair ShortcutSetting::makeWidgets(QWidget* parent) { QKeySequence sequence; - int ignored = 0; - State::get().getShortcutManager().getSequence(getKey(), sequence, ignored); + State::get().getShortcutManager().getSequence(getKey(), sequence); QString text = QString::fromUtf8(State::get().getShortcutManager().convertToString(sequence).c_str()); @@ -156,13 +155,10 @@ namespace CSMPrefs void ShortcutSetting::storeValue(const QKeySequence& sequence) { - QKeySequence ignored; - int modifier; - State::get().getShortcutManager().getSequence(getKey(), ignored, modifier); - State::get().getShortcutManager().setSequence(getKey(), sequence, modifier); + State::get().getShortcutManager().setSequence(getKey(), sequence); // Convert to string and assign - std::string value = State::get().getShortcutManager().convertToString(sequence, modifier); + std::string value = State::get().getShortcutManager().convertToString(sequence); { QMutexLocker lock(getMutex()); @@ -184,8 +180,7 @@ namespace CSMPrefs // Button text QKeySequence sequence; - int modifier = 0; - State::get().getShortcutManager().getSequence(getKey(), sequence, modifier); + State::get().getShortcutManager().getSequence(getKey(), sequence); QString text = QString::fromUtf8(State::get().getShortcutManager().convertToString(sequence).c_str()); mButton->setText(text); diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index 64a01bf27..718d9a107 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -287,27 +287,6 @@ void CSMPrefs::State::declare() declareShortcut ("reporttable-replace", "Replace Report", QKeySequence()); declareShortcut ("reporttable-refresh", "Refresh Report", QKeySequence()); - declareSubcategory ("1st/Free Camera"); - declareShortcut ("free-forward", "Forward", QKeySequence(Qt::Key_W), Qt::Key_Shift); - declareShortcut ("free-backward", "Backward", QKeySequence(Qt::Key_S)); - declareShortcut ("free-left", "Left", QKeySequence(Qt::Key_A)); - declareShortcut ("free-right", "Right", QKeySequence(Qt::Key_D)); - declareModifier ("free-forward", "Speed Modifier"); - declareShortcut ("free-roll-left", "Roll Left", QKeySequence(Qt::Key_Q)); - declareShortcut ("free-roll-right", "Roll Right", QKeySequence(Qt::Key_E)); - declareShortcut ("free-speed-mode", "Toggle Speed Mode", QKeySequence(Qt::Key_F)); - - declareSubcategory ("Orbit Camera"); - declareShortcut ("orbit-up", "Up", QKeySequence(Qt::Key_W), Qt::Key_Shift); - declareShortcut ("orbit-down", "Down", QKeySequence(Qt::Key_S)); - declareShortcut ("orbit-left", "Left", QKeySequence(Qt::Key_A)); - declareShortcut ("orbit-right", "Right", QKeySequence(Qt::Key_D)); - declareModifier ("orbit-up", "Speed Modifier"); - declareShortcut ("orbit-roll-left", "Roll Left", QKeySequence(Qt::Key_Q)); - declareShortcut ("orbit-roll-right", "Roll Right", QKeySequence(Qt::Key_E)); - declareShortcut ("orbit-speed-mode", "Toggle Speed Mode", QKeySequence(Qt::Key_F)); - declareShortcut ("orbit-center-selection", "Center On Selected", QKeySequence(Qt::Key_C)); - declareSubcategory ("Scene"); declareShortcut ("scene-navi-primary", "Camera Rotation From Mouse Movement", QKeySequence(Qt::LeftButton)); declareShortcut ("scene-navi-secondary", "Camera Translation From Mouse Movement", @@ -318,6 +297,7 @@ void CSMPrefs::State::declare() declareShortcut ("scene-select-primary", "Primary Select", QKeySequence(Qt::MiddleButton)); declareShortcut ("scene-select-secondary", "Secondary Select", QKeySequence(Qt::ControlModifier | (int)Qt::MiddleButton)); + declareModifier ("scene-speed-modifier", "Speed Modifier", Qt::Key_Shift); declareShortcut ("scene-load-cam-cell", "Load Camera Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_5)); declareShortcut ("scene-load-cam-eastcell", "Load East Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_6)); declareShortcut ("scene-load-cam-northcell", "Load North Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_8)); @@ -326,6 +306,25 @@ void CSMPrefs::State::declare() declareShortcut ("scene-edit-abort", "Abort", QKeySequence(Qt::Key_Escape)); declareShortcut ("scene-focus-toolbar", "Toggle Toolbar Focus", QKeySequence(Qt::Key_T)); declareShortcut ("scene-render-stats", "Debug Rendering Stats", QKeySequence(Qt::Key_F3)); + + declareSubcategory ("1st/Free Camera"); + declareShortcut ("free-forward", "Forward", QKeySequence(Qt::Key_W)); + declareShortcut ("free-backward", "Backward", QKeySequence(Qt::Key_S)); + declareShortcut ("free-left", "Left", QKeySequence(Qt::Key_A)); + declareShortcut ("free-right", "Right", QKeySequence(Qt::Key_D)); + declareShortcut ("free-roll-left", "Roll Left", QKeySequence(Qt::Key_Q)); + declareShortcut ("free-roll-right", "Roll Right", QKeySequence(Qt::Key_E)); + declareShortcut ("free-speed-mode", "Toggle Speed Mode", QKeySequence(Qt::Key_F)); + + declareSubcategory ("Orbit Camera"); + declareShortcut ("orbit-up", "Up", QKeySequence(Qt::Key_W)); + declareShortcut ("orbit-down", "Down", QKeySequence(Qt::Key_S)); + declareShortcut ("orbit-left", "Left", QKeySequence(Qt::Key_A)); + declareShortcut ("orbit-right", "Right", QKeySequence(Qt::Key_D)); + declareShortcut ("orbit-roll-left", "Roll Left", QKeySequence(Qt::Key_Q)); + declareShortcut ("orbit-roll-right", "Roll Right", QKeySequence(Qt::Key_E)); + declareShortcut ("orbit-speed-mode", "Toggle Speed Mode", QKeySequence(Qt::Key_F)); + declareShortcut ("orbit-center-selection", "Center On Selected", QKeySequence(Qt::Key_C)); } void CSMPrefs::State::declareCategory (const std::string& key) @@ -443,20 +442,19 @@ CSMPrefs::ColourSetting& CSMPrefs::State::declareColour (const std::string& key, } CSMPrefs::ShortcutSetting& CSMPrefs::State::declareShortcut (const std::string& key, const std::string& label, - const QKeySequence& default_, int modifier_) + const QKeySequence& default_) { if (mCurrentCategory==mCategories.end()) throw std::logic_error ("no category for setting"); - std::string seqStr = getShortcutManager().convertToString(default_, modifier_); + std::string seqStr = getShortcutManager().convertToString(default_); setDefault (key, seqStr); // Setup with actual data QKeySequence sequence; - int mod; - getShortcutManager().convertFromString(mSettings.getString(key, mCurrentCategory->second.getKey()), sequence, mod); - getShortcutManager().setSequence(key, sequence, mod); + getShortcutManager().convertFromString(mSettings.getString(key, mCurrentCategory->second.getKey()), sequence); + getShortcutManager().setSequence(key, sequence); CSMPrefs::ShortcutSetting *setting = new CSMPrefs::ShortcutSetting (&mCurrentCategory->second, &mSettings, &mMutex, key, label); @@ -465,11 +463,21 @@ CSMPrefs::ShortcutSetting& CSMPrefs::State::declareShortcut (const std::string& return *setting; } -CSMPrefs::ModifierSetting& CSMPrefs::State::declareModifier(const std::string& key, const std::string& label) +CSMPrefs::ModifierSetting& CSMPrefs::State::declareModifier(const std::string& key, const std::string& label, + int default_) { if (mCurrentCategory==mCategories.end()) throw std::logic_error ("no category for setting"); + std::string modStr = getShortcutManager().convertToString(default_); + setDefault (key, modStr); + + // Setup with actual data + int modifier; + + getShortcutManager().convertFromString(mSettings.getString(key, mCurrentCategory->second.getKey()), modifier); + getShortcutManager().setModifier(key, modifier); + CSMPrefs::ModifierSetting *setting = new CSMPrefs::ModifierSetting (&mCurrentCategory->second, &mSettings, &mMutex, key, label); mCurrentCategory->second.addSetting (setting); diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index 64927f881..1e46c68ee 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -76,9 +76,9 @@ namespace CSMPrefs ColourSetting& declareColour (const std::string& key, const std::string& label, QColor default_); ShortcutSetting& declareShortcut (const std::string& key, const std::string& label, - const QKeySequence& default_, int modifier_=0); + const QKeySequence& default_); - ModifierSetting& declareModifier(const std::string& key, const std::string& label); + ModifierSetting& declareModifier(const std::string& key, const std::string& label, int modifier_); void declareSeparator(); diff --git a/apps/opencs/view/render/cameracontroller.cpp b/apps/opencs/view/render/cameracontroller.cpp index 6df7c0478..7e3570657 100644 --- a/apps/opencs/view/render/cameracontroller.cpp +++ b/apps/opencs/view/render/cameracontroller.cpp @@ -189,8 +189,8 @@ namespace CSVRender addShortcut(naviSecondaryShortcut); - CSMPrefs::Shortcut* forwardShortcut = new CSMPrefs::Shortcut("free-forward", CSMPrefs::Shortcut::SM_Detach, - widget); + CSMPrefs::Shortcut* forwardShortcut = new CSMPrefs::Shortcut("free-forward", "scene-speed-modifier", + CSMPrefs::Shortcut::SM_Detach, widget); forwardShortcut->enable(false); connect(forwardShortcut, SIGNAL(activated(bool)), this, SLOT(forward(bool))); connect(forwardShortcut, SIGNAL(secondary(bool)), this, SLOT(alternateFast(bool))); @@ -476,7 +476,8 @@ namespace CSVRender addShortcut(naviSecondaryShortcut); - CSMPrefs::Shortcut* upShortcut = new CSMPrefs::Shortcut("orbit-up", CSMPrefs::Shortcut::SM_Detach, widget); + CSMPrefs::Shortcut* upShortcut = new CSMPrefs::Shortcut("orbit-up", "scene-speed-modifier", + CSMPrefs::Shortcut::SM_Detach, widget); upShortcut->enable(false); connect(upShortcut, SIGNAL(activated(bool)), this, SLOT(up(bool))); connect(upShortcut, SIGNAL(secondary(bool)), this, SLOT(alternateFast(bool))); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index dda665c31..2dfa66a12 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -168,7 +168,7 @@ CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeNavigationSelector ( "
  • Movement keys: {free-forward}(forward), {free-left}(left), {free-backward}(back), {free-right}(right)
  • " "
  • Strafing (also vertically) by holding {scene-navi-secondary}
  • " "
  • Mouse wheel moves the camera forward/backward
  • " - "
  • Hold {free-forward:mod} to speed up movement
  • " + "
  • Hold {scene-speed-modifier} to speed up movement
  • " ""); tool->addButton (":scenetoolbar/free-camera", "free", "Free Camera" @@ -188,7 +188,7 @@ CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeNavigationSelector ( "
  • Roll camera with {orbit-roll-left} and {orbit-roll-right} keys
  • " "
  • Strafing (also vertically) by holding {scene-navi-secondary} (includes relocation of the centre point)
  • " "
  • Mouse wheel moves camera away or towards centre point but can not pass through it
  • " - "
  • Hold {orbit-up:mod} to speed up movement
  • " + "
  • Hold {scene-speed-modifier} to speed up movement
  • " "", tool), "orbit");