diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/events.cpp | 136 | ||||
-rw-r--r-- | common/events.h | 143 |
2 files changed, 279 insertions, 0 deletions
diff --git a/common/events.cpp b/common/events.cpp new file mode 100644 index 0000000000..9cb5d8aba6 --- /dev/null +++ b/common/events.cpp @@ -0,0 +1,136 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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. + * + * $URL$ + * $Id$ + * + */ + +#include "common/events.h" + +DECLARE_SINGLETON(Common::EventDispatcher); + +namespace Common { + +EventDispatcher::EventDispatcher() : _mapper(0) { +} + +EventDispatcher::~EventDispatcher() { + for (Common::List<SourceEntry>::iterator i = _sources.begin(); i != _sources.end(); ++i) { + if (i->autoFree) + delete i->source; + } + + for (Common::List<ObserverEntry>::iterator i = _observers.begin(); i != _observers.end(); ++i) { + if (i->autoFree) + delete i->observer; + } + + delete _mapper; + _mapper = 0; +} + +void EventDispatcher::dispatch() { + Common::Event event; + + for (Common::List<SourceEntry>::iterator i = _sources.begin(); i != _sources.end(); ++i) { + while (i->source->pollEvent(event)) { + if (_mapper) { + if (_mapper->notifyEvent(event)) { + // We allow the event mapper to create multiple events, when + // eating an event. + while (_mapper->pollEvent(event)) + dispatchEvent(event); + + // Try getting another event from the current EventSource. + continue; + } + } + + dispatchEvent(event); + } + } +} + +void EventDispatcher::registerMapper(EventMapper *mapper) { + if (_mapper) + delete _mapper; + _mapper = mapper; +} + +void EventDispatcher::registerSource(EventSource *source, bool autoFree) { + SourceEntry newEntry; + + newEntry.source = source; + newEntry.autoFree = autoFree; + + _sources.push_back(newEntry); +} + +void EventDispatcher::unregisterSource(EventSource *source) { + for (Common::List<SourceEntry>::iterator i = _sources.begin(); i != _sources.end(); ++i) { + if (i->source == source) { + if (i->autoFree) + delete source; + + _sources.erase(i); + return; + } + } +} + +void EventDispatcher::registerObserver(EventObserver *obs, uint priority, bool autoFree) { + ObserverEntry newEntry; + + newEntry.observer = obs; + newEntry.priority = priority; + newEntry.autoFree = autoFree; + + for (Common::List<ObserverEntry>::iterator i = _observers.begin(); i != _observers.end(); ++i) { + if (i->priority < priority) { + _observers.insert(i, newEntry); + return; + } + } + + _observers.push_back(newEntry); +} + +void EventDispatcher::unregisterObserver(EventObserver *obs) { + for (Common::List<ObserverEntry>::iterator i = _observers.begin(); i != _observers.end(); ++i) { + if (i->observer == obs) { + if (i->autoFree) + delete obs; + + _observers.erase(i); + return; + } + } +} + +void EventDispatcher::dispatchEvent(const Event &event) { + for (Common::List<ObserverEntry>::iterator i = _observers.begin(); i != _observers.end(); ++i) { + if (i->observer->notifyEvent(event)) + break; + } +} + +} // end of namespace Common + diff --git a/common/events.h b/common/events.h index 82b85e60ea..7a187cc7c8 100644 --- a/common/events.h +++ b/common/events.h @@ -31,6 +31,9 @@ #include "common/rect.h" #include "common/noncopyable.h" +#include "common/list.h" +#include "common/singleton.h" + namespace Common { /** @@ -126,6 +129,146 @@ struct Event { Event() : type(EVENT_INVALID), synthetic(false) {} }; +/** + * A source of Events. + * + * An example for this is OSystem, it provides events created by the system + * and or user. + */ +class EventSource { +public: + virtual ~EventSource() {} + + /** + * Queries a event from the source. + * + * @param event a reference to the event struct, where the event should be stored. + * @return true if an event was polled, false otherwise. + */ + virtual bool pollEvent(Event &event) = 0; +}; + +/** + * Object which catches and processes Events. + * + * An example for this is the Engine object, it is catching events and processing them. + */ +class EventObserver { +public: + virtual ~EventObserver() {} + + /** + * Notifies the source of an incoming event. + * + * An obeser is supposed to eat the event, with returning true, when + * it might want prevent other observers from preventing to receive + * the event. An usage example here is the keymapper: + * If it processes an Event, it should 'eat' it and create a new + * event, which the EventDispatcher will then catch. + * + * @param event the event, which is incoming. + * @return true if this observer uses this event, false otherwise. + */ + virtual bool notifyEvent(const Event &event) = 0; +}; + +/** + * A event mapper, which will map events to others. + * + * An example for this is the Keymapper. + */ +class EventMapper : public EventSource, public EventObserver { +}; + +/** + * Dispatches events from various sources to various observers. + * + * EventDispatcher is using a priority based approach. Observers + * with higher priority will be notified before observers with + * lower priority. Because of the possibility that oberservers + * might 'eat' events, not all observers might be notified. + * + * Another speciality is the support for a event mapper, which + * will catch events and create new events out of them. This + * mapper will be processed before an event is sent to the + * observers. + */ +class EventDispatcher : public Singleton<EventDispatcher> { + friend class Singleton<SingletonBaseType>; +public: + /** + * Tries to catch events from the registered event + * sources and dispatch them to the observers. + */ + void dispatch(); + + /** + * Registers an event mapper with the dispatcher. + * + * The ownership of the "mapper" variable will pass + * to the EventDispatcher, thus it will be deleted + * with "delete", when EventDispatcher is destroyed. + * + * Note there is only one mapper per EventDispatcher + * possible, thus when this method is called twice, + * the former mapper will be destroied. + */ + void registerMapper(EventMapper *mapper); + + /** + * Queries the setup event mapper. + */ + EventMapper *queryMapper() const { return _mapper; } + + /** + * Registers a new EventSource with the Dispatcher. + */ + void registerSource(EventSource *source, bool autoFree); + + /** + * Unregisters a EventSource. + * + * This takes the "autoFree" flag passed to registerSource into account. + */ + void unregisterSource(EventSource *source); + + /** + * Registers a new EventObserver with the Dispatcher. + */ + void registerObserver(EventObserver *obs, uint priority, bool autoFree); + + /** + * Unregisters a EventObserver. + * + * This takes the "autoFree" flag passed to registerObserver into account. + */ + void unregisterObserver(EventObserver *obs); +private: + EventDispatcher(); + ~EventDispatcher(); + + EventMapper *_mapper; + + struct Entry { + bool autoFree; + }; + + struct SourceEntry : public Entry { + EventSource *source; + }; + + Common::List<SourceEntry> _sources; + + struct ObserverEntry : public Entry { + uint priority; + EventObserver *observer; + }; + + Common::List<ObserverEntry> _observers; + + void dispatchEvent(const Event &event); +}; + class Keymapper; /** |