Commit a145f882 authored by Stefan Majewsky's avatar Stefan Majewsky

Split the trigger configuration from InteractorManager into a singleton class TriggerMapper.

svn path=/trunk/KDE/kdegames/palapeli/; revision=1118467
parent ba331526
......@@ -21,6 +21,7 @@ set(palapeli_SRCS
engine/scene.cpp
engine/texturehelper.cpp
engine/trigger.cpp
engine/triggermapper.cpp
engine/view.cpp
engine/zoomwidget.cpp
file-io/collection.cpp
......
......@@ -17,8 +17,7 @@
***************************************************************************/
#include "interactormanager.h"
#include "constraintinteractor.h"
#include "interactors.h"
#include "triggermapper.h"
#include <QKeyEvent>
#include <QMouseEvent>
......@@ -27,27 +26,9 @@
Palapeli::InteractorManager::InteractorManager(QGraphicsView* view)
: QObject(view)
, m_view(view)
, m_interactors(Palapeli::TriggerMapper::createInteractors(view))
{
//create interactors
m_interactors["MovePiece"] = new Palapeli::MovePieceInteractor(view);
m_interactors["SelectPiece"] = new Palapeli::SelectPieceInteractor(view);
m_interactors["MoveViewport"] = new Palapeli::MoveViewportInteractor(view);
m_interactors["ZoomViewport"] = new Palapeli::ZoomViewportInteractor(view);
m_interactors["RubberBand"] = new Palapeli::RubberBandInteractor(view);
m_interactors["Constraints"] = new Palapeli::ConstraintInteractor(view);
//setup triggers
typedef Palapeli::Trigger PIT;
m_triggers << qMakePair(PIT("LeftButton;NoModifier"), m_interactors["MovePiece"]);
m_triggers << qMakePair(PIT("LeftButton;ControlModifier"), m_interactors["SelectPiece"]);
m_triggers << qMakePair(PIT("RightButton;NoModifier"), m_interactors["MoveViewport"]);
m_triggers << qMakePair(PIT("wheel:Vertical;NoModifier"), m_interactors["ZoomViewport"]);
m_triggers << qMakePair(PIT("LeftButton;NoModifier"), m_interactors["Constraints"]);
m_triggers << qMakePair(PIT("LeftButton;NoModifier"), m_interactors["RubberBand"]);
//initialize quasi-static data
m_keyModifierMap[Qt::Key_Shift] = Qt::ShiftModifier;
m_keyModifierMap[Qt::Key_Control] = Qt::ControlModifier;
m_keyModifierMap[Qt::Key_Alt] = Qt::AltModifier;
m_keyModifierMap[Qt::Key_Meta] = Qt::MetaModifier;
connect(Palapeli::TriggerMapper::instance(), SIGNAL(associationsChanged()), SLOT(resetActiveTriggers()));
}
void Palapeli::InteractorManager::updateScene()
......@@ -56,6 +37,12 @@ void Palapeli::InteractorManager::updateScene()
interactor->updateScene();
}
void Palapeli::InteractorManager::resetActiveTriggers()
{
foreach (Palapeli::Interactor* interactor, m_interactors)
interactor->setInactive();
}
/*
* Wheel events are delivered to all interactors that accept them.
*/
......@@ -63,10 +50,11 @@ void Palapeli::InteractorManager::handleEvent(QWheelEvent* event)
{
//convert event
Palapeli::WheelEvent pEvent(m_view, event->pos(), event->delta());
//try to handle event
foreach (const Palapeli::AssociatedTrigger& aTrigger, m_triggers)
if (testTrigger(aTrigger.first, event) & Palapeli::EventMatches)
aTrigger.second->sendEvent(pEvent);
//check interactors
QMap<QByteArray, Palapeli::Interactor*>::const_iterator it1 = m_interactors.begin(), it2 = m_interactors.end();
for (; it1 != it2; ++it1)
if (Palapeli::TriggerMapper::instance()->testTrigger(it1.key(), event) & Palapeli::EventMatches)
it1.value()->sendEvent(pEvent);
}
/*
......@@ -85,16 +73,11 @@ void Palapeli::InteractorManager::handleEvent(QMouseEvent* event)
if (event->type() != QEvent::MouseButtonRelease)
m_buttons |= event->button();
m_mousePos = event->pos();
//check which triggers are activated by this event
//check which interactors are triggered by this event
QMap<Palapeli::Interactor*, EventContext> interactorData;
foreach (const Palapeli::AssociatedTrigger& trigger, m_triggers)
{
//NOTE: One interactor may have multiple triggers, so we OR stuff together.
const Palapeli::EventProcessingFlags flags = testTrigger(trigger.first, event);
interactorData[trigger.second].flags |= flags;
if (flags & Palapeli::EventMatches)
interactorData[trigger.second].triggeringButtons |= trigger.first.button();
}
QMap<QByteArray, Palapeli::Interactor*>::const_iterator it1 = m_interactors.begin(), it2 = m_interactors.end();
for (; it1 != it2; ++it1)
interactorData[it1.value()] = Palapeli::TriggerMapper::instance()->testTrigger(it1.key(), event);
//further processing in a method which is shared with the KeyEvent handler
handleEventCommon(pEvent, interactorData, event->buttons() | event->button());
}
......@@ -106,14 +89,11 @@ void Palapeli::InteractorManager::handleEvent(QKeyEvent* event)
{
//convert event
Palapeli::MouseEvent pEvent(m_view, m_mousePos);
//check which triggers are activated by this event
//check which interactors are triggered by this event
QMap<Palapeli::Interactor*, EventContext> interactorData;
foreach (const Palapeli::AssociatedTrigger& trigger, m_triggers)
{
//NOTE: One interactor may have multiple triggers, so we OR all flags together.
interactorData[trigger.second].flags |= testTrigger(trigger.first, event);
interactorData[trigger.second].triggeringButtons |= trigger.first.button();
}
QMap<QByteArray, Palapeli::Interactor*>::const_iterator it1 = m_interactors.begin(), it2 = m_interactors.end();
for (; it1 != it2; ++it1)
interactorData[it1.value()] = Palapeli::TriggerMapper::instance()->testTrigger(it1.key(), event, m_buttons);
//further processing in a method which is shared with the KeyEvent handler
handleEventCommon(pEvent, interactorData, m_buttons);
}
......@@ -121,7 +101,7 @@ void Palapeli::InteractorManager::handleEvent(QKeyEvent* event)
/*
* This is the common base for handleEvent(QMouseEvent*) and handleEvent(QKeyEvent*).
*/
void Palapeli::InteractorManager::handleEventCommon(const Palapeli::MouseEvent& pEvent, QMap<Palapeli::Interactor*, EventContext>& interactorData, Qt::MouseButtons unhandledButtons)
void Palapeli::InteractorManager::handleEventCommon(const Palapeli::MouseEvent& pEvent, QMap<Palapeli::Interactor*, Palapeli::EventContext>& interactorData, Qt::MouseButtons unhandledButtons)
{
//try to use active triggers where possible
foreach (Palapeli::Interactor* interactor, m_interactors)
......@@ -163,98 +143,4 @@ void Palapeli::InteractorManager::handleEventCommon(const Palapeli::MouseEvent&
}
}
Palapeli::EventProcessingFlags Palapeli::InteractorManager::testTrigger(const Palapeli::Trigger& trigger, QWheelEvent* event)
{
if (trigger.isValid())
{
const bool testModifiers = trigger.modifiers() == event->modifiers();
const bool checkDirection = trigger.wheelDirection() != 0;
const bool testDirection = trigger.wheelDirection() == event->orientation();
if (testModifiers && checkDirection && testDirection)
return Palapeli::EventMatches;
}
//if execution comes to this point, trigger does not match
return 0;
}
Palapeli::EventProcessingFlags Palapeli::InteractorManager::testTrigger(const Palapeli::Trigger& trigger, QMouseEvent* event)
{
if (trigger.isValid())
{
const bool testModifiers = trigger.modifiers() == event->modifiers();
const bool checkDirection = trigger.wheelDirection() == 0;
if (testModifiers && checkDirection)
{
if (trigger.button() == Qt::NoButton)
//trigger matches
return Palapeli::EventMatches;
const bool checkButtons = (event->button() | event->buttons()) & trigger.button();
if (checkButtons)
{
//trigger matches - construct result
Palapeli::EventProcessingFlags result = Palapeli::EventMatches;
if (event->button() == trigger.button())
{
if (event->type() == QEvent::MouseButtonPress)
result |= Palapeli::EventStartsInteraction;
if (event->type() == QEvent::MouseButtonRelease)
result |= Palapeli::EventConcludesInteraction;
}
return result;
}
}
}
//if execution comes to this point, trigger does not match
return 0;
}
Palapeli::EventProcessingFlags Palapeli::InteractorManager::testTrigger(const Palapeli::Trigger& trigger, QKeyEvent* event)
{
if (trigger.isValid())
{
//read modifiers
const Qt::KeyboardModifier keyModifier = m_keyModifierMap.value((Qt::Key) event->key(), Qt::NoModifier);
const Qt::KeyboardModifiers modifiers = keyModifier | event->modifiers();
//checking
const bool testModifiers = trigger.modifiers() == modifiers;
const bool checkDirection = trigger.wheelDirection() == 0;
const bool checkButton = trigger.button() & m_buttons;
if (testModifiers && checkDirection && checkButton)
{
//trigger matches - construct result
Palapeli::EventProcessingFlags result = Palapeli::EventMatches;
if (keyModifier != Qt::NoModifier)
{
if (event->type() == QEvent::KeyPress)
result |= Palapeli::EventStartsInteraction;
if (event->type() == QEvent::KeyRelease)
result |= Palapeli::EventConcludesInteraction;
}
return result;
}
}
//if execution comes to this point, trigger does not match
return 0;
}
//BEGIN API to configuration UI
const QList<Palapeli::Interactor*> Palapeli::InteractorManager::interactors() const
{
return m_interactors.values();
}
const QList<Palapeli::AssociatedTrigger> Palapeli::InteractorManager::triggers() const
{
return m_triggers;
}
void Palapeli::InteractorManager::setTriggers(const QList<Palapeli::AssociatedTrigger>& triggers)
{
foreach (Palapeli::Interactor* interactor, m_interactors)
interactor->setInactive();
m_triggers = triggers;
//TODO: write triggers to config file
}
//END API to configuration UI
#include "interactormanager.moc"
......@@ -19,19 +19,18 @@
#ifndef PALAPELI_INTERACTORMANAGER_H
#define PALAPELI_INTERACTORMANAGER_H
#include "interactor.h"
#include "trigger.h"
#include <QEvent>
#include <QGraphicsView>
#include <QMap>
namespace Palapeli
{
typedef QPair<Palapeli::Trigger, Palapeli::Interactor*> AssociatedTrigger;
class EventContext;
class Interactor;
class MouseEvent;
class InteractorManager : public QObject
{
Q_OBJECT
public:
explicit InteractorManager(QGraphicsView* view);
......@@ -40,32 +39,16 @@ namespace Palapeli
void handleEvent(QKeyEvent* event);
void updateScene();
///\note This list will never change at run-time.
const QList<Palapeli::Interactor*> interactors() const;
const QList<Palapeli::AssociatedTrigger> triggers() const;
void setTriggers(const QList<Palapeli::AssociatedTrigger>& triggers);
public Q_SLOTS:
void resetActiveTriggers();
protected:
Palapeli::EventProcessingFlags testTrigger(const Palapeli::Trigger& trigger, QWheelEvent* event);
Palapeli::EventProcessingFlags testTrigger(const Palapeli::Trigger& trigger, QMouseEvent* event);
Palapeli::EventProcessingFlags testTrigger(const Palapeli::Trigger& trigger, QKeyEvent* event);
struct EventContext
{
Palapeli::EventProcessingFlags flags;
Qt::MouseButtons triggeringButtons;
};
void handleEventCommon(const Palapeli::MouseEvent& pEvent, QMap<Palapeli::Interactor*, EventContext>& interactorData, Qt::MouseButtons unhandledButtons);
void handleEventCommon(const Palapeli::MouseEvent& pEvent, QMap<Palapeli::Interactor*, Palapeli::EventContext>& interactorData, Qt::MouseButtons unhandledButtons);
private:
QGraphicsView* m_view;
QMap<QByteArray, Palapeli::Interactor*> m_interactors; //NOTE: The interactor list is always hard-coded, based on what is available. The keys are used for writing the trigger list to the config.
//configuration
QList<Palapeli::AssociatedTrigger> m_triggers;
//state
Qt::MouseButtons m_buttons;
QPoint m_mousePos;
//quasi-static data
QMap<Qt::Key, Qt::KeyboardModifier> m_keyModifierMap;
};
}
......
/***************************************************************************
* Copyright 2010 Stefan Majewsky <majewsky@gmx.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
***************************************************************************/
#include "triggermapper.h"
#include "constraintinteractor.h"
#include "interactors.h"
#include <QKeyEvent>
#include <QMouseEvent>
#include <QWheelEvent>
Palapeli::TriggerMapper* Palapeli::TriggerMapper::instance()
{
static Palapeli::TriggerMapper instance;
return &instance;
}
QMap<QByteArray, Palapeli::Interactor*> Palapeli::TriggerMapper::createInteractors(QGraphicsView* view)
{
QMap<QByteArray, Palapeli::Interactor*> result;
result["MovePiece"] = new Palapeli::MovePieceInteractor(view);
result["SelectPiece"] = new Palapeli::SelectPieceInteractor(view);
result["MoveViewport"] = new Palapeli::MoveViewportInteractor(view);
result["ZoomViewport"] = new Palapeli::ZoomViewportInteractor(view);
result["RubberBand"] = new Palapeli::RubberBandInteractor(view);
result["Constraints"] = new Palapeli::ConstraintInteractor(view);
return result;
}
Palapeli::TriggerMapper::TriggerMapper()
{
//initialize quasi-static data
m_keyModifierMap[Qt::Key_Shift] = Qt::ShiftModifier;
m_keyModifierMap[Qt::Key_Control] = Qt::ControlModifier;
m_keyModifierMap[Qt::Key_Alt] = Qt::AltModifier;
m_keyModifierMap[Qt::Key_Meta] = Qt::MetaModifier;
//intialize dynamic data
readSettings();
}
void Palapeli::TriggerMapper::readDefaultSettings()
{
m_associations.clear();
m_associations.insert("MovePiece", Palapeli::Trigger("LeftButton;NoModifier"));
m_associations.insert("SelectPiece", Palapeli::Trigger("LeftButton;ControlModifier"));
m_associations.insert("MoveViewport", Palapeli::Trigger("RightButton;NoModifier"));
m_associations.insert("ZoomViewport", Palapeli::Trigger("wheel:Vertical;NoModifier"));
m_associations.insert("RubberBand", Palapeli::Trigger("LeftButton;NoModifier"));
m_associations.insert("Constraints", Palapeli::Trigger("LeftButton;NoModifier"));
emit associationsChanged();
}
void Palapeli::TriggerMapper::readSettings()
{
//TODO: read settings from config
readDefaultSettings();
}
void Palapeli::TriggerMapper::writeSettings()
{
//TODO: write settings to config
}
Palapeli::EventProcessingFlags Palapeli::TriggerMapper::testTrigger(const QByteArray& interactor, QWheelEvent* event) const
{
Palapeli::EventProcessingFlags result;
QMap<QByteArray, Palapeli::Trigger>::const_iterator it1 = m_associations.begin(), it2 = m_associations.end();
for (; it1 != it2; ++it1)
if (it1.key() == interactor)
result |= testTrigger(it1.value(), event);
return result;
}
Palapeli::EventContext Palapeli::TriggerMapper::testTrigger(const QByteArray& interactor, QMouseEvent* event) const
{
Palapeli::EventContext result;
QMap<QByteArray, Palapeli::Trigger>::const_iterator it1 = m_associations.begin(), it2 = m_associations.end();
for (; it1 != it2; ++it1)
if (it1.key() == interactor)
{
const Palapeli::EventProcessingFlags flags = testTrigger(it1.value(), event);
result.flags |= flags;
if (flags & Palapeli::EventMatches)
result.triggeringButtons |= it1.value().button();
}
return result;
}
Palapeli::EventContext Palapeli::TriggerMapper::testTrigger(const QByteArray& interactor, QKeyEvent* event, Qt::MouseButtons buttons) const
{
Palapeli::EventContext result;
QMap<QByteArray, Palapeli::Trigger>::const_iterator it1 = m_associations.begin(), it2 = m_associations.end();
for (; it1 != it2; ++it1)
if (it1.key() == interactor)
{
result.flags |= testTrigger(it1.value(), event, buttons);
result.triggeringButtons |= it1.value().button();
}
return result;
}
Palapeli::EventProcessingFlags Palapeli::TriggerMapper::testTrigger(const Palapeli::Trigger& trigger, QWheelEvent* event) const
{
if (trigger.isValid())
{
const bool testModifiers = trigger.modifiers() == event->modifiers();
const bool checkDirection = trigger.wheelDirection() != 0;
const bool testDirection = trigger.wheelDirection() == event->orientation();
if (testModifiers && checkDirection && testDirection)
return Palapeli::EventMatches;
}
//if execution comes to this point, trigger does not match
return 0;
}
Palapeli::EventProcessingFlags Palapeli::TriggerMapper::testTrigger(const Palapeli::Trigger& trigger, QMouseEvent* event) const
{
if (trigger.isValid())
{
const bool testModifiers = trigger.modifiers() == event->modifiers();
const bool checkDirection = trigger.wheelDirection() == 0;
if (testModifiers && checkDirection)
{
if (trigger.button() == Qt::NoButton)
//trigger matches
return Palapeli::EventMatches;
const bool checkButtons = (event->button() | event->buttons()) & trigger.button();
if (checkButtons)
{
//trigger matches - construct result
Palapeli::EventProcessingFlags result = Palapeli::EventMatches;
if (event->button() == trigger.button())
{
if (event->type() == QEvent::MouseButtonPress)
result |= Palapeli::EventStartsInteraction;
if (event->type() == QEvent::MouseButtonRelease)
result |= Palapeli::EventConcludesInteraction;
}
return result;
}
}
}
//if execution comes to this point, trigger does not match
return 0;
}
Palapeli::EventProcessingFlags Palapeli::TriggerMapper::testTrigger(const Palapeli::Trigger& trigger, QKeyEvent* event, Qt::MouseButtons buttons) const
{
if (trigger.isValid())
{
//read modifiers
const Qt::KeyboardModifier keyModifier = m_keyModifierMap.value((Qt::Key) event->key(), Qt::NoModifier);
const Qt::KeyboardModifiers modifiers = keyModifier | event->modifiers();
//checking
const bool testModifiers = trigger.modifiers() == modifiers;
const bool checkDirection = trigger.wheelDirection() == 0;
const bool checkButton = (trigger.button() & buttons) || trigger.button() == Qt::NoButton;
if (testModifiers && checkDirection && checkButton)
{
//trigger matches - construct result
Palapeli::EventProcessingFlags result = Palapeli::EventMatches;
if (keyModifier != Qt::NoModifier)
{
if (event->type() == QEvent::KeyPress)
result |= Palapeli::EventStartsInteraction;
if (event->type() == QEvent::KeyRelease)
result |= Palapeli::EventConcludesInteraction;
}
return result;
}
}
//if execution comes to this point, trigger does not match
return 0;
}
#include "triggermapper.moc"
/***************************************************************************
* Copyright 2010 Stefan Majewsky <majewsky@gmx.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
***************************************************************************/
#ifndef PALAPELI_TRIGGERMAPPER_H
#define PALAPELI_TRIGGERMAPPER_H
#include "interactor.h"
#include "trigger.h"
#include <QMap>
class QKeyEvent;
class QMouseEvent;
class QWheelEvent;
namespace Palapeli
{
struct EventContext
{
Palapeli::EventProcessingFlags flags;
Qt::MouseButtons triggeringButtons;
};
class TriggerMapper : public QObject
{
Q_OBJECT
public:
static Palapeli::TriggerMapper* instance();
Q_SIGNALS:
void associationsChanged();
public Q_SLOTS:
void readDefaultSettings();
void readSettings();
void writeSettings();
protected:
friend class InteractorManager;
static QMap<QByteArray, Palapeli::Interactor*> createInteractors(QGraphicsView* view);
Palapeli::EventProcessingFlags testTrigger(const QByteArray& interactor, QWheelEvent* event) const;
Palapeli::EventContext testTrigger(const QByteArray& interactor, QMouseEvent* event) const;
Palapeli::EventContext testTrigger(const QByteArray& interactor, QKeyEvent* event, Qt::MouseButtons buttons) const;
private:
TriggerMapper();
Palapeli::EventProcessingFlags testTrigger(const Palapeli::Trigger& trigger, QWheelEvent* event) const;
Palapeli::EventProcessingFlags testTrigger(const Palapeli::Trigger& trigger, QMouseEvent* event) const;
Palapeli::EventProcessingFlags testTrigger(const Palapeli::Trigger& trigger, QKeyEvent* event, Qt::MouseButtons buttons) const;
QMap<QByteArray, Palapeli::Trigger> m_associations;
//quasi-static data
QMap<Qt::Key, Qt::KeyboardModifier> m_keyModifierMap;
};
}
#endif // PALAPELI_TRIGGERMAPPER_H
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment