diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index f8cf1e2d8..d95317aaf 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -86,12 +86,12 @@ opencs_units (view/widget opencs_units (view/render scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget previewwidget editmode instancemode instanceselectionmode instancemovemode - orbitcameramode pathgridmode selectionmode pathgridselectionmode + orbitcameramode pathgridmode selectionmode pathgridselectionmode cameracontroller ) opencs_units_noqt (view/render lighting lightingday lightingnight lightingbright object cell terrainstorage tagbase - cellarrow cellmarker cellborder cameracontroller pathgrid + cellarrow cellmarker cellborder pathgrid ) opencs_hdrs_noqt (view/render @@ -112,7 +112,8 @@ opencs_units (view/prefs ) opencs_units (model/prefs - state setting intsetting doublesetting boolsetting enumsetting coloursetting + state setting intsetting doublesetting boolsetting enumsetting coloursetting shortcut + shortcutmanager shortcutsetting ) opencs_units_noqt (model/prefs diff --git a/apps/opencs/model/prefs/shortcut.cpp b/apps/opencs/model/prefs/shortcut.cpp new file mode 100644 index 000000000..f691cede9 --- /dev/null +++ b/apps/opencs/model/prefs/shortcut.cpp @@ -0,0 +1,139 @@ +#include "shortcut.hpp" + +#include +#include +#include + +#include "state.hpp" +#include "shortcutmanager.hpp" + +namespace CSMPrefs +{ + Shortcut::Shortcut(const std::string& name, QObject* parent) + : QObject(parent) + , mName(name) + , mCurrentPos(0) + , mLastPos(0) + { + State::get().getShortcutManager().addShortcut(this); + setSequence(State::get().getShortcutManager().getSequence(name)); + } + + Shortcut::~Shortcut() + { + State::get().getShortcutManager().removeShortcut(this); + } + + const std::string& Shortcut::getName() const + { + return mName; + } + + const QKeySequence& Shortcut::getSequence() const + { + return mSequence; + } + + void Shortcut::setSequence(const QKeySequence& sequence) + { + mSequence = sequence; + mCurrentPos = 0; + mLastPos = sequence.count() - 1; + } + + void Shortcut::keyPressEvent(QKeyEvent* event) + { + int withMod = event->key() | event->modifiers(); + int noMod = event->key(); + + if (withMod == mSequence[mCurrentPos] || (mCurrentPos > 0 && noMod == mSequence[mCurrentPos])) + { + if (mCurrentPos == mLastPos) + { + activated(true); + } + else + ++mCurrentPos; + } + } + + void Shortcut::keyReleaseEvent(QKeyEvent* event) + { + const int KeyMask = 0x01FFFFFF; + + if ((mSequence[mCurrentPos] & KeyMask) == event->key()) + { + if (mCurrentPos == mLastPos) + { + activated(false); + mCurrentPos = 0; // Resets to start, maybe shouldn't? + } + else if (mCurrentPos > 0) + { + --mCurrentPos; + } + } + } + + void Shortcut::mousePressEvent(QMouseEvent* event) + { + int withMod = event->button() | (int)event->modifiers(); + int noMod = event->button(); + + if (withMod == mSequence[mCurrentPos] || (mCurrentPos > 0 && noMod == mSequence[mCurrentPos])) + { + if (mCurrentPos == mLastPos) + activated(true); + else + ++mCurrentPos; + } + } + + void Shortcut::mouseReleaseEvent(QMouseEvent* event) + { + const int MouseMask = 0x0000001F; + + if ((mSequence[mCurrentPos] & MouseMask) == event->button()) + { + if (mCurrentPos == mLastPos) + { + activated(false); + mCurrentPos = 0; + } + else if (mCurrentPos > 0) + { + --mCurrentPos; + } + } + } + + QShortcutWrapper::QShortcutWrapper(const std::string& name, QShortcut* shortcut) + : QObject(shortcut) + , mName(name) + , mShortcut(shortcut) + { + State::get().getShortcutManager().addShortcut(this); + setSequence(State::get().getShortcutManager().getSequence(name)); + } + + QShortcutWrapper::~QShortcutWrapper() + { + State::get().getShortcutManager().removeShortcut(this); + } + + const std::string& QShortcutWrapper::getName() const + { + return mName; + } + + const QKeySequence& QShortcutWrapper::getSequence() const + { + return mSequence; + } + + void QShortcutWrapper::setSequence(const QKeySequence& sequence) + { + mSequence = sequence; + mShortcut->setKey(sequence); + } +} diff --git a/apps/opencs/model/prefs/shortcut.hpp b/apps/opencs/model/prefs/shortcut.hpp new file mode 100644 index 000000000..b121c0610 --- /dev/null +++ b/apps/opencs/model/prefs/shortcut.hpp @@ -0,0 +1,71 @@ +#ifndef CSM_PREFS_SHORTCUT_H +#define CSM_PREFS_SHORTCUT_H + +#include +#include + +class QKeyEvent; +class QMouseEvent; +class QShortcut; + +namespace CSMPrefs +{ + /// A class similar in purpose to QShortcut, but with the ability to use mouse buttons + class Shortcut : public QObject + { + Q_OBJECT + + public: + + Shortcut(const std::string& name, QObject* parent); + ~Shortcut(); + + const std::string& getName() const; + const QKeySequence& getSequence() const; + + void setSequence(const QKeySequence& sequence); + + private: + + std::string mName; + QKeySequence mSequence; + int mCurrentPos; + int mLastPos; + + public slots: + + void keyPressEvent(QKeyEvent* event); + void keyReleaseEvent(QKeyEvent* event); + void mousePressEvent(QMouseEvent* event); + void mouseReleaseEvent(QMouseEvent* event); + + signals: + + /// Triggered when the shortcut is activated or deactived; can be determined from \p active + void activated(bool active); + }; + + /// Wraps a QShortcut object so that the sequence can be modified by the settings + class QShortcutWrapper : public QObject + { + Q_OBJECT + + public: + + QShortcutWrapper(const std::string& name, QShortcut* shortcut); + ~QShortcutWrapper(); + + const std::string& getName() const; + const QKeySequence& getSequence() const; + + void setSequence(const QKeySequence& sequence); + + private: + + std::string mName; + QKeySequence mSequence; + QShortcut* mShortcut; + }; +} + +#endif diff --git a/apps/opencs/model/prefs/shortcutmanager.cpp b/apps/opencs/model/prefs/shortcutmanager.cpp new file mode 100644 index 000000000..3e81a5e3d --- /dev/null +++ b/apps/opencs/model/prefs/shortcutmanager.cpp @@ -0,0 +1,197 @@ +#include "shortcutmanager.hpp" + +#include +#include + +#include + +#include "shortcut.hpp" + +namespace CSMPrefs +{ + void ShortcutManager::addShortcut(Shortcut* shortcut) + { + mShortcuts.insert(std::make_pair(shortcut->getName(), shortcut)); + } + + void ShortcutManager::addShortcut(QShortcutWrapper* wrapper) + { + mShortcutWrappers.insert(std::make_pair(wrapper->getName(), wrapper)); + } + + void ShortcutManager::removeShortcut(Shortcut* shortcut) + { + std::pair range = mShortcuts.equal_range(shortcut->getName()); + + for (ShortcutMap::iterator it = range.first; it != range.second;) + { + if (it->second == shortcut) + { + it = mShortcuts.erase(it); + } + else + { + ++it; + } + } + } + + void ShortcutManager::removeShortcut(QShortcutWrapper* wrapper) + { + std::pair range = mShortcutWrappers.equal_range( + wrapper->getName()); + + for (ShortcutWrapperMap::iterator it = range.first; it != range.second;) + { + if (it->second == wrapper) + { + it = mShortcutWrappers.erase(it); + } + else + { + ++it; + } + } + } + + QKeySequence ShortcutManager::getSequence(const std::string& name) const + { + QKeySequence sequence; + SequenceMap::const_iterator item = mSequences.find(name); + + if (item != mSequences.end()) + { + sequence = item->second; + } + + return sequence; + } + + 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 = sequence; + } + else + { + mSequences.insert(std::make_pair(name, sequence)); + } + + // Change active shortcuts + std::pair rangeS = mShortcuts.equal_range(name); + std::pair rangeW = mShortcutWrappers.equal_range(name); + + for (ShortcutMap::iterator it = rangeS.first; it != rangeS.second; ++it) + { + it->second->setSequence(sequence); + } + + for (ShortcutWrapperMap::iterator it = rangeW.first; it != rangeW.second; ++it) + { + it->second->setSequence(sequence); + } + } + + std::string ShortcutManager::sequenceToString(const QKeySequence& seq) + { + const int MouseMask = 0x0000001F; // Conflicts with key + const int KeyMask = 0x01FFFFFF; + const int ModMask = 0x7E000000; + + const int KeyEnumIndex = staticQtMetaObject.indexOfEnumerator("Key"); + const int ModEnumIndex = staticQtMetaObject.indexOfEnumerator("KeyboardModifiers"); + + std::string output; + + for (int i = 0; i < seq.count(); ++i) + { + if (seq[i] & ModMask) + { + // TODO separate out modifiers to allow more than 1 + output.append(staticQtMetaObject.enumerator(ModEnumIndex).valueToKey(seq[i] & ModMask)); + output.append("+"); + } + + if (seq[i] & KeyMask & ~MouseMask) + { + // Is a key + output.append(staticQtMetaObject.enumerator(KeyEnumIndex).valueToKey(seq[i] & KeyMask)); + output.append(","); + } + else if (seq[i] & MouseMask) + { + std::stringstream ss; + std::string num; + + unsigned int value = (unsigned int)(seq[i] & MouseMask); + + // value will never be 0 + int exponent = 1; // Offset by 1 + while (value >>= 1) + ++exponent; + + ss << exponent; + ss >> num; + + // Is a mouse button + output.append("Mouse"); + output.append(num); + output.append(","); + } + } + + // Remove last comma + if (output.size() > 0) + { + output.resize(output.size() - 1); + } + + return output; + } + + QKeySequence ShortcutManager::stringToSequence(const std::string& input) + { + const int KeyEnumIndex = staticQtMetaObject.indexOfEnumerator("Key"); + const int ModEnumIndex = staticQtMetaObject.indexOfEnumerator("KeyboardModifiers"); + + int keys[4] = { 0, 0, 0, 0 }; + + QRegExp splitRX("[, ]"); + QStringList keyStrs = QString(input.c_str()).split(splitRX, QString::SkipEmptyParts); + + for (int i = 0; i < keyStrs.size(); ++i) + { + QRegExp modSeparator("[+]"); + + QStringList separatedList = keyStrs[i].split(modSeparator, QString::SkipEmptyParts); + for (int j = 0; j < separatedList.size(); ++j) + { + if (separatedList[j].startsWith("Mouse")) + { + QString num = separatedList[j].mid(5); + if (num > 0) + { + keys[i] |= 1 << (num.toInt() - 1); // offset by 1 + } + } + else if (staticQtMetaObject.enumerator(ModEnumIndex).keyToValue(separatedList[j].toUtf8().data()) != -1) + { + keys[i] |= staticQtMetaObject.enumerator(ModEnumIndex).keyToValue(separatedList[j].toUtf8().data()); + } + else if (staticQtMetaObject.enumerator(KeyEnumIndex).keyToValue(separatedList[j].toUtf8().data()) != -1) + { + keys[i] |= staticQtMetaObject.enumerator(KeyEnumIndex).keyToValue(separatedList[j].toUtf8().data()); + } + } + } + + // TODO remove + std::cout << input << '.' << keys[0] << '.'<< keys[1] << '.'<< keys[2] << '.'<< keys[3] << std::endl; + + return QKeySequence(keys[0], keys[1], keys[2], keys[3]); + } +} diff --git a/apps/opencs/model/prefs/shortcutmanager.hpp b/apps/opencs/model/prefs/shortcutmanager.hpp new file mode 100644 index 000000000..f2534347a --- /dev/null +++ b/apps/opencs/model/prefs/shortcutmanager.hpp @@ -0,0 +1,51 @@ +#ifndef CSM_PREFS_SHORTCUTMANAGER_H +#define CSM_PREFS_SHORTCUTMANAGER_H + +#include + +#include +#include + +namespace CSMPrefs +{ + class Shortcut; + class QShortcutWrapper; + + /// Class used to track and update shortcuts/sequences + class ShortcutManager : public QObject + { + Q_OBJECT + + public: + + /// The shortcut class will do this automatically + void addShortcut(Shortcut* shortcut); + /// The wrapper class will do this automatically + void addShortcut(QShortcutWrapper* wrapper); + + /// The shortcut class will do this automatically + void removeShortcut(Shortcut* shortcut); + /// The wrapper class will do this automatically + void removeShortcut(QShortcutWrapper* wrapper); + + QKeySequence getSequence(const std::string& name) const; + void setSequence(const std::string& name, const QKeySequence& sequence); + + std::string sequenceToString(const QKeySequence& sequence); + QKeySequence stringToSequence(const std::string& str); + + private: + + // Need a multimap in case multiple shortcuts share the same name + typedef std::multimap ShortcutMap; + typedef std::multimap ShortcutWrapperMap; + + typedef std::map SequenceMap; + + ShortcutMap mShortcuts; + ShortcutWrapperMap mShortcutWrappers; + SequenceMap mSequences; + }; +} + +#endif diff --git a/apps/opencs/model/prefs/shortcutsetting.cpp b/apps/opencs/model/prefs/shortcutsetting.cpp new file mode 100644 index 000000000..5b2008241 --- /dev/null +++ b/apps/opencs/model/prefs/shortcutsetting.cpp @@ -0,0 +1,43 @@ +#include "shortcutsetting.hpp" + +#include +#include +#include + +#include "state.hpp" +#include "shortcutmanager.hpp" + +namespace CSMPrefs +{ + ShortcutSetting::ShortcutSetting(Category* parent, Settings::Manager* values, QMutex* mutex, const std::string& key, + const std::string& label, const QKeySequence& default_) + : Setting(parent, values, mutex, key, label) + , mDefault(default_) + { + State::get().getShortcutManager().setSequence(key, mDefault); + } + + std::pair ShortcutSetting::makeWidgets(QWidget* parent) + { + QLabel* label = new QLabel(QString::fromUtf8(getLabel().c_str()), parent); + QLineEdit* widget = new QLineEdit(State::get().getShortcutManager().sequenceToString(mDefault).c_str(), parent); + + connect(widget, SIGNAL(textChanged(const QString&)), this, SLOT(valueChanged(const QString&))); + + return std::make_pair(label, widget); + } + + void ShortcutSetting::valueChanged(const QString& text) + { + { + QMutexLocker lock(getMutex()); + getValues().setString(getKey(), getParent()->getKey(), text.toUtf8().data()); + + QKeySequence sequence = State::get().getShortcutManager().stringToSequence(text.toUtf8().data()); + + State::get().getShortcutManager().setSequence(getKey(), sequence); + } + + getParent()->getState()->update(*this); + } +} diff --git a/apps/opencs/model/prefs/shortcutsetting.hpp b/apps/opencs/model/prefs/shortcutsetting.hpp new file mode 100644 index 000000000..893b01f93 --- /dev/null +++ b/apps/opencs/model/prefs/shortcutsetting.hpp @@ -0,0 +1,30 @@ +#ifndef CSM_PREFS_SHORTCUTSETTING_H +#define CSM_PREFS_SHORTCUTSETTING_H + +#include + +#include "setting.hpp" + +namespace CSMPrefs +{ + class ShortcutSetting : public Setting + { + Q_OBJECT + + QKeySequence mDefault; + + public: + + ShortcutSetting(Category* parent, Settings::Manager* values, QMutex* mutex, const std::string& key, + const std::string& label, const QKeySequence& default_); + + // TODO replace with custom page + virtual std::pair makeWidgets(QWidget* parent); + + private slots: + + void valueChanged(const QString& text); + }; +} + +#endif diff --git a/apps/opencs/model/prefs/state.cpp b/apps/opencs/model/prefs/state.cpp index c70e71deb..f2a0b31e1 100644 --- a/apps/opencs/model/prefs/state.cpp +++ b/apps/opencs/model/prefs/state.cpp @@ -5,10 +5,13 @@ #include #include +#include + #include "intsetting.hpp" #include "doublesetting.hpp" #include "boolsetting.hpp" #include "coloursetting.hpp" +#include "shortcutsetting.hpp" CSMPrefs::State *CSMPrefs::State::sThis = 0; @@ -224,6 +227,15 @@ void CSMPrefs::State::declare() addValues (insertOutsideCell); declareEnum ("outside-visible-drop", "Handling drops outside of visible cells", showAndInsert). addValues (insertOutsideVisibleCell); + + declareCategory ("Key Bindings"); + declareShortcut ("free-forward", "Free camera forward", QKeySequence(Qt::Key_W)); + declareShortcut ("free-backward", "Free camera backward", QKeySequence(Qt::Key_S)); + declareShortcut ("free-left", "Free camera left", QKeySequence(Qt::Key_A)); + declareShortcut ("free-right", "Free camera right", QKeySequence(Qt::Key_D)); + declareShortcut ("free-roll-left", "Free camera roll left", QKeySequence(Qt::Key_Q)); + declareShortcut ("free-roll-right", "Free camera roll right", QKeySequence(Qt::Key_E)); + declareShortcut ("free-speed-mode", "Free camera speed mode toggle", QKeySequence(Qt::Key_F)); } void CSMPrefs::State::declareCategory (const std::string& key) @@ -340,6 +352,26 @@ CSMPrefs::ColourSetting& CSMPrefs::State::declareColour (const std::string& key, return *setting; } +CSMPrefs::ShortcutSetting& CSMPrefs::State::declareShortcut (const std::string& key, const std::string& label, + const QKeySequence& default_) +{ + if (mCurrentCategory==mCategories.end()) + throw std::logic_error ("no category for setting"); + + std::string seqStr = getShortcutManager().sequenceToString(default_); + setDefault (key, seqStr); + + QKeySequence seq = getShortcutManager().stringToSequence(mSettings.getString(key, + mCurrentCategory->second.getKey())); + + CSMPrefs::ShortcutSetting *setting = new CSMPrefs::ShortcutSetting (&mCurrentCategory->second, &mSettings, &mMutex, + key, label, seq); + + mCurrentCategory->second.addSetting (setting); + + return *setting; +} + void CSMPrefs::State::declareSeparator() { if (mCurrentCategory==mCategories.end()) @@ -369,10 +401,10 @@ CSMPrefs::State::State (const Files::ConfigurationManager& configurationManager) if (sThis) throw std::logic_error ("An instance of CSMPRefs::State already exists"); + sThis = this; + load(); declare(); - - sThis = this; } CSMPrefs::State::~State() @@ -396,6 +428,11 @@ CSMPrefs::State::Iterator CSMPrefs::State::end() return mCategories.end(); } +CSMPrefs::ShortcutManager& CSMPrefs::State::getShortcutManager() +{ + return mShortcutManager; +} + CSMPrefs::Category& CSMPrefs::State::operator[] (const std::string& key) { Iterator iter = mCategories.find (key); diff --git a/apps/opencs/model/prefs/state.hpp b/apps/opencs/model/prefs/state.hpp index fffadee5e..15f6e6d1b 100644 --- a/apps/opencs/model/prefs/state.hpp +++ b/apps/opencs/model/prefs/state.hpp @@ -16,6 +16,7 @@ #include "category.hpp" #include "setting.hpp" #include "enumsetting.hpp" +#include "shortcutmanager.hpp" class QColor; @@ -25,6 +26,7 @@ namespace CSMPrefs class DoubleSetting; class BoolSetting; class ColourSetting; + class ShortcutSetting; /// \brief User settings state /// @@ -45,6 +47,7 @@ namespace CSMPrefs const std::string mConfigFile; const Files::ConfigurationManager& mConfigurationManager; + ShortcutManager mShortcutManager; Settings::Manager mSettings; Collection mCategories; Iterator mCurrentCategory; @@ -71,6 +74,8 @@ 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_); + void declareSeparator(); void setDefault (const std::string& key, const std::string& default_); @@ -87,6 +92,8 @@ namespace CSMPrefs Iterator end(); + ShortcutManager& getShortcutManager(); + Category& operator[](const std::string& key); void update (const Setting& setting); diff --git a/apps/opencs/view/render/cameracontroller.cpp b/apps/opencs/view/render/cameracontroller.cpp index dc356827a..ec78db011 100644 --- a/apps/opencs/view/render/cameracontroller.cpp +++ b/apps/opencs/view/render/cameracontroller.cpp @@ -14,6 +14,10 @@ #include +#include "../../model/prefs/shortcut.hpp" + +#include "scenewidget.hpp" + namespace CSVRender { @@ -140,7 +144,7 @@ namespace CSVRender Free Camera Controller */ - FreeCameraController::FreeCameraController() + FreeCameraController::FreeCameraController(SceneWidget* scene) : mLockUpright(false) , mModified(false) , mFast(false) @@ -155,6 +159,33 @@ namespace CSVRender , mRotSpeed(osg::PI / 2) , mSpeedMult(8) { + CSMPrefs::Shortcut* forwardShortcut = new CSMPrefs::Shortcut("free-forward", this); + scene->addShortcut(forwardShortcut); + connect(forwardShortcut, SIGNAL(activated(bool)), this, SLOT(forward(bool))); + + CSMPrefs::Shortcut* leftShortcut = new CSMPrefs::Shortcut("free-left", this); + scene->addShortcut(leftShortcut); + connect(leftShortcut, SIGNAL(activated(bool)), this, SLOT(left(bool))); + + CSMPrefs::Shortcut* backShortcut = new CSMPrefs::Shortcut("free-backward", this); + scene->addShortcut(backShortcut); + connect(backShortcut, SIGNAL(activated(bool)), this, SLOT(backward(bool))); + + CSMPrefs::Shortcut* rightShortcut = new CSMPrefs::Shortcut("free-right", this); + scene->addShortcut(rightShortcut); + connect(rightShortcut, SIGNAL(activated(bool)), this, SLOT(right(bool))); + + CSMPrefs::Shortcut* rollLeftShortcut = new CSMPrefs::Shortcut("free-roll-left", this); + scene->addShortcut(rollLeftShortcut); + connect(rollLeftShortcut, SIGNAL(activated(bool)), this, SLOT(rollLeft(bool))); + + CSMPrefs::Shortcut* rollRightShortcut = new CSMPrefs::Shortcut("free-roll-right", this); + scene->addShortcut(rollRightShortcut); + connect(rollRightShortcut, SIGNAL(activated(bool)), this, SLOT(rollRight(bool))); + + CSMPrefs::Shortcut* speedModeShortcut = new CSMPrefs::Shortcut("free-speed-mode", this); + scene->addShortcut(speedModeShortcut); + connect(speedModeShortcut, SIGNAL(activated(bool)), this, SLOT(swapSpeedMode(bool))); } double FreeCameraController::getLinearSpeed() const @@ -204,39 +235,6 @@ namespace CSVRender if (!isActive()) return false; - if (event->key() == Qt::Key_Q) - { - mRollLeft = pressed; - } - else if (event->key() == Qt::Key_E) - { - mRollRight = pressed; - } - else if (event->key() == Qt::Key_A) - { - mLeft = pressed; - } - else if (event->key() == Qt::Key_D) - { - mRight = pressed; - } - else if (event->key() == Qt::Key_W) - { - mForward = pressed; - } - else if (event->key() == Qt::Key_S) - { - mBackward = pressed; - } - else if (event->key() == Qt::Key_Shift) - { - mFast = pressed; - } - else - { - return false; - } - return true; } @@ -368,11 +366,53 @@ namespace CSVRender getCamera()->setViewMatrixAsLookAt(eye, center, mUp); } + void FreeCameraController::forward(bool active) + { + if (isActive()) + mForward = active; + } + + void FreeCameraController::left(bool active) + { + if (isActive()) + mLeft = active; + } + + void FreeCameraController::backward(bool active) + { + if (isActive()) + mBackward = active; + } + + void FreeCameraController::right(bool active) + { + if (isActive()) + mRight = active; + } + + void FreeCameraController::rollLeft(bool active) + { + if (isActive()) + mRollLeft = active; + } + + void FreeCameraController::rollRight(bool active) + { + if (isActive()) + mRollRight = active; + } + + void FreeCameraController::swapSpeedMode(bool active) + { + if (isActive() && active) + mFast = !mFast; + } + /* Orbit Camera Controller */ - OrbitCameraController::OrbitCameraController() + OrbitCameraController::OrbitCameraController(SceneWidget* widget) : mInitialized(false) , mFast(false) , mLeft(false) diff --git a/apps/opencs/view/render/cameracontroller.hpp b/apps/opencs/view/render/cameracontroller.hpp index f9021f04b..2131e1f02 100644 --- a/apps/opencs/view/render/cameracontroller.hpp +++ b/apps/opencs/view/render/cameracontroller.hpp @@ -3,6 +3,8 @@ #include +#include + #include #include @@ -16,8 +18,12 @@ namespace osg namespace CSVRender { - class CameraController + class SceneWidget; + + class CameraController : public QObject { + Q_OBJECT + public: static const osg::Vec3d WorldUp; @@ -69,9 +75,11 @@ namespace CSVRender class FreeCameraController : public CameraController { + Q_OBJECT + public: - FreeCameraController(); + FreeCameraController(SceneWidget* widget); double getLinearSpeed() const; double getRotationalSpeed() const; @@ -107,13 +115,25 @@ namespace CSVRender double mLinSpeed; double mRotSpeed; double mSpeedMult; + + private slots: + + void forward(bool active); + void left(bool active); + void backward(bool active); + void right(bool active); + void rollLeft(bool active); + void rollRight(bool active); + void swapSpeedMode(bool active); }; class OrbitCameraController : public CameraController { + Q_OBJECT + public: - OrbitCameraController(); + OrbitCameraController(SceneWidget* widget); osg::Vec3d getCenter() const; double getOrbitSpeed() const; diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index b2b5b30d6..48fe4abdc 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -19,6 +19,7 @@ #include "../widget/scenetoolmode.hpp" #include "../../model/prefs/state.hpp" +#include "../../model/prefs/shortcut.hpp" #include "lighting.hpp" #include "mask.hpp" @@ -158,11 +159,15 @@ SceneWidget::SceneWidget(boost::shared_ptr resourceSys , mHasDefaultAmbient(false) , mPrevMouseX(0) , mPrevMouseY(0) - , mFreeCamControl(new FreeCameraController()) - , mOrbitCamControl(new OrbitCameraController()) - , mCurrentCamControl(mFreeCamControl.get()) + , mFreeCamControl(0) + , mOrbitCamControl(0) + , mCurrentCamControl(0) , mCamPositionSet(false) { + mFreeCamControl.reset(new FreeCameraController(this)); + mOrbitCamControl.reset(new OrbitCameraController(this)); + mCurrentCamControl = mFreeCamControl.get(); + mOrbitCamControl->setPickingMask(Mask_Reference | Mask_Terrain); selectNavigationMode("free"); @@ -175,11 +180,11 @@ SceneWidget::SceneWidget(boost::shared_ptr resourceSys // Recieve mouse move event even if mouse button is not pressed setMouseTracking(true); - setFocusPolicy(Qt::StrongFocus); + setFocusPolicy(Qt::ClickFocus); /// \todo make shortcut configurable - QShortcut *focusToolbar = new QShortcut (Qt::Key_T, this, 0, 0, Qt::WidgetWithChildrenShortcut); - connect (focusToolbar, SIGNAL (activated()), this, SIGNAL (focusToolbarRequest())); + //QShortcut *focusToolbar = new QShortcut (Qt::Key_T, this, 0, 0, Qt::WidgetWithChildrenShortcut); + //connect (focusToolbar, SIGNAL (activated()), this, SIGNAL (focusToolbarRequest())); connect (&CSMPrefs::State::get(), SIGNAL (settingChanged (const CSMPrefs::Setting *)), this, SLOT (settingChanged (const CSMPrefs::Setting *))); @@ -271,17 +276,57 @@ void SceneWidget::setDefaultAmbient (const osg::Vec4f& colour) setAmbient(mLighting->getAmbientColour(&mDefaultAmbient)); } +bool SceneWidget::event(QEvent *event) +{ + if (event->type() == QEvent::KeyPress) + { + QKeyEvent* keyEvent = static_cast(event); + SceneWidget::keyPressEvent(keyEvent); + } + else if (event->type() == QEvent::KeyRelease) + { + QKeyEvent* keyEvent = static_cast(event); + SceneWidget::keyReleaseEvent(keyEvent); + } + else if (event->type() == QEvent::MouseButtonPress) + { + QMouseEvent* keyEvent = static_cast(event); + SceneWidget::mousePressEvent(keyEvent); + } + else if (event->type() == QEvent::MouseButtonRelease) + { + QMouseEvent* keyEvent = static_cast(event); + SceneWidget::mouseReleaseEvent(keyEvent); + } + else + { + return RenderWidget::event(event); + } + + return true; +} + void SceneWidget::mousePressEvent (QMouseEvent *event) { mMouseMode = mapButton(event); mPrevMouseX = event->x(); mPrevMouseY = event->y(); + + for (std::vector::iterator it = mShortcuts.begin(); it != mShortcuts.end(); ++it) + { + (*it)->mousePressEvent(event); + } } void SceneWidget::mouseReleaseEvent (QMouseEvent *event) { mMouseMode = ""; + + for (std::vector::iterator it = mShortcuts.begin(); it != mShortcuts.end(); ++it) + { + (*it)->mouseReleaseEvent(event); + } } void SceneWidget::mouseMoveEvent (QMouseEvent *event) @@ -305,11 +350,21 @@ void SceneWidget::wheelEvent(QWheelEvent *event) void SceneWidget::keyPressEvent (QKeyEvent *event) { mCurrentCamControl->handleKeyEvent(event, true); + + for (std::vector::iterator it = mShortcuts.begin(); it != mShortcuts.end(); ++it) + { + (*it)->keyPressEvent(event); + } } void SceneWidget::keyReleaseEvent (QKeyEvent *event) { mCurrentCamControl->handleKeyEvent(event, false); + + for (std::vector::iterator it = mShortcuts.begin(); it != mShortcuts.end(); ++it) + { + (*it)->keyReleaseEvent(event); + } } void SceneWidget::update(double dt) @@ -453,4 +508,9 @@ std::string SceneWidget::mapButton (QMouseEvent *event) return ""; } +void SceneWidget::addShortcut(CSMPrefs::Shortcut* shortcut) +{ + mShortcuts.push_back(shortcut); +} + } diff --git a/apps/opencs/view/render/scenewidget.hpp b/apps/opencs/view/render/scenewidget.hpp index 4df49543a..0744cc645 100644 --- a/apps/opencs/view/render/scenewidget.hpp +++ b/apps/opencs/view/render/scenewidget.hpp @@ -36,6 +36,7 @@ namespace CSVWidget namespace CSMPrefs { class Setting; + class Shortcut; } namespace CSVRender @@ -84,12 +85,15 @@ namespace CSVRender void setDefaultAmbient (const osg::Vec4f& colour); ///< \note The actual ambient colour may differ based on lighting settings. + void addShortcut(CSMPrefs::Shortcut* shortcut); + protected: void setLighting (Lighting *lighting); ///< \attention The ownership of \a lighting is not transferred to *this. void setAmbient(const osg::Vec4f& ambient); + virtual bool event(QEvent *event); virtual void mousePressEvent (QMouseEvent *event); virtual void mouseReleaseEvent (QMouseEvent *event); virtual void mouseMoveEvent (QMouseEvent *event); @@ -120,6 +124,7 @@ namespace CSVRender CameraController* mCurrentCamControl; std::map, std::string> mButtonMapping; + std::vector mShortcuts; private: bool mCamPositionSet;