Merge remote-tracking branch 'aesylwinn/KeyConfigAndShortcuts'

pull/29/head
Marc Zinnschlag 9 years ago
commit f32d0121fc

@ -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
@ -108,11 +108,12 @@ opencs_units_noqt (view/tools
)
opencs_units (view/prefs
dialogue pagebase page
dialogue pagebase page keybindingpage
)
opencs_units (model/prefs
state setting intsetting doublesetting boolsetting enumsetting coloursetting
state setting intsetting doublesetting boolsetting enumsetting coloursetting shortcut
shortcuteventhandler shortcutmanager shortcutsetting modifiersetting
)
opencs_units_noqt (model/prefs

@ -0,0 +1,146 @@
#include "modifiersetting.hpp"
#include <QEvent>
#include <QKeyEvent>
#include <QLabel>
#include <QMouseEvent>
#include <QPushButton>
#include <QWidget>
#include "state.hpp"
#include "shortcutmanager.hpp"
namespace CSMPrefs
{
ModifierSetting::ModifierSetting(Category* parent, Settings::Manager* values, QMutex* mutex, const std::string& key,
const std::string& label)
: Setting(parent, values, mutex, key, label)
, mEditorActive(false)
{
}
std::pair<QWidget*, QWidget*> ModifierSetting::makeWidgets(QWidget* parent)
{
int modifier = 0;
State::get().getShortcutManager().getModifier(getKey(), modifier);
QString text = QString::fromUtf8(State::get().getShortcutManager().convertToString(modifier).c_str());
QLabel* label = new QLabel(QString::fromUtf8(getLabel().c_str()), parent);
QPushButton* widget = new QPushButton(text, parent);
widget->setCheckable(true);
widget->installEventFilter(this);
mButton = widget;
connect(widget, SIGNAL(toggled(bool)), this, SLOT(buttonToggled(bool)));
return std::make_pair(label, widget);
}
bool ModifierSetting::eventFilter(QObject* target, QEvent* event)
{
if (event->type() == QEvent::KeyPress)
{
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->isAutoRepeat())
return true;
int mod = keyEvent->modifiers();
int key = keyEvent->key();
return handleEvent(target, mod, key);
}
else if (event->type() == QEvent::MouseButtonPress)
{
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
int mod = mouseEvent->modifiers();
int button = mouseEvent->button();
return handleEvent(target, mod, button);
}
else if (event->type() == QEvent::FocusOut)
{
resetState();
}
return false;
}
bool ModifierSetting::handleEvent(QObject* target, int mod, int value)
{
// For potential future exceptions
const int Blacklist[] =
{
0
};
const size_t BlacklistSize = sizeof(Blacklist) / sizeof(int);
if (!mEditorActive)
{
if (value == Qt::RightButton)
{
// Clear modifier
int modifier = 0;
storeValue(modifier);
resetState();
}
return false;
}
// Handle blacklist
for (size_t i = 0; i < BlacklistSize; ++i)
{
if (value == Blacklist[i])
return true;
}
// Update modifier
int modifier = value;
storeValue(modifier);
resetState();
return true;
}
void ModifierSetting::storeValue(int modifier)
{
State::get().getShortcutManager().setModifier(getKey(), modifier);
// Convert to string and assign
std::string value = State::get().getShortcutManager().convertToString(modifier);
{
QMutexLocker lock(getMutex());
getValues().setString(getKey(), getParent()->getKey(), value);
}
getParent()->getState()->update(*this);
}
void ModifierSetting::resetState()
{
mButton->setChecked(false);
mEditorActive = false;
// Button text
int modifier = 0;
State::get().getShortcutManager().getModifier(getKey(), modifier);
QString text = QString::fromUtf8(State::get().getShortcutManager().convertToString(modifier).c_str());
mButton->setText(text);
}
void ModifierSetting::buttonToggled(bool checked)
{
if (checked)
mButton->setText("Press keys or click here...");
mEditorActive = checked;
}
}

@ -0,0 +1,44 @@
#ifndef CSM_PREFS_MODIFIERSETTING_H
#define CSM_PREFS_MODIFIERSETTING_H
#include <QKeySequence>
#include "setting.hpp"
class QEvent;
class QPushButton;
namespace CSMPrefs
{
class ModifierSetting : public Setting
{
Q_OBJECT
public:
ModifierSetting(Category* parent, Settings::Manager* values, QMutex* mutex, const std::string& key,
const std::string& label);
virtual std::pair<QWidget*, QWidget*> makeWidgets(QWidget* parent);
protected:
bool eventFilter(QObject* target, QEvent* event);
private:
bool handleEvent(QObject* target, int mod, int value);
void storeValue(int modifier);
void resetState();
QPushButton* mButton;
bool mEditorActive;
private slots:
void buttonToggled(bool checked);
};
}
#endif

@ -0,0 +1,214 @@
#include "shortcut.hpp"
#include <cassert>
#include <QAction>
#include <QWidget>
#include "state.hpp"
#include "shortcutmanager.hpp"
namespace CSMPrefs
{
Shortcut::Shortcut(const std::string& name, QWidget* parent)
: QObject(parent)
, mEnabled(true)
, mName(name)
, mModName("")
, 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);
}
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)
, 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()
{
State::get().getShortcutManager().removeShortcut(this);
}
bool Shortcut::isEnabled() const
{
return mEnabled;
}
const std::string& Shortcut::getName() const
{
return mName;
}
const std::string& Shortcut::getModifierName() const
{
return mModName;
}
Shortcut::SecondaryMode Shortcut::getSecondaryMode() const
{
return mSecondaryMode;
}
const QKeySequence& Shortcut::getSequence() const
{
return mSequence;
}
int Shortcut::getModifier() const
{
return mModifier;
}
int Shortcut::getPosition() const
{
return mCurrentPos;
}
int Shortcut::getLastPosition() const
{
return mLastPos;
}
Shortcut::ActivationStatus Shortcut::getActivationStatus() const
{
return mActivationStatus;
}
bool Shortcut::getModifierStatus() const
{
return mModifierStatus;
}
void Shortcut::enable(bool state)
{
mEnabled = state;
}
void Shortcut::setSequence(const QKeySequence& sequence)
{
mSequence = sequence;
mCurrentPos = 0;
mLastPos = sequence.count() - 1;
if (mAction)
{
mAction->setText(mActionText + "\t" + State::get().getShortcutManager().convertToString(mSequence).data());
}
}
void Shortcut::setModifier(int modifier)
{
mModifier = modifier;
}
void Shortcut::setPosition(int pos)
{
mCurrentPos = pos;
}
void Shortcut::setActivationStatus(ActivationStatus status)
{
mActivationStatus = status;
}
void Shortcut::setModifierStatus(bool status)
{
mModifierStatus = status;
}
void Shortcut::associateAction(QAction* action)
{
if (mAction)
{
mAction->setText(mActionText);
disconnect(this, SIGNAL(activated()), mAction, SLOT(trigger()));
disconnect(mAction, SIGNAL(destroyed()), this, SLOT(actionDeleted()));
}
mAction = action;
if (mAction)
{
mActionText = mAction->text();
mAction->setText(mActionText + "\t" + State::get().getShortcutManager().convertToString(mSequence).data());
connect(this, SIGNAL(activated()), mAction, SLOT(trigger()));
connect(mAction, SIGNAL(destroyed()), this, SLOT(actionDeleted()));
}
}
void Shortcut::signalActivated(bool state)
{
emit activated(state);
}
void Shortcut::signalActivated()
{
emit activated();
}
void Shortcut::signalSecondary(bool state)
{
emit secondary(state);
}
void Shortcut::signalSecondary()
{
emit secondary();
}
QString Shortcut::toString() const
{
return QString(State::get().getShortcutManager().convertToString(mSequence, mModifier).data());
}
void Shortcut::actionDeleted()
{
mAction = 0;
}
}

@ -0,0 +1,122 @@
#ifndef CSM_PREFS_SHORTCUT_H
#define CSM_PREFS_SHORTCUT_H
#include <string>
#include <QKeySequence>
#include <QObject>
#include <QString>
class QAction;
class QWidget;
namespace CSMPrefs
{
/// A class similar in purpose to QShortcut, but with the ability to use mouse buttons
class Shortcut : public QObject
{
Q_OBJECT
public:
enum ActivationStatus
{
AS_Regular,
AS_Secondary,
AS_Inactive
};
enum SecondaryMode
{
SM_Replace, ///< The secondary signal replaces the regular signal when the modifier is active
SM_Detach, ///< The secondary signal is emitted independant of the regular signal, even if not active
SM_Ignore ///< The secondary signal will not ever be emitted
};
Shortcut(const std::string& name, 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;
int getModifier() const;
/// The position in the sequence
int getPosition() const;
/// The position in the sequence
int getLastPosition() const;
ActivationStatus getActivationStatus() const;
bool getModifierStatus() const;
void enable(bool state);
void setSequence(const QKeySequence& sequence);
void setModifier(int modifier);
/// The position in the sequence
void setPosition(int pos);
void setActivationStatus(ActivationStatus status);
void setModifierStatus(bool status);
/// Appends the sequence to the QAction text, also keeps it up to date
void associateAction(QAction* action);
// Workaround for Qt4 signals being "protected"
void signalActivated(bool state);
void signalActivated();
void signalSecondary(bool state);
void signalSecondary();
QString toString() const;
private:
bool mEnabled;
std::string mName;
std::string mModName;
SecondaryMode mSecondaryMode;
QKeySequence mSequence;
int mModifier;
int mCurrentPos;
int mLastPos;
ActivationStatus mActivationStatus;
bool mModifierStatus;
QAction* mAction;
QString mActionText;
private slots:
void actionDeleted();
signals:
/// Triggered when the shortcut is activated or deactivated; can be determined from \p state
void activated(bool state);
/// Convenience signal.
void activated();
/// Triggered depending on SecondaryMode
void secondary(bool state);
/// Convenience signal.
void secondary();
};
}
#endif

@ -0,0 +1,338 @@
#include "shortcuteventhandler.hpp"
#include <algorithm>
#include <cassert>
#include <QEvent>
#include <QKeyEvent>
#include <QMouseEvent>
#include <QWidget>
#include "shortcut.hpp"
namespace CSMPrefs
{
ShortcutEventHandler::ShortcutEventHandler(QObject* parent)
: QObject(parent)
{
}
void ShortcutEventHandler::addShortcut(Shortcut* shortcut)
{
// Enforced by shortcut class
QWidget* widget = static_cast<QWidget*>(shortcut->parent());
// Check if widget setup is needed
ShortcutMap::iterator shortcutListIt = mWidgetShortcuts.find(widget);
if (shortcutListIt == mWidgetShortcuts.end())
{
// Create list
shortcutListIt = mWidgetShortcuts.insert(std::make_pair(widget, ShortcutList())).first;
// Check if widget has a parent with shortcuts, unfortunately it is not typically set yet
updateParent(widget);
// Intercept widget events
widget->installEventFilter(this);
connect(widget, SIGNAL(destroyed()), this, SLOT(widgetDestroyed()));
}
// Add to list
shortcutListIt->second.push_back(shortcut);
}
void ShortcutEventHandler::removeShortcut(Shortcut* shortcut)
{
// Enforced by shortcut class
QWidget* widget = static_cast<QWidget*>(shortcut->parent());
ShortcutMap::iterator shortcutListIt = mWidgetShortcuts.find(widget);
if (shortcutListIt != mWidgetShortcuts.end())
{
std::remove(shortcutListIt->second.begin(), shortcutListIt->second.end(), shortcut);
}
}
bool ShortcutEventHandler::eventFilter(QObject* watched, QEvent* event)
{
// Process event
if (event->type() == QEvent::KeyPress)
{
QWidget* widget = static_cast<QWidget*>(watched);
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
unsigned int mod = (unsigned int) keyEvent->modifiers();
unsigned int key = (unsigned int) keyEvent->key();
if (!keyEvent->isAutoRepeat())
return activate(widget, mod, key);
}
else if (event->type() == QEvent::KeyRelease)
{
QWidget* widget = static_cast<QWidget*>(watched);
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
unsigned int mod = (unsigned int) keyEvent->modifiers();
unsigned int key = (unsigned int) keyEvent->key();
if (!keyEvent->isAutoRepeat())
return deactivate(widget, mod, key);
}
else if (event->type() == QEvent::MouseButtonPress)
{
QWidget* widget = static_cast<QWidget*>(watched);
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
unsigned int mod = (unsigned int) mouseEvent->modifiers();
unsigned int button = (unsigned int) mouseEvent->button();
return activate(widget, mod, button);
}
else if (event->type() == QEvent::MouseButtonRelease)
{
QWidget* widget = static_cast<QWidget*>(watched);
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
unsigned int mod = (unsigned int) mouseEvent->modifiers();
unsigned int button = (unsigned int) mouseEvent->button();
return deactivate(widget, mod, button);
}
else if (event->type() == QEvent::FocusOut)
{
QWidget* widget = static_cast<QWidget*>(watched);
ShortcutMap::iterator shortcutListIt = mWidgetShortcuts.find(widget);
// Deactivate in case events are missed
for (ShortcutList::iterator it = shortcutListIt->second.begin(); it != shortcutListIt->second.end(); ++it)
{
Shortcut* shortcut = *it;
shortcut->setPosition(0);
shortcut->setModifierStatus(false);
if (shortcut->getActivationStatus() == Shortcut::AS_Regular)
{
shortcut->setActivationStatus(Shortcut::AS_Inactive);
shortcut->signalActivated(false);
}
else if (shortcut->getActivationStatus() == Shortcut::AS_Secondary)
{
shortcut->setActivationStatus(Shortcut::AS_Inactive);
shortcut->signalSecondary(false);
}
}
}
else if (event->type() == QEvent::FocusIn)
{
QWidget* widget = static_cast<QWidget*>(watched);
updateParent(widget);
}
return false;
}
void ShortcutEventHandler::updateParent(QWidget* widget)
{
QWidget* parent = widget->parentWidget();
while (parent)
{
ShortcutMap::iterator parentIt = mWidgetShortcuts.find(parent);
if (parentIt != mWidgetShortcuts.end())
{
mChildParentRelations.insert(std::make_pair(widget, parent));
updateParent(parent);
break;
}
// Check next
parent = parent->parentWidget();
}
}
bool ShortcutEventHandler::activate(QWidget* widget, unsigned int mod, unsigned int button)
{
std::vector<std::pair<MatchResult, Shortcut*> > potentials;
bool used = false;
while (widget)
{
ShortcutMap::iterator shortcutListIt = mWidgetShortcuts.find(widget);
assert(shortcutListIt != mWidgetShortcuts.end());
// Find potential activations
for (ShortcutList::iterator it = shortcutListIt->second.begin(); it != shortcutListIt->second.end(); ++it)
{
Shortcut* shortcut = *it;
if (!shortcut->isEnabled())
continue;
if (checkModifier(mod, button, shortcut, true))
used = true;
if (shortcut->getActivationStatus() != Shortcut::AS_Inactive)
continue;
int pos = shortcut->getPosition();
int lastPos = shortcut->getLastPosition();
MatchResult result = match(mod, button, shortcut->getSequence()[pos]);
if (result == Matches_WithMod || result == Matches_NoMod)
{
if (pos < lastPos && (result == Matches_WithMod || pos > 0))
{
shortcut->setPosition(pos+1);
}
else if (pos == lastPos)
{
potentials.push_back(std::make_pair(result, shortcut));
}
}
}
// Move on to parent
WidgetMap::iterator widgetIt = mChildParentRelations.find(widget);
widget = (widgetIt != mChildParentRelations.end()) ? widgetIt->second : 0;
}
// Only activate the best match; in exact conflicts, this will favor the first shortcut added.
if (!potentials.empty())
{
std::sort(potentials.begin(), potentials.end(), ShortcutEventHandler::sort);
Shortcut* shortcut = potentials.front().second;
if (shortcut->getModifierStatus() && shortcut->getSecondaryMode() == Shortcut::SM_Replace)
{
shortcut->setActivationStatus(Shortcut::AS_Secondary);
shortcut->signalSecondary(true);
shortcut->signalSecondary();
}
else
{
shortcut->setActivationStatus(Shortcut::AS_Regular);
shortcut->signalActivated(true);
shortcut->signalActivated();
}
used = true;
}
return used;
}
bool ShortcutEventHandler::deactivate(QWidget* widget, unsigned int mod, unsigned int button)
{
const int KeyMask = 0x01FFFFFF;
bool used = false;
while (widget)
{
ShortcutMap::iterator shortcutListIt = mWidgetShortcuts.find(widget);
assert(shortcutListIt != mWidgetShortcuts.end());
for (ShortcutList::iterator it = shortcutListIt->second.begin(); it != shortcutListIt->second.end(); ++it)
{
Shortcut* shortcut = *it;
if (checkModifier(mod, button, shortcut, false))
used = true;
int pos = shortcut->getPosition();
MatchResult result = match(0, button, shortcut->getSequence()[pos] & KeyMask);
if (result != Matches_Not)
{
shortcut->setPosition(0);
if (shortcut->getActivationStatus() == Shortcut::AS_Regular)
{
shortcut->setActivationStatus(Shortcut::AS_Inactive);
shortcut->signalActivated(false);
used = true;
}
else if (shortcut->getActivationStatus() == Shortcut::AS_Secondary)
{
shortcut->setActivationStatus(Shortcut::AS_Inactive);
shortcut->signalSecondary(false);
used = true;
}
}
}
// Move on to parent
WidgetMap::iterator widgetIt = mChildParentRelations.find(widget);
widget = (widgetIt != mChildParentRelations.end()) ? widgetIt->second : 0;
}
return used;
}
bool ShortcutEventHandler::checkModifier(unsigned int mod, unsigned int button, Shortcut* shortcut, bool activate)
{
if (!shortcut->isEnabled() || !shortcut->getModifier() || shortcut->getSecondaryMode() == Shortcut::SM_Ignore ||
shortcut->getModifierStatus() == activate)
return false;
MatchResult result = match(mod, button, shortcut->getModifier());
bool used = false;
if (result != Matches_Not)
{
shortcut->setModifierStatus(activate);
if (shortcut->getSecondaryMode() == Shortcut::SM_Detach)
{
if (activate)
{
shortcut->signalSecondary(true);
shortcut->signalSecondary();
}
else
{
shortcut->signalSecondary(false);
}
}
else if (!activate && shortcut->getActivationStatus() == Shortcut::AS_Secondary)
{
shortcut->setActivationStatus(Shortcut::AS_Inactive);
shortcut->setPosition(0);
shortcut->signalSecondary(false);
used = true;
}
}
return used;
}
ShortcutEventHandler::MatchResult ShortcutEventHandler::match(unsigned int mod, unsigned int button,
unsigned int value)
{
if ((mod | button) == value)
{
return Matches_WithMod;
}
else if (button == value)
{
return Matches_NoMod;
}
else
{
return Matches_Not;
}
}
bool ShortcutEventHandler::sort(const std::pair<MatchResult, Shortcut*>& left,
const std::pair<MatchResult, Shortcut*>& right)
{
if (left.first == Matches_WithMod && right.first == Matches_NoMod)
return true;
else
return left.second->getPosition() >= right.second->getPosition();
}
void ShortcutEventHandler::widgetDestroyed()
{
QWidget* widget = static_cast<QWidget*>(sender());
mWidgetShortcuts.erase(widget);
mChildParentRelations.erase(widget);
}
}

@ -0,0 +1,69 @@
#ifndef CSM_PREFS_SHORTCUT_EVENT_HANDLER_H
#define CSM_PREFS_SHORTCUT_EVENT_HANDLER_H
#include <map>
#include <vector>
#include <QObject>
class QEvent;
class QWidget;
namespace CSMPrefs
{
class Shortcut;
/// Users of this class should install it as an event handler
class ShortcutEventHandler : public QObject
{
Q_OBJECT
public:
ShortcutEventHandler(QObject* parent);
void addShortcut(Shortcut* shortcut);
void removeShortcut(Shortcut* shortcut);
protected:
bool eventFilter(QObject* watched, QEvent* event);
private:
typedef std::vector<Shortcut*> ShortcutList;
// Child, Parent
typedef std::map<QWidget*, QWidget*> WidgetMap;
typedef std::map<QWidget*, ShortcutList> ShortcutMap;
enum MatchResult
{
Matches_WithMod,
Matches_NoMod,
Matches_Not
};
void updateParent(QWidget* widget);
bool activate(QWidget* widget, unsigned int mod, unsigned int button);
bool deactivate(QWidget* widget, unsigned int mod, unsigned int button);
bool checkModifier(unsigned int mod, unsigned int button, Shortcut* shortcut, bool activate);
MatchResult match(unsigned int mod, unsigned int button, unsigned int value);
// Prefers Matches_WithMod and a larger number of buttons
static bool sort(const std::pair<MatchResult, Shortcut*>& left,
const std::pair<MatchResult, Shortcut*>& right);
WidgetMap mChildParentRelations;
ShortcutMap mWidgetShortcuts;
private slots:
void widgetDestroyed();
};
}
#endif

@ -0,0 +1,791 @@
#include "shortcutmanager.hpp"
#include <algorithm>
#include <QApplication>
#include <QStringList>
#include "shortcut.hpp"
#include "shortcuteventhandler.hpp"
namespace CSMPrefs
{
ShortcutManager::ShortcutManager()
{
createLookupTables();
mEventHandler = new ShortcutEventHandler(this);
}
void ShortcutManager::addShortcut(Shortcut* shortcut)
{
mShortcuts.insert(std::make_pair(shortcut->getName(), shortcut));
mShortcuts.insert(std::make_pair(shortcut->getModifierName(), shortcut));
mEventHandler->addShortcut(shortcut);
}
void ShortcutManager::removeShortcut(Shortcut* shortcut)
{
std::pair<ShortcutMap::iterator, ShortcutMap::iterator> range = mShortcuts.equal_range(shortcut->getName());
for (ShortcutMap::iterator it = range.first; it != range.second;)
{
if (it->second == shortcut)
{
mShortcuts.erase(it++);
}
else
{
++it;
}
}
mEventHandler->removeShortcut(shortcut);
}
bool ShortcutManager::getSequence(const std::string& name, QKeySequence& sequence) const
{
SequenceMap::const_iterator item = mSequences.find(name);
if (item != mSequences.end())
{
sequence = item->second;
return true;
}
else
return false;
}
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<ShortcutMap::iterator, ShortcutMap::iterator> rangeS = mShortcuts.equal_range(name);
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<ShortcutMap::iterator, ShortcutMap::iterator> rangeS = mShortcuts.equal_range(name);
for (ShortcutMap::iterator it = rangeS.first; it != rangeS.second; ++it)
{
it->second->setModifier(modifier);
}
}
std::string ShortcutManager::convertToString(const QKeySequence& sequence) const
{
const int MouseKeyMask = 0x01FFFFFF;
const int ModMask = 0x7E000000;
std::string result;
for (int i = 0; i < (int)sequence.count(); ++i)
{
int mods = sequence[i] & ModMask;
int key = sequence[i] & MouseKeyMask;
if (key)
{
NameMap::const_iterator searchResult = mNames.find(key);
if (searchResult != mNames.end())
{
if (mods && i == 0)
{
if (mods & Qt::ControlModifier)
result.append("Ctl+");
if (mods & Qt::ShiftModifier)
result.append("Shift+");
if (mods & Qt::AltModifier)
result.append("Alt+");
if (mods & Qt::MetaModifier)
result.append("Meta+");
if (mods & Qt::KeypadModifier)
result.append("Keypad+");
if (mods & Qt::GroupSwitchModifier)
result.append("GroupSwitch+");
}
else if (i > 0)
{
result.append("+");
}
result.append(searchResult->second);
}
}
}
return result;
}
std::string ShortcutManager::convertToString(int modifier) const
{
NameMap::const_iterator searchResult = mNames.find(modifier);
if (searchResult != mNames.end())
{
return searchResult->second;
}
else
return "";
}
std::string ShortcutManager::convertToString(const QKeySequence& sequence, int modifier) const
{
std::string concat = convertToString(sequence) + ";" + convertToString(modifier);
return concat;
}
void ShortcutManager::convertFromString(const std::string& data, QKeySequence& sequence) const
{
const int MaxKeys = 4; // A limitation of QKeySequence
size_t end = data.find(";");
size_t size = std::min(end, data.size());
std::string value = data.substr(0, size);
size_t start = 0;
int keyPos = 0;
int mods = 0;
int keys[MaxKeys] = {};
while (start < value.size())
{
end = data.find("+", start);
end = std::min(end, value.size());
std::string name = value.substr(start, end - start);
if (name == "Ctl")
{
mods |= Qt::ControlModifier;
}
else if (name == "Shift")
{
mods |= Qt::ShiftModifier;
}
else if (name == "Alt")
{
mods |= Qt::AltModifier;
}
else if (name == "Meta")
{
mods |= Qt::MetaModifier;
}
else if (name == "Keypad")
{
mods |= Qt::KeypadModifier;
}
else if (name == "GroupSwitch")
{
mods |= Qt::GroupSwitchModifier;
}
else
{
KeyMap::const_iterator searchResult = mKeys.find(name);
if (searchResult != mKeys.end())
{
keys[keyPos] = mods | searchResult->second;
mods = 0;
keyPos += 1;
if (keyPos >= MaxKeys)
break;
}
}
start = end + 1;
}
sequence = QKeySequence(keys[0], keys[1], keys[2], keys[3]);
}
void ShortcutManager::convertFromString(const std::string& data, int& modifier) const
{
size_t start = data.find(";") + 1;
start = std::min(start, data.size());
std::string name = data.substr(start);
KeyMap::const_iterator searchResult = mKeys.find(name);
if (searchResult != mKeys.end())
{
modifier = searchResult->second;
}
else
{
modifier = 0;
}
}
void ShortcutManager::convertFromString(const std::string& data, QKeySequence& sequence, int& modifier) const
{
convertFromString(data, sequence);
convertFromString(data, modifier);
}
void ShortcutManager::createLookupTables()
{
// Mouse buttons
mNames.insert(std::make_pair(Qt::LeftButton, "LMB"));
mNames.insert(std::make_pair(Qt::RightButton, "RMB"));
mNames.insert(std::make_pair(Qt::MiddleButton, "MMB"));
mNames.insert(std::make_pair(Qt::XButton1, "Mouse4"));
mNames.insert(std::make_pair(Qt::XButton2, "Mouse5"));
// Keyboard buttons
for (size_t i = 0; QtKeys[i].first != 0; ++i)
{
mNames.insert(QtKeys[i]);
}
// Generate inverse map
for (NameMap::const_iterator it = mNames.begin(); it != mNames.end(); ++it)
{
mKeys.insert(std::make_pair(it->second, it->first));
}
}
QString ShortcutManager::processToolTip(const QString& toolTip) const
{
const QChar SequenceStart = '{';
const QChar SequenceEnd = '}';
QStringList substrings;
int prevIndex = 0;
int startIndex = toolTip.indexOf(SequenceStart);
int endIndex = (startIndex != -1) ? toolTip.indexOf(SequenceEnd, startIndex) : -1;
// Process every valid shortcut escape sequence
while (startIndex != -1 && endIndex != -1)
{
int count = startIndex - prevIndex;
if (count > 0)
{
substrings.push_back(toolTip.mid(prevIndex, count));
}
// Find sequence name
startIndex += 1; // '{' character
count = endIndex - startIndex;
if (count > 0)
{
QString settingName = toolTip.mid(startIndex, count);
QKeySequence sequence;
int modifier;
if (getSequence(settingName.toUtf8().data(), sequence))
{
QString value = QString::fromUtf8(convertToString(sequence).c_str());
substrings.push_back(value);
}
else if (getModifier(settingName.toUtf8().data(), modifier))
{
QString value = QString::fromUtf8(convertToString(modifier).c_str());
substrings.push_back(value);
}
prevIndex = endIndex + 1; // '}' character
}
startIndex = toolTip.indexOf(SequenceStart, endIndex);
endIndex = (startIndex != -1) ? toolTip.indexOf(SequenceEnd, startIndex) : -1;
}
if (prevIndex < toolTip.size())
{
substrings.push_back(toolTip.mid(prevIndex));
}
return substrings.join("");
}
const std::pair<int, const char*> ShortcutManager::QtKeys[] =
{
std::make_pair((int)Qt::Key_Space , "Space"),
std::make_pair((int)Qt::Key_Exclam , "Exclam"),
std::make_pair((int)Qt::Key_QuoteDbl , "QuoteDbl"),
std::make_pair((int)Qt::Key_NumberSign , "NumberSign"),
std::make_pair((int)Qt::Key_Dollar , "Dollar"),
std::make_pair((int)Qt::Key_Percent , "Percent"),
std::make_pair((int)Qt::Key_Ampersand , "Ampersand"),
std::make_pair((int)Qt::Key_Apostrophe , "Apostrophe"),
std::make_pair((int)Qt::Key_ParenLeft , "ParenLeft"),
std::make_pair((int)Qt::Key_ParenRight , "ParenRight"),
std::make_pair((int)Qt::Key_Asterisk , "Asterisk"),
std::make_pair((int)Qt::Key_Plus , "Plus"),
std::make_pair((int)Qt::Key_Comma , "Comma"),
std::make_pair((int)Qt::Key_Minus , "Minus"),
std::make_pair((int)Qt::Key_Period , "Period"),
std::make_pair((int)Qt::Key_Slash , "Slash"),
std::make_pair((int)Qt::Key_0 , "0"),
std::make_pair((int)Qt::Key_1 , "1"),
std::make_pair((int)Qt::Key_2 , "2"),
std::make_pair((int)Qt::Key_3 , "3"),
std::make_pair((int)Qt::Key_4 , "4"),
std::make_pair((int)Qt::Key_5 , "5"),
std::make_pair((int)Qt::Key_6 , "6"),
std::make_pair((int)Qt::Key_7 , "7"),
std::make_pair((int)Qt::Key_8 , "8"),
std::make_pair((int)Qt::Key_9 , "9"),
std::make_pair((int)Qt::Key_Colon , "Colon"),
std::make_pair((int)Qt::Key_Semicolon , "Semicolon"),
std::make_pair((int)Qt::Key_Less , "Less"),
std::make_pair((int)Qt::Key_Equal , "Equal"),
std::make_pair((int)Qt::Key_Greater , "Greater"),
std::make_pair((int)Qt::Key_Question , "Question"),
std::make_pair((int)Qt::Key_At , "At"),
std::make_pair((int)Qt::Key_A , "A"),
std::make_pair((int)Qt::Key_B , "B"),
std::make_pair((int)Qt::Key_C , "C"),
std::make_pair((int)Qt::Key_D , "D"),
std::make_pair((int)Qt::Key_E , "E"),
std::make_pair((int)Qt::Key_F , "F"),
std::make_pair((int)Qt::Key_G , "G"),
std::make_pair((int)Qt::Key_H , "H"),
std::make_pair((int)Qt::Key_I , "I"),
std::make_pair((int)Qt::Key_J , "J"),
std::make_pair((int)Qt::Key_K , "K"),
std::make_pair((int)Qt::Key_L , "L"),
std::make_pair((int)Qt::Key_M , "M"),
std::make_pair((int)Qt::Key_N , "N"),
std::make_pair((int)Qt::Key_O , "O"),
std::make_pair((int)Qt::Key_P , "P"),
std::make_pair((int)Qt::Key_Q , "Q"),
std::make_pair((int)Qt::Key_R , "R"),
std::make_pair((int)Qt::Key_S , "S"),
std::make_pair((int)Qt::Key_T , "T"),
std::make_pair((int)Qt::Key_U , "U"),
std::make_pair((int)Qt::Key_V , "V"),
std::make_pair((int)Qt::Key_W , "W"),
std::make_pair((int)Qt::Key_X , "X"),
std::make_pair((int)Qt::Key_Y , "Y"),
std::make_pair((int)Qt::Key_Z , "Z"),
std::make_pair((int)Qt::Key_BracketLeft , "BracketLeft"),
std::make_pair((int)Qt::Key_Backslash , "Backslash"),
std::make_pair((int)Qt::Key_BracketRight , "BracketRight"),
std::make_pair((int)Qt::Key_AsciiCircum , "AsciiCircum"),
std::make_pair((int)Qt::Key_Underscore , "Underscore"),
std::make_pair((int)Qt::Key_QuoteLeft , "QuoteLeft"),
std::make_pair((int)Qt::Key_BraceLeft , "BraceLeft"),
std::make_pair((int)Qt::Key_Bar , "Bar"),
std::make_pair((int)Qt::Key_BraceRight , "BraceRight"),
std::make_pair((int)Qt::Key_AsciiTilde , "AsciiTilde"),
std::make_pair((int)Qt::Key_nobreakspace , "nobreakspace"),
std::make_pair((int)Qt::Key_exclamdown , "exclamdown"),
std::make_pair((int)Qt::Key_cent , "cent"),
std::make_pair((int)Qt::Key_sterling , "sterling"),
std::make_pair((int)Qt::Key_currency , "currency"),
std::make_pair((int)Qt::Key_yen , "yen"),
std::make_pair((int)Qt::Key_brokenbar , "brokenbar"),
std::make_pair((int)Qt::Key_section , "section"),
std::make_pair((int)Qt::Key_diaeresis , "diaeresis"),
std::make_pair((int)Qt::Key_copyright , "copyright"),
std::make_pair((int)Qt::Key_ordfeminine , "ordfeminine"),
std::make_pair((int)Qt::Key_guillemotleft , "guillemotleft"),
std::make_pair((int)Qt::Key_notsign , "notsign"),
std::make_pair((int)Qt::Key_hyphen , "hyphen"),
std::make_pair((int)Qt::Key_registered , "registered"),
std::make_pair((int)Qt::Key_macron , "macron"),
std::make_pair((int)Qt::Key_degree , "degree"),
std::make_pair((int)Qt::Key_plusminus , "plusminus"),
std::make_pair((int)Qt::Key_twosuperior , "twosuperior"),
std::make_pair((int)Qt::Key_threesuperior , "threesuperior"),
std::make_pair((int)Qt::Key_acute , "acute"),
std::make_pair((int)Qt::Key_mu , "mu"),
std::make_pair((int)Qt::Key_paragraph , "paragraph"),
std::make_pair((int)Qt::Key_periodcentered , "periodcentered"),
std::make_pair((int)Qt::Key_cedilla , "cedilla"),
std::make_pair((int)Qt::Key_onesuperior , "onesuperior"),
std::make_pair((int)Qt::Key_masculine , "masculine"),
std::make_pair((int)Qt::Key_guillemotright , "guillemotright"),
std::make_pair((int)Qt::Key_onequarter , "onequarter"),
std::make_pair((int)Qt::Key_onehalf , "onehalf"),
std::make_pair((int)Qt::Key_threequarters , "threequarters"),
std::make_pair((int)Qt::Key_questiondown , "questiondown"),
std::make_pair((int)Qt::Key_Agrave , "Agrave"),
std::make_pair((int)Qt::Key_Aacute , "Aacute"),
std::make_pair((int)Qt::Key_Acircumflex , "Acircumflex"),
std::make_pair((int)Qt::Key_Atilde , "Atilde"),
std::make_pair((int)Qt::Key_Adiaeresis , "Adiaeresis"),
std::make_pair((int)Qt::Key_Aring , "Aring"),
std::make_pair((int)Qt::Key_AE , "AE"),
std::make_pair((int)Qt::Key_Ccedilla , "Ccedilla"),
std::make_pair((int)Qt::Key_Egrave , "Egrave"),
std::make_pair((int)Qt::Key_Eacute , "Eacute"),
std::make_pair((int)Qt::Key_Ecircumflex , "Ecircumflex"),
std::make_pair((int)Qt::Key_Ediaeresis , "Ediaeresis"),
std::make_pair((int)Qt::Key_Igrave , "Igrave"),
std::make_pair((int)Qt::Key_Iacute , "Iacute"),
std::make_pair((int)Qt::Key_Icircumflex , "Icircumflex"),
std::make_pair((int)Qt::Key_Idiaeresis , "Idiaeresis"),
std::make_pair((int)Qt::Key_ETH , "ETH"),
std::make_pair((int)Qt::Key_Ntilde , "Ntilde"),
std::make_pair((int)Qt::Key_Ograve , "Ograve"),
std::make_pair((int)Qt::Key_Oacute , "Oacute"),
std::make_pair((int)Qt::Key_Ocircumflex , "Ocircumflex"),
std::make_pair((int)Qt::Key_Otilde , "Otilde"),
std::make_pair((int)Qt::Key_Odiaeresis , "Odiaeresis"),
std::make_pair((int)Qt::Key_multiply , "multiply"),
std::make_pair((int)Qt::Key_Ooblique , "Ooblique"),
std::make_pair((int)Qt::Key_Ugrave , "Ugrave"),
std::make_pair((int)Qt::Key_Uacute , "Uacute"),
std::make_pair((int)Qt::Key_Ucircumflex , "Ucircumflex"),
std::make_pair((int)Qt::Key_Udiaeresis , "Udiaeresis"),
std::make_pair((int)Qt::Key_Yacute , "Yacute"),
std::make_pair((int)Qt::Key_THORN , "THORN"),
std::make_pair((int)Qt::Key_ssharp , "ssharp"),
std::make_pair((int)Qt::Key_division , "division"),
std::make_pair((int)Qt::Key_ydiaeresis , "ydiaeresis"),
std::make_pair((int)Qt::Key_Escape , "Escape"),
std::make_pair((int)Qt::Key_Tab , "Tab"),
std::make_pair((int)Qt::Key_Backtab , "Backtab"),
std::make_pair((int)Qt::Key_Backspace , "Backspace"),
std::make_pair((int)Qt::Key_Return , "Return"),
std::make_pair((int)Qt::Key_Enter , "Enter"),
std::make_pair((int)Qt::Key_Insert , "Insert"),
std::make_pair((int)Qt::Key_Delete , "Delete"),
std::make_pair((int)Qt::Key_Pause , "Pause"),
std::make_pair((int)Qt::Key_Print , "Print"),
std::make_pair((int)Qt::Key_SysReq , "SysReq"),
std::make_pair((int)Qt::Key_Clear , "Clear"),
std::make_pair((int)Qt::Key_Home , "Home"),
std::make_pair((int)Qt::Key_End , "End"),
std::make_pair((int)Qt::Key_Left , "Left"),
std::make_pair((int)Qt::Key_Up , "Up"),
std::make_pair((int)Qt::Key_Right , "Right"),
std::make_pair((int)Qt::Key_Down , "Down"),
std::make_pair((int)Qt::Key_PageUp , "PageUp"),
std::make_pair((int)Qt::Key_PageDown , "PageDown"),
std::make_pair((int)Qt::Key_Shift , "Shift"),
std::make_pair((int)Qt::Key_Control , "Control"),
std::make_pair((int)Qt::Key_Meta , "Meta"),
std::make_pair((int)Qt::Key_Alt , "Alt"),
std::make_pair((int)Qt::Key_CapsLock , "CapsLock"),
std::make_pair((int)Qt::Key_NumLock , "NumLock"),
std::make_pair((int)Qt::Key_ScrollLock , "ScrollLock"),
std::make_pair((int)Qt::Key_F1 , "F1"),
std::make_pair((int)Qt::Key_F2 , "F2"),
std::make_pair((int)Qt::Key_F3 , "F3"),
std::make_pair((int)Qt::Key_F4 , "F4"),
std::make_pair((int)Qt::Key_F5 , "F5"),
std::make_pair((int)Qt::Key_F6 , "F6"),
std::make_pair((int)Qt::Key_F7 , "F7"),
std::make_pair((int)Qt::Key_F8 , "F8"),
std::make_pair((int)Qt::Key_F9 , "F9"),
std::make_pair((int)Qt::Key_F10 , "F10"),
std::make_pair((int)Qt::Key_F11 , "F11"),
std::make_pair((int)Qt::Key_F12 , "F12"),
std::make_pair((int)Qt::Key_F13 , "F13"),
std::make_pair((int)Qt::Key_F14 , "F14"),
std::make_pair((int)Qt::Key_F15 , "F15"),
std::make_pair((int)Qt::Key_F16 , "F16"),
std::make_pair((int)Qt::Key_F17 , "F17"),
std::make_pair((int)Qt::Key_F18 , "F18"),
std::make_pair((int)Qt::Key_F19 , "F19"),
std::make_pair((int)Qt::Key_F20 , "F20"),
std::make_pair((int)Qt::Key_F21 , "F21"),
std::make_pair((int)Qt::Key_F22 , "F22"),
std::make_pair((int)Qt::Key_F23 , "F23"),
std::make_pair((int)Qt::Key_F24 , "F24"),
std::make_pair((int)Qt::Key_F25 , "F25"),
std::make_pair((int)Qt::Key_F26 , "F26"),
std::make_pair((int)Qt::Key_F27 , "F27"),
std::make_pair((int)Qt::Key_F28 , "F28"),
std::make_pair((int)Qt::Key_F29 , "F29"),
std::make_pair((int)Qt::Key_F30 , "F30"),
std::make_pair((int)Qt::Key_F31 , "F31"),
std::make_pair((int)Qt::Key_F32 , "F32"),
std::make_pair((int)Qt::Key_F33 , "F33"),
std::make_pair((int)Qt::Key_F34 , "F34"),
std::make_pair((int)Qt::Key_F35 , "F35"),
std::make_pair((int)Qt::Key_Super_L , "Super_L"),
std::make_pair((int)Qt::Key_Super_R , "Super_R"),
std::make_pair((int)Qt::Key_Menu , "Menu"),
std::make_pair((int)Qt::Key_Hyper_L , "Hyper_L"),
std::make_pair((int)Qt::Key_Hyper_R , "Hyper_R"),
std::make_pair((int)Qt::Key_Help , "Help"),
std::make_pair((int)Qt::Key_Direction_L , "Direction_L"),
std::make_pair((int)Qt::Key_Direction_R , "Direction_R"),
std::make_pair((int)Qt::Key_Back , "Back"),
std::make_pair((int)Qt::Key_Forward , "Forward"),
std::make_pair((int)Qt::Key_Stop , "Stop"),
std::make_pair((int)Qt::Key_Refresh , "Refresh"),
std::make_pair((int)Qt::Key_VolumeDown , "VolumeDown"),
std::make_pair((int)Qt::Key_VolumeMute , "VolumeMute"),
std::make_pair((int)Qt::Key_VolumeUp , "VolumeUp"),
std::make_pair((int)Qt::Key_BassBoost , "BassBoost"),
std::make_pair((int)Qt::Key_BassUp , "BassUp"),
std::make_pair((int)Qt::Key_BassDown , "BassDown"),
std::make_pair((int)Qt::Key_TrebleUp , "TrebleUp"),
std::make_pair((int)Qt::Key_TrebleDown , "TrebleDown"),
std::make_pair((int)Qt::Key_MediaPlay , "MediaPlay"),
std::make_pair((int)Qt::Key_MediaStop , "MediaStop"),
std::make_pair((int)Qt::Key_MediaPrevious , "MediaPrevious"),
std::make_pair((int)Qt::Key_MediaNext , "MediaNext"),
std::make_pair((int)Qt::Key_MediaRecord , "MediaRecord"),
std::make_pair((int)Qt::Key_MediaPause , "MediaPause"),
std::make_pair((int)Qt::Key_MediaTogglePlayPause , "MediaTogglePlayPause"),
std::make_pair((int)Qt::Key_HomePage , "HomePage"),
std::make_pair((int)Qt::Key_Favorites , "Favorites"),
std::make_pair((int)Qt::Key_Search , "Search"),
std::make_pair((int)Qt::Key_Standby , "Standby"),
std::make_pair((int)Qt::Key_OpenUrl , "OpenUrl"),
std::make_pair((int)Qt::Key_LaunchMail , "LaunchMail"),
std::make_pair((int)Qt::Key_LaunchMedia , "LaunchMedia"),
std::make_pair((int)Qt::Key_Launch0 , "Launch0"),
std::make_pair((int)Qt::Key_Launch1 , "Launch1"),
std::make_pair((int)Qt::Key_Launch2 , "Launch2"),
std::make_pair((int)Qt::Key_Launch3 , "Launch3"),
std::make_pair((int)Qt::Key_Launch4 , "Launch4"),
std::make_pair((int)Qt::Key_Launch5 , "Launch5"),
std::make_pair((int)Qt::Key_Launch6 , "Launch6"),
std::make_pair((int)Qt::Key_Launch7 , "Launch7"),
std::make_pair((int)Qt::Key_Launch8 , "Launch8"),
std::make_pair((int)Qt::Key_Launch9 , "Launch9"),
std::make_pair((int)Qt::Key_LaunchA , "LaunchA"),
std::make_pair((int)Qt::Key_LaunchB , "LaunchB"),
std::make_pair((int)Qt::Key_LaunchC , "LaunchC"),
std::make_pair((int)Qt::Key_LaunchD , "LaunchD"),
std::make_pair((int)Qt::Key_LaunchE , "LaunchE"),
std::make_pair((int)Qt::Key_LaunchF , "LaunchF"),
std::make_pair((int)Qt::Key_MonBrightnessUp , "MonBrightnessUp"),
std::make_pair((int)Qt::Key_MonBrightnessDown , "MonBrightnessDown"),
std::make_pair((int)Qt::Key_KeyboardLightOnOff , "KeyboardLightOnOff"),
std::make_pair((int)Qt::Key_KeyboardBrightnessUp , "KeyboardBrightnessUp"),
std::make_pair((int)Qt::Key_KeyboardBrightnessDown , "KeyboardBrightnessDown"),
std::make_pair((int)Qt::Key_PowerOff , "PowerOff"),
std::make_pair((int)Qt::Key_WakeUp , "WakeUp"),
std::make_pair((int)Qt::Key_Eject , "Eject"),
std::make_pair((int)Qt::Key_ScreenSaver , "ScreenSaver"),
std::make_pair((int)Qt::Key_WWW , "WWW"),
std::make_pair((int)Qt::Key_Memo , "Memo"),
std::make_pair((int)Qt::Key_LightBulb , "LightBulb"),
std::make_pair((int)Qt::Key_Shop , "Shop"),
std::make_pair((int)Qt::Key_History , "History"),
std::make_pair((int)Qt::Key_AddFavorite , "AddFavorite"),
std::make_pair((int)Qt::Key_HotLinks , "HotLinks"),
std::make_pair((int)Qt::Key_BrightnessAdjust , "BrightnessAdjust"),
std::make_pair((int)Qt::Key_Finance , "Finance"),
std::make_pair((int)Qt::Key_Community , "Community"),
std::make_pair((int)Qt::Key_AudioRewind , "AudioRewind"),
std::make_pair((int)Qt::Key_BackForward , "BackForward"),
std::make_pair((int)Qt::Key_ApplicationLeft , "ApplicationLeft"),
std::make_pair((int)Qt::Key_ApplicationRight , "ApplicationRight"),
std::make_pair((int)Qt::Key_Book , "Book"),
std::make_pair((int)Qt::Key_CD , "CD"),
std::make_pair((int)Qt::Key_Calculator , "Calculator"),
std::make_pair((int)Qt::Key_ToDoList , "ToDoList"),
std::make_pair((int)Qt::Key_ClearGrab , "ClearGrab"),
std::make_pair((int)Qt::Key_Close , "Close"),
std::make_pair((int)Qt::Key_Copy , "Copy"),
std::make_pair((int)Qt::Key_Cut , "Cut"),
std::make_pair((int)Qt::Key_Display , "Display"),
std::make_pair((int)Qt::Key_DOS , "DOS"),
std::make_pair((int)Qt::Key_Documents , "Documents"),
std::make_pair((int)Qt::Key_Excel , "Excel"),
std::make_pair((int)Qt::Key_Explorer , "Explorer"),
std::make_pair((int)Qt::Key_Game , "Game"),
std::make_pair((int)Qt::Key_Go , "Go"),
std::make_pair((int)Qt::Key_iTouch , "iTouch"),
std::make_pair((int)Qt::Key_LogOff , "LogOff"),
std::make_pair((int)Qt::Key_Market , "Market"),
std::make_pair((int)Qt::Key_Meeting , "Meeting"),
std::make_pair((int)Qt::Key_MenuKB , "MenuKB"),
std::make_pair((int)Qt::Key_MenuPB , "MenuPB"),
std::make_pair((int)Qt::Key_MySites , "MySites"),
std::make_pair((int)Qt::Key_News , "News"),
std::make_pair((int)Qt::Key_OfficeHome , "OfficeHome"),
std::make_pair((int)Qt::Key_Option , "Option"),
std::make_pair((int)Qt::Key_Paste , "Paste"),
std::make_pair((int)Qt::Key_Phone , "Phone"),
std::make_pair((int)Qt::Key_Calendar , "Calendar"),
std::make_pair((int)Qt::Key_Reply , "Reply"),
std::make_pair((int)Qt::Key_Reload , "Reload"),
std::make_pair((int)Qt::Key_RotateWindows , "RotateWindows"),
std::make_pair((int)Qt::Key_RotationPB , "RotationPB"),
std::make_pair((int)Qt::Key_RotationKB , "RotationKB"),
std::make_pair((int)Qt::Key_Save , "Save"),
std::make_pair((int)Qt::Key_Send , "Send"),
std::make_pair((int)Qt::Key_Spell , "Spell"),
std::make_pair((int)Qt::Key_SplitScreen , "SplitScreen"),
std::make_pair((int)Qt::Key_Support , "Support"),
std::make_pair((int)Qt::Key_TaskPane , "TaskPane"),
std::make_pair((int)Qt::Key_Terminal , "Terminal"),
std::make_pair((int)Qt::Key_Tools , "Tools"),
std::make_pair((int)Qt::Key_Travel , "Travel"),
std::make_pair((int)Qt::Key_Video , "Video"),
std::make_pair((int)Qt::Key_Word , "Word"),
std::make_pair((int)Qt::Key_Xfer , "Xfer"),
std::make_pair((int)Qt::Key_ZoomIn , "ZoomIn"),
std::make_pair((int)Qt::Key_ZoomOut , "ZoomOut"),
std::make_pair((int)Qt::Key_Away , "Away"),
std::make_pair((int)Qt::Key_Messenger , "Messenger"),
std::make_pair((int)Qt::Key_WebCam , "WebCam"),
std::make_pair((int)Qt::Key_MailForward , "MailForward"),
std::make_pair((int)Qt::Key_Pictures , "Pictures"),
std::make_pair((int)Qt::Key_Music , "Music"),
std::make_pair((int)Qt::Key_Battery , "Battery"),
std::make_pair((int)Qt::Key_Bluetooth , "Bluetooth"),
std::make_pair((int)Qt::Key_WLAN , "WLAN"),
std::make_pair((int)Qt::Key_UWB , "UWB"),
std::make_pair((int)Qt::Key_AudioForward , "AudioForward"),
std::make_pair((int)Qt::Key_AudioRepeat , "AudioRepeat"),
std::make_pair((int)Qt::Key_AudioRandomPlay , "AudioRandomPlay"),
std::make_pair((int)Qt::Key_Subtitle , "Subtitle"),
std::make_pair((int)Qt::Key_AudioCycleTrack , "AudioCycleTrack"),
std::make_pair((int)Qt::Key_Time , "Time"),
std::make_pair((int)Qt::Key_Hibernate , "Hibernate"),
std::make_pair((int)Qt::Key_View , "View"),
std::make_pair((int)Qt::Key_TopMenu , "TopMenu"),
std::make_pair((int)Qt::Key_PowerDown , "PowerDown"),
std::make_pair((int)Qt::Key_Suspend , "Suspend"),
std::make_pair((int)Qt::Key_ContrastAdjust , "ContrastAdjust"),
std::make_pair((int)Qt::Key_LaunchG , "LaunchG"),
std::make_pair((int)Qt::Key_LaunchH , "LaunchH"),
#if QT_VERSION >= QT_VERSION_CHECK(5,7,0)
std::make_pair((int)Qt::Key_TouchpadToggle , "TouchpadToggle"),
std::make_pair((int)Qt::Key_TouchpadOn , "TouchpadOn"),
std::make_pair((int)Qt::Key_TouchpadOff , "TouchpadOff"),
std::make_pair((int)Qt::Key_MicMute , "MicMute"),
std::make_pair((int)Qt::Key_Red , "Red"),
std::make_pair((int)Qt::Key_Green , "Green"),
std::make_pair((int)Qt::Key_Yellow , "Yellow"),
std::make_pair((int)Qt::Key_Blue , "Blue"),
std::make_pair((int)Qt::Key_ChannelUp , "ChannelUp"),
std::make_pair((int)Qt::Key_ChannelDown , "ChannelDown"),
std::make_pair((int)Qt::Key_Guide , "Guide"),
std::make_pair((int)Qt::Key_Info , "Info"),
std::make_pair((int)Qt::Key_Settings , "Settings"),
std::make_pair((int)Qt::Key_MicVolumeUp , "MicVolumeUp"),
std::make_pair((int)Qt::Key_MicVolumeDown , "MicVolumeDown"),
std::make_pair((int)Qt::Key_New , "New"),
std::make_pair((int)Qt::Key_Open , "Open"),
std::make_pair((int)Qt::Key_Find , "Find"),
std::make_pair((int)Qt::Key_Undo , "Undo"),
std::make_pair((int)Qt::Key_Redo , "Redo"),
#endif
std::make_pair((int)Qt::Key_AltGr , "AltGr"),
std::make_pair((int)Qt::Key_Multi_key , "Multi_key"),
std::make_pair((int)Qt::Key_Kanji , "Kanji"),
std::make_pair((int)Qt::Key_Muhenkan , "Muhenkan"),
std::make_pair((int)Qt::Key_Henkan , "Henkan"),
std::make_pair((int)Qt::Key_Romaji , "Romaji"),
std::make_pair((int)Qt::Key_Hiragana , "Hiragana"),
std::make_pair((int)Qt::Key_Katakana , "Katakana"),
std::make_pair((int)Qt::Key_Hiragana_Katakana , "Hiragana_Katakana"),
std::make_pair((int)Qt::Key_Zenkaku , "Zenkaku"),
std::make_pair((int)Qt::Key_Hankaku , "Hankaku"),
std::make_pair((int)Qt::Key_Zenkaku_Hankaku , "Zenkaku_Hankaku"),
std::make_pair((int)Qt::Key_Touroku , "Touroku"),
std::make_pair((int)Qt::Key_Massyo , "Massyo"),
std::make_pair((int)Qt::Key_Kana_Lock , "Kana_Lock"),
std::make_pair((int)Qt::Key_Kana_Shift , "Kana_Shift"),
std::make_pair((int)Qt::Key_Eisu_Shift , "Eisu_Shift"),
std::make_pair((int)Qt::Key_Eisu_toggle , "Eisu_toggle"),
std::make_pair((int)Qt::Key_Hangul , "Hangul"),
std::make_pair((int)Qt::Key_Hangul_Start , "Hangul_Start"),
std::make_pair((int)Qt::Key_Hangul_End , "Hangul_End"),
std::make_pair((int)Qt::Key_Hangul_Hanja , "Hangul_Hanja"),
std::make_pair((int)Qt::Key_Hangul_Jamo , "Hangul_Jamo"),
std::make_pair((int)Qt::Key_Hangul_Romaja , "Hangul_Romaja"),
std::make_pair((int)Qt::Key_Codeinput , "Codeinput"),
std::make_pair((int)Qt::Key_Hangul_Jeonja , "Hangul_Jeonja"),
std::make_pair((int)Qt::Key_Hangul_Banja , "Hangul_Banja"),
std::make_pair((int)Qt::Key_Hangul_PreHanja , "Hangul_PreHanja"),
std::make_pair((int)Qt::Key_Hangul_PostHanja , "Hangul_PostHanja"),
std::make_pair((int)Qt::Key_SingleCandidate , "SingleCandidate"),
std::make_pair((int)Qt::Key_MultipleCandidate , "MultipleCandidate"),
std::make_pair((int)Qt::Key_PreviousCandidate , "PreviousCandidate"),
std::make_pair((int)Qt::Key_Hangul_Special , "Hangul_Special"),
std::make_pair((int)Qt::Key_Mode_switch , "Mode_switch"),
std::make_pair((int)Qt::Key_Dead_Grave , "Dead_Grave"),
std::make_pair((int)Qt::Key_Dead_Acute , "Dead_Acute"),
std::make_pair((int)Qt::Key_Dead_Circumflex , "Dead_Circumflex"),
std::make_pair((int)Qt::Key_Dead_Tilde , "Dead_Tilde"),
std::make_pair((int)Qt::Key_Dead_Macron , "Dead_Macron"),
std::make_pair((int)Qt::Key_Dead_Breve , "Dead_Breve"),
std::make_pair((int)Qt::Key_Dead_Abovedot , "Dead_Abovedot"),
std::make_pair((int)Qt::Key_Dead_Diaeresis , "Dead_Diaeresis"),
std::make_pair((int)Qt::Key_Dead_Abovering , "Dead_Abovering"),
std::make_pair((int)Qt::Key_Dead_Doubleacute , "Dead_Doubleacute"),
std::make_pair((int)Qt::Key_Dead_Caron , "Dead_Caron"),
std::make_pair((int)Qt::Key_Dead_Cedilla , "Dead_Cedilla"),
std::make_pair((int)Qt::Key_Dead_Ogonek , "Dead_Ogonek"),
std::make_pair((int)Qt::Key_Dead_Iota , "Dead_Iota"),
std::make_pair((int)Qt::Key_Dead_Voiced_Sound , "Dead_Voiced_Sound"),
std::make_pair((int)Qt::Key_Dead_Semivoiced_Sound , "Dead_Semivoiced_Sound"),
std::make_pair((int)Qt::Key_Dead_Belowdot , "Dead_Belowdot"),
std::make_pair((int)Qt::Key_Dead_Hook , "Dead_Hook"),
std::make_pair((int)Qt::Key_Dead_Horn , "Dead_Horn"),
std::make_pair((int)Qt::Key_MediaLast , "MediaLast"),
std::make_pair((int)Qt::Key_Select , "Select"),
std::make_pair((int)Qt::Key_Yes , "Yes"),
std::make_pair((int)Qt::Key_No , "No"),
std::make_pair((int)Qt::Key_Cancel , "Cancel"),
std::make_pair((int)Qt::Key_Printer , "Printer"),
std::make_pair((int)Qt::Key_Execute , "Execute"),
std::make_pair((int)Qt::Key_Sleep , "Sleep"),
std::make_pair((int)Qt::Key_Play , "Play"),
std::make_pair((int)Qt::Key_Zoom , "Zoom"),
#if QT_VERSION >= QT_VERSION_CHECK(5,7,0)
std::make_pair((int)Qt::Key_Exit , "Exit"),
#endif
std::make_pair((int)Qt::Key_Context1 , "Context1"),
std::make_pair((int)Qt::Key_Context2 , "Context2"),
std::make_pair((int)Qt::Key_Context3 , "Context3"),
std::make_pair((int)Qt::Key_Context4 , "Context4"),
std::make_pair((int)Qt::Key_Call , "Call"),
std::make_pair((int)Qt::Key_Hangup , "Hangup"),
std::make_pair((int)Qt::Key_Flip , "Flip"),
std::make_pair((int)Qt::Key_ToggleCallHangup , "ToggleCallHangup"),
std::make_pair((int)Qt::Key_VoiceDial , "VoiceDial"),
std::make_pair((int)Qt::Key_LastNumberRedial , "LastNumberRedial"),
std::make_pair((int)Qt::Key_Camera , "Camera"),
std::make_pair((int)Qt::Key_CameraFocus , "CameraFocus"),
std::make_pair(0 , (const char*) 0)
};
}

@ -0,0 +1,73 @@
#ifndef CSM_PREFS_SHORTCUTMANAGER_H
#define CSM_PREFS_SHORTCUTMANAGER_H
#include <map>
#include <QKeySequence>
#include <QObject>
#include <QString>
namespace CSMPrefs
{
class Shortcut;
class ShortcutEventHandler;
/// Class used to track and update shortcuts/sequences
class ShortcutManager : public QObject
{
Q_OBJECT
public:
ShortcutManager();
/// The shortcut class will do this automatically
void addShortcut(Shortcut* shortcut);
/// The shortcut class will do this automatically
void removeShortcut(Shortcut* shortcut);
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;
std::string convertToString(const QKeySequence& sequence, int modifier) const;
void convertFromString(const std::string& data, QKeySequence& sequence) const;
void convertFromString(const std::string& data, int& modifier) const;
void convertFromString(const std::string& data, QKeySequence& sequence, int& modifier) const;
/// Replaces "{sequence-name}" or "{modifier-name}" with the appropriate text
QString processToolTip(const QString& toolTip) const;
private:
// Need a multimap in case multiple shortcuts share the same name
typedef std::multimap<std::string, Shortcut*> ShortcutMap;
typedef std::map<std::string, QKeySequence> SequenceMap;
typedef std::map<std::string, int> ModifierMap;
typedef std::map<int, std::string> NameMap;
typedef std::map<std::string, int> KeyMap;
ShortcutMap mShortcuts;
SequenceMap mSequences;
ModifierMap mModifiers;
NameMap mNames;
KeyMap mKeys;
ShortcutEventHandler* mEventHandler;
void createLookupTables();
static const std::pair<int, const char*> QtKeys[];
};
}
#endif

@ -0,0 +1,196 @@
#include "shortcutsetting.hpp"
#include <QEvent>
#include <QKeyEvent>
#include <QLabel>
#include <QMouseEvent>
#include <QPushButton>
#include <QWidget>
#include "state.hpp"
#include "shortcutmanager.hpp"
namespace CSMPrefs
{
const int ShortcutSetting::MaxKeys;
ShortcutSetting::ShortcutSetting(Category* parent, Settings::Manager* values, QMutex* mutex, const std::string& key,
const std::string& label)
: Setting(parent, values, mutex, key, label)
, mEditorActive(false)
, mEditorPos(0)
{
for (int i = 0; i < MaxKeys; ++i)
{
mEditorKeys[i] = 0;
}
}
std::pair<QWidget*, QWidget*> ShortcutSetting::makeWidgets(QWidget* parent)
{
QKeySequence sequence;
State::get().getShortcutManager().getSequence(getKey(), sequence);
QString text = QString::fromUtf8(State::get().getShortcutManager().convertToString(sequence).c_str());
QLabel* label = new QLabel(QString::fromUtf8(getLabel().c_str()), parent);
QPushButton* widget = new QPushButton(text, parent);
widget->setCheckable(true);
widget->installEventFilter(this);
mButton = widget;
connect(widget, SIGNAL(toggled(bool)), this, SLOT(buttonToggled(bool)));
return std::make_pair(label, widget);
}
bool ShortcutSetting::eventFilter(QObject* target, QEvent* event)
{
if (event->type() == QEvent::KeyPress)
{
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->isAutoRepeat())
return true;
int mod = keyEvent->modifiers();
int key = keyEvent->key();
return handleEvent(target, mod, key, true);
}
else if (event->type() == QEvent::KeyRelease)
{
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->isAutoRepeat())
return true;
int mod = keyEvent->modifiers();
int key = keyEvent->key();
return handleEvent(target, mod, key, false);
}
else if (event->type() == QEvent::MouseButtonPress)
{
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
int mod = mouseEvent->modifiers();
int key = mouseEvent->button();
return handleEvent(target, mod, key, true);
}
else if (event->type() == QEvent::MouseButtonRelease)
{
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
int mod = mouseEvent->modifiers();
int key = mouseEvent->button();
return handleEvent(target, mod, key, false);
}
else if (event->type() == QEvent::FocusOut)
{
resetState();
}
return false;
}
bool ShortcutSetting::handleEvent(QObject* target, int mod, int value, bool active)
{
// Modifiers are handled differently
const int Blacklist[] =
{
Qt::Key_Shift,
Qt::Key_Control,
Qt::Key_Meta,
Qt::Key_Alt,
Qt::Key_AltGr
};
const size_t BlacklistSize = sizeof(Blacklist) / sizeof(int);
if (!mEditorActive)
{
if (value == Qt::RightButton && !active)
{
// Clear sequence
QKeySequence sequence = QKeySequence(0, 0, 0, 0);
storeValue(sequence);
resetState();
}
return false;
}
// Handle blacklist
for (size_t i = 0; i < BlacklistSize; ++i)
{
if (value == Blacklist[i])
return true;
}
if (!active || mEditorPos >= MaxKeys)
{
// Update key
QKeySequence sequence = QKeySequence(mEditorKeys[0], mEditorKeys[1], mEditorKeys[2], mEditorKeys[3]);
storeValue(sequence);
resetState();
}
else
{
if (mEditorPos == 0)
{
mEditorKeys[0] = mod | value;
}
else
{
mEditorKeys[mEditorPos] = value;
}
mEditorPos += 1;
}
return true;
}
void ShortcutSetting::storeValue(const QKeySequence& sequence)
{
State::get().getShortcutManager().setSequence(getKey(), sequence);
// Convert to string and assign
std::string value = State::get().getShortcutManager().convertToString(sequence);
{
QMutexLocker lock(getMutex());
getValues().setString(getKey(), getParent()->getKey(), value);
}
getParent()->getState()->update(*this);
}
void ShortcutSetting::resetState()
{
mButton->setChecked(false);
mEditorActive = false;
mEditorPos = 0;
for (int i = 0; i < MaxKeys; ++i)
{
mEditorKeys[i] = 0;
}
// Button text
QKeySequence sequence;
State::get().getShortcutManager().getSequence(getKey(), sequence);
QString text = QString::fromUtf8(State::get().getShortcutManager().convertToString(sequence).c_str());
mButton->setText(text);
}
void ShortcutSetting::buttonToggled(bool checked)
{
if (checked)
mButton->setText("Press keys or click here...");
mEditorActive = checked;
}
}

@ -0,0 +1,49 @@
#ifndef CSM_PREFS_SHORTCUTSETTING_H
#define CSM_PREFS_SHORTCUTSETTING_H
#include <QKeySequence>
#include "setting.hpp"
class QEvent;
class QPushButton;
namespace CSMPrefs
{
class ShortcutSetting : public Setting
{
Q_OBJECT
public:
ShortcutSetting(Category* parent, Settings::Manager* values, QMutex* mutex, const std::string& key,
const std::string& label);
virtual std::pair<QWidget*, QWidget*> makeWidgets(QWidget* parent);
protected:
bool eventFilter(QObject* target, QEvent* event);
private:
bool handleEvent(QObject* target, int mod, int value, bool active);
void storeValue(const QKeySequence& sequence);
void resetState();
static const int MaxKeys = 4;
QPushButton* mButton;
bool mEditorActive;
int mEditorPos;
int mEditorKeys[MaxKeys];
private slots:
void buttonToggled(bool checked);
};
}
#endif

@ -9,6 +9,8 @@
#include "doublesetting.hpp"
#include "boolsetting.hpp"
#include "coloursetting.hpp"
#include "shortcutsetting.hpp"
#include "modifiersetting.hpp"
CSMPrefs::State *CSMPrefs::State::sThis = 0;
@ -165,16 +167,6 @@ void CSMPrefs::State::declare()
"list go to the first/last item");
declareCategory ("3D Scene Input");
EnumValue left ("Left Mouse-Button");
EnumValue cLeft ("Ctrl-Left Mouse-Button");
EnumValue right ("Right Mouse-Button");
EnumValue cRight ("Ctrl-Right Mouse-Button");
EnumValue middle ("Middle Mouse-Button");
EnumValue cMiddle ("Ctrl-Middle Mouse-Button");
EnumValues inputButtons;
inputButtons.add (left).add (cLeft).add (right).add (cRight).add (middle).add (cMiddle);
declareEnum ("p-navi", "Primary Camera Navigation Button", left).addValues (inputButtons);
declareEnum ("s-navi", "Secondary Camera Navigation Button", cLeft).addValues (inputButtons);
declareDouble ("p-navi-free-sensitivity", "Free Camera Sensitivity", 1/650.).setPrecision(5).setRange(0.0, 1.0);
declareBool ("p-navi-free-invert", "Invert Free Camera Mouse Input", false);
declareDouble ("p-navi-orbit-sensitivity", "Orbit Camera Sensitivity", 1/650.).setPrecision(5).setRange(0.0, 1.0);
@ -186,10 +178,6 @@ void CSMPrefs::State::declare()
declareDouble ("navi-free-speed-mult", "Free Camera Speed Multiplier (from Modifier)", 8).setRange(0.001, 1000.0);
declareDouble ("navi-orbit-rot-speed", "Orbital Camera Rotational Speed", 3.14 / 4).setRange(0.001, 6.28);
declareDouble ("navi-orbit-speed-mult", "Orbital Camera Speed Multiplier (from Modifier)", 4).setRange(0.001, 1000.0);
declareEnum ("p-edit", "Primary Editing Button", right).addValues (inputButtons);
declareEnum ("s-edit", "Secondary Editing Button", cRight).addValues (inputButtons);
declareEnum ("p-select", "Primary Selection Button", middle).addValues (inputButtons);
declareEnum ("s-select", "Secondary Selection Button", cMiddle).addValues (inputButtons);
declareSeparator();
declareBool ("context-select", "Context Sensitive Selection", false);
declareDouble ("drag-factor", "Mouse sensitivity during drag operations", 1.0).
@ -224,6 +212,119 @@ void CSMPrefs::State::declare()
addValues (insertOutsideCell);
declareEnum ("outside-visible-drop", "Handling drops outside of visible cells", showAndInsert).
addValues (insertOutsideVisibleCell);
declareCategory ("Key Bindings");
declareSubcategory ("Document");
declareShortcut ("document-file-newgame", "New Game", QKeySequence(Qt::ControlModifier | Qt::Key_N));
declareShortcut ("document-file-newaddon", "New Addon", QKeySequence());
declareShortcut ("document-file-open", "Open", QKeySequence(Qt::ControlModifier | Qt::Key_O));
declareShortcut ("document-file-save", "Save", QKeySequence(Qt::ControlModifier | Qt::Key_S));
declareShortcut ("document-file-verify", "Verify", QKeySequence());
declareShortcut ("document-file-merge", "Merge", QKeySequence());
declareShortcut ("document-file-errorlog", "Open Load Error Log", QKeySequence());
declareShortcut ("document-file-metadata", "Meta Data", QKeySequence());
declareShortcut ("document-file-close", "Close Document", QKeySequence(Qt::ControlModifier | Qt::Key_W));
declareShortcut ("document-file-exit", "Exit Application", QKeySequence(Qt::ControlModifier | Qt::Key_Q));
declareShortcut ("document-edit-undo", "Undo", QKeySequence(Qt::ControlModifier | Qt::Key_Z));
declareShortcut ("document-edit-redo", "Redo", QKeySequence(Qt::ControlModifier | Qt::ShiftModifier | Qt::Key_Z));
declareShortcut ("document-edit-preferences", "Open Preferences", QKeySequence());
declareShortcut ("document-edit-search", "Search", QKeySequence(Qt::ControlModifier | Qt::Key_F));
declareShortcut ("document-view-newview", "New View", QKeySequence());
declareShortcut ("document-view-statusbar", "Toggle Status Bar", QKeySequence());
declareShortcut ("document-view-filters", "Open Filter List", QKeySequence());
declareShortcut ("document-world-regions", "Open Region List", QKeySequence());
declareShortcut ("document-world-cells", "Open Cell List", QKeySequence());
declareShortcut ("document-world-referencables", "Open Object List", QKeySequence());
declareShortcut ("document-world-references", "Open Instance List", QKeySequence());
declareShortcut ("document-world-pathgrid", "Open Pathgrid List", QKeySequence());
declareShortcut ("document-world-regionmap", "Open Region Map", QKeySequence());
declareShortcut ("document-mechanics-globals", "Open Global List", QKeySequence());
declareShortcut ("document-mechanics-gamesettings", "Open Game Settings", QKeySequence());
declareShortcut ("document-mechanics-scripts", "Open Script List", QKeySequence());
declareShortcut ("document-mechanics-spells", "Open Spell List", QKeySequence());
declareShortcut ("document-mechanics-enchantments", "Open Enchantment List", QKeySequence());
declareShortcut ("document-mechanics-magiceffects", "Open Magic Effect List", QKeySequence());
declareShortcut ("document-mechanics-startscripts", "Open Start Script List", QKeySequence());
declareShortcut ("document-character-skills", "Open Skill List", QKeySequence());
declareShortcut ("document-character-classes", "Open Class List", QKeySequence());
declareShortcut ("document-character-factions", "Open Faction List", QKeySequence());
declareShortcut ("document-character-races", "Open Race List", QKeySequence());
declareShortcut ("document-character-birthsigns", "Open Birthsign List", QKeySequence());
declareShortcut ("document-character-topics", "Open Topic List", QKeySequence());
declareShortcut ("document-character-journals", "Open Journal List", QKeySequence());
declareShortcut ("document-character-topicinfos", "Open Topic Info List", QKeySequence());
declareShortcut ("document-character-journalinfos", "Open Journal Info List", QKeySequence());
declareShortcut ("document-character-bodyparts", "Open Body Part List", QKeySequence());
declareShortcut ("document-assets-sounds", "Open Sound Asset List", QKeySequence());
declareShortcut ("document-assets-soundgens", "Open Sound Generator List", QKeySequence());
declareShortcut ("document-assets-meshes", "Open Mesh Asset List", QKeySequence());
declareShortcut ("document-assets-icons", "Open Icon Asset List", QKeySequence());
declareShortcut ("document-assets-music", "Open Music Asset List", QKeySequence());
declareShortcut ("document-assets-soundres", "Open Sound File List", QKeySequence());
declareShortcut ("document-assets-textures", "Open Texture Asset List", QKeySequence());
declareShortcut ("document-assets-videos", "Open Video Asset List", QKeySequence());
declareShortcut ("document-debug-run", "Run Debug", QKeySequence());
declareShortcut ("document-debug-shutdown", "Stop Debug", QKeySequence());
declareShortcut ("document-debug-runlog", "Open Run Log", QKeySequence());
declareSubcategory ("Table");
declareShortcut ("table-edit", "Edit Record", QKeySequence());
declareShortcut ("table-add", "Add Row/Record", QKeySequence(Qt::ShiftModifier | Qt::Key_A));
declareShortcut ("table-clone", "Clone Record", QKeySequence(Qt::ShiftModifier | Qt::Key_D));
declareShortcut ("table-revert", "Revert Record", QKeySequence());
declareShortcut ("table-remove", "Remove Row/Record", QKeySequence(Qt::Key_Delete));
declareShortcut ("table-moveup", "Move Record Up", QKeySequence());
declareShortcut ("table-movedown", "Move Record Down", QKeySequence());
declareShortcut ("table-view", "View Record", QKeySequence());
declareShortcut ("table-preview", "Preview Record", QKeySequence());
declareShortcut ("table-extendeddelete", "Extended Record Deletion", QKeySequence());
declareShortcut ("table-extendedrevert", "Extended Record Revertion", QKeySequence());
declareSubcategory ("Report Table");
declareShortcut ("reporttable-show", "Show Report", QKeySequence());
declareShortcut ("reporttable-remove", "Remove Report", QKeySequence(Qt::Key_Delete));
declareShortcut ("reporttable-replace", "Replace Report", QKeySequence());
declareShortcut ("reporttable-refresh", "Refresh Report", QKeySequence());
declareSubcategory ("Scene");
declareShortcut ("scene-navi-primary", "Camera Rotation From Mouse Movement", QKeySequence(Qt::LeftButton));
declareShortcut ("scene-navi-secondary", "Camera Translation From Mouse Movement",
QKeySequence(Qt::ControlModifier | (int)Qt::LeftButton));
declareShortcut ("scene-edit-primary", "Primary Edit", QKeySequence(Qt::RightButton));
declareShortcut ("scene-edit-secondary", "Secondary Edit",
QKeySequence(Qt::ControlModifier | (int)Qt::RightButton));
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));
declareShortcut ("scene-load-cam-westcell", "Load West Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_4));
declareShortcut ("scene-load-cam-southcell", "Load South Cell", QKeySequence(Qt::KeypadModifier | Qt::Key_2));
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)
@ -340,6 +441,50 @@ 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().convertToString(default_);
setDefault (key, seqStr);
// Setup with actual data
QKeySequence sequence;
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);
mCurrentCategory->second.addSetting (setting);
return *setting;
}
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);
return *setting;
}
void CSMPrefs::State::declareSeparator()
{
if (mCurrentCategory==mCategories.end())
@ -351,6 +496,17 @@ void CSMPrefs::State::declareSeparator()
mCurrentCategory->second.addSetting (setting);
}
void CSMPrefs::State::declareSubcategory(const std::string& label)
{
if (mCurrentCategory==mCategories.end())
throw std::logic_error ("no category for setting");
CSMPrefs::Setting *setting =
new CSMPrefs::Setting (&mCurrentCategory->second, &mSettings, &mMutex, "", label);
mCurrentCategory->second.addSetting (setting);
}
void CSMPrefs::State::setDefault (const std::string& key, const std::string& default_)
{
Settings::CategorySetting fullKey (mCurrentCategory->second.getKey(), key);
@ -369,10 +525,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 +552,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);

@ -16,6 +16,7 @@
#include "category.hpp"
#include "setting.hpp"
#include "enumsetting.hpp"
#include "shortcutmanager.hpp"
class QColor;
@ -25,6 +26,8 @@ namespace CSMPrefs
class DoubleSetting;
class BoolSetting;
class ColourSetting;
class ShortcutSetting;
class ModifierSetting;
/// \brief User settings state
///
@ -45,6 +48,7 @@ namespace CSMPrefs
const std::string mConfigFile;
const Files::ConfigurationManager& mConfigurationManager;
ShortcutManager mShortcutManager;
Settings::Manager mSettings;
Collection mCategories;
Iterator mCurrentCategory;
@ -71,8 +75,15 @@ 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_);
ModifierSetting& declareModifier(const std::string& key, const std::string& label, int modifier_);
void declareSeparator();
void declareSubcategory(const std::string& label);
void setDefault (const std::string& key, const std::string& default_);
public:
@ -87,6 +98,8 @@ namespace CSMPrefs
Iterator end();
ShortcutManager& getShortcutManager();
Category& operator[](const std::string& key);
void update (const Setting& setting);

@ -16,6 +16,7 @@
#include "../../model/doc/document.hpp"
#include "../../model/prefs/state.hpp"
#include "../../model/prefs/shortcut.hpp"
#include "../../model/world/idtable.hpp"
@ -44,83 +45,98 @@ void CSVDoc::View::closeEvent (QCloseEvent *event)
void CSVDoc::View::setupFileMenu()
{
QMenu *file = menuBar()->addMenu (tr ("&File"));
QMenu *file = menuBar()->addMenu (tr ("File"));
QAction *newGame = new QAction (tr ("New Game"), this);
connect (newGame, SIGNAL (triggered()), this, SIGNAL (newGameRequest()));
setupShortcut("document-file-newgame", newGame);
file->addAction (newGame);
QAction *newAddon = new QAction (tr ("New Addon"), this);
connect (newAddon, SIGNAL (triggered()), this, SIGNAL (newAddonRequest()));
setupShortcut("document-file-newaddon", newAddon);
file->addAction (newAddon);
QAction *open = new QAction (tr ("&Open"), this);
QAction *open = new QAction (tr ("Open"), this);
connect (open, SIGNAL (triggered()), this, SIGNAL (loadDocumentRequest()));
setupShortcut("document-file-open", open);
file->addAction (open);
mSave = new QAction (tr ("&Save"), this);
mSave = new QAction (tr ("Save"), this);
connect (mSave, SIGNAL (triggered()), this, SLOT (save()));
setupShortcut("document-file-save", mSave);
file->addAction (mSave);
mVerify = new QAction (tr ("&Verify"), this);
mVerify = new QAction (tr ("Verify"), this);
connect (mVerify, SIGNAL (triggered()), this, SLOT (verify()));
setupShortcut("document-file-verify", mVerify);
file->addAction (mVerify);
mMerge = new QAction (tr ("Merge"), this);
connect (mMerge, SIGNAL (triggered()), this, SLOT (merge()));
setupShortcut("document-file-merge", mMerge);
file->addAction (mMerge);
QAction *loadErrors = new QAction (tr ("Load Error Log"), this);
QAction *loadErrors = new QAction (tr ("Open Load Error Log"), this);
connect (loadErrors, SIGNAL (triggered()), this, SLOT (loadErrorLog()));
setupShortcut("document-file-errorlog", loadErrors);
file->addAction (loadErrors);
QAction *meta = new QAction (tr ("Meta Data"), this);
connect (meta, SIGNAL (triggered()), this, SLOT (addMetaDataSubView()));
setupShortcut("document-file-metadata", meta);
file->addAction (meta);
QAction *close = new QAction (tr ("&Close"), this);
QAction *close = new QAction (tr ("Close Document"), this);
connect (close, SIGNAL (triggered()), this, SLOT (close()));
setupShortcut("document-file-close", close);
file->addAction(close);
QAction *exit = new QAction (tr ("&Exit"), this);
QAction *exit = new QAction (tr ("Exit Application"), this);
connect (exit, SIGNAL (triggered()), this, SLOT (exit()));
connect (this, SIGNAL(exitApplicationRequest(CSVDoc::View *)), &mViewManager, SLOT(exitApplication(CSVDoc::View *)));
setupShortcut("document-file-exit", exit);
file->addAction(exit);
}
void CSVDoc::View::setupEditMenu()
{
QMenu *edit = menuBar()->addMenu (tr ("&Edit"));
QMenu *edit = menuBar()->addMenu (tr ("Edit"));
mUndo = mDocument->getUndoStack().createUndoAction (this, tr("&Undo"));
mUndo->setShortcuts (QKeySequence::Undo);
mUndo = mDocument->getUndoStack().createUndoAction (this, tr("Undo"));
setupShortcut("document-edit-undo", mUndo);
edit->addAction (mUndo);
mRedo= mDocument->getUndoStack().createRedoAction (this, tr("&Redo"));
mRedo->setShortcuts (QKeySequence::Redo);
mRedo= mDocument->getUndoStack().createRedoAction (this, tr("Redo"));
setupShortcut("document-edit-redo", mRedo);
edit->addAction (mRedo);
QAction *userSettings = new QAction (tr ("&Preferences"), this);
QAction *userSettings = new QAction (tr ("Preferences"), this);
connect (userSettings, SIGNAL (triggered()), this, SIGNAL (editSettingsRequest()));
setupShortcut("document-edit-preferences", userSettings);
edit->addAction (userSettings);
QAction *search = new QAction (tr ("Search"), this);
connect (search, SIGNAL (triggered()), this, SLOT (addSearchSubView()));
setupShortcut("document-edit-search", search);
edit->addAction (search);
}
void CSVDoc::View::setupViewMenu()
{
QMenu *view = menuBar()->addMenu (tr ("&View"));
QMenu *view = menuBar()->addMenu (tr ("View"));
QAction *newWindow = new QAction (tr ("&New View"), this);
QAction *newWindow = new QAction (tr ("New View"), this);
connect (newWindow, SIGNAL (triggered()), this, SLOT (newView()));
setupShortcut("document-view-newview", newWindow);
view->addAction (newWindow);
mShowStatusBar = new QAction (tr ("Show Status Bar"), this);
mShowStatusBar = new QAction (tr ("Toggle Status Bar"), this);
mShowStatusBar->setCheckable (true);
connect (mShowStatusBar, SIGNAL (toggled (bool)), this, SLOT (toggleShowStatusBar (bool)));
setupShortcut("document-view-statusbar", mShowStatusBar);
mShowStatusBar->setChecked (CSMPrefs::get()["Windows"]["show-statusbar"].isTrue());
@ -128,70 +144,84 @@ void CSVDoc::View::setupViewMenu()
QAction *filters = new QAction (tr ("Filters"), this);
connect (filters, SIGNAL (triggered()), this, SLOT (addFiltersSubView()));
setupShortcut("document-view-filters", filters);
view->addAction (filters);
}
void CSVDoc::View::setupWorldMenu()
{
QMenu *world = menuBar()->addMenu (tr ("&World"));
QMenu *world = menuBar()->addMenu (tr ("World"));
QAction *regions = new QAction (tr ("Regions"), this);
connect (regions, SIGNAL (triggered()), this, SLOT (addRegionsSubView()));
setupShortcut("document-world-regions", regions);
world->addAction (regions);
QAction *cells = new QAction (tr ("Cells"), this);
connect (cells, SIGNAL (triggered()), this, SLOT (addCellsSubView()));
setupShortcut("document-world-cells", cells);
world->addAction (cells);
QAction *referenceables = new QAction (tr ("Objects"), this);
connect (referenceables, SIGNAL (triggered()), this, SLOT (addReferenceablesSubView()));
setupShortcut("document-world-referencables", referenceables);
world->addAction (referenceables);
QAction *references = new QAction (tr ("Instances"), this);
connect (references, SIGNAL (triggered()), this, SLOT (addReferencesSubView()));
setupShortcut("document-world-references", references);
world->addAction (references);
QAction *grid = new QAction (tr ("Pathgrid"), this);
connect (grid, SIGNAL (triggered()), this, SLOT (addPathgridSubView()));
setupShortcut("document-world-pathgrid", grid);
world->addAction (grid);
world->addSeparator(); // items that don't represent single record lists follow here
QAction *regionMap = new QAction (tr ("Region Map"), this);
connect (regionMap, SIGNAL (triggered()), this, SLOT (addRegionMapSubView()));
setupShortcut("document-world-regionmap", regionMap);
world->addAction (regionMap);
}
void CSVDoc::View::setupMechanicsMenu()
{
QMenu *mechanics = menuBar()->addMenu (tr ("&Mechanics"));
QMenu *mechanics = menuBar()->addMenu (tr ("Mechanics"));
QAction *globals = new QAction (tr ("Globals"), this);
connect (globals, SIGNAL (triggered()), this, SLOT (addGlobalsSubView()));
setupShortcut("document-mechanics-globals", globals);
mechanics->addAction (globals);
QAction *gmsts = new QAction (tr ("Game settings"), this);
QAction *gmsts = new QAction (tr ("Game Settings"), this);
connect (gmsts, SIGNAL (triggered()), this, SLOT (addGmstsSubView()));
setupShortcut("document-mechanics-gamesettings", gmsts);
mechanics->addAction (gmsts);
QAction *scripts = new QAction (tr ("Scripts"), this);
connect (scripts, SIGNAL (triggered()), this, SLOT (addScriptsSubView()));
setupShortcut("document-mechanics-scripts", scripts);
mechanics->addAction (scripts);
QAction *spells = new QAction (tr ("Spells"), this);
connect (spells, SIGNAL (triggered()), this, SLOT (addSpellsSubView()));
setupShortcut("document-mechanics-spells", spells);
mechanics->addAction (spells);
QAction *enchantments = new QAction (tr ("Enchantments"), this);
connect (enchantments, SIGNAL (triggered()), this, SLOT (addEnchantmentsSubView()));
setupShortcut("document-mechanics-enchantments", enchantments);
mechanics->addAction (enchantments);
QAction *effects = new QAction (tr ("Magic Effects"), this);
connect (effects, SIGNAL (triggered()), this, SLOT (addMagicEffectsSubView()));
setupShortcut("document-mechanics-magiceffects", effects);
mechanics->addAction (effects);
QAction *startScripts = new QAction (tr ("Start Scripts"), this);
connect (startScripts, SIGNAL (triggered()), this, SLOT (addStartScriptsSubView()));
setupShortcut("document-mechanics-startscripts", startScripts);
mechanics->addAction (startScripts);
}
@ -201,81 +231,99 @@ void CSVDoc::View::setupCharacterMenu()
QAction *skills = new QAction (tr ("Skills"), this);
connect (skills, SIGNAL (triggered()), this, SLOT (addSkillsSubView()));
setupShortcut("document-character-skills", skills);
characters->addAction (skills);
QAction *classes = new QAction (tr ("Classes"), this);
connect (classes, SIGNAL (triggered()), this, SLOT (addClassesSubView()));
setupShortcut("document-character-classes", classes);
characters->addAction (classes);
QAction *factions = new QAction (tr ("Factions"), this);
connect (factions, SIGNAL (triggered()), this, SLOT (addFactionsSubView()));
setupShortcut("document-character-factions", factions);
characters->addAction (factions);
QAction *races = new QAction (tr ("Races"), this);
connect (races, SIGNAL (triggered()), this, SLOT (addRacesSubView()));
setupShortcut("document-character-races", races);
characters->addAction (races);
QAction *birthsigns = new QAction (tr ("Birthsigns"), this);
connect (birthsigns, SIGNAL (triggered()), this, SLOT (addBirthsignsSubView()));
setupShortcut("document-character-birthsigns", birthsigns);
characters->addAction (birthsigns);
QAction *topics = new QAction (tr ("Topics"), this);
connect (topics, SIGNAL (triggered()), this, SLOT (addTopicsSubView()));
setupShortcut("document-character-topics", topics);
characters->addAction (topics);
QAction *journals = new QAction (tr ("Journals"), this);
connect (journals, SIGNAL (triggered()), this, SLOT (addJournalsSubView()));
setupShortcut("document-character-journals", journals);
characters->addAction (journals);
QAction *topicInfos = new QAction (tr ("Topic Infos"), this);
connect (topicInfos, SIGNAL (triggered()), this, SLOT (addTopicInfosSubView()));
setupShortcut("document-character-topicinfos", topicInfos);
characters->addAction (topicInfos);
QAction *journalInfos = new QAction (tr ("Journal Infos"), this);
connect (journalInfos, SIGNAL (triggered()), this, SLOT (addJournalInfosSubView()));
setupShortcut("document-character-journalinfos", journalInfos);
characters->addAction (journalInfos);
QAction *bodyParts = new QAction (tr ("Body Parts"), this);
connect (bodyParts, SIGNAL (triggered()), this, SLOT (addBodyPartsSubView()));
setupShortcut("document-character-bodyparts", bodyParts);
characters->addAction (bodyParts);
}
void CSVDoc::View::setupAssetsMenu()
{
QMenu *assets = menuBar()->addMenu (tr ("&Assets"));
QMenu *assets = menuBar()->addMenu (tr ("Assets"));
QAction *sounds = new QAction (tr ("Sounds"), this);
connect (sounds, SIGNAL (triggered()), this, SLOT (addSoundsSubView()));
setupShortcut("document-assets-sounds", sounds);
assets->addAction (sounds);
QAction *soundGens = new QAction (tr ("Sound Generators"), this);
connect (soundGens, SIGNAL (triggered()), this, SLOT (addSoundGensSubView()));
setupShortcut("document-assets-soundgens", soundGens);
assets->addAction (soundGens);
assets->addSeparator(); // resources follow here
QAction *meshes = new QAction (tr ("Meshes"), this);
connect (meshes, SIGNAL (triggered()), this, SLOT (addMeshesSubView()));
setupShortcut("document-assets-meshes", meshes);
assets->addAction (meshes);
QAction *icons = new QAction (tr ("Icons"), this);
connect (icons, SIGNAL (triggered()), this, SLOT (addIconsSubView()));
setupShortcut("document-assets-icons", icons);
assets->addAction (icons);
QAction *musics = new QAction (tr ("Music"), this);
connect (musics, SIGNAL (triggered()), this, SLOT (addMusicsSubView()));
setupShortcut("document-assets-music", musics);
assets->addAction (musics);
QAction *soundsRes = new QAction (tr ("Sound Files"), this);
connect (soundsRes, SIGNAL (triggered()), this, SLOT (addSoundsResSubView()));
setupShortcut("document-assets-soundres", soundsRes);
assets->addAction (soundsRes);
QAction *textures = new QAction (tr ("Textures"), this);
connect (textures, SIGNAL (triggered()), this, SLOT (addTexturesSubView()));
setupShortcut("document-assets-textures", textures);
assets->addAction (textures);
QAction *videos = new QAction (tr ("Videos"), this);
connect (videos, SIGNAL (triggered()), this, SLOT (addVideosSubView()));
setupShortcut("document-assets-videos", videos);
assets->addAction (videos);
}
@ -299,12 +347,16 @@ void CSVDoc::View::setupDebugMenu()
QAction *runDebug = debug->addMenu (mGlobalDebugProfileMenu);
runDebug->setText (tr ("Run OpenMW"));
setupShortcut("document-debug-run", runDebug);
mStopDebug = new QAction (tr ("Shutdown OpenMW"), this);
connect (mStopDebug, SIGNAL (triggered()), this, SLOT (stop()));
setupShortcut("document-debug-shutdown", mStopDebug);
debug->addAction (mStopDebug);
QAction *runLog = new QAction (tr ("Run Log"), this);
QAction *runLog = new QAction (tr ("Open Run Log"), this);
connect (runLog, SIGNAL (triggered()), this, SLOT (addRunLogSubView()));
setupShortcut("document-debug-runlog", runLog);
debug->addAction (runLog);
}
@ -320,6 +372,12 @@ void CSVDoc::View::setupUi()
setupDebugMenu();
}
void CSVDoc::View::setupShortcut(const char* name, QAction* action)
{
CSMPrefs::Shortcut* shortcut = new CSMPrefs::Shortcut(name, this);
shortcut->associateAction(action);
}
void CSVDoc::View::updateTitle()
{
std::ostringstream stream;

@ -84,6 +84,8 @@ namespace CSVDoc
void setupUi();
void setupShortcut(const char* name, QAction* action);
void updateActions();
void exitApplication();

@ -11,6 +11,7 @@
#include "../../model/prefs/state.hpp"
#include "page.hpp"
#include "keybindingpage.hpp"
void CSVPrefs::Dialogue::buildCategorySelector (QSplitter *main)
{
@ -52,8 +53,10 @@ void CSVPrefs::Dialogue::buildContentArea (QSplitter *main)
CSVPrefs::PageBase *CSVPrefs::Dialogue::makePage (const std::string& key)
{
// special case page code goes here
return new Page (CSMPrefs::get()[key], mContent);
if (key == "Key Bindings")
return new KeyBindingPage(CSMPrefs::get()[key], mContent);
else
return new Page (CSMPrefs::get()[key], mContent);
}
CSVPrefs::Dialogue::Dialogue()

@ -0,0 +1,88 @@
#include "keybindingpage.hpp"
#include <cassert>
#include <QComboBox>
#include <QGridLayout>
#include <QStackedLayout>
#include <QVBoxLayout>
#include "../../model/prefs/setting.hpp"
#include "../../model/prefs/category.hpp"
namespace CSVPrefs
{
KeyBindingPage::KeyBindingPage(CSMPrefs::Category& category, QWidget* parent)
: PageBase(category, parent)
, mStackedLayout(0)
, mPageLayout(0)
, mPageSelector(0)
{
// Need one widget for scroll area
QWidget* topWidget = new QWidget();
QVBoxLayout* topLayout = new QVBoxLayout(topWidget);
// Allows switching between "pages"
QWidget* stackedWidget = new QWidget();
mStackedLayout = new QStackedLayout(stackedWidget);
mPageSelector = new QComboBox();
connect(mPageSelector, SIGNAL(currentIndexChanged(int)), mStackedLayout, SLOT(setCurrentIndex(int)));
topLayout->addWidget(mPageSelector);
topLayout->addWidget(stackedWidget);
topLayout->setSizeConstraint(QLayout::SetMinAndMaxSize);
// Add each option
for (CSMPrefs::Category::Iterator iter = category.begin(); iter!=category.end(); ++iter)
addSetting (*iter);
setWidgetResizable(true);
setWidget(topWidget);
}
void KeyBindingPage::addSetting(CSMPrefs::Setting *setting)
{
std::pair<QWidget*, QWidget*> widgets = setting->makeWidgets (this);
if (widgets.first)
{
// Label, Option widgets
assert(mPageLayout);
int next = mPageLayout->rowCount();
mPageLayout->addWidget(widgets.first, next, 0);
mPageLayout->addWidget(widgets.second, next, 1);
}
else if (widgets.second)
{
// Wide single widget
assert(mPageLayout);
int next = mPageLayout->rowCount();
mPageLayout->addWidget(widgets.second, next, 0, 1, 2);
}
else
{
if (setting->getLabel().empty())
{
// Insert empty space
assert(mPageLayout);
int next = mPageLayout->rowCount();
mPageLayout->addWidget(new QWidget(), next, 0);
}
else
{
// Create new page
QWidget* pageWidget = new QWidget();
mPageLayout = new QGridLayout(pageWidget);
mPageLayout->setSizeConstraint(QLayout::SetMinAndMaxSize);
mStackedLayout->addWidget(pageWidget);
mPageSelector->addItem(QString::fromUtf8(setting->getLabel().c_str()));
}
}
}
}

@ -0,0 +1,35 @@
#ifndef CSV_PREFS_KEYBINDINGPAGE_H
#define CSV_PREFS_KEYBINDINGPAGE_H
#include "pagebase.hpp"
class QComboBox;
class QGridLayout;
class QStackedLayout;
namespace CSMPrefs
{
class Setting;
}
namespace CSVPrefs
{
class KeyBindingPage : public PageBase
{
Q_OBJECT
public:
KeyBindingPage(CSMPrefs::Category& category, QWidget* parent);
void addSetting(CSMPrefs::Setting* setting);
private:
QStackedLayout* mStackedLayout;
QGridLayout* mPageLayout;
QComboBox* mPageSelector;
};
}
#endif

@ -2,7 +2,7 @@
#include <cmath>
#include <QKeyEvent>
#include <QWidget>
#include <osg/BoundingBox>
#include <osg/Camera>
@ -14,6 +14,10 @@
#include <osgUtil/LineSegmentIntersector>
#include "../../model/prefs/shortcut.hpp"
#include "scenewidget.hpp"
namespace CSVRender
{
@ -27,8 +31,9 @@ namespace CSVRender
const osg::Vec3d CameraController::LocalLeft = osg::Vec3d(1, 0, 0);
const osg::Vec3d CameraController::LocalForward = osg::Vec3d(0, 0, 1);
CameraController::CameraController()
: mActive(false)
CameraController::CameraController(QObject* parent)
: QObject(parent)
, mActive(false)
, mInverted(false)
, mCameraSensitivity(1/650.f)
, mSecondaryMoveMult(50)
@ -73,11 +78,19 @@ namespace CSVRender
void CameraController::setCamera(osg::Camera* camera)
{
bool wasActive = mActive;
mCamera = camera;
mActive = (mCamera != NULL);
if (mActive)
onActivate();
if (mActive != wasActive)
{
for (std::vector<CSMPrefs::Shortcut*>::iterator it = mShortcuts.begin(); it != mShortcuts.end(); ++it)
{
CSMPrefs::Shortcut* shortcut = *it;
shortcut->enable(mActive);
}
}
}
void CameraController::setCameraSensitivity(double value)
@ -136,14 +149,23 @@ namespace CSVRender
getCamera()->setViewMatrixAsLookAt(eye, center, up);
}
void CameraController::addShortcut(CSMPrefs::Shortcut* shortcut)
{
mShortcuts.push_back(shortcut);
}
/*
Free Camera Controller
*/
FreeCameraController::FreeCameraController()
: mLockUpright(false)
FreeCameraController::FreeCameraController(QWidget* widget)
: CameraController(widget)
, mLockUpright(false)
, mModified(false)
, mNaviPrimary(false)
, mNaviSecondary(false)
, mFast(false)
, mFastAlternate(false)
, mLeft(false)
, mRight(false)
, mForward(false)
@ -155,6 +177,61 @@ namespace CSVRender
, mRotSpeed(osg::PI / 2)
, mSpeedMult(8)
{
CSMPrefs::Shortcut* naviPrimaryShortcut = new CSMPrefs::Shortcut("scene-navi-primary", widget);
naviPrimaryShortcut->enable(false);
connect(naviPrimaryShortcut, SIGNAL(activated(bool)), this, SLOT(naviPrimary(bool)));
addShortcut(naviPrimaryShortcut);
CSMPrefs::Shortcut* naviSecondaryShortcut = new CSMPrefs::Shortcut("scene-navi-secondary", widget);
naviSecondaryShortcut->enable(false);
connect(naviSecondaryShortcut, SIGNAL(activated(bool)), this, SLOT(naviSecondary(bool)));
addShortcut(naviSecondaryShortcut);
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)));
addShortcut(forwardShortcut);
CSMPrefs::Shortcut* leftShortcut = new CSMPrefs::Shortcut("free-left", widget);
leftShortcut->enable(false);
connect(leftShortcut, SIGNAL(activated(bool)), this, SLOT(left(bool)));
addShortcut(leftShortcut);
CSMPrefs::Shortcut* backShortcut = new CSMPrefs::Shortcut("free-backward", widget);
backShortcut->enable(false);
connect(backShortcut, SIGNAL(activated(bool)), this, SLOT(backward(bool)));
addShortcut(backShortcut);
CSMPrefs::Shortcut* rightShortcut = new CSMPrefs::Shortcut("free-right", widget);
rightShortcut->enable(false);
connect(rightShortcut, SIGNAL(activated(bool)), this, SLOT(right(bool)));
addShortcut(rightShortcut);
CSMPrefs::Shortcut* rollLeftShortcut = new CSMPrefs::Shortcut("free-roll-left", widget);
rollLeftShortcut->enable(false);
connect(rollLeftShortcut, SIGNAL(activated(bool)), this, SLOT(rollLeft(bool)));
addShortcut(rollLeftShortcut);
CSMPrefs::Shortcut* rollRightShortcut = new CSMPrefs::Shortcut("free-roll-right", widget);
rollRightShortcut->enable(false);
connect(rollRightShortcut, SIGNAL(activated(bool)), this, SLOT(rollRight(bool)));
addShortcut(rollRightShortcut);
CSMPrefs::Shortcut* speedModeShortcut = new CSMPrefs::Shortcut("free-speed-mode", widget);
speedModeShortcut->enable(false);
connect(speedModeShortcut, SIGNAL(activated()), this, SLOT(swapSpeedMode()));
addShortcut(speedModeShortcut);
}
double FreeCameraController::getLinearSpeed() const
@ -199,59 +276,18 @@ namespace CSVRender
mLockUpright = false;
}
bool FreeCameraController::handleKeyEvent(QKeyEvent* event, bool pressed)
void FreeCameraController::handleMouseMoveEvent(int x, int y)
{
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;
}
bool FreeCameraController::handleMouseMoveEvent(std::string mode, int x, int y)
{
if (!isActive())
return false;
return;
if (mode == "p-navi")
if (mNaviPrimary)
{
double scalar = getCameraSensitivity() * (getInverted() ? -1.0 : 1.0);
yaw(x * scalar);
pitch(y * scalar);
}
else if (mode == "s-navi")
else if (mNaviSecondary)
{
osg::Vec3d movement;
movement += LocalLeft * -x * getSecondaryMovementMultiplier();
@ -259,16 +295,14 @@ namespace CSVRender
translate(movement);
}
else if (mode == "t-navi")
{
translate(LocalForward * x * (mFast ? getWheelMovementMultiplier() : 1));
}
else
{
return false;
}
}
return true;
void FreeCameraController::handleMouseScrollEvent(int x)
{
if (!isActive())
return;
translate(LocalForward * x * ((mFast ^ mFastAlternate) ? getWheelMovementMultiplier() : 1));
}
void FreeCameraController::update(double dt)
@ -279,7 +313,7 @@ namespace CSVRender
double linDist = mLinSpeed * dt;
double rotDist = mRotSpeed * dt;
if (mFast)
if (mFast ^ mFastAlternate)
linDist *= mSpeedMult;
if (mLeft)
@ -308,17 +342,6 @@ namespace CSVRender
getCamera()->getViewMatrix().orthoNormal(getCamera()->getViewMatrix());
}
void FreeCameraController::resetInput()
{
mFast = false;
mLeft = false;
mRight = false;
mForward = false;
mBackward = false;
mRollLeft = false;
mRollRight = false;
}
void FreeCameraController::yaw(double value)
{
getCamera()->getViewMatrix() *= osg::Matrixd::rotate(value, LocalUp);
@ -368,13 +391,67 @@ namespace CSVRender
getCamera()->setViewMatrixAsLookAt(eye, center, mUp);
}
void FreeCameraController::naviPrimary(bool active)
{
mNaviPrimary = active;
}
void FreeCameraController::naviSecondary(bool active)
{
mNaviSecondary = active;
}
void FreeCameraController::forward(bool active)
{
mForward = active;
}
void FreeCameraController::left(bool active)
{
mLeft = active;
}
void FreeCameraController::backward(bool active)
{
mBackward = active;
}
void FreeCameraController::right(bool active)
{
mRight = active;
}
void FreeCameraController::rollLeft(bool active)
{
mRollLeft = active;
}
void FreeCameraController::rollRight(bool active)
{
mRollRight = active;
}
void FreeCameraController::alternateFast(bool active)
{
mFastAlternate = active;
}
void FreeCameraController::swapSpeedMode()
{
mFast = !mFast;
}
/*
Orbit Camera Controller
*/
OrbitCameraController::OrbitCameraController()
: mInitialized(false)
OrbitCameraController::OrbitCameraController(QWidget* widget)
: CameraController(widget)
, mInitialized(false)
, mNaviPrimary(false)
, mNaviSecondary(false)
, mFast(false)
, mFastAlternate(false)
, mLeft(false)
, mRight(false)
, mUp(false)
@ -387,6 +464,61 @@ namespace CSVRender
, mOrbitSpeed(osg::PI / 4)
, mOrbitSpeedMult(4)
{
CSMPrefs::Shortcut* naviPrimaryShortcut = new CSMPrefs::Shortcut("scene-navi-primary", widget);
naviPrimaryShortcut->enable(false);
connect(naviPrimaryShortcut, SIGNAL(activated(bool)), this, SLOT(naviPrimary(bool)));
addShortcut(naviPrimaryShortcut);
CSMPrefs::Shortcut* naviSecondaryShortcut = new CSMPrefs::Shortcut("scene-navi-secondary", widget);
naviSecondaryShortcut->enable(false);
connect(naviSecondaryShortcut, SIGNAL(activated(bool)), this, SLOT(naviSecondary(bool)));
addShortcut(naviSecondaryShortcut);
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)));
addShortcut(upShortcut);
CSMPrefs::Shortcut* leftShortcut = new CSMPrefs::Shortcut("orbit-left", widget);
leftShortcut->enable(false);
connect(leftShortcut, SIGNAL(activated(bool)), this, SLOT(left(bool)));
addShortcut(leftShortcut);
CSMPrefs::Shortcut* downShortcut = new CSMPrefs::Shortcut("orbit-down", widget);
downShortcut->enable(false);
connect(downShortcut, SIGNAL(activated(bool)), this, SLOT(down(bool)));
addShortcut(downShortcut);
CSMPrefs::Shortcut* rightShortcut = new CSMPrefs::Shortcut("orbit-right", widget);
rightShortcut->enable(false);
connect(rightShortcut, SIGNAL(activated(bool)), this, SLOT(right(bool)));
addShortcut(rightShortcut);
CSMPrefs::Shortcut* rollLeftShortcut = new CSMPrefs::Shortcut("orbit-roll-left", widget);
rollLeftShortcut->enable(false);
connect(rollLeftShortcut, SIGNAL(activated(bool)), this, SLOT(rollLeft(bool)));
addShortcut(rollLeftShortcut);
CSMPrefs::Shortcut* rollRightShortcut = new CSMPrefs::Shortcut("orbit-roll-right", widget);
rollRightShortcut->enable(false);
connect(rollRightShortcut, SIGNAL(activated(bool)), this, SLOT(rollRight(bool)));
addShortcut(rollRightShortcut);
CSMPrefs::Shortcut* speedModeShortcut = new CSMPrefs::Shortcut("orbit-speed-mode", widget);
speedModeShortcut->enable(false);
connect(speedModeShortcut, SIGNAL(activated()), this, SLOT(swapSpeedMode()));
addShortcut(speedModeShortcut);
}
osg::Vec3d OrbitCameraController::getCenter() const
@ -437,65 +569,21 @@ namespace CSVRender
mPickingMask = value;
}
bool OrbitCameraController::handleKeyEvent(QKeyEvent* event, bool pressed)
{
if (!isActive())
return false;
if (!mInitialized)
initialize();
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)
{
mUp = pressed;
}
else if (event->key() == Qt::Key_S)
{
mDown = pressed;
}
else if (event->key() == Qt::Key_Shift)
{
mFast = pressed;
}
else
{
return false;
}
return true;
}
bool OrbitCameraController::handleMouseMoveEvent(std::string mode, int x, int y)
void OrbitCameraController::handleMouseMoveEvent(int x, int y)
{
if (!isActive())
return false;
return;
if (!mInitialized)
initialize();
if (mode == "p-navi")
if (mNaviPrimary)
{
double scalar = getCameraSensitivity() * (getInverted() ? -1.0 : 1.0);
rotateHorizontal(x * scalar);
rotateVertical(-y * scalar);
}
else if (mode == "s-navi")
else if (mNaviSecondary)
{
osg::Vec3d movement;
movement += LocalLeft * x * getSecondaryMovementMultiplier();
@ -503,16 +591,14 @@ namespace CSVRender
translate(movement);
}
else if (mode == "t-navi")
{
zoom(-x * (mFast ? getWheelMovementMultiplier() : 1));
}
else
{
return false;
}
}
void OrbitCameraController::handleMouseScrollEvent(int x)
{
if (!isActive())
return;
return true;
zoom(-x * ((mFast ^ mFastAlternate) ? getWheelMovementMultiplier() : 1));
}
void OrbitCameraController::update(double dt)
@ -525,7 +611,7 @@ namespace CSVRender
double rotDist = mOrbitSpeed * dt;
if (mFast)
if (mFast ^ mFastAlternate)
rotDist *= mOrbitSpeedMult;
if (mLeft)
@ -546,17 +632,6 @@ namespace CSVRender
getCamera()->getViewMatrix().orthoNormal(getCamera()->getViewMatrix());
}
void OrbitCameraController::resetInput()
{
mFast = false;
mLeft = false;
mRight =false;
mUp = false;
mDown = false;
mRollLeft = false;
mRollRight = false;
}
void OrbitCameraController::onActivate()
{
mInitialized = false;
@ -647,4 +722,55 @@ namespace CSVRender
getCamera()->setViewMatrixAsLookAt(mCenter + offset, mCenter, up);
}
void OrbitCameraController::naviPrimary(bool active)
{
mNaviPrimary = active;
}
void OrbitCameraController::naviSecondary(bool active)
{
mNaviSecondary = active;
}
void OrbitCameraController::up(bool active)
{
mUp = active;
}
void OrbitCameraController::left(bool active)
{
mLeft = active;
}
void OrbitCameraController::down(bool active)
{
mDown = active;
}
void OrbitCameraController::right(bool active)
{
mRight = active;
}
void OrbitCameraController::rollLeft(bool active)
{
if (isActive())
mRollLeft = active;
}
void OrbitCameraController::rollRight(bool active)
{
mRollRight = active;
}
void OrbitCameraController::alternateFast(bool active)
{
mFastAlternate = active;
}
void OrbitCameraController::swapSpeedMode()
{
mFast = !mFast;
}
}

@ -2,22 +2,32 @@
#define OPENCS_VIEW_CAMERACONTROLLER_H
#include <string>
#include <vector>
#include <QObject>
#include <osg/ref_ptr>
#include <osg/Vec3d>
class QKeyEvent;
namespace osg
{
class Camera;
class Group;
}
namespace CSMPrefs
{
class Shortcut;
}
namespace CSVRender
{
class CameraController
class SceneWidget;
class CameraController : public QObject
{
Q_OBJECT
public:
static const osg::Vec3d WorldUp;
@ -26,7 +36,7 @@ namespace CSVRender
static const osg::Vec3d LocalLeft;
static const osg::Vec3d LocalForward;
CameraController();
CameraController(QObject* parent);
virtual ~CameraController();
bool isActive() const;
@ -46,17 +56,17 @@ namespace CSVRender
// moves the camera to an intelligent position
void setup(osg::Group* root, unsigned int mask, const osg::Vec3d& up);
virtual bool handleKeyEvent(QKeyEvent* event, bool pressed) = 0;
virtual bool handleMouseMoveEvent(std::string mode, int x, int y) = 0;
virtual void handleMouseMoveEvent(int x, int y) = 0;
virtual void handleMouseScrollEvent(int x) = 0;
virtual void update(double dt) = 0;
virtual void resetInput() = 0;
protected:
virtual void onActivate(){}
void addShortcut(CSMPrefs::Shortcut* shortcut);
private:
bool mActive, mInverted;
@ -65,13 +75,17 @@ namespace CSVRender
double mWheelMoveMult;
osg::Camera* mCamera;
std::vector<CSMPrefs::Shortcut*> mShortcuts;
};
class FreeCameraController : public CameraController
{
Q_OBJECT
public:
FreeCameraController();
FreeCameraController(QWidget* parent);
double getLinearSpeed() const;
double getRotationalSpeed() const;
@ -84,13 +98,11 @@ namespace CSVRender
void fixUpAxis(const osg::Vec3d& up);
void unfixUpAxis();
bool handleKeyEvent(QKeyEvent* event, bool pressed);
bool handleMouseMoveEvent(std::string mode, int x, int y);
void handleMouseMoveEvent(int x, int y);
void handleMouseScrollEvent(int x);
void update(double dt);
void resetInput();
private:
void yaw(double value);
@ -101,19 +113,36 @@ namespace CSVRender
void stabilize();
bool mLockUpright, mModified;
bool mFast, mLeft, mRight, mForward, mBackward, mRollLeft, mRollRight;
bool mNaviPrimary, mNaviSecondary;
bool mFast, mFastAlternate;
bool mLeft, mRight, mForward, mBackward, mRollLeft, mRollRight;
osg::Vec3d mUp;
double mLinSpeed;
double mRotSpeed;
double mSpeedMult;
private slots:
void naviPrimary(bool active);
void naviSecondary(bool active);
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 alternateFast(bool active);
void swapSpeedMode();
};
class OrbitCameraController : public CameraController
{
Q_OBJECT
public:
OrbitCameraController();
OrbitCameraController(QWidget* parent);
osg::Vec3d getCenter() const;
double getOrbitSpeed() const;
@ -125,13 +154,11 @@ namespace CSVRender
void setOrbitSpeedMultiplier(double value);
void setPickingMask(unsigned int value);
bool handleKeyEvent(QKeyEvent* event, bool pressed);
bool handleMouseMoveEvent(std::string mode, int x, int y);
void handleMouseMoveEvent(int x, int y);
void handleMouseScrollEvent(int x);
void update(double dt);
void resetInput();
private:
void onActivate();
@ -145,13 +172,28 @@ namespace CSVRender
void zoom(double value);
bool mInitialized;
bool mFast, mLeft, mRight, mUp, mDown, mRollLeft, mRollRight;
bool mNaviPrimary, mNaviSecondary;
bool mFast, mFastAlternate;
bool mLeft, mRight, mUp, mDown, mRollLeft, mRollRight;
unsigned int mPickingMask;
osg::Vec3d mCenter;
double mDistance;
double mOrbitSpeed;
double mOrbitSpeedMult;
private slots:
void naviPrimary(bool active);
void naviSecondary(bool active);
void up(bool active);
void left(bool active);
void down(bool active);
void right(bool active);
void rollLeft(bool active);
void rollRight(bool active);
void alternateFast(bool active);
void swapSpeedMode();
};
}

@ -7,6 +7,9 @@
#include <osg/Geometry>
#include <osg/PrimitiveSet>
#include "../../model/prefs/state.hpp"
#include "../../model/prefs/shortcutmanager.hpp"
#include "mask.hpp"
CSVRender::CellArrowTag::CellArrowTag (CellArrow *arrow)
@ -35,14 +38,19 @@ QString CSVRender::CellArrowTag::getToolTip (bool hideBasics) const
text +=
"<p>"
"Modify which cells are shown"
"<ul><li>Primary-Edit: Add cell in given direction</li>"
"<li>Secondary-Edit: Add cell and remove old cell</li>"
"<li>Shift Primary-Edit: Add cells in given direction</li>"
"<li>Shift Secondary-Edit: Add cells and remove old cells</li>"
"<ul><li>{scene-edit-primary}: Add cell in given direction</li>"
"<li>{scene-edit-secondary}: Add cell and remove old cell</li>"
"<li>{scene-select-primary}: Add cells in given direction</li>"
"<li>{scene-select-secondary}: Add cells and remove old cells</li>"
"<li>{scene-load-cam-cell}: Load cell where camera is located</li>"
"<li>{scene-load-cam-eastcell}: Load cell to east</li>"
"<li>{scene-load-cam-northcell}: Load cell to north</li>"
"<li>{scene-load-cam-westcell}: Load cell to west</li>"
"<li>{scene-load-cam-southcell}: Load cell to south</li>"
"</ul>";
}
return text;
return CSMPrefs::State::get().getShortcutManager().processToolTip(text);
}

@ -42,14 +42,14 @@ void CSVRender::InstanceMode::activate (CSVWidget::SceneToolbar *toolbar)
mSubMode->addButton (new InstanceMoveMode (this), "move");
mSubMode->addButton (":placeholder", "rotate",
"Rotate selected instances"
"<ul><li>Use primary edit to rotate instances freely</li>"
"<li>Use secondary edit to rotate instances within the grid</li>"
"<ul><li>Use {scene-edit-primary} to rotate instances freely</li>"
"<li>Use {scene-edit-secondary} to rotate instances within the grid</li>"
"</ul>"
"<font color=Red>Not implemented yet</font color>");
mSubMode->addButton (":placeholder", "scale",
"Scale selected instances"
"<ul><li>Use primary edit to scale instances freely</li>"
"<li>Use secondary edit to scale instances along the grid</li>"
"<ul><li>Use {scene-edit-primary} to scale instances freely</li>"
"<li>Use {scene-edit-secondary} to scale instances along the grid</li>"
"</ul>"
"<font color=Red>Not implemented yet</font color>");

@ -4,8 +4,8 @@
CSVRender::InstanceMoveMode::InstanceMoveMode (QWidget *parent)
: ModeButton (QIcon (QPixmap (":placeholder")),
"Move selected instances"
"<ul><li>Use primary edit to move instances around freely</li>"
"<li>Use secondary edit to move instances around within the grid</li>"
"<ul><li>Use {scene-edit-primary} to move instances around freely</li>"
"<li>Use {scene-edit-secondary} to move instances around within the grid</li>"
"</ul>"
"<font color=Red>Grid move not implemented yet</font color>",
parent)

@ -2,6 +2,9 @@
#include <QMenu>
#include "../../model/prefs/shortcut.hpp"
#include "../../model/prefs/shortcuteventhandler.hpp"
#include "worldspacewidget.hpp"
namespace CSVRender
@ -11,13 +14,29 @@ namespace CSVRender
: ModeButton(icon, tooltip, parent)
, mWorldspaceWidget(worldspaceWidget)
, mCenterOnSelection(0)
{
mCenterShortcut.reset(new CSMPrefs::Shortcut("orbit-center-selection", worldspaceWidget));
mCenterShortcut->enable(false);
connect(mCenterShortcut.get(), SIGNAL(activated()), this, SLOT(centerSelection()));
}
OrbitCameraMode::~OrbitCameraMode()
{
}
void OrbitCameraMode::activate(CSVWidget::SceneToolbar* toolbar)
{
mCenterOnSelection = new QAction("Center on selected object", this);
mCenterShortcut->associateAction(mCenterOnSelection);
connect(mCenterOnSelection, SIGNAL(triggered()), this, SLOT(centerSelection()));
mCenterShortcut->enable(true);
}
void OrbitCameraMode::deactivate(CSVWidget::SceneToolbar* toolbar)
{
mCenterShortcut->associateAction(0);
mCenterShortcut->enable(false);
}
bool OrbitCameraMode::createContextMenu(QMenu* menu)

@ -1,8 +1,15 @@
#ifndef CSV_RENDER_ORBITCAMERAPICKMODE_H
#define CSV_RENDER_ORBITCAMERAPICKMODE_H
#include <memory>
#include "../widget/modebutton.hpp"
namespace CSMPrefs
{
class Shortcut;
}
namespace CSVRender
{
class WorldspaceWidget;
@ -15,14 +22,17 @@ namespace CSVRender
OrbitCameraMode(WorldspaceWidget* worldspaceWidget, const QIcon& icon, const QString& tooltip = "",
QWidget* parent = 0);
~OrbitCameraMode();
virtual void activate(CSVWidget::SceneToolbar* toolbar);
virtual void deactivate(CSVWidget::SceneToolbar* toolbar);
virtual bool createContextMenu(QMenu* menu);
private:
WorldspaceWidget* mWorldspaceWidget;
QAction* mCenterOnSelection;
std::auto_ptr<CSMPrefs::Shortcut> mCenterShortcut;
private slots:

@ -8,6 +8,8 @@
#include <components/esm/loadland.hpp>
#include "../../model/prefs/shortcut.hpp"
#include "../../model/world/tablemimedata.hpp"
#include "../../model/world/idtable.hpp"
@ -142,75 +144,71 @@ void CSVRender::PagedWorldspaceWidget::addEditModeSelectorButtons (
"terrain-move");
}
void CSVRender::PagedWorldspaceWidget::handleMouseClick (const WorldspaceHitResult& hit, const std::string& button,
bool shift)
void CSVRender::PagedWorldspaceWidget::handleInteractionPress (const WorldspaceHitResult& hit, InteractionType type)
{
if (hit.tag && hit.tag->getMask()==Mask_CellArrow)
{
if (button=="p-edit" || button=="s-edit")
if (CellArrowTag *cellArrowTag = dynamic_cast<CSVRender::CellArrowTag *> (hit.tag.get()))
{
if (CellArrowTag *cellArrowTag =
dynamic_cast<CSVRender::CellArrowTag *> (hit.tag.get()))
{
CellArrow *arrow = cellArrowTag->getCellArrow();
CellArrow *arrow = cellArrowTag->getCellArrow();
CSMWorld::CellCoordinates coordinates = arrow->getCoordinates();
CSMWorld::CellCoordinates coordinates = arrow->getCoordinates();
CellArrow::Direction direction = arrow->getDirection();
CellArrow::Direction direction = arrow->getDirection();
int x = 0;
int y = 0;
int x = 0;
int y = 0;
switch (direction)
{
case CellArrow::Direction_North: y = 1; break;
case CellArrow::Direction_West: x = -1; break;
case CellArrow::Direction_South: y = -1; break;
case CellArrow::Direction_East: x = 1; break;
}
switch (direction)
{
case CellArrow::Direction_North: y = 1; break;
case CellArrow::Direction_West: x = -1; break;
case CellArrow::Direction_South: y = -1; break;
case CellArrow::Direction_East: x = 1; break;
}
bool modified = false;
bool modified = false;
if (shift)
{
if (button=="p-edit")
addCellSelection (x, y);
else
moveCellSelection (x, y);
if (type == InteractionType_PrimarySelect)
{
addCellSelection (x, y);
modified = true;
}
else if (type == InteractionType_SecondarySelect)
{
moveCellSelection (x, y);
modified = true;
}
else // Primary/SecondaryEdit
{
CSMWorld::CellCoordinates newCoordinates = coordinates.move (x, y);
if (mCells.find (newCoordinates)==mCells.end())
{
addCellToScene (newCoordinates);
mSelection.add (newCoordinates);
modified = true;
}
else
{
CSMWorld::CellCoordinates newCoordinates = coordinates.move (x, y);
if (mCells.find (newCoordinates)==mCells.end())
if (type == InteractionType_SecondaryEdit)
{
if (mCells.find (coordinates)!=mCells.end())
{
addCellToScene (newCoordinates);
mSelection.add (newCoordinates);
removeCellFromScene (coordinates);
mSelection.remove (coordinates);
modified = true;
}
if (button=="s-edit")
{
if (mCells.find (coordinates)!=mCells.end())
{
removeCellFromScene (coordinates);
mSelection.remove (coordinates);
modified = true;
}
}
}
}
if (modified)
adjustCells();
if (modified)
adjustCells();
return;
}
return;
}
}
WorldspaceWidget::handleMouseClick (hit, button, shift);
WorldspaceWidget::handleInteractionPress (hit, type);
}
void CSVRender::PagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft,
@ -437,6 +435,27 @@ void CSVRender::PagedWorldspaceWidget::moveCellSelection (int x, int y)
mSelection = newSelection;
}
void CSVRender::PagedWorldspaceWidget::addCellToSceneFromCamera (int offsetX, int offsetY)
{
const int CellSize = 8192;
osg::Vec3f eye, center, up;
getCamera()->getViewMatrixAsLookAt(eye, center, up);
int cellX = (int)std::floor(center.x() / CellSize) + offsetX;
int cellY = (int)std::floor(center.y() / CellSize) + offsetY;
CSMWorld::CellCoordinates cellCoordinates(cellX, cellY);
if (!mSelection.has(cellCoordinates))
{
addCellToScene(cellCoordinates);
mSelection.add(cellCoordinates);
adjustCells();
}
}
CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc::Document& document)
: WorldspaceWidget (document, parent), mDocument (document), mWorldspace ("std::default"),
mControlElements(NULL), mDisplayCellCoord(true)
@ -450,6 +469,22 @@ CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc
this, SLOT (cellRemoved (const QModelIndex&, int, int)));
connect (cells, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
this, SLOT (cellAdded (const QModelIndex&, int, int)));
// Shortcuts
CSMPrefs::Shortcut* loadCameraCellShortcut = new CSMPrefs::Shortcut("scene-load-cam-cell", this);
connect(loadCameraCellShortcut, SIGNAL(activated()), this, SLOT(loadCameraCell()));
CSMPrefs::Shortcut* loadCameraEastCellShortcut = new CSMPrefs::Shortcut("scene-load-cam-eastcell", this);
connect(loadCameraEastCellShortcut, SIGNAL(activated()), this, SLOT(loadEastCell()));
CSMPrefs::Shortcut* loadCameraNorthCellShortcut = new CSMPrefs::Shortcut("scene-load-cam-northcell", this);
connect(loadCameraNorthCellShortcut, SIGNAL(activated()), this, SLOT(loadNorthCell()));
CSMPrefs::Shortcut* loadCameraWestCellShortcut = new CSMPrefs::Shortcut("scene-load-cam-westcell", this);
connect(loadCameraWestCellShortcut, SIGNAL(activated()), this, SLOT(loadWestCell()));
CSMPrefs::Shortcut* loadCameraSouthCellShortcut = new CSMPrefs::Shortcut("scene-load-cam-southcell", this);
connect(loadCameraSouthCellShortcut, SIGNAL(activated()), this, SLOT(loadSouthCell()));
}
CSVRender::PagedWorldspaceWidget::~PagedWorldspaceWidget()
@ -722,3 +757,28 @@ void CSVRender::PagedWorldspaceWidget::cellAdded (const QModelIndex& index, int
if (adjustCells())
flagAsModified();
}
void CSVRender::PagedWorldspaceWidget::loadCameraCell()
{
addCellToSceneFromCamera(0, 0);
}
void CSVRender::PagedWorldspaceWidget::loadEastCell()
{
addCellToSceneFromCamera(1, 0);
}
void CSVRender::PagedWorldspaceWidget::loadNorthCell()
{
addCellToSceneFromCamera(0, 1);
}
void CSVRender::PagedWorldspaceWidget::loadWestCell()
{
addCellToSceneFromCamera(-1, 0);
}
void CSVRender::PagedWorldspaceWidget::loadSouthCell()
{
addCellToSceneFromCamera(0, -1);
}

@ -74,6 +74,8 @@ namespace CSVRender
/// \note Does not update the view or any cell marker
void moveCellSelection (int x, int y);
void addCellToSceneFromCamera (int offsetX, int offsetY);
public:
PagedWorldspaceWidget (QWidget *parent, CSMDoc::Document& document);
@ -138,7 +140,7 @@ namespace CSVRender
virtual void addEditModeSelectorButtons (CSVWidget::SceneToolMode *tool);
virtual void handleMouseClick (const WorldspaceHitResult& hit, const std::string& button, bool shift);
virtual void handleInteractionPress (const WorldspaceHitResult& hit, InteractionType type);
signals:
@ -152,6 +154,16 @@ namespace CSVRender
virtual void cellAdded (const QModelIndex& index, int start, int end);
void loadCameraCell();
void loadEastCell();
void loadNorthCell();
void loadWestCell();
void loadSouthCell();
};
}

@ -35,10 +35,10 @@ namespace CSVRender
{
return QString(
"Pathgrid editing"
"<ul><li>Primary edit: Add node to scene</li>"
"<li>Secondary edit: Connect selected nodes to node</li>"
"<li>Primary drag: Move selected nodes</li>"
"<li>Secondary drag: Connect one node to another</li>"
"<ul><li>Press {scene-edit-primary} to add a node to the cursor location</li>"
"<li>Press {scene-edit-secondary} to connect the selected nodes to the node beneath the cursor</li>"
"<li>Press {scene-edit-primary} and drag to move selected nodes</li>"
"<li>Press {scene-edit-secondary} and drag to connect one node to another</li>"
"</ul><p>Note: Only a single cell's pathgrid may be edited at a time");
}
@ -53,6 +53,16 @@ namespace CSVRender
toolbar->addTool(mSelectionMode);
}
void PathgridMode::deactivate(CSVWidget::SceneToolbar* toolbar)
{
if (mSelectionMode)
{
toolbar->removeTool (mSelectionMode);
delete mSelectionMode;
mSelectionMode = 0;
}
}
void PathgridMode::primaryEditPressed(const WorldspaceHitResult& hitResult)
{
if (CSMPrefs::get()["3D Scene Input"]["context-select"].isTrue() &&

@ -19,6 +19,8 @@ namespace CSVRender
virtual void activate(CSVWidget::SceneToolbar* toolbar);
virtual void deactivate(CSVWidget::SceneToolbar* toolbar);
virtual void primaryEditPressed(const WorldspaceHitResult& hit);
virtual void secondaryEditPressed(const WorldspaceHitResult& hit);

@ -3,7 +3,6 @@
#include <QEvent>
#include <QResizeEvent>
#include <QTimer>
#include <QShortcut>
#include <QLayout>
#include <extern/osgQt/GraphicsWindowQt>
@ -19,6 +18,8 @@
#include "../widget/scenetoolmode.hpp"
#include "../../model/prefs/state.hpp"
#include "../../model/prefs/shortcut.hpp"
#include "../../model/prefs/shortcuteventhandler.hpp"
#include "lighting.hpp"
#include "mask.hpp"
@ -75,7 +76,7 @@ RenderWidget::RenderWidget(QWidget *parent, Qt::WindowFlags f)
mView->setSceneData(mRootNode);
// Press S to reveal profiling stats
// Add ability to signal osg to show its statistics for debugging purposes
mView->addEventHandler(new osgViewer::StatsHandler);
mView->getCamera()->setCullMask(~(Mask_UpdateVisitor));
@ -105,6 +106,15 @@ osg::Camera *RenderWidget::getCamera()
return mView->getCamera();
}
void RenderWidget::toggleRenderStats()
{
osgViewer::GraphicsWindow* window =
static_cast<osgViewer::GraphicsWindow*>(mView->getCamera()->getGraphicsContext());
window->getEventQueue()->keyPress(osgGA::GUIEventAdapter::KEY_S);
window->getEventQueue()->keyRelease(osgGA::GUIEventAdapter::KEY_S);
}
// --------------------------------------------------
@ -158,13 +168,13 @@ SceneWidget::SceneWidget(boost::shared_ptr<Resource::ResourceSystem> resourceSys
, mHasDefaultAmbient(false)
, mPrevMouseX(0)
, mPrevMouseY(0)
, mFreeCamControl(new FreeCameraController())
, mOrbitCamControl(new OrbitCameraController())
, mCurrentCamControl(mFreeCamControl.get())
, mCamPositionSet(false)
{
mFreeCamControl = new FreeCameraController(this);
mOrbitCamControl = new OrbitCameraController(this);
mCurrentCamControl = mFreeCamControl;
mOrbitCamControl->setPickingMask(Mask_Reference | Mask_Terrain);
selectNavigationMode("free");
// we handle lighting manually
mView->setLightingMode(osgViewer::View::NO_LIGHT);
@ -175,11 +185,7 @@ SceneWidget::SceneWidget(boost::shared_ptr<Resource::ResourceSystem> resourceSys
// Recieve mouse move event even if mouse button is not pressed
setMouseTracking(true);
setFocusPolicy(Qt::StrongFocus);
/// \todo make shortcut configurable
QShortcut *focusToolbar = new QShortcut (Qt::Key_T, this, 0, 0, Qt::WidgetWithChildrenShortcut);
connect (focusToolbar, SIGNAL (activated()), this, SIGNAL (focusToolbarRequest()));
setFocusPolicy(Qt::ClickFocus);
connect (&CSMPrefs::State::get(), SIGNAL (settingChanged (const CSMPrefs::Setting *)),
this, SLOT (settingChanged (const CSMPrefs::Setting *)));
@ -192,6 +198,13 @@ SceneWidget::SceneWidget(boost::shared_ptr<Resource::ResourceSystem> resourceSys
}
connect (&CompositeViewer::get(), SIGNAL (simulationUpdated(double)), this, SLOT (update(double)));
// Shortcuts
CSMPrefs::Shortcut* focusToolbarShortcut = new CSMPrefs::Shortcut("scene-focus-toolbar", this);
connect(focusToolbarShortcut, SIGNAL(activated()), this, SIGNAL(focusToolbarRequest()));
CSMPrefs::Shortcut* renderStatsShortcut = new CSMPrefs::Shortcut("scene-render-stats", this);
connect(renderStatsShortcut, SIGNAL(activated()), this, SLOT(toggleRenderStats()));
}
SceneWidget::~SceneWidget()
@ -271,45 +284,17 @@ void SceneWidget::setDefaultAmbient (const osg::Vec4f& colour)
setAmbient(mLighting->getAmbientColour(&mDefaultAmbient));
}
void SceneWidget::mousePressEvent (QMouseEvent *event)
{
mMouseMode = mapButton(event);
mPrevMouseX = event->x();
mPrevMouseY = event->y();
}
void SceneWidget::mouseReleaseEvent (QMouseEvent *event)
{
mMouseMode = "";
}
void SceneWidget::mouseMoveEvent (QMouseEvent *event)
{
mCurrentCamControl->handleMouseMoveEvent(mMouseMode, event->x() - mPrevMouseX, event->y() - mPrevMouseY);
mCurrentCamControl->handleMouseMoveEvent(event->x() - mPrevMouseX, event->y() - mPrevMouseY);
mPrevMouseX = event->x();
mPrevMouseY = event->y();
}
void SceneWidget::focusOutEvent (QFocusEvent *event)
{
mCurrentCamControl->resetInput();
}
void SceneWidget::wheelEvent(QWheelEvent *event)
{
mCurrentCamControl->handleMouseMoveEvent("t-navi", event->delta(), 0);
}
void SceneWidget::keyPressEvent (QKeyEvent *event)
{
mCurrentCamControl->handleKeyEvent(event, true);
}
void SceneWidget::keyReleaseEvent (QKeyEvent *event)
{
mCurrentCamControl->handleKeyEvent(event, false);
mCurrentCamControl->handleMouseScrollEvent(event->delta());
}
void SceneWidget::update(double dt)
@ -373,10 +358,6 @@ void SceneWidget::settingChanged (const CSMPrefs::Setting *setting)
{
mOrbitCamControl->setOrbitSpeedMultiplier(setting->toDouble());
}
else
{
storeMappingSetting(setting);
}
}
void SceneWidget::selectNavigationMode (const std::string& mode)
@ -384,73 +365,23 @@ void SceneWidget::selectNavigationMode (const std::string& mode)
if (mode=="1st")
{
mCurrentCamControl->setCamera(NULL);
mCurrentCamControl = mFreeCamControl.get();
mCurrentCamControl->setCamera(getCamera());
mCurrentCamControl = mFreeCamControl;
mFreeCamControl->setCamera(getCamera());
mFreeCamControl->fixUpAxis(CameraController::WorldUp);
}
else if (mode=="free")
{
mCurrentCamControl->setCamera(NULL);
mCurrentCamControl = mFreeCamControl.get();
mCurrentCamControl->setCamera(getCamera());
mCurrentCamControl = mFreeCamControl;
mFreeCamControl->setCamera(getCamera());
mFreeCamControl->unfixUpAxis();
}
else if (mode=="orbit")
{
mCurrentCamControl->setCamera(NULL);
mCurrentCamControl = mOrbitCamControl.get();
mCurrentCamControl->setCamera(getCamera());
mCurrentCamControl = mOrbitCamControl;
mOrbitCamControl->setCamera(getCamera());
}
}
bool SceneWidget::storeMappingSetting (const CSMPrefs::Setting *setting)
{
if (setting->getParent()->getKey()!="3D Scene Input")
return false;
static const char * const sMappingSettings[] =
{
"p-navi", "s-navi",
0
};
for (int i=0; sMappingSettings[i]; ++i)
if (setting->getKey()==sMappingSettings[i])
{
QString value = QString::fromUtf8 (setting->toString().c_str());
Qt::MouseButton button = Qt::NoButton;
if (value.endsWith ("Left Mouse-Button"))
button = Qt::LeftButton;
else if (value.endsWith ("Right Mouse-Button"))
button = Qt::RightButton;
else if (value.endsWith ("Middle Mouse-Button"))
button = Qt::MiddleButton;
else
return false;
bool ctrl = value.startsWith ("Ctrl-");
mButtonMapping[std::make_pair (button, ctrl)] = sMappingSettings[i];
return true;
}
return false;
}
std::string SceneWidget::mapButton (QMouseEvent *event)
{
std::pair<Qt::MouseButton, bool> phyiscal (
event->button(), event->modifiers() & Qt::ControlModifier);
std::map<std::pair<Qt::MouseButton, bool>, std::string>::const_iterator iter =
mButtonMapping.find (phyiscal);
if (iter!=mButtonMapping.end())
return iter->second;
return "";
}
}

@ -7,14 +7,15 @@
#include <QWidget>
#include <QTimer>
#include <osgViewer/View>
#include <osgViewer/CompositeViewer>
#include <boost/shared_ptr.hpp>
#include "lightingday.hpp"
#include "lightingnight.hpp"
#include "lightingbright.hpp"
#include <osgViewer/View>
#include <osgViewer/CompositeViewer>
namespace Resource
{
@ -53,6 +54,7 @@ namespace CSVRender
RenderWidget(QWidget* parent = 0, Qt::WindowFlags f = 0);
virtual ~RenderWidget();
/// Initiates a request to redraw the view
void flagAsModified();
void setVisibilityMask(int mask);
@ -62,13 +64,16 @@ namespace CSVRender
protected:
osg::ref_ptr<osgViewer::View> mView;
osg::Group* mRootNode;
osg::ref_ptr<osg::Group> mRootNode;
QTimer mTimer;
protected slots:
void toggleRenderStats();
};
// Extension of RenderWidget to support lighting mode selection & toolbar
/// Extension of RenderWidget to support lighting mode selection & toolbar
class SceneWidget : public RenderWidget
{
Q_OBJECT
@ -90,18 +95,8 @@ namespace CSVRender
void setAmbient(const osg::Vec4f& ambient);
virtual void mousePressEvent (QMouseEvent *event);
virtual void mouseReleaseEvent (QMouseEvent *event);
virtual void mouseMoveEvent (QMouseEvent *event);
virtual void wheelEvent (QWheelEvent *event);
virtual void keyPressEvent (QKeyEvent *event);
virtual void keyReleaseEvent (QKeyEvent *event);
virtual void focusOutEvent (QFocusEvent *event);
/// \return Is \a key a button mapping setting? (ignored otherwise)
virtual bool storeMappingSetting (const CSMPrefs::Setting *setting);
std::string mapButton (QMouseEvent *event);
boost::shared_ptr<Resource::ResourceSystem> mResourceSystem;
@ -114,12 +109,10 @@ namespace CSVRender
LightingBright mLightingBright;
int mPrevMouseX, mPrevMouseY;
std::string mMouseMode;
std::auto_ptr<FreeCameraController> mFreeCamControl;
std::auto_ptr<OrbitCameraController> mOrbitCamControl;
CameraController* mCurrentCamControl;
std::map<std::pair<Qt::MouseButton, bool>, std::string> mButtonMapping;
FreeCameraController* mFreeCamControl;
OrbitCameraController* mOrbitCamControl;
CameraController* mCurrentCamControl;
private:
bool mCamPositionSet;

@ -15,22 +15,28 @@ namespace CSVRender
{
addButton(":placeholder", "cube-centre",
"Centred cube"
"<ul><li>Drag with primary (make instances the selection) or secondary (invert selection state) select button from the centre of the selection cube outwards</li>"
"<ul><li>Drag with {scene-select-primary} (make instances the selection) or {scene-select-secondary} "
"(invert selection state) from the centre of the selection cube outwards</li>"
"<li>The selection cube is aligned to the word space axis</li>"
"<li>If context selection mode is enabled, a drag with primary/secondary edit not starting on an instance will have the same effect</li>"
"<li>If context selection mode is enabled, a drag with {scene-edit-primary} or {scene-edit-secondary} not "
"starting on an instance will have the same effect</li>"
"</ul>"
"<font color=Red>Not implemented yet</font color>");
addButton(":placeholder", "cube-corner",
"Cube corner to corner"
"<ul><li>Drag with primary (make instances the selection) or secondary (invert selection state) select button from one corner of the selection cube to the opposite corner</li>"
"<ul><li>Drag with {scene-select-primary} (make instances the selection) or {scene-select-secondary} "
"(invert selection state) from one corner of the selection cube to the opposite corner</li>"
"<li>The selection cube is aligned to the word space axis</li>"
"<li>If context selection mode is enabled, a drag with primary/secondary edit not starting on an instance will have the same effect</li>"
"<li>If context selection mode is enabled, a drag with {scene-edit-primary} or {scene-edit-secondary} not "
"starting on an instance will have the same effect</li>"
"</ul>"
"<font color=Red>Not implemented yet</font color>");
addButton(":placeholder", "sphere",
"Centred sphere"
"<ul><li>Drag with primary (make instances the selection) or secondary (invert selection state) select button from the centre of the selection sphere outwards</li>"
"<li>If context selection mode is enabled, a drag with primary/secondary edit not starting on an instance will have the same effect</li>"
"<ul><li>Drag with {scene-select-primary} (make instances the selection) or {scene-select-secondary} "
"(invert selection state) from the centre of the selection sphere outwards</li>"
"<li>If context selection mode is enabled, a drag with {scene-edit-primary} or {scene-edit-secondary} not "
"starting on an instance will have the same effect</li>"
"</ul>"
"<font color=Red>Not implemented yet</font color>");

@ -16,6 +16,8 @@
#include "../../model/world/universalid.hpp"
#include "../../model/world/idtable.hpp"
#include "../../model/prefs/shortcut.hpp"
#include "../../model/prefs/shortcuteventhandler.hpp"
#include "../../model/prefs/state.hpp"
#include "../render/orbitcameramode.hpp"
@ -31,10 +33,24 @@
#include "cameracontroller.hpp"
CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent)
: SceneWidget (document.getData().getResourceSystem(), parent, 0, false), mSceneElements(0), mRun(0), mDocument(document),
mInteractionMask (0), mEditMode (0), mLocked (false), mDragging (false), mDragX(0), mDragY(0), mDragFactor(0),
mDragWheelFactor(0), mDragShiftFactor(0),
mToolTipPos (-1, -1), mShowToolTips(false), mToolTipDelay(0)
: SceneWidget (document.getData().getResourceSystem(), parent, 0, false)
, mSceneElements(0)
, mRun(0)
, mDocument(document)
, mInteractionMask (0)
, mEditMode (0)
, mLocked (false)
, mDragMode(InteractionType_None)
, mDragging (false)
, mDragX(0)
, mDragY(0)
, mSpeedMode(false)
, mDragFactor(0)
, mDragWheelFactor(0)
, mDragShiftFactor(0)
, mToolTipPos (-1, -1)
, mShowToolTips(false)
, mToolTipDelay(0)
{
setAcceptDrops(true);
@ -80,6 +96,24 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg
CSMPrefs::get()["3D Scene Input"].update();
CSMPrefs::get()["Tooltips"].update();
// Shortcuts
CSMPrefs::Shortcut* primaryEditShortcut = new CSMPrefs::Shortcut("scene-edit-primary", "scene-speed-modifier",
CSMPrefs::Shortcut::SM_Detach, this);
connect(primaryEditShortcut, SIGNAL(activated(bool)), this, SLOT(primaryEdit(bool)));
connect(primaryEditShortcut, SIGNAL(secondary(bool)), this, SLOT(speedMode(bool)));
CSMPrefs::Shortcut* secondaryEditShortcut = new CSMPrefs::Shortcut("scene-edit-secondary", this);
connect(secondaryEditShortcut, SIGNAL(activated(bool)), this, SLOT(secondaryEdit(bool)));
CSMPrefs::Shortcut* primarySelectShortcut = new CSMPrefs::Shortcut("scene-select-primary", this);
connect(primarySelectShortcut, SIGNAL(activated(bool)), this, SLOT(primarySelect(bool)));
CSMPrefs::Shortcut* secondarySelectShortcut = new CSMPrefs::Shortcut("scene-select-secondary", this);
connect(secondarySelectShortcut, SIGNAL(activated(bool)), this, SLOT(secondarySelect(bool)));
CSMPrefs::Shortcut* abortShortcut = new CSMPrefs::Shortcut("scene-edit-abort", this);
connect(abortShortcut, SIGNAL(activated()), this, SLOT(abortDrag()));
}
CSVRender::WorldspaceWidget::~WorldspaceWidget ()
@ -132,30 +166,32 @@ CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeNavigationSelector (
/// \todo consider user-defined button-mapping
tool->addButton (":scenetoolbar/1st-person", "1st",
"First Person"
"<ul><li>Mouse-Look while holding the left button</li>"
"<li>WASD movement keys</li>"
"<ul><li>Camera is held upright</li>"
"<li>Mouse-Look while holding {scene-navi-primary}</li>"
"<li>Movement keys: {free-forward}(forward), {free-left}(left), {free-backward}(back), {free-right}(right)</li>"
"<li>Strafing (also vertically) by holding {scene-navi-secondary}</li>"
"<li>Mouse wheel moves the camera forward/backward</li>"
"<li>Strafing (also vertically) by holding the left mouse button and control</li>"
"<li>Camera is held upright</li>"
"<li>Hold shift to speed up movement</li>"
"<li>Hold {scene-speed-modifier} to speed up movement</li>"
"</ul>");
tool->addButton (":scenetoolbar/free-camera", "free",
"Free Camera"
"<ul><li>Mouse-Look while holding the left button</li>"
"<li>Strafing (also vertically) via WASD or by holding the left mouse button and control</li>"
"<ul><li>Mouse-Look while holding {scene-navi-primary}</li>"
"<li>Movement keys: {free-forward}(forward), {free-left}(left), {free-backward}(back), {free-right}(right)</li>"
"<li>Roll camera with {free-roll-left} and {free-roll-right} keys</li>"
"<li>Strafing (also vertically) by holding {scene-navi-secondary}</li>"
"<li>Mouse wheel moves the camera forward/backward</li>"
"<li>Roll camera with Q and E keys</li>"
"<li>Hold shift to speed up movement</li>"
"<li>Hold {free-forward:mod} to speed up movement</li>"
"</ul>");
tool->addButton(
new CSVRender::OrbitCameraMode(this, QIcon(":scenetoolbar/orbiting-camera"),
"Orbiting Camera"
"<ul><li>Always facing the centre point</li>"
"<li>Rotate around the centre point via WASD or by moving the mouse while holding the left button</li>"
"<li>Rotate around the centre point via {orbit-up}, {orbit-left}, {orbit-down}, {orbit-right} or by moving "
"the mouse while holding {scene-navi-primary}</li>"
"<li>Roll camera with {orbit-roll-left} and {orbit-roll-right} keys</li>"
"<li>Strafing (also vertically) by holding {scene-navi-secondary} (includes relocation of the centre point)</li>"
"<li>Mouse wheel moves camera away or towards centre point but can not pass through it</li>"
"<li>Roll camera with Q and E keys</li>"
"<li>Strafing (also vertically) by holding the left mouse button and control (includes relocation of the centre point)</li>"
"<li>Hold shift to speed up movement</li>"
"<li>Hold {scene-speed-modifier} to speed up movement</li>"
"</ul>", tool),
"orbit");
@ -409,7 +445,7 @@ void CSVRender::WorldspaceWidget::abortDrag()
editMode.dragAborted();
mDragging = false;
mDragMode.clear();
mDragMode = InteractionType_None;
}
}
@ -453,45 +489,6 @@ void CSVRender::WorldspaceWidget::dragMoveEvent(QDragMoveEvent *event)
}
}
bool CSVRender::WorldspaceWidget::storeMappingSetting (const CSMPrefs::Setting *setting)
{
static const char * const sMappingSettings[] =
{
"p-edit", "s-edit",
"p-select", "s-select",
0
};
if (setting->getParent()->getKey()=="3D Scene Input")
{
for (int i=0; sMappingSettings[i]; ++i)
{
if (setting->getKey()==sMappingSettings[i])
{
QString value = QString::fromUtf8 (setting->toString().c_str());
Qt::MouseButton button = Qt::NoButton;
if (value.endsWith ("Left Mouse-Button"))
button = Qt::LeftButton;
else if (value.endsWith ("Right Mouse-Button"))
button = Qt::RightButton;
else if (value.endsWith ("Middle Mouse-Button"))
button = Qt::MiddleButton;
else
return false;
bool ctrl = value.startsWith ("Ctrl-");
mButtonMapping[std::make_pair (button, ctrl)] = sMappingSettings[i];
return true;
}
}
}
return SceneWidget::storeMappingSetting(setting);
}
void CSVRender::WorldspaceWidget::dropEvent (QDropEvent* event)
{
const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData());
@ -567,7 +564,7 @@ void CSVRender::WorldspaceWidget::editModeChanged (const std::string& id)
{
dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent()).setEditLock (mLocked);
mDragging = false;
mDragMode.clear();
mDragMode = InteractionType_None;
}
void CSVRender::WorldspaceWidget::showToolTip()
@ -608,24 +605,24 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event)
double factor = mDragFactor;
if (event->modifiers() & Qt::ShiftModifier)
if (mSpeedMode)
factor *= mDragShiftFactor;
EditMode& editMode = dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent());
editMode.drag (event->pos(), diffX, diffY, factor);
}
else if (mDragMode=="p-edit" || mDragMode=="s-edit" || mDragMode=="p-select" || mDragMode=="s-select")
else if (mDragMode != InteractionType_None)
{
EditMode& editMode = dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent());
if (mDragMode=="p-edit")
if (mDragMode == InteractionType_PrimaryEdit)
mDragging = editMode.primaryEditStartDrag (event->pos());
else if (mDragMode=="s-edit")
else if (mDragMode == InteractionType_SecondaryEdit)
mDragging = editMode.secondaryEditStartDrag (event->pos());
else if (mDragMode=="p-select")
else if (mDragMode == InteractionType_PrimarySelect)
mDragging = editMode.primarySelectStartDrag (event->pos());
else if (mDragMode=="s-select")
else if (mDragMode == InteractionType_SecondarySelect)
mDragging = editMode.secondarySelectStartDrag (event->pos());
if (mDragging)
@ -656,53 +653,13 @@ void CSVRender::WorldspaceWidget::mouseMoveEvent (QMouseEvent *event)
}
}
void CSVRender::WorldspaceWidget::mousePressEvent (QMouseEvent *event)
{
std::string button = mapButton (event);
if (button=="p-edit" || button=="s-edit" ||
button=="p-select" || button=="s-select")
{
if (!mDragging)
mDragMode = button;
}
else
SceneWidget::mousePressEvent(event);
}
void CSVRender::WorldspaceWidget::mouseReleaseEvent (QMouseEvent *event)
{
std::string button = mapButton (event);
mDragMode.clear();
if (button=="p-edit" || button=="s-edit" ||
button=="p-select" || button=="s-select")
{
if (mDragging)
{
EditMode& editMode = dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent());
editMode.dragCompleted(event->pos());
mDragging = false;
}
else
{
WorldspaceHitResult hit = mousePick(event->pos(), getInteractionMask());
handleMouseClick (hit, button, event->modifiers() & Qt::ShiftModifier);
}
}
else
SceneWidget::mouseReleaseEvent(event);
}
void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event)
{
if (mDragging)
{
double factor = mDragWheelFactor;
if (event->modifiers() & Qt::ShiftModifier)
if (mSpeedMode)
factor *= mDragShiftFactor;
EditMode& editMode = dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent());
@ -713,27 +670,17 @@ void CSVRender::WorldspaceWidget::wheelEvent (QWheelEvent *event)
SceneWidget::wheelEvent(event);
}
void CSVRender::WorldspaceWidget::keyPressEvent (QKeyEvent *event)
{
if(event->key() == Qt::Key_Escape)
{
abortDrag();
}
else
SceneWidget::keyPressEvent(event);
}
void CSVRender::WorldspaceWidget::handleMouseClick (const WorldspaceHitResult& hit, const std::string& button, bool shift)
void CSVRender::WorldspaceWidget::handleInteractionPress (const WorldspaceHitResult& hit, InteractionType type)
{
EditMode& editMode = dynamic_cast<CSVRender::EditMode&> (*mEditMode->getCurrent());
if (button=="p-edit")
if (type == InteractionType_PrimaryEdit)
editMode.primaryEditPressed (hit);
else if (button=="s-edit")
else if (type == InteractionType_SecondaryEdit)
editMode.secondaryEditPressed (hit);
else if (button=="p-select")
else if (type == InteractionType_PrimarySelect)
editMode.primarySelectPressed (hit);
else if (button=="s-select")
else if (type == InteractionType_SecondarySelect)
editMode.secondarySelectPressed (hit);
}
@ -741,3 +688,53 @@ CSVRender::EditMode *CSVRender::WorldspaceWidget::getEditMode()
{
return dynamic_cast<CSVRender::EditMode *> (mEditMode->getCurrent());
}
void CSVRender::WorldspaceWidget::primaryEdit(bool activate)
{
handleInteraction(InteractionType_PrimaryEdit, activate);
}
void CSVRender::WorldspaceWidget::secondaryEdit(bool activate)
{
handleInteraction(InteractionType_SecondaryEdit, activate);
}
void CSVRender::WorldspaceWidget::primarySelect(bool activate)
{
handleInteraction(InteractionType_PrimarySelect, activate);
}
void CSVRender::WorldspaceWidget::secondarySelect(bool activate)
{
handleInteraction(InteractionType_SecondarySelect, activate);
}
void CSVRender::WorldspaceWidget::speedMode(bool activate)
{
mSpeedMode = activate;
}
void CSVRender::WorldspaceWidget::handleInteraction(InteractionType type, bool activate)
{
if (activate)
{
if (!mDragging)
mDragMode = type;
}
else
{
mDragMode = InteractionType_None;
if (mDragging)
{
EditMode* editMode = getEditMode();
editMode->dragCompleted(mapFromGlobal(QCursor::pos()));
mDragging = false;
}
else
{
WorldspaceHitResult hit = mousePick(mapFromGlobal(QCursor::pos()), getInteractionMask());
handleInteractionPress(hit, type);
}
}
}

@ -55,10 +55,11 @@ namespace CSVRender
unsigned int mInteractionMask;
CSVWidget::SceneToolMode *mEditMode;
bool mLocked;
std::string mDragMode;
int mDragMode;
bool mDragging;
int mDragX;
int mDragY;
bool mSpeedMode;
double mDragFactor;
double mDragWheelFactor;
double mDragShiftFactor;
@ -85,6 +86,15 @@ namespace CSVRender
ignored //either mixed cells, or not cells
};
enum InteractionType
{
InteractionType_PrimaryEdit,
InteractionType_PrimarySelect,
InteractionType_SecondaryEdit,
InteractionType_SecondarySelect,
InteractionType_None
};
WorldspaceWidget (CSMDoc::Document& document, QWidget *parent = 0);
~WorldspaceWidget ();
@ -171,12 +181,6 @@ namespace CSVRender
/// Erase all overrides and restore the visual representation to its true state.
virtual void reset (unsigned int elementMask) = 0;
/// \note Drags will be automatically aborted when the aborting is triggered
/// (either explicitly or implicitly) from within this class. This function only
/// needs to be called, when the drag abort is triggered externally (e.g. from
/// an edit mode).
void abortDrag();
protected:
/// Visual elements in a scene
@ -197,21 +201,16 @@ namespace CSVRender
virtual void updateOverlay();
virtual void mouseMoveEvent (QMouseEvent *event);
virtual void mousePressEvent (QMouseEvent *event);
virtual void mouseReleaseEvent (QMouseEvent *event);
virtual void wheelEvent (QWheelEvent *event);
virtual void keyPressEvent (QKeyEvent *event);
virtual void handleMouseClick (const WorldspaceHitResult& hit, const std::string& button,
bool shift);
/// \return Is \a key a button mapping setting? (ignored otherwise)
virtual bool storeMappingSetting (const CSMPrefs::Setting *setting);
virtual void handleInteractionPress (const WorldspaceHitResult& hit, InteractionType type);
virtual void settingChanged (const CSMPrefs::Setting *setting);
EditMode *getEditMode();
bool getSpeedMode();
private:
void dragEnterEvent(QDragEnterEvent *event);
@ -222,6 +221,16 @@ namespace CSVRender
virtual std::string getStartupInstruction() = 0;
void handleInteraction(InteractionType type, bool activate);
public slots:
/// \note Drags will be automatically aborted when the aborting is triggered
/// (either explicitly or implicitly) from within this class. This function only
/// needs to be called, when the drag abort is triggered externally (e.g. from
/// an edit mode).
void abortDrag();
private slots:
virtual void referenceableDataChanged (const QModelIndex& topLeft,
@ -255,6 +264,16 @@ namespace CSVRender
void showToolTip();
void primaryEdit(bool activate);
void secondaryEdit(bool activate);
void primarySelect(bool activate);
void secondarySelect(bool activate);
void speedMode(bool activate);
protected slots:
void elementSelectionChanged();

@ -15,6 +15,7 @@
#include "../../model/tools/reportmodel.hpp"
#include "../../model/prefs/state.hpp"
#include "../../model/prefs/shortcut.hpp"
#include "../../view/world/idtypedelegate.hpp"
@ -171,14 +172,20 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document,
mShowAction = new QAction (tr ("Show"), this);
connect (mShowAction, SIGNAL (triggered()), this, SLOT (showSelection()));
addAction (mShowAction);
CSMPrefs::Shortcut* showShortcut = new CSMPrefs::Shortcut("reporttable-show", this);
showShortcut->associateAction(mShowAction);
mRemoveAction = new QAction (tr ("Remove from list"), this);
connect (mRemoveAction, SIGNAL (triggered()), this, SLOT (removeSelection()));
addAction (mRemoveAction);
CSMPrefs::Shortcut* removeShortcut = new CSMPrefs::Shortcut("reporttable-remove", this);
removeShortcut->associateAction(mRemoveAction);
mReplaceAction = new QAction (tr ("Replace"), this);
connect (mReplaceAction, SIGNAL (triggered()), this, SIGNAL (replaceRequest()));
addAction (mReplaceAction);
CSMPrefs::Shortcut* replaceShortcut = new CSMPrefs::Shortcut("reporttable-replace", this);
replaceShortcut->associateAction(mReplaceAction);
if (mRefreshState)
{
@ -186,6 +193,8 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document,
mRefreshAction->setEnabled (!(mDocument.getState() & mRefreshState));
connect (mRefreshAction, SIGNAL (triggered()), this, SIGNAL (refreshRequest()));
addAction (mRefreshAction);
CSMPrefs::Shortcut* refreshShortcut = new CSMPrefs::Shortcut("reporttable-refresh", this);
refreshShortcut->associateAction(mRefreshAction);
}
mDoubleClickActions.insert (std::make_pair (Qt::NoModifier, Action_Edit));

@ -3,9 +3,17 @@
#include <QMouseEvent>
#include <QKeyEvent>
#include "../../model/prefs/state.hpp"
#include "../../model/prefs/shortcutmanager.hpp"
void CSVWidget::PushButton::processShortcuts()
{
mProcessedToolTip = CSMPrefs::State::get().getShortcutManager().processToolTip(mToolTip);
}
void CSVWidget::PushButton::setExtendedToolTip()
{
QString tooltip = mToolTip;
QString tooltip = mProcessedToolTip;
if (tooltip.isEmpty())
tooltip = "(Tool tip not implemented yet)";
@ -77,13 +85,18 @@ CSVWidget::PushButton::PushButton (const QIcon& icon, Type type, const QString&
connect (this, SIGNAL (toggled (bool)), this, SLOT (checkedStateChanged (bool)));
}
setCheckable (type==Type_Mode || type==Type_Toggle);
processShortcuts();
setExtendedToolTip();
connect (&CSMPrefs::State::get(), SIGNAL (settingChanged (const CSMPrefs::Setting *)),
this, SLOT (settingChanged (const CSMPrefs::Setting *)));
}
CSVWidget::PushButton::PushButton (Type type, const QString& tooltip, QWidget *parent)
: QPushButton (parent), mKeepOpen (false), mType (type), mToolTip (tooltip)
{
setCheckable (type==Type_Mode || type==Type_Toggle);
processShortcuts();
setExtendedToolTip();
}
@ -94,7 +107,7 @@ bool CSVWidget::PushButton::hasKeepOpen() const
QString CSVWidget::PushButton::getBaseToolTip() const
{
return mToolTip;
return mProcessedToolTip;
}
CSVWidget::PushButton::Type CSVWidget::PushButton::getType() const
@ -106,3 +119,12 @@ void CSVWidget::PushButton::checkedStateChanged (bool checked)
{
setExtendedToolTip();
}
void CSVWidget::PushButton::settingChanged (const CSMPrefs::Setting *setting)
{
if (setting->getParent()->getKey() == "Key Bindings")
{
processShortcuts();
setExtendedToolTip();
}
}

@ -3,6 +3,11 @@
#include <QPushButton>
namespace CSMPrefs
{
class Setting;
}
namespace CSVWidget
{
class PushButton : public QPushButton
@ -24,9 +29,11 @@ namespace CSVWidget
bool mKeepOpen;
Type mType;
QString mToolTip;
QString mProcessedToolTip;
private:
void processShortcuts();
void setExtendedToolTip();
protected:
@ -57,6 +64,7 @@ namespace CSVWidget
private slots:
void checkedStateChanged (bool checked);
void settingChanged (const CSMPrefs::Setting *setting);
};
}

@ -1,7 +1,8 @@
#include "scenetoolbar.hpp"
#include <QVBoxLayout>
#include <QShortcut>
#include "../../model/prefs/shortcut.hpp"
#include "scenetool.hpp"
@ -25,9 +26,8 @@ CSVWidget::SceneToolbar::SceneToolbar (int buttonSize, QWidget *parent)
setLayout (mLayout);
/// \todo make shortcut configurable
QShortcut *focusScene = new QShortcut (Qt::Key_T, this, 0, 0, Qt::WidgetWithChildrenShortcut);
connect (focusScene, SIGNAL (activated()), this, SIGNAL (focusSceneRequest()));
CSMPrefs::Shortcut* focusSceneShortcut = new CSMPrefs::Shortcut("scene-focus-toolbar", this);
connect(focusSceneShortcut, SIGNAL(activated()), this, SIGNAL(focusSceneRequest()));
}
void CSVWidget::SceneToolbar::addTool (SceneTool *tool, SceneTool *insertPoint)

@ -5,6 +5,7 @@
#include <QSignalMapper>
#include <QMenu>
#include <QContextMenuEvent>
#include <QEvent>
#include "scenetoolbar.hpp"
#include "modebutton.hpp"
@ -133,6 +134,16 @@ void CSVWidget::SceneToolMode::setButton (const std::string& id)
}
}
bool CSVWidget::SceneToolMode::event(QEvent* event)
{
if (event->type() == QEvent::ToolTip)
{
adjustToolTip(mCurrent);
}
return SceneTool::event(event);
}
void CSVWidget::SceneToolMode::selected()
{
std::map<ModeButton *, std::string>::iterator iter =

@ -7,6 +7,7 @@
class QHBoxLayout;
class QMenu;
class QEvent;
namespace CSVWidget
{
@ -43,6 +44,10 @@ namespace CSVWidget
void setButton (std::map<ModeButton *, std::string>::iterator iter);
protected:
bool event(QEvent* event);
public:
SceneToolMode (SceneToolbar *parent, const QString& toolTip);

@ -5,6 +5,8 @@
#include <QMenu>
#include <QDebug>
#include "../../model/prefs/shortcut.hpp"
#include "../../model/world/nestedtableproxymodel.hpp"
#include "../../model/world/universalid.hpp"
#include "../../model/world/commands.hpp"
@ -60,14 +62,16 @@ CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document,
if (!fixedRows)
{
mAddNewRowAction = new QAction (tr ("Add new row"), this);
connect(mAddNewRowAction, SIGNAL(triggered()),
this, SLOT(addNewRowActionTriggered()));
CSMPrefs::Shortcut* addRowShortcut = new CSMPrefs::Shortcut("table-add", this);
addRowShortcut->associateAction(mAddNewRowAction);
mRemoveRowAction = new QAction (tr ("Remove rows"), this);
connect(mRemoveRowAction, SIGNAL(triggered()),
this, SLOT(removeRowActionTriggered()));
CSMPrefs::Shortcut* removeRowShortcut = new CSMPrefs::Shortcut("table-remove", this);
removeRowShortcut->associateAction(mRemoveRowAction);
}
mEditIdAction = new TableEditIdAction(*this, this);

@ -21,6 +21,7 @@
#include "../../model/world/commanddispatcher.hpp"
#include "../../model/prefs/state.hpp"
#include "../../model/prefs/shortcut.hpp"
#include "tableeditidaction.hpp"
#include "util.hpp"
@ -283,49 +284,72 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id,
mEditAction = new QAction (tr ("Edit Record"), this);
connect (mEditAction, SIGNAL (triggered()), this, SLOT (editRecord()));
addAction (mEditAction);
CSMPrefs::Shortcut* editShortcut = new CSMPrefs::Shortcut("table-edit", this);
editShortcut->associateAction(mEditAction);
if (createAndDelete)
{
mCreateAction = new QAction (tr ("Add Record"), this);
connect (mCreateAction, SIGNAL (triggered()), this, SIGNAL (createRequest()));
addAction (mCreateAction);
CSMPrefs::Shortcut* createShortcut = new CSMPrefs::Shortcut("table-add", this);
createShortcut->associateAction(mCreateAction);
mCloneAction = new QAction (tr ("Clone Record"), this);
connect(mCloneAction, SIGNAL (triggered()), this, SLOT (cloneRecord()));
addAction(mCloneAction);
CSMPrefs::Shortcut* cloneShortcut = new CSMPrefs::Shortcut("table-clone", this);
cloneShortcut->associateAction(mCloneAction);
}
mRevertAction = new QAction (tr ("Revert Record"), this);
connect (mRevertAction, SIGNAL (triggered()), mDispatcher, SLOT (executeRevert()));
addAction (mRevertAction);
CSMPrefs::Shortcut* revertShortcut = new CSMPrefs::Shortcut("table-revert", this);
revertShortcut->associateAction(mRevertAction);
mDeleteAction = new QAction (tr ("Delete Record"), this);
connect (mDeleteAction, SIGNAL (triggered()), mDispatcher, SLOT (executeDelete()));
addAction (mDeleteAction);
CSMPrefs::Shortcut* deleteShortcut = new CSMPrefs::Shortcut("table-remove", this);
deleteShortcut->associateAction(mDeleteAction);
mMoveUpAction = new QAction (tr ("Move Up"), this);
connect (mMoveUpAction, SIGNAL (triggered()), this, SLOT (moveUpRecord()));
addAction (mMoveUpAction);
CSMPrefs::Shortcut* moveUpShortcut = new CSMPrefs::Shortcut("table-moveup", this);
moveUpShortcut->associateAction(mMoveUpAction);
mMoveDownAction = new QAction (tr ("Move Down"), this);
connect (mMoveDownAction, SIGNAL (triggered()), this, SLOT (moveDownRecord()));
addAction (mMoveDownAction);
CSMPrefs::Shortcut* moveDownShortcut = new CSMPrefs::Shortcut("table-movedown", this);
moveDownShortcut->associateAction(mMoveDownAction);
mViewAction = new QAction (tr ("View"), this);
connect (mViewAction, SIGNAL (triggered()), this, SLOT (viewRecord()));
addAction (mViewAction);
CSMPrefs::Shortcut* viewShortcut = new CSMPrefs::Shortcut("table-view", this);
viewShortcut->associateAction(mViewAction);
mPreviewAction = new QAction (tr ("Preview"), this);
connect (mPreviewAction, SIGNAL (triggered()), this, SLOT (previewRecord()));
addAction (mPreviewAction);
CSMPrefs::Shortcut* previewShortcut = new CSMPrefs::Shortcut("table-preview", this);
previewShortcut->associateAction(mPreviewAction);
mExtendedDeleteAction = new QAction (tr ("Extended Delete Record"), this);
connect (mExtendedDeleteAction, SIGNAL (triggered()), this, SLOT (executeExtendedDelete()));
addAction (mExtendedDeleteAction);
CSMPrefs::Shortcut* extendedDeleteShortcut = new CSMPrefs::Shortcut("table-extendeddelete", this);
extendedDeleteShortcut->associateAction(mExtendedDeleteAction);
mExtendedRevertAction = new QAction (tr ("Extended Revert Record"), this);
connect (mExtendedRevertAction, SIGNAL (triggered()), this, SLOT (executeExtendedRevert()));
addAction (mExtendedRevertAction);
CSMPrefs::Shortcut* extendedRevertShortcut = new CSMPrefs::Shortcut("table-extendedrevert", this);
extendedRevertShortcut->associateAction(mExtendedRevertAction);
mEditIdAction = new TableEditIdAction (*this, this);
connect (mEditIdAction, SIGNAL (triggered()), this, SLOT (editCell()));

Loading…
Cancel
Save