Merge pull request #29 from OpenMW/master

Add OpenMW commits from end of July
pull/33/head
David Cernat 9 years ago committed by GitHub
commit 8686b9cc12

17
.gitignore vendored

@ -10,7 +10,6 @@ prebuilt
## doxygen
Doxygen
!docs/cs-manual/Makefile
## ides/editors
*~
@ -35,17 +34,15 @@ resources
## binaries
/esmtool
/mwiniimport
/omwlauncher
/openmw
/opencs
/niftest
bsatool
openmw-cs
openmw-essimporter
openmw-iniimporter
openmw-launcher
openmw-wizard
/bsatool
/openmw-cs
/openmw-essimporter
/openmw-iniimporter
/openmw-launcher
/openmw-wizard
## generated objects
apps/openmw/config.hpp
@ -80,4 +77,4 @@ moc_*.cxx
*.so
gamecontrollerdb.txt
openmw.appdata.xml
venv/

@ -77,6 +77,14 @@ option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF)
option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest" OFF)
option(BUILD_NIFTEST "build nif file tester" OFF)
option(BUILD_MYGUI_PLUGIN "build MyGUI plugin for OpenMW resources, to use with MyGUI tools" ON)
option(BUILD_DOCS "build documentation." OFF )
# what is necessary to build documentation
IF( BUILD_DOCS )
# Builds the documentation.
FIND_PACKAGE( Sphinx REQUIRED )
FIND_PACKAGE( Doxygen REQUIRED )
ENDIF()
# OS X deployment
option(OPENMW_OSX_DEPLOYMENT OFF)

@ -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,7 +53,9 @@ void CSVPrefs::Dialogue::buildContentArea (QSplitter *main)
CSVPrefs::PageBase *CSVPrefs::Dialogue::makePage (const std::string& key)
{
// special case page code goes here
if (key == "Key Bindings")
return new KeyBindingPage(CSMPrefs::get()[key], mContent);
else
return new Page (CSMPrefs::get()[key], mContent);
}

@ -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
void FreeCameraController::handleMouseScrollEvent(int x)
{
return false;
}
if (!isActive())
return;
return true;
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
void OrbitCameraController::handleMouseScrollEvent(int x)
{
return false;
}
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,15 +144,11 @@ 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();
@ -171,16 +169,17 @@ void CSVRender::PagedWorldspaceWidget::handleMouseClick (const WorldspaceHitResu
bool modified = false;
if (shift)
if (type == InteractionType_PrimarySelect)
{
if (button=="p-edit")
addCellSelection (x, y);
else
modified = true;
}
else if (type == InteractionType_SecondarySelect)
{
moveCellSelection (x, y);
modified = true;
}
else
else // Primary/SecondaryEdit
{
CSMWorld::CellCoordinates newCoordinates = coordinates.move (x, y);
@ -191,7 +190,7 @@ void CSVRender::PagedWorldspaceWidget::handleMouseClick (const WorldspaceHitResu
modified = true;
}
if (button=="s-edit")
if (type == InteractionType_SecondaryEdit)
{
if (mCells.find (coordinates)!=mCells.end())
{
@ -208,9 +207,8 @@ void CSVRender::PagedWorldspaceWidget::handleMouseClick (const WorldspaceHitResu
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());
}
}
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;
mCurrentCamControl = mOrbitCamControl;
mOrbitCamControl->setCamera(getCamera());
}
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()));

@ -3,6 +3,7 @@
#include <components/version/version.hpp>
#include <components/files/configurationmanager.hpp>
#include <components/files/escape.hpp>
#include <components/fallback/validate.hpp>
#include <SDL_messagebox.h>
@ -76,7 +77,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
desc.add_options()
("help", "print help message")
("version", "print version information and quit")
("data", bpo::value<Files::PathContainer>()->default_value(Files::PathContainer(), "data")
("data", bpo::value<Files::EscapePathContainer>()->default_value(Files::EscapePathContainer(), "data")
->multitoken()->composing(), "set data directories (later directories have higher priority)")
("data-local", bpo::value<Files::EscapeHashString>()->default_value(""),
@ -193,7 +194,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
// directory settings
engine.enableFSStrict(variables["fs-strict"].as<bool>());
Files::PathContainer dataDirs(variables["data"].as<Files::PathContainer>());
Files::PathContainer dataDirs(Files::EscapePath::toPathContainer(variables["data"].as<Files::EscapePathContainer>()));
std::string local(variables["data-local"].as<Files::EscapeHashString>().toStdString());
if (!local.empty())

@ -395,7 +395,9 @@ namespace MWGui
const MWWorld::ESMStore& store = MWBase::Environment::get().getWorld()->getStore();
if (info.enchant != "")
{
enchant = store.get<ESM::Enchantment>().find(info.enchant);
enchant = store.get<ESM::Enchantment>().search(info.enchant);
if (enchant)
{
if (enchant->mData.mType == ESM::Enchantment::CastOnce)
text += "\n#{sItemCastOnce}";
else if (enchant->mData.mType == ESM::Enchantment::WhenStrikes)
@ -405,6 +407,7 @@ namespace MWGui
else if (enchant->mData.mType == ESM::Enchantment::ConstantEffect)
text += "\n#{sItemCastConstant}";
}
}
// this the maximum width of the tooltip before it starts word-wrapping
setCoord(0, 0, 300, 300);
@ -472,9 +475,8 @@ namespace MWGui
totalSize.width = std::max(totalSize.width, coord.width);
}
if (info.enchant != "")
if (enchant)
{
assert(enchant);
MyGUI::Widget* enchantArea = mDynamicToolTipBox->createWidget<MyGUI::Widget>("",
MyGUI::IntCoord(padding.left, totalSize.height, 300-padding.left, 300-totalSize.height),
MyGUI::Align::Stretch);

@ -1143,10 +1143,18 @@ namespace MWRender
std::string enchantmentName = item.getClass().getEnchantment(item);
if (enchantmentName.empty())
return result;
const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().find(enchantmentName);
const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().search(enchantmentName);
if (!enchantment)
return result;
assert (enchantment->mEffects.mList.size());
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().search(
enchantment->mEffects.mList.front().mEffectID);
if (!magicEffect)
return result;
result.x() = magicEffect->mData.mRed / 255.f;
result.y() = magicEffect->mData.mGreen / 255.f;
result.z() = magicEffect->mData.mBlue / 255.f;

@ -29,6 +29,18 @@ namespace MWWorld
mList.push_back(item);
return mList.back();
}
/// Remove all references with the given refNum from this list.
void remove (const ESM::RefNum &refNum)
{
for (typename List::iterator it = mList.begin(); it != mList.end();)
{
if (*it == refNum)
mList.erase(it++);
else
++it;
}
}
};
}

@ -524,8 +524,10 @@ namespace MWWorld
// List moved references, from separately tracked list.
for (ESM::CellRefTracker::const_iterator it = mCell->mLeasedRefs.begin(); it != mCell->mLeasedRefs.end(); ++it)
{
const ESM::CellRef &ref = *it;
const ESM::CellRef &ref = it->first;
bool deleted = it->second;
if (!deleted)
mIds.push_back(Misc::StringUtils::lowerCase(ref.mRefID));
}
@ -541,6 +543,8 @@ namespace MWWorld
if (mCell->mContextList.empty())
return; // this is a dynamically generated cell -> skipping.
std::map<ESM::RefNum, std::string> refNumToID; // used to detect refID modifications
// Load references from all plugins that do something with this cell.
for (size_t i = 0; i < mCell->mContextList.size(); i++)
{
@ -564,7 +568,7 @@ namespace MWWorld
continue;
}
loadRef (ref, deleted);
loadRef (ref, deleted, refNumToID);
}
}
catch (std::exception& e)
@ -576,9 +580,10 @@ namespace MWWorld
// Load moved references, from separately tracked list.
for (ESM::CellRefTracker::const_iterator it = mCell->mLeasedRefs.begin(); it != mCell->mLeasedRefs.end(); ++it)
{
ESM::CellRef &ref = const_cast<ESM::CellRef&>(*it);
ESM::CellRef &ref = const_cast<ESM::CellRef&>(it->first);
bool deleted = it->second;
loadRef (ref, false);
loadRef (ref, deleted, refNumToID);
}
updateMergedRefs();
@ -609,12 +614,47 @@ namespace MWWorld
return Ptr();
}
void CellStore::loadRef (ESM::CellRef& ref, bool deleted)
void CellStore::loadRef (ESM::CellRef& ref, bool deleted, std::map<ESM::RefNum, std::string>& refNumToID)
{
Misc::StringUtils::lowerCaseInPlace (ref.mRefID);
const MWWorld::ESMStore& store = mStore;
std::map<ESM::RefNum, std::string>::iterator it = refNumToID.find(ref.mRefNum);
if (it != refNumToID.end())
{
if (it->second != ref.mRefID)
{
// refID was modified, make sure we don't end up with duplicated refs
switch (store.find(it->second))
{
case ESM::REC_ACTI: mActivators.remove(ref.mRefNum); break;
case ESM::REC_ALCH: mPotions.remove(ref.mRefNum); break;
case ESM::REC_APPA: mAppas.remove(ref.mRefNum); break;
case ESM::REC_ARMO: mArmors.remove(ref.mRefNum); break;
case ESM::REC_BOOK: mBooks.remove(ref.mRefNum); break;
case ESM::REC_CLOT: mClothes.remove(ref.mRefNum); break;
case ESM::REC_CONT: mContainers.remove(ref.mRefNum); break;
case ESM::REC_CREA: mCreatures.remove(ref.mRefNum); break;
case ESM::REC_DOOR: mDoors.remove(ref.mRefNum); break;
case ESM::REC_INGR: mIngreds.remove(ref.mRefNum); break;
case ESM::REC_LEVC: mCreatureLists.remove(ref.mRefNum); break;
case ESM::REC_LEVI: mItemLists.remove(ref.mRefNum); break;
case ESM::REC_LIGH: mLights.remove(ref.mRefNum); break;
case ESM::REC_LOCK: mLockpicks.remove(ref.mRefNum); break;
case ESM::REC_MISC: mMiscItems.remove(ref.mRefNum); break;
case ESM::REC_NPC_: mNpcs.remove(ref.mRefNum); break;
case ESM::REC_PROB: mProbes.remove(ref.mRefNum); break;
case ESM::REC_REPA: mRepairs.remove(ref.mRefNum); break;
case ESM::REC_STAT: mStatics.remove(ref.mRefNum); break;
case ESM::REC_WEAP: mWeapons.remove(ref.mRefNum); break;
case ESM::REC_BODY: mBodyParts.remove(ref.mRefNum); break;
default:
break;
}
}
}
switch (store.find (ref.mRefID))
{
case ESM::REC_ACTI: mActivators.load(ref, deleted, store); break;
@ -639,12 +679,15 @@ namespace MWWorld
case ESM::REC_WEAP: mWeapons.load(ref, deleted, store); break;
case ESM::REC_BODY: mBodyParts.load(ref, deleted, store); break;
case 0: std::cerr << "Cell reference '" + ref.mRefID + "' not found!\n"; break;
case 0: std::cerr << "Cell reference '" + ref.mRefID + "' not found!\n"; return;
default:
std::cerr
<< "WARNING: Ignoring reference '" << ref.mRefID << "' of unhandled type\n";
return;
}
refNumToID[ref.mRefNum] = ref.mRefID;
}
void CellStore::loadState (const ESM::CellState& state)

@ -385,7 +385,7 @@ namespace MWWorld
void loadRefs();
void loadRef (ESM::CellRef& ref, bool deleted);
void loadRef (ESM::CellRef& ref, bool deleted, std::map<ESM::RefNum, std::string>& refNumToID);
///< Make case-adjustments to \a ref and insert it into the respective container.
///
/// Invalid \a ref objects are silently dropped.

@ -513,19 +513,16 @@ namespace MWWorld
bool deleted = false;
cell->getNextRef(esm, ref, deleted);
if (!deleted)
{
// Add data required to make reference appear in the correct cell.
// We should not need to test for duplicates, as this part of the code is pre-cell merge.
cell->mMovedRefs.push_back(cMRef);
// But there may be duplicates here!
ESM::CellRefTracker::iterator iter = std::find(cellAlt->mLeasedRefs.begin(), cellAlt->mLeasedRefs.end(), ref.mRefNum);
ESM::CellRefTracker::iterator iter = std::find_if(cellAlt->mLeasedRefs.begin(), cellAlt->mLeasedRefs.end(), ESM::CellRefTrackerPredicate(ref.mRefNum));
if (iter == cellAlt->mLeasedRefs.end())
cellAlt->mLeasedRefs.push_back(ref);
cellAlt->mLeasedRefs.push_back(std::make_pair(ref, deleted));
else
*iter = ref;
}
*iter = std::make_pair(ref, deleted);
}
}
const ESM::Cell *Store<ESM::Cell>::search(const std::string &id) const
@ -678,14 +675,17 @@ namespace MWWorld
for (ESM::MovedCellRefTracker::const_iterator it = cell.mMovedRefs.begin(); it != cell.mMovedRefs.end(); ++it) {
// remove reference from current leased ref tracker and add it to new cell
ESM::MovedCellRefTracker::iterator itold = std::find(oldcell->mMovedRefs.begin(), oldcell->mMovedRefs.end(), it->mRefNum);
if (itold != oldcell->mMovedRefs.end()) {
ESM::MovedCellRef target0 = *itold;
ESM::Cell *wipecell = const_cast<ESM::Cell*>(search(target0.mTarget[0], target0.mTarget[1]));
ESM::CellRefTracker::iterator it_lease = std::find(wipecell->mLeasedRefs.begin(), wipecell->mLeasedRefs.end(), it->mRefNum);
if (itold != oldcell->mMovedRefs.end())
{
if (it->mTarget[0] != itold->mTarget[0] || it->mTarget[1] != itold->mTarget[1])
{
ESM::Cell *wipecell = const_cast<ESM::Cell*>(search(itold->mTarget[0], itold->mTarget[1]));
ESM::CellRefTracker::iterator it_lease = std::find_if(wipecell->mLeasedRefs.begin(), wipecell->mLeasedRefs.end(), ESM::CellRefTrackerPredicate(it->mRefNum));
if (it_lease != wipecell->mLeasedRefs.end())
wipecell->mLeasedRefs.erase(it_lease);
else
std::cerr << "can't find " << it->mRefNum.mIndex << " " << it->mRefNum.mContentFile << " in leasedRefs " << std::endl;
}
*itold = *it;
}
else

@ -0,0 +1,145 @@
# - This module looks for Sphinx
# Find the Sphinx documentation generator
#
# This modules defines
# SPHINX_EXECUTABLE
# SPHINX_FOUND
find_program(SPHINX_EXECUTABLE
NAMES sphinx-build
PATHS
/usr/bin
/usr/local/bin
/opt/local/bin
DOC "Sphinx documentation generator"
)
if( NOT SPHINX_EXECUTABLE )
set(_Python_VERSIONS
2.7 2.6 2.5 2.4 2.3 2.2 2.1 2.0 1.6 1.5
)
foreach( _version ${_Python_VERSIONS} )
set( _sphinx_NAMES sphinx-build-${_version} )
find_program( SPHINX_EXECUTABLE
NAMES ${_sphinx_NAMES}
PATHS
/usr/bin
/usr/local/bin
/opt/loca/bin
DOC "Sphinx documentation generator"
)
endforeach()
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Sphinx DEFAULT_MSG
SPHINX_EXECUTABLE
)
option( SPHINX_HTML_OUTPUT "Build a single HTML with the whole content." ON )
option( SPHINX_DIRHTML_OUTPUT "Build HTML pages, but with a single directory per document." OFF )
option( SPHINX_HTMLHELP_OUTPUT "Build HTML pages with additional information for building a documentation collection in htmlhelp." OFF )
option( SPHINX_QTHELP_OUTPUT "Build HTML pages with additional information for building a documentation collection in qthelp." OFF )
option( SPHINX_DEVHELP_OUTPUT "Build HTML pages with additional information for building a documentation collection in devhelp." OFF )
option( SPHINX_EPUB_OUTPUT "Build HTML pages with additional information for building a documentation collection in epub." OFF )
option( SPHINX_LATEX_OUTPUT "Build LaTeX sources that can be compiled to a PDF document using pdflatex." OFF )
option( SPHINX_MAN_OUTPUT "Build manual pages in groff format for UNIX systems." OFF )
option( SPHINX_TEXT_OUTPUT "Build plain text files." OFF )
mark_as_advanced(
SPHINX_EXECUTABLE
SPHINX_HTML_OUTPUT
SPHINX_DIRHTML_OUTPUT
SPHINX_HTMLHELP_OUTPUT
SPHINX_QTHELP_OUTPUT
SPHINX_DEVHELP_OUTPUT
SPHINX_EPUB_OUTPUT
SPHINX_LATEX_OUTPUT
SPHINX_MAN_OUTPUT
SPHINX_TEXT_OUTPUT
)
function( Sphinx_add_target target_name builder conf source destination )
add_custom_target( ${target_name} ALL
COMMAND ${SPHINX_EXECUTABLE} -b ${builder}
-c ${conf}
${source}
${destination}
COMMENT "Generating sphinx documentation: ${builder}"
)
set_property(
DIRECTORY APPEND PROPERTY
ADDITIONAL_MAKE_CLEAN_FILES
${destination}
)
endfunction()
# Target dependencies can be optionally listed at the end.
function( Sphinx_add_targets target_base_name conf source base_destination )
set( _dependencies )
foreach( arg IN LISTS ARGN )
set( _dependencies ${_dependencies} ${arg} )
endforeach()
if( ${SPHINX_HTML_OUTPUT} )
Sphinx_add_target( ${target_base_name}_html html ${conf} ${source} ${base_destination}/html )
add_dependencies( ${target_base_name}_html ${_dependencies} )
endif()
if( ${SPHINX_DIRHTML_OUTPUT} )
Sphinx_add_target( ${target_base_name}_dirhtml dirhtml ${conf} ${source} ${base_destination}/dirhtml )
add_dependencies( ${target_base_name}_dirhtml ${_dependencies} )
endif()
if( ${SPHINX_QTHELP_OUTPUT} )
Sphinx_add_target( ${target_base_name}_qthelp qthelp ${conf} ${source} ${base_destination}/qthelp )
add_dependencies( ${target_base_name}_qthelp ${_dependencies} )
endif()
if( ${SPHINX_DEVHELP_OUTPUT} )
Sphinx_add_target( ${target_base_name}_devhelp devhelp ${conf} ${source} ${base_destination}/devhelp )
add_dependencies( ${target_base_name}_devhelp ${_dependencies} )
endif()
if( ${SPHINX_EPUB_OUTPUT} )
Sphinx_add_target( ${target_base_name}_epub epub ${conf} ${source} ${base_destination}/epub )
add_dependencies( ${target_base_name}_epub ${_dependencies} )
endif()
if( ${SPHINX_LATEX_OUTPUT} )
Sphinx_add_target( ${target_base_name}_latex latex ${conf} ${source} ${base_destination}/latex )
add_dependencies( ${target_base_name}_latex ${_dependencies} )
endif()
if( ${SPHINX_MAN_OUTPUT} )
Sphinx_add_target( ${target_base_name}_man man ${conf} ${source} ${base_destination}/man )
add_dependencies( ${target_base_name}_man ${_dependencies} )
endif()
if( ${SPHINX_TEXT_OUTPUT} )
Sphinx_add_target( ${target_base_name}_text text ${conf} ${source} ${base_destination}/text )
add_dependencies( ${target_base_name}_text ${_dependencies} )
endif()
if( ${BUILD_TESTING} )
sphinx_add_target( ${target_base_name}_linkcheck linkcheck ${conf} ${source} ${base_destination}/linkcheck )
add_dependencies( ${target_base_name}_linkcheck ${_dependencies} )
endif()
endfunction()

@ -95,7 +95,7 @@ IF(NOT WIN32 AND NOT APPLE)
add_definitions(-DGLOBAL_CONFIG_PATH="${GLOBAL_CONFIG_PATH}")
ENDIF()
add_component_dir (files
linuxpath androidpath windowspath macospath fixedpath multidircollection collections configurationmanager
linuxpath androidpath windowspath macospath fixedpath multidircollection collections configurationmanager escape
lowlevelfile constrainedfilestream memorystream
)

@ -43,7 +43,15 @@ bool operator==(const MovedCellRef& ref, const RefNum& refNum);
bool operator==(const CellRef& ref, const RefNum& refNum);
typedef std::list<MovedCellRef> MovedCellRefTracker;
typedef std::list<CellRef> CellRefTracker;
typedef std::list<std::pair<CellRef, bool> > CellRefTracker;
struct CellRefTrackerPredicate
{
RefNum mRefNum;
CellRefTrackerPredicate(const RefNum& refNum) : mRefNum(refNum) {}
bool operator() (const std::pair<CellRef, bool>& refdelPair) { return refdelPair.first == mRefNum; }
};
/* Cells hold data about objects, creatures, statics (rocks, walls,
buildings) and landscape (for exterior cells). Cells frequently

@ -3,7 +3,7 @@
#include <boost/program_options.hpp>
#include <components/files/configurationmanager.hpp>
#include <components/files/escape.hpp>
// Parses and validates a fallback map from boost program_options.
// Note: for boost to pick up the validate function, you need to pull in the namespace e.g.
@ -47,25 +47,4 @@ namespace Fallback
}
}
namespace Files {
void validate(boost::any &v, const std::vector<std::string> &tokens, Files::EscapeHashString * eHS, int a)
{
boost::program_options::validators::check_first_occurrence(v);
if (v.empty())
v = boost::any(EscapeHashString(boost::program_options::validators::get_single_string(tokens)));
}
void validate(boost::any &v, const std::vector<std::string> &tokens, EscapeStringVector *, int)
{
if (v.empty())
v = boost::any(EscapeStringVector());
EscapeStringVector * eSV = boost::any_cast<EscapeStringVector>(&v);
for (std::vector<std::string>::const_iterator it = tokens.begin(); it != tokens.end(); ++it)
eSV->mVector.push_back(EscapeHashString(*it));
}
}
#endif

@ -5,10 +5,13 @@
#include <algorithm>
#include <ctype.h>
#include <components/files/escape.hpp>
#include <boost/bind.hpp>
#include <boost/algorithm/string/erase.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/iostreams/filtering_stream.hpp>
/**
* \namespace Files
@ -164,152 +167,6 @@ bool ConfigurationManager::loadConfig(const boost::filesystem::path& path,
return false;
}
const int escape_hash_filter::sEscape = '@';
const int escape_hash_filter::sEscapeIdentifier = 'a';
const int escape_hash_filter::sHashIdentifier = 'h';
escape_hash_filter::escape_hash_filter() : mNext(), mSeenNonWhitespace(false), mFinishLine(false)
{
}
escape_hash_filter::~escape_hash_filter()
{
}
template <typename Source>
int escape_hash_filter::get(Source & src)
{
if (mNext.empty())
{
int character = boost::iostreams::get(src);
bool record = true;
if (character == boost::iostreams::WOULD_BLOCK)
{
mNext.push(character);
record = false;
}
else if (character == EOF)
{
mSeenNonWhitespace = false;
mFinishLine = false;
mNext.push(character);
}
else if (character == '\n')
{
mSeenNonWhitespace = false;
mFinishLine = false;
mNext.push(character);
}
else if (mFinishLine)
{
mNext.push(character);
}
else if (character == '#')
{
if (mSeenNonWhitespace)
{
mNext.push(sEscape);
mNext.push(sHashIdentifier);
}
else
{
//it's fine being interpreted by Boost as a comment, and so is anything afterwards
mNext.push(character);
mFinishLine = true;
}
}
else if (mPrevious == sEscape)
{
mNext.push(sEscape);
mNext.push(sEscapeIdentifier);
}
else
{
mNext.push(character);
}
if (!mSeenNonWhitespace && !isspace(character))
mSeenNonWhitespace = true;
if (record)
mPrevious = character;
}
int retval = mNext.front();
mNext.pop();
return retval;
}
std::string EscapeHashString::processString(const std::string & str)
{
std::string temp = boost::replace_all_copy<std::string>(str, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sHashIdentifier, "#");
boost::replace_all(temp, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sEscapeIdentifier, std::string((char) escape_hash_filter::sEscape, 1));
return temp;
}
EscapeHashString::EscapeHashString() : mData()
{
}
EscapeHashString::EscapeHashString(const std::string & str) : mData(EscapeHashString::processString(str))
{
}
EscapeHashString::EscapeHashString(const std::string & str, size_t pos, size_t len) : mData(EscapeHashString::processString(str), pos, len)
{
}
EscapeHashString::EscapeHashString(const char * s) : mData(EscapeHashString::processString(std::string(s)))
{
}
EscapeHashString::EscapeHashString(const char * s, size_t n) : mData(EscapeHashString::processString(std::string(s)), 0, n)
{
}
EscapeHashString::EscapeHashString(size_t n, char c) : mData(n, c)
{
}
template <class InputIterator>
EscapeHashString::EscapeHashString(InputIterator first, InputIterator last) : mData(EscapeHashString::processString(std::string(first, last)))
{
}
std::string EscapeHashString::toStdString() const
{
return std::string(mData);
}
std::istream & operator>> (std::istream & is, EscapeHashString & eHS)
{
std::string temp;
is >> temp;
eHS = EscapeHashString(temp);
return is;
}
std::ostream & operator<< (std::ostream & os, const EscapeHashString & eHS)
{
os << eHS.mData;
return os;
}
EscapeStringVector::EscapeStringVector() : mVector()
{
}
EscapeStringVector::~EscapeStringVector()
{
}
std::vector<std::string> EscapeStringVector::toStdStringVector() const
{
std::vector<std::string> temp = std::vector<std::string>();
for (std::vector<EscapeHashString>::const_iterator it = mVector.begin(); it != mVector.end(); ++it)
{
temp.push_back(it->toStdString());
}
return temp;
}
const boost::filesystem::path& ConfigurationManager::getGlobalPath() const
{
return mFixedPath.getGlobalConfigPath();

@ -2,10 +2,8 @@
#define COMPONENTS_FILES_CONFIGURATIONMANAGER_HPP
#include <map>
#include <queue>
#include <boost/program_options.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <components/files/fixedpath.hpp>
#include <components/files/collections.hpp>
@ -64,66 +62,6 @@ struct ConfigurationManager
bool mSilent;
};
/**
* \struct escape_hash_filter
*/
struct escape_hash_filter : public boost::iostreams::input_filter
{
static const int sEscape;
static const int sHashIdentifier;
static const int sEscapeIdentifier;
escape_hash_filter();
virtual ~escape_hash_filter();
template <typename Source> int get(Source & src);
private:
std::queue<int> mNext;
int mPrevious;
bool mSeenNonWhitespace;
bool mFinishLine;
};
/**
* \class EscapeHashString
*/
class EscapeHashString
{
private:
std::string mData;
public:
static std::string processString(const std::string & str);
EscapeHashString();
EscapeHashString(const std::string & str);
EscapeHashString(const std::string & str, size_t pos, size_t len = std::string::npos);
EscapeHashString(const char * s);
EscapeHashString(const char * s, size_t n);
EscapeHashString(size_t n, char c);
template <class InputIterator>
EscapeHashString(InputIterator first, InputIterator last);
std::string toStdString() const;
friend std::ostream & operator<< (std::ostream & os, const EscapeHashString & eHS);
};
std::istream & operator>> (std::istream & is, EscapeHashString & eHS);
struct EscapeStringVector
{
std::vector<Files::EscapeHashString> mVector;
EscapeStringVector();
virtual ~EscapeStringVector();
std::vector<std::string> toStdStringVector() const;
};
} /* namespace Cfg */
#endif /* COMPONENTS_FILES_CONFIGURATIONMANAGER_HPP */

@ -0,0 +1,140 @@
#include "escape.hpp"
#include <boost/algorithm/string/replace.hpp>
#include <boost/program_options.hpp>
namespace Files
{
const int escape_hash_filter::sEscape = '@';
const int escape_hash_filter::sEscapeIdentifier = 'a';
const int escape_hash_filter::sHashIdentifier = 'h';
escape_hash_filter::escape_hash_filter() : mNext(), mSeenNonWhitespace(false), mFinishLine(false)
{
}
escape_hash_filter::~escape_hash_filter()
{
}
unescape_hash_filter::unescape_hash_filter() : expectingIdentifier(false)
{
}
unescape_hash_filter::~unescape_hash_filter()
{
}
std::string EscapeHashString::processString(const std::string & str)
{
std::string temp = boost::replace_all_copy<std::string>(str, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sHashIdentifier, "#");
boost::replace_all(temp, std::string() + (char)escape_hash_filter::sEscape + (char)escape_hash_filter::sEscapeIdentifier, std::string((char)escape_hash_filter::sEscape, 1));
return temp;
}
EscapeHashString::EscapeHashString() : mData()
{
}
EscapeHashString::EscapeHashString(const std::string & str) : mData(EscapeHashString::processString(str))
{
}
EscapeHashString::EscapeHashString(const std::string & str, size_t pos, size_t len) : mData(EscapeHashString::processString(str), pos, len)
{
}
EscapeHashString::EscapeHashString(const char * s) : mData(EscapeHashString::processString(std::string(s)))
{
}
EscapeHashString::EscapeHashString(const char * s, size_t n) : mData(EscapeHashString::processString(std::string(s)), 0, n)
{
}
EscapeHashString::EscapeHashString(size_t n, char c) : mData(n, c)
{
}
template <class InputIterator>
EscapeHashString::EscapeHashString(InputIterator first, InputIterator last) : mData(EscapeHashString::processString(std::string(first, last)))
{
}
std::string EscapeHashString::toStdString() const
{
return std::string(mData);
}
std::istream & operator>> (std::istream & is, EscapeHashString & eHS)
{
std::string temp;
is >> temp;
eHS = EscapeHashString(temp);
return is;
}
std::ostream & operator<< (std::ostream & os, const EscapeHashString & eHS)
{
os << eHS.mData;
return os;
}
EscapeStringVector::EscapeStringVector() : mVector()
{
}
EscapeStringVector::~EscapeStringVector()
{
}
std::vector<std::string> EscapeStringVector::toStdStringVector() const
{
std::vector<std::string> temp = std::vector<std::string>();
for (std::vector<EscapeHashString>::const_iterator it = mVector.begin(); it != mVector.end(); ++it)
{
temp.push_back(it->toStdString());
}
return temp;
}
// boost program options validation
void validate(boost::any &v, const std::vector<std::string> &tokens, Files::EscapeHashString * eHS, int a)
{
boost::program_options::validators::check_first_occurrence(v);
if (v.empty())
v = boost::any(EscapeHashString(boost::program_options::validators::get_single_string(tokens)));
}
void validate(boost::any &v, const std::vector<std::string> &tokens, EscapeStringVector *, int)
{
if (v.empty())
v = boost::any(EscapeStringVector());
EscapeStringVector * eSV = boost::any_cast<EscapeStringVector>(&v);
for (std::vector<std::string>::const_iterator it = tokens.begin(); it != tokens.end(); ++it)
eSV->mVector.push_back(EscapeHashString(*it));
}
PathContainer EscapePath::toPathContainer(const EscapePathContainer & escapePathContainer)
{
PathContainer temp;
for (EscapePathContainer::const_iterator it = escapePathContainer.begin(); it != escapePathContainer.end(); ++it)
temp.push_back(it->mPath);
return temp;
}
std::istream & operator>> (std::istream & istream, EscapePath & escapePath)
{
boost::iostreams::filtering_istream filteredStream;
filteredStream.push(unescape_hash_filter());
filteredStream.push(istream);
filteredStream >> escapePath.mPath;
return istream;
}
}

@ -0,0 +1,196 @@
#ifndef COMPONENTS_FILES_ESCAPE_HPP
#define COMPONENTS_FILES_ESCAPE_HPP
#include <queue>
#include <components/files/multidircollection.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/program_options.hpp>
/**
* \namespace Files
*/
namespace Files
{
/**
* \struct escape_hash_filter
*/
struct escape_hash_filter : public boost::iostreams::input_filter
{
static const int sEscape;
static const int sHashIdentifier;
static const int sEscapeIdentifier;
escape_hash_filter();
virtual ~escape_hash_filter();
template <typename Source> int get(Source & src);
private:
std::queue<int> mNext;
int mPrevious;
bool mSeenNonWhitespace;
bool mFinishLine;
};
template <typename Source>
int escape_hash_filter::get(Source & src)
{
if (mNext.empty())
{
int character = boost::iostreams::get(src);
bool record = true;
if (character == boost::iostreams::WOULD_BLOCK)
{
mNext.push(character);
record = false;
}
else if (character == EOF)
{
mSeenNonWhitespace = false;
mFinishLine = false;
mNext.push(character);
}
else if (character == '\n')
{
mSeenNonWhitespace = false;
mFinishLine = false;
mNext.push(character);
}
else if (mFinishLine)
{
mNext.push(character);
}
else if (character == '#')
{
if (mSeenNonWhitespace)
{
mNext.push(sEscape);
mNext.push(sHashIdentifier);
}
else
{
//it's fine being interpreted by Boost as a comment, and so is anything afterwards
mNext.push(character);
mFinishLine = true;
}
}
else if (mPrevious == sEscape)
{
mNext.push(sEscape);
mNext.push(sEscapeIdentifier);
}
else
{
mNext.push(character);
}
if (!mSeenNonWhitespace && !isspace(character))
mSeenNonWhitespace = true;
if (record)
mPrevious = character;
}
int retval = mNext.front();
mNext.pop();
return retval;
}
struct unescape_hash_filter : public boost::iostreams::input_filter
{
unescape_hash_filter();
virtual ~unescape_hash_filter();
template <typename Source> int get(Source & src);
private:
bool expectingIdentifier;
};
template <typename Source>
int unescape_hash_filter::get(Source & src)
{
int character;
if (!expectingIdentifier)
character = boost::iostreams::get(src);
else
{
character = escape_hash_filter::sEscape;
expectingIdentifier = false;
}
if (character == escape_hash_filter::sEscape)
{
int nextChar = boost::iostreams::get(src);
int intended;
if (nextChar == escape_hash_filter::sEscapeIdentifier)
intended = escape_hash_filter::sEscape;
else if (nextChar == escape_hash_filter::sHashIdentifier)
intended = '#';
else if (nextChar == boost::iostreams::WOULD_BLOCK)
{
expectingIdentifier = true;
intended = nextChar;
}
else
intended = '?';
return intended;
}
else
return character;
}
/**
* \class EscapeHashString
*/
class EscapeHashString
{
private:
std::string mData;
public:
static std::string processString(const std::string & str);
EscapeHashString();
EscapeHashString(const std::string & str);
EscapeHashString(const std::string & str, size_t pos, size_t len = std::string::npos);
EscapeHashString(const char * s);
EscapeHashString(const char * s, size_t n);
EscapeHashString(size_t n, char c);
template <class InputIterator>
EscapeHashString(InputIterator first, InputIterator last);
std::string toStdString() const;
friend std::ostream & operator<< (std::ostream & os, const EscapeHashString & eHS);
};
std::istream & operator>> (std::istream & is, EscapeHashString & eHS);
struct EscapeStringVector
{
std::vector<Files::EscapeHashString> mVector;
EscapeStringVector();
virtual ~EscapeStringVector();
std::vector<std::string> toStdStringVector() const;
};
//boost program options validation
void validate(boost::any &v, const std::vector<std::string> &tokens, Files::EscapeHashString * eHS, int a);
void validate(boost::any &v, const std::vector<std::string> &tokens, EscapeStringVector *, int);
struct EscapePath
{
boost::filesystem::path mPath;
static PathContainer toPathContainer(const std::vector<EscapePath> & escapePathContainer);
};
typedef std::vector<EscapePath> EscapePathContainer;
std::istream & operator>> (std::istream & istream, EscapePath & escapePath);
} /* namespace Files */
#endif /* COMPONENTS_FILES_ESCAPE_HPP */

@ -1,216 +0,0 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = build
# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
endif
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
.PHONY: help
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " applehelp to make an Apple Help Book"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " xml to make Docutils-native XML files"
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
@echo " coverage to run coverage check of the documentation (if enabled)"
.PHONY: clean
clean:
rm -rf $(BUILDDIR)/*
.PHONY: html
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
.PHONY: dirhtml
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
.PHONY: singlehtml
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
.PHONY: pickle
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
.PHONY: json
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
.PHONY: htmlhelp
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
.PHONY: qthelp
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/OpenMWCSManual.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/OpenMWCSManual.qhc"
.PHONY: applehelp
applehelp:
$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
@echo
@echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
@echo "N.B. You won't be able to view it unless you put it in" \
"~/Library/Documentation/Help or install it in your application" \
"bundle."
.PHONY: devhelp
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/OpenMWCSManual"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/OpenMWCSManual"
@echo "# devhelp"
.PHONY: epub
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
.PHONY: latex
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
.PHONY: latexpdf
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
.PHONY: latexpdfja
latexpdfja:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through platex and dvipdfmx..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
.PHONY: text
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
.PHONY: man
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
.PHONY: texinfo
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
.PHONY: info
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
.PHONY: gettext
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
.PHONY: changes
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
.PHONY: linkcheck
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
.PHONY: doctest
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
.PHONY: coverage
coverage:
$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
@echo "Testing of coverage in the sources finished, look at the " \
"results in $(BUILDDIR)/coverage/python.txt."
.PHONY: xml
xml:
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
@echo
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
.PHONY: pseudoxml
pseudoxml:
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
@echo
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."

@ -1,263 +0,0 @@
@ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source
set I18NSPHINXOPTS=%SPHINXOPTS% source
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. texinfo to make Texinfo files
echo. gettext to make PO message catalogs
echo. changes to make an overview over all changed/added/deprecated items
echo. xml to make Docutils-native XML files
echo. pseudoxml to make pseudoxml-XML files for display purposes
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
echo. coverage to run coverage check of the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
REM Check if sphinx-build is available and fallback to Python version if any
%SPHINXBUILD% 1>NUL 2>NUL
if errorlevel 9009 goto sphinx_python
goto sphinx_ok
:sphinx_python
set SPHINXBUILD=python -m sphinx.__init__
%SPHINXBUILD% 2> nul
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
:sphinx_ok
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\OpenMWCSManual.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\OpenMWCSManual.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdf" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf
cd %~dp0
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdfja" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf-ja
cd %~dp0
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "texinfo" (
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
goto end
)
if "%1" == "gettext" (
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
if "%1" == "coverage" (
%SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage
if errorlevel 1 exit /b 1
echo.
echo.Testing of coverage in the sources finished, look at the ^
results in %BUILDDIR%/coverage/python.txt.
goto end
)
if "%1" == "xml" (
%SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The XML files are in %BUILDDIR%/xml.
goto end
)
if "%1" == "pseudoxml" (
%SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
goto end
)
:end

@ -0,0 +1,3 @@
breathe
parse_cmake
sphinx

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
#
# OpenMW CS Manual documentation build configuration file, created by
# sphinx-quickstart on Fri Feb 5 21:28:27 2016.
# OpenMW documentation build configuration file, created by
# sphinx-quickstart on Wed May 14 15:16:35 2014.
#
# This file is execfile()d with the current directory set to its
# containing dir.
@ -18,7 +18,8 @@ import os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
project_root = os.path.abspath('../../')
sys.path.insert(0, project_root)
# -- General configuration ------------------------------------------------
@ -29,14 +30,27 @@ import os
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.doctest',
'sphinx.ext.todo',
'sphinx.ext.coverage',
'sphinx.ext.viewcode',
'breathe',
]
# Where breathe can find the source files
breathe_projects_source = {
"openmw": (project_root+"/apps/openmw", ["engine.hpp",
"mwbase/dialoguemanager.hpp", "mwbase/environment.hpp",
"mwbase/inputmanager.hpp", "mwbase/journal.hpp", "mwbase/mechanicsmanager.hpp",
"mwbase/scriptmanager.hpp", "mwbase/soundmanager.hpp", "mwbase/statemanager.hpp",
"mwbase/windowmanager.hpp", "mwbase/world.hpp"])
}
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
# source_suffix = ['.rst', '.md']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
@ -46,25 +60,25 @@ source_suffix = '.rst'
master_doc = 'index'
# General information about the project.
project = u'OpenMW CS Manual'
copyright = u'2016, The OpenMW Project'
author = u'HiPhish'
project = u'OpenMW'
copyright = u'2016, OpenMW Team'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = u'0.0'
# The full version, including alpha/beta/rc tags.
release = u'0.0'
from parse_cmake import parsing
cmake_raw = open(project_root+'/CMakeLists.txt', 'r').read()
cmake_data = parsing.parse(cmake_raw)
release = version = int(cmake_data[24][1][1].contents), int(cmake_data[25][1][1].contents), int(cmake_data[26][1][1].contents)
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
#language = cpp
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
@ -100,15 +114,13 @@ pygments_style = 'sphinx'
# If true, keep warnings as "system message" paragraphs in the built documents.
#keep_warnings = False
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
primary_domain = 'c'
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'alabaster'
html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
@ -137,7 +149,9 @@ html_theme = 'alabaster'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
html_static_path = ['_static',
'openmw-cs/_static'
]
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
@ -185,22 +199,9 @@ html_static_path = ['_static']
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Language to be used for generating the HTML full-text search index.
# Sphinx supports the following languages:
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
#html_search_language = 'en'
# A dictionary with options for the search language support, empty by default.
# Now only 'ja' uses this config value
#html_search_options = {'type': 'default'}
# The name of a javascript file (relative to the configuration directory) that
# implements a search results scorer. If empty, the default will be used.
#html_search_scorer = 'scorer.js'
# Output file base name for HTML help builder.
htmlhelp_basename = 'OpenMWCSManualdoc'
htmlhelp_basename = 'OpenMWdoc'
# -- Options for LaTeX output ---------------------------------------------
@ -213,17 +214,14 @@ latex_elements = {
# Additional stuff for the LaTeX preamble.
#'preamble': '',
# Latex figure (float) alignment
#'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'OpenMWCSManual.tex', u'OpenMW CS Manual Documentation',
u'HiPhish', 'manual'),
('index', 'OpenMW.tex', u'OpenMW Documentation',
u'Bret Curtis', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
@ -252,8 +250,8 @@ latex_documents = [
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'openmwcsmanual', u'OpenMW CS Manual Documentation',
[author], 1)
('index', 'openmw', u'OpenMW Documentation',
[u'Bret Curtis'], 1)
]
# If true, show URL addresses after external links.
@ -266,8 +264,8 @@ man_pages = [
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'OpenMWCSManual', u'OpenMW CS Manual Documentation',
author, 'OpenMWCSManual', 'One line description of project.',
('index', 'OpenMW', u'OpenMW Documentation',
u'Bret Curtis', 'OpenMW', 'One line description of project.',
'Miscellaneous'),
]
@ -282,77 +280,3 @@ texinfo_documents = [
# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False
# -- Options for Epub output ----------------------------------------------
# Bibliographic Dublin Core info.
epub_title = project
epub_author = author
epub_publisher = author
epub_copyright = copyright
# The basename for the epub file. It defaults to the project name.
#epub_basename = project
# The HTML theme for the epub output. Since the default themes are not
# optimized for small screen space, using the same theme for HTML and epub
# output is usually not wise. This defaults to 'epub', a theme designed to save
# visual space.
#epub_theme = 'epub'
# The language of the text. It defaults to the language option
# or 'en' if the language is not set.
#epub_language = ''
# The scheme of the identifier. Typical schemes are ISBN or URL.
#epub_scheme = ''
# The unique identifier of the text. This can be a ISBN number
# or the project homepage.
#epub_identifier = ''
# A unique identification for the text.
#epub_uid = ''
# A tuple containing the cover image and cover page html template filenames.
#epub_cover = ()
# A sequence of (type, uri, title) tuples for the guide element of content.opf.
#epub_guide = ()
# HTML files that should be inserted before the pages created by sphinx.
# The format is a list of tuples containing the path and title.
#epub_pre_files = []
# HTML files that should be inserted after the pages created by sphinx.
# The format is a list of tuples containing the path and title.
#epub_post_files = []
# A list of files that should not be packed into the epub file.
epub_exclude_files = ['search.html']
# The depth of the table of contents in toc.ncx.
#epub_tocdepth = 3
# Allow duplicate toc entries.
#epub_tocdup = True
# Choose between 'default' and 'includehidden'.
#epub_tocscope = 'default'
# Fix unsupported image types using the Pillow.
#epub_fix_images = False
# Scale large images.
#epub_max_image_width = 0
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#epub_show_urls = 'inline'
# If false, no index is generated.
#epub_use_index = True
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'https://docs.python.org/': None}

@ -0,0 +1,20 @@
Welcome to OpenMW's documentation!
=====================================
Components
----------
.. toctree::
:maxdepth: 2
openmw/index
openmw-cs/index
Indices and tables
==================
* :ref:`genindex`
* :ref:`search`

@ -1,8 +1,3 @@
.. OpenMW CS Manual documentation master file, created by
sphinx-quickstart on Fri Feb 5 21:28:27 2016.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
#####################
OpenMW CS user manual
#####################

@ -24,7 +24,7 @@ We will start by launching OpenMW CS, the location of the program depends on
your operating system. You will be presented with a dialogue with three
options: create a new game, create a new addon, edit a content file.
.. figure:: ./_static/images/chapter-1/opening-dialogue.png
.. figure:: _static/images/chapter-1/opening-dialogue.png
:alt: Opening dialogue with three option and setting button (the wrench)
The first option is for creating an entirely new game, that's not what we want.
@ -37,7 +37,7 @@ optionally a number of other addons we want to depend on. The name of the
project is arbitrary, it will be used to identify the addon later in the OpenMW
launcher.
.. figure:: ./_static/images/chapter-1/new-project.png
.. figure:: _static/images/chapter-1/new-project.png
:alt: Creation dialogue for a new project, pick content modules and name
Choose Morrowind as your content file and enter `Ring of Night Vision` as the
@ -47,7 +47,7 @@ to, but for this mod the base game is enough.
Once the addon has been created you will be presented with a table. If you see
a blank window rather than a table choose *World**Objects* from the menu.
.. figure:: ./_static/images/chapter-1/objects.png
.. figure:: _static/images/chapter-1/objects.png
:alt: The table showing all objet records in the game.
Let's talk about the interface for a second. Every window in OpenMW CS has
@ -83,7 +83,7 @@ We need to enter an *ID* (short for *identifier*) and pick the type. The
identifier is a unique name by which the ring can later be identified; I have
chosen `ring_night_vision`. For the type choose *Clothing*.
.. figure:: ./_static/images/chapter-1/add-record.png
.. figure:: _static/images/chapter-1/add-record.png
:alt: Enter the ID and type of the new ring
The table should jump right to our newly created record, if not read further
@ -101,7 +101,7 @@ instead of using the context menu; the default is double-clicking while
holding down the shift key.
.. figure:: ./_static/images/chapter-1/edit-record.png
.. figure:: _static/images/chapter-1/edit-record.png
:alt: Edit the properties of the record in a separate panel
You can set the name, weight and coin value as you like, I chose `Ring of Night

@ -0,0 +1,17 @@
###########################
OpenMW Source Documentation
###########################
.. toctree::
:maxdepth: 2
mwbase
.. autodoxygenfile:: engine.hpp
:project: openmw
Indices and tables
==================
* :ref:`genindex`
* :ref:`search`

@ -0,0 +1,34 @@
########
./mwbase
########
.. autodoxygenfile:: mwbase/dialoguemanager.hpp
:project: openmw
.. autodoxygenfile:: mwbase/environment.hpp
:project: openmw
.. autodoxygenfile:: mwbase/inputmanager.hpp
:project: openmw
.. autodoxygenfile:: mwbase/journal.hpp
:project: openmw
.. autodoxygenfile:: mwbase/mechanicsmanager.hpp
:project: openmw
.. autodoxygenfile:: mwbase/scriptmanager.hpp
:project: openmw
.. autodoxygenfile:: mwbase/soundmanager.hpp
:project: openmw
.. autodoxygenfile:: mwbase/statemanager.hpp
:project: openmw
.. autodoxygenfile:: mwbase/windowmanager.hpp
:project: openmw
.. autodoxygenfile:: mwbase/world.hpp
:project: openmw
Loading…
Cancel
Save