// DOM-style event object // // Mark Thompson (mot20@cam.ac.uk / mark@wildfiregames.com) // Note: Cancellable [UK]? Cancelable [US]? DOM says one l, OED says 2. // JS interface uses 1. // Entity and e.g. projectile classes derive from this and use it for // sending/receiving events. #ifndef DOMEVENT_INCLUDED #define DOMEVENT_INCLUDED #include "ScriptableObject.h" #include "EventTypes.h" // for EVENT_LAST class CScriptObject; class CScriptEvent; typedef CScriptObject* DOMEventHandler; class IEventTarget { // Return 'true' if we should stop propagating. bool _DispatchEvent( CScriptEvent* evt, IEventTarget* target ); // Events dispatched to this object are sent here before being processed. IEventTarget* before; // Events dispatched to this object are sent here after being processed. IEventTarget* after; typedef std::vector HandlerList; HandlerList m_Handlers_id[EVENT_LAST]; typedef STL_HASH_MULTIMAP HandlerMap; HandlerMap m_Handlers_name; typedef std::pair HandlerRange; public: IEventTarget() { before = NULL; after = NULL; } virtual ~IEventTarget(); // Set target that will receive each event after it is processed. // unused inline void SetPriorObject( IEventTarget* obj ) { before = obj; } // Set target that will receive each event after it is processed. // used by Entity and EntityTemplate. inline void SetNextObject( IEventTarget* obj ) { after = obj; } // Register a handler for the given event type. // Returns false if the handler was already present bool AddHandler( int TypeCode, DOMEventHandler handler ); bool AddHandler( const CStrW& TypeString, DOMEventHandler handler ); // Remove a previously registered handler for the specified event. // Returns false if the handler was not present bool RemoveHandler( int TypeCode, DOMEventHandler handler ); bool RemoveHandler( const CStrW& TypeString, DOMEventHandler handler ); // called by ScriptGlue.cpp for add|RemoveGlobalHandler bool AddHandlerJS( JSContext* cx, uintN argc, jsval* argv ); bool RemoveHandlerJS( JSContext* cx, uintN argc, jsval* argv ); // Return the JSObject* we'd like to be the 'this' object // when executing the handler. The argument is the object // to which the event is targeted. // It is passed to CScriptObject::DispatchEvent. virtual JSObject* GetScriptExecContext( IEventTarget* target ) = 0; // Dispatch an event to its handler. // returns: whether the event arrived (i.e. wasn't cancelled) [bool] bool DispatchEvent( CScriptEvent* evt ); }; class CScriptEvent : public CJSObject { public: enum EPhaseType { CAPTURING_PHASE = 1, AT_TARGET = 2, BUBBLING_PHASE = 3 }; // Target (currently unused) IEventTarget* m_Target; // Listening object currently being processed (currently unused) IEventTarget* m_CurrentTarget; // Phase type (currently unused) // EPhaseType m_EventPhase; // Can bubble? (currently unused) // bool m_Bubbles; // Can be cancelled (default actions prevented) bool m_Cancelable; // Can be blocked (prevented from propogating along the handler chain) bool m_Blockable; // Timestamp (milliseconds since epoch (start of game?)) i32 m_Timestamp; // Event type string CStrW m_Type; // Type code (to speed lookups) unsigned int m_TypeCode; // Has been cancelled? bool m_Cancelled; // Has it been blocked (won't be sent to any more handlers) bool m_Blocked; // -- jsval ToString( JSContext* cx, uintN argc, jsval* argv ); jsval PreventDefault( JSContext* cx, uintN argc, jsval* argv ); jsval StopPropagation( JSContext* cx, uintN argc, jsval* argv ); public: CScriptEvent( const CStrW& Type, unsigned int TypeCode = (unsigned int)-1, bool Cancelable = true, bool Blockable = true ); static void ScriptingInit(); }; #endif