Browse Source

Make Event unaware of event specification, pass by parameter instead.
Event performance issues corrected: Don't make a backup of the parameters, don't project mouse when unnecessary.

Michael Ragazzon 6 years ago
parent
commit
d2c395645c

+ 9 - 11
Include/Rocket/Core/Element.h

@@ -240,15 +240,11 @@ public:
 	/// Returns this element's TransformState
 	const TransformState *GetTransformState() const noexcept;
 	/// Returns the TransformStates that are effective for this element.
-	void GetEffectiveTransformState(
-		const TransformState **local_perspective,
-		const TransformState **perspective,
-		const TransformState **transform
-	) noexcept;
+	void GetEffectiveTransformState(const TransformState **local_perspective, const TransformState **perspective, const TransformState **transform) const noexcept;
 	/// Project a 2D point in pixel coordinates onto the element's plane.
 	/// @param[in] point The point to project.
 	/// @return The projected coordinates.
-	const Vector2f Project(const Vector2f& point) noexcept;
+	Vector2f Project(const Vector2f& point) const noexcept;
 
 	/// Start an animation of the given property on this element.
 	/// If an animation of the same property name exists, it will be replaced.
@@ -344,7 +340,7 @@ public:
 
 	/// Returns the element's context.
 	/// @return The context this element's document exists within.
-	Context* GetContext();
+	Context* GetContext() const;
 
 	/** @name DOM Properties
 	 */
@@ -489,12 +485,14 @@ public:
 	/// @param[in] in_capture_phase True to detach from the capture phase, false from the bubble phase.
 	void RemoveEventListener(const String& event, EventListener* listener, bool in_capture_phase = false);
 	/// Sends an event to this element.
-	/// @param[in] event Name of the event in string form.
+	/// @param[in] type Event type in string form.
 	/// @param[in] parameters The event parameters.
-	/// @param[in] interruptible True if the propagation of the event be stopped.
 	/// @return True if the event was not consumed (ie, was prevented from propagating by an element), false if it was.
-	bool DispatchEvent(const String& event, const Dictionary& parameters);
-	bool DispatchEvent(EventId event_id, const Dictionary& parameters);
+	bool DispatchEvent(const String& type, const Dictionary& parameters);
+	/// Sends an event to this element, overriding the default behavior for the given event type.
+	bool DispatchEvent(const String& type, const Dictionary& parameters, bool interruptible, bool bubbles);
+	/// Sends an event to this element by event id.
+	bool DispatchEvent(EventId id, const Dictionary& parameters);
 
 	/// Scrolls the parent element's contents so that this element is visible.
 	/// @param[in] align_with_top If true, the element will align itself to the top of the parent element's window. If false, the element will be aligned to the bottom of the parent element's window.

+ 13 - 12
Include/Rocket/Core/Event.h

@@ -60,7 +60,7 @@ public:
 	/// @param[in] type The event type
 	/// @param[in] parameters The event parameters
 	/// @param[in] interruptible Can this event have is propagation stopped?
-	Event(Element* target, EventId id, const Dictionary& parameters);
+	Event(Element* target, EventId id, const String& type, const Dictionary& parameters, bool interruptible);
 	/// Destructor
 	virtual ~Event();
 
@@ -84,12 +84,15 @@ public:
 	Element* GetTargetElement() const;
 
 	/// Get the event type.
-	/// @return The event type.
 	const String& GetType() const;
+	/// Get the event id.
+	EventId GetId() const;
 	/// Checks if the event is of a certain type.
 	/// @param type The name of the type to check for.
 	/// @return True if the event is of the requested type, false otherwise.
 	bool operator==(const String& type) const;
+	/// Checks if the event is of a certain id.
+	bool operator==(EventId id) const;
 
 	/// Has the event been stopped?
 	/// @return True if the event is still propogating
@@ -101,7 +104,7 @@ public:
 	/// @param key[in] The name of the desired parameter.
 	/// @return The value of the requested parameter.
 	template < typename T >
-	T GetParameter(const String& key, const T& default_value)
+	T GetParameter(const String& key, const T& default_value) const
 	{
 		return Get(parameters, key, default_value);
 	}
@@ -112,11 +115,6 @@ public:
 	/// Release this event.
 	virtual void OnReferenceDeactivate() override;
 
-
-	EventId GetId() const;
-	DefaultActionPhase GetDefaultActionPhase() const;
-	bool GetBubbles() const;
-
 private:
 	/// Project the mouse coordinates to the current element to enable
 	/// interacting with transformed elements.
@@ -129,13 +127,16 @@ protected:
 	Element* current_element;
 
 private:
-	Dictionary parameters_backup;
-
-	const EventSpecification& specification;
+	String type;
+	EventId id;
+	bool interruptible;
+	
 	bool interrupted;
-
 	EventPhase phase;
 
+	bool has_mouse_position;
+	Vector2f mouse_screen_position;
+
 	EventInstancer* instancer;
 
 	friend class Factory;

+ 1 - 1
Include/Rocket/Core/EventInstancer.h

@@ -53,7 +53,7 @@ public:
 	/// @param[in] name Name of this event.
 	/// @param[in] parameters Additional parameters for this event.
 	/// @param[in] interruptible If the event propagation can be stopped.
-	virtual Event* InstanceEvent(Element* target, EventId id, const Dictionary& parameters) = 0;
+	virtual Event* InstanceEvent(Element* target, EventId id, const String& type, const Dictionary& parameters, bool interruptible) = 0;
 
 	/// Releases an event instanced by this instancer.
 	/// @param[in] event The event to release.

+ 1 - 1
Include/Rocket/Core/Factory.h

@@ -159,7 +159,7 @@ public:
 	/// @param[in] parameters Additional parameters for this event.
 	/// @param[in] interruptible If the event propagation can be stopped.
 	/// @return The instanced event.
-	static Event* InstanceEvent(Element* target, EventId id, const Dictionary& parameters);
+	static Event* InstanceEvent(Element* target, EventId id, const String& type, const Dictionary& parameters, bool interruptible);
 
 	/// Register the instancer to be used for all event listeners.
 	/// @return The registered instancer on success, NULL on failure.

+ 1 - 2
Source/Controls/WidgetTextInput.cpp

@@ -405,8 +405,7 @@ void WidgetTextInput::ProcessEvent(Core::Event& event)
 			  event == "drag") &&
 			 event.GetTargetElement() == parent)
 	{
-		Rocket::Core::Vector2f mouse_position = Rocket::Core::Vector2f((float) event.GetParameter< int >("mouse_x", 0),
-																 (float) event.GetParameter< int >("mouse_y", 0));
+		Core::Vector2f mouse_position = Core::Vector2f(event.GetParameter< float >("mouse_x", 0), event.GetParameter< float >("mouse_y", 0));
 		mouse_position -= text_element->GetAbsoluteOffset();
 
 		cursor_line_index = CalculateLineIndex(mouse_position.y);

+ 44 - 31
Source/Core/Element.cpp

@@ -693,27 +693,25 @@ void Element::GetEffectiveTransformState(
 	const TransformState **local_perspective,
 	const TransformState **perspective,
 	const TransformState **transform
-) noexcept
+) const noexcept
 {
-	UpdateTransformState();
-
 	if (local_perspective)
 	{
-		*local_perspective = 0;
+		*local_perspective = nullptr;
 	}
 	if (perspective)
 	{
-		*perspective = 0;
+		*perspective = nullptr;
 	}
 	if (transform)
 	{
-		*transform = 0;
+		*transform = nullptr;
 	}
 
-	Element *perspective_node = 0, *transform_node = 0;
+	const Element *perspective_node = nullptr, *transform_node = nullptr;
 
 	// Find the TransformState to use for unprojecting.
-	if (transform_state.get() && transform_state->GetLocalPerspective(0))
+	if (transform_state.get() && transform_state->GetLocalPerspective(nullptr))
 	{
 		if (local_perspective)
 		{
@@ -722,10 +720,10 @@ void Element::GetEffectiveTransformState(
 	}
 	else
 	{
-		Element *node = 0;
+		const Element *node = nullptr;
 		for (node = parent; node; node = node->parent)
 		{
-			if (node->transform_state.get() && node->transform_state->GetPerspective(0))
+			if (node->transform_state.get() && node->transform_state->GetPerspective(nullptr))
 			{
 				if (perspective)
 				{
@@ -738,10 +736,10 @@ void Element::GetEffectiveTransformState(
 	}
 
 	// Find the TransformState to use for transforming.
-	Element *node = 0;
+	const Element *node = nullptr;
 	for (node = this; node; node = node->parent)
 	{
-		if (node->transform_state.get() && node->transform_state->GetRecursiveTransform(0))
+		if (node->transform_state.get() && node->transform_state->GetRecursiveTransform(nullptr))
 		{
 			if (transform)
 			{
@@ -754,11 +752,9 @@ void Element::GetEffectiveTransformState(
 }
 
 // Project a 2D point in pixel coordinates onto the element's plane.
-const Vector2f Element::Project(const Vector2f& point) noexcept
+Vector2f Element::Project(const Vector2f& point) const noexcept
 {
-	UpdateTransformState();
-
-	Context *context = GetContext();
+	const Context *context = GetContext();
 	if (!context)
 	{
 		return point;
@@ -957,7 +953,7 @@ Element* Element::GetFocusLeafNode()
 }
 
 // Returns the element's context.
-Context* Element::GetContext()
+Context* Element::GetContext() const
 {
 	ElementDocument* document = GetOwnerDocument();
 	if (document != NULL)
@@ -1298,28 +1294,36 @@ void Element::Click()
 // Adds an event listener
 void Element::AddEventListener(const String& event, EventListener* listener, bool in_capture_phase)
 {
-	EventId id = EventSpecificationInterface::GetIdOrDefineDefault(event);
+	EventId id = EventSpecificationInterface::GetIdOrInsert(event);
 	event_dispatcher->AttachEvent(id, listener, in_capture_phase);
 }
 
 // Removes an event listener from this element.
 void Element::RemoveEventListener(const String& event, EventListener* listener, bool in_capture_phase)
 {
-	EventId id = EventSpecificationInterface::GetIdOrDefineDefault(event);
+	EventId id = EventSpecificationInterface::GetIdOrInsert(event);
 	event_dispatcher->DetachEvent(id, listener, in_capture_phase);
 }
 
 // Dispatches the specified event
-bool Element::DispatchEvent(const String& event, const Dictionary& parameters)
+bool Element::DispatchEvent(const String& type, const Dictionary& parameters)
+{
+	const EventSpecification& specification = EventSpecificationInterface::GetOrInsert(type);
+	return event_dispatcher->DispatchEvent(this, specification.id, type, parameters, specification.interruptible, specification.bubbles, specification.default_action_phase);
+}
+
+// Dispatches the specified event
+bool Element::DispatchEvent(const String& type, const Dictionary& parameters, bool interruptible, bool bubbles)
 {
-	EventId id = EventSpecificationInterface::GetIdOrDefineDefault(event);
-	return event_dispatcher->DispatchEvent(this, id, parameters);
+	const EventSpecification& specification = EventSpecificationInterface::GetOrInsert(type);
+	return event_dispatcher->DispatchEvent(this, specification.id, type, parameters, interruptible, bubbles, specification.default_action_phase);
 }
 
 // Dispatches the specified event
-bool Element::DispatchEvent(EventId event_id, const Dictionary& parameters)
+bool Element::DispatchEvent(EventId id, const Dictionary& parameters)
 {
-	return event_dispatcher->DispatchEvent(this, event_id, parameters);
+	const EventSpecification& specification = EventSpecificationInterface::Get(id);
+	return event_dispatcher->DispatchEvent(this, specification.id, specification.type, parameters, specification.interruptible, specification.bubbles, specification.default_action_phase);
 }
 
 // Scrolls the parent element's contents so that this element is visible.
@@ -1951,11 +1955,11 @@ void Element::OnReferenceDeactivate()
 
 void Element::ProcessDefaultAction(Event& event)
 {
-	if (event == MOUSEDOWN && IsPointWithinElement(Vector2f(event.GetParameter< float >("mouse_x", 0), event.GetParameter< float >("mouse_y", 0))) &&
+	if (event == EventId::Mousedown && IsPointWithinElement(Vector2f(event.GetParameter< float >("mouse_x", 0), event.GetParameter< float >("mouse_y", 0))) &&
 		event.GetParameter< int >("button", 0) == 0)
 		SetPseudoClass("active", true);
 
-	if (event == MOUSESCROLL)
+	if (event == EventId::Mousescroll)
 	{
 		if (GetScrollHeight() > GetClientHeight())
 		{
@@ -1986,16 +1990,25 @@ void Element::ProcessDefaultAction(Event& event)
 		return;
 	}
 
-	if (event.GetTargetElement() == this)
+	if (event.GetPhase() == EventPhase::Target)
 	{
-		if (event == MOUSEOVER)
+		switch (event.GetId())
+		{
+		case EventId::Mouseover:
 			SetPseudoClass("hover", true);
-		else if (event == MOUSEOUT)
+			break;
+		case EventId::Mouseout:
 			SetPseudoClass("hover", false);
-		else if (event == FOCUS)
+			break;
+		case EventId::Focus:
 			SetPseudoClass(FOCUS, true);
-		else if (event == BLUR)
+			break;
+		case EventId::Blur:
 			SetPseudoClass(FOCUS, false);
+			break;
+		default:
+			break;
+		}
 	}
 }
 

+ 45 - 40
Source/Core/Event.cpp

@@ -28,25 +28,40 @@
 #include "precompiled.h"
 #include "../../Include/Rocket/Core/Event.h"
 #include "../../Include/Rocket/Core/EventInstancer.h"
-#include "EventSpecification.h"
 
 namespace Rocket {
 namespace Core {
 
-Event::Event() : specification(EventSpecificationInterface::Get(EventId::Invalid))
+Event::Event() : id(EventId::Invalid)
 {
+	id = EventId::Invalid;
 	phase = EventPhase::None;
+	interruptible = false;
 	interrupted = false;
 	current_element = nullptr;
 	target_element = nullptr;
+	has_mouse_position = false;
+	mouse_screen_position = Vector2f(0, 0);
 }
 
-Event::Event(Element* _target_element, EventId id, const Dictionary& _parameters) 
-	: specification(EventSpecificationInterface::Get(id)), parameters(_parameters), target_element(_target_element), parameters_backup(_parameters)
+Event::Event(Element* _target_element, EventId id, const String& type, const Dictionary& _parameters, bool interruptible)
+	: id(id), type(type), interruptible(interruptible), parameters(_parameters), target_element(_target_element)
 {
 	phase = EventPhase::None;
 	interrupted = false;
 	current_element = nullptr;
+
+	has_mouse_position = false;
+	mouse_screen_position = Vector2f(0, 0);
+
+	const Variant* mouse_x = GetIf(parameters, "mouse_x");
+	const Variant* mouse_y = GetIf(parameters, "mouse_y");
+	if (mouse_x && mouse_y)
+	{
+		has_mouse_position = true;
+		mouse_x->GetInto(mouse_screen_position.x);
+		mouse_y->GetInto(mouse_screen_position.y);
+	}
 }
 
 Event::~Event()
@@ -55,8 +70,11 @@ Event::~Event()
 
 void Event::SetCurrentElement(Element* element)
 {
-	ProjectMouse(element);
 	current_element = element;
+	if(has_mouse_position)
+	{
+		ProjectMouse(element);
+	}
 }
 
 Element* Event::GetCurrentElement() const
@@ -71,12 +89,17 @@ Element* Event::GetTargetElement() const
 
 const String& Event::GetType() const
 {
-	return specification.type;
+	return type;
 }
 
 bool Event::operator==(const String& _type) const
 {
-	return specification.type == _type;
+	return type == _type;
+}
+
+bool Event::operator==(EventId _id) const
+{
+	return id == _id;
 }
 
 void Event::SetPhase(EventPhase _phase)
@@ -97,7 +120,7 @@ bool Event::IsPropagating() const
 void Event::StopPropagation()
 {
 	// Set interrupted to true if we can be interrupted
-	if (specification.interruptible)
+	if (interruptible)
 	{
 		interrupted = true;
 	}
@@ -115,51 +138,33 @@ void Event::OnReferenceDeactivate()
 
 EventId Event::GetId() const
 {
-	return specification.id;
-}
-
-DefaultActionPhase Event::GetDefaultActionPhase() const
-{
-	return specification.default_action_phase;
-}
-
-bool Event::GetBubbles() const
-{
-	return specification.bubbles;
+	return id;
 }
 
 void Event::ProjectMouse(Element* element)
 {
-	if (element)
+	if(!element)
 	{
-		Variant *old_mouse_x = GetIf(parameters_backup, "mouse_x");
-		Variant *old_mouse_y = GetIf(parameters_backup, "mouse_y");
-		if (!old_mouse_x || !old_mouse_y)
-		{
-			// This is not a mouse event.
-			return;
-		}
+		parameters["mouse_x"] = mouse_screen_position.x;
+		parameters["mouse_y"] = mouse_screen_position.y;
+		return;
+	}
 
+	// Only need to project mouse position if element has a transform state
+	if (element->GetTransformState())
+	{
+		// Project mouse from parent (previous 'mouse_x/y' property) to child (element)
 		Variant *mouse_x = GetIf(parameters, "mouse_x");
 		Variant *mouse_y = GetIf(parameters, "mouse_y");
 		if (!mouse_x || !mouse_y)
 		{
-			// This should not happen.
+			ROCKET_ERROR;
 			return;
 		}
 
-		Vector2f old_mouse(
-			old_mouse_x->Get< float >(),
-			old_mouse_y->Get< float >()
-		);
-		Vector2f mouse = element->Project(old_mouse);
-
-		mouse_x->Reset(mouse.x);
-		mouse_y->Reset(mouse.y);
-	}
-	else
-	{
-		parameters = parameters_backup;
+		Vector2f new_pos = element->Project(mouse_screen_position);
+		mouse_x->Reset(new_pos.x);
+		mouse_y->Reset(new_pos.y);
 	}
 }
 

+ 2 - 6
Source/Core/EventDispatcher.cpp

@@ -113,16 +113,12 @@ void EventDispatcher::DetachAllEvents()
 		element->GetChild(i)->GetEventDispatcher()->DetachAllEvents();
 }
 
-bool EventDispatcher::DispatchEvent(Element* target_element, EventId id, const Dictionary& parameters)
+bool EventDispatcher::DispatchEvent(Element* target_element, EventId id, const String& type, const Dictionary& parameters, bool interruptible, bool bubbles, DefaultActionPhase default_action_phase)
 {
-	Event* event = Factory::InstanceEvent(target_element, id, parameters);
+	Event* event = Factory::InstanceEvent(target_element, id, type, parameters, interruptible);
 	if (!event)
 		return false;
 
-	const DefaultActionPhase default_action_phase = event->GetDefaultActionPhase();
-	const bool bubbles = event->GetBubbles();
-
-
 	// Build the element traversal from the tree
 	typedef std::vector<Element*> Elements;
 	Elements elements;

+ 1 - 1
Source/Core/EventDispatcher.h

@@ -76,7 +76,7 @@ public:
 	/// @param[in] parameters The event parameters
 	/// @param[in] interruptible Can the event propagation be stopped
 	/// @return True if the event was not consumed (ie, was prevented from propagating by an element), false if it was.
-	bool DispatchEvent(Element* element, EventId id, const Dictionary& parameters);
+	bool DispatchEvent(Element* element, EventId id, const String& type, const Dictionary& parameters, bool interruptible, bool bubbles, DefaultActionPhase default_action_phase);
 
 	/// Returns event types with number of listeners for debugging.
 	/// @return Summary of attached listeners.

+ 2 - 2
Source/Core/EventInstancerDefault.cpp

@@ -40,9 +40,9 @@ EventInstancerDefault::~EventInstancerDefault()
 {
 }
 
-Event* EventInstancerDefault::InstanceEvent(Element* target, EventId id, const Dictionary& parameters)
+Event* EventInstancerDefault::InstanceEvent(Element* target, EventId id, const String& type, const Dictionary& parameters, bool interruptible)
 {
-	return new Event(target, id, parameters);
+	return new Event(target, id, type, parameters, interruptible);
 }
 
 // Releases an event instanced by this instancer.

+ 1 - 1
Source/Core/EventInstancerDefault.h

@@ -50,7 +50,7 @@ public:
 	/// @param[in] name Name of this event.
 	/// @param[in] parameters Additional parameters for this event.
 	/// @param[in] interruptible If the event propagation can be stopped.
-	virtual Event* InstanceEvent(Element* target, EventId id, const Dictionary& parameters) override;
+	virtual Event* InstanceEvent(Element* target, EventId id, const String& type, const Dictionary& parameters, bool interruptible) override;
 
 	/// Releases an event instanced by this instancer.
 	/// @param[in] event The event to release.

+ 29 - 9
Source/Core/EventSpecification.cpp

@@ -33,17 +33,20 @@
 namespace Rocket {
 namespace Core {
 
-// An EventId is an index into the specifications vector
+// An EventId is an index into the specifications vector.
 static std::vector<EventSpecification> specifications = { { EventId::Invalid, "invalid", false, false, DefaultActionPhase::None } };
 
+// Reverse lookup map from event type to id.
 static UnorderedMap<String, EventId> type_lookup;
 
+
 namespace EventSpecificationInterface {
 
 void Initialize()
 {
-	// Must be specified in the same order as their event_id
+	// Must be specified in the same order as in EventId
 	specifications = {
+		//      id                 name      interruptible  bubbles     default_action
 		{EventId::Invalid       , "invalid"       , false , false , DefaultActionPhase::None},
 		{EventId::Mousedown     , "mousedown"     , true  , true  , DefaultActionPhase::TargetAndBubble},
 		{EventId::Mousescroll   , "mousescroll"   , true  , true  , DefaultActionPhase::TargetAndBubble},
@@ -65,7 +68,7 @@ void Initialize()
 		{EventId::Dragmove      , "dragmove"      , true  , true  , DefaultActionPhase::Target},
 		{EventId::Drag          , "drag"          , false , true  , DefaultActionPhase::Target},
 		{EventId::Dragstart     , "dragstart"     , false , true  , DefaultActionPhase::Target},
-		{EventId::Dragover      , "dragstart"     , true  , false , DefaultActionPhase::Target},
+		{EventId::Dragover      , "dragover"      , true  , false , DefaultActionPhase::Target},
 		{EventId::Dragdrop      , "dragdrop"      , true  , false , DefaultActionPhase::Target},
 		{EventId::Dragout       , "dragout"       , true  , false , DefaultActionPhase::Target},
 		{EventId::Dragend       , "dragend"       , true  , true  , DefaultActionPhase::None},
@@ -79,7 +82,7 @@ void Initialize()
 		{EventId::Change        , "change"        , false , true  , DefaultActionPhase::None},
 		{EventId::Submit        , "submit"        , true  , true  , DefaultActionPhase::None},
 		{EventId::Tabchange     , "tabchange"     , false , true  , DefaultActionPhase::None},
-		{EventId::Columnadd     , "tabchange"     , false , true  , DefaultActionPhase::None},
+		{EventId::Columnadd     , "columnadd"     , false , true  , DefaultActionPhase::None},
 		{EventId::Rowadd        , "rowadd"        , false , true  , DefaultActionPhase::None},
 		{EventId::Rowchange     , "rowchange"     , false , true  , DefaultActionPhase::None},
 		{EventId::Rowremove     , "rowremove"     , false , true  , DefaultActionPhase::None},
@@ -92,7 +95,7 @@ void Initialize()
 		type_lookup.emplace(specification.type, specification.id);
 
 #ifdef ROCKET_DEBUG
-	// Verify all event ids specified
+	// Verify that all event ids are specified
 	ROCKET_ASSERT((int)specifications.size() == (int)EventId::NumDefinedIds);
 
 	for (int i = 0; i < (int)specifications.size(); i++)
@@ -111,21 +114,38 @@ const EventSpecification& Get(EventId id)
 	return specifications[0];
 }
 
-EventId GetIdOrDefineDefault(const String& event_type)
+const EventSpecification& GetOrInsert(const String& event_type)
+{
+	// Default values for new event types defined as follows:
+	constexpr bool interruptible = true;
+	constexpr bool bubbles = true;
+	constexpr DefaultActionPhase default_action_phase = DefaultActionPhase::None;
+
+	return GetOrInsert(event_type, interruptible, bubbles, default_action_phase);
+}
+
+const EventSpecification& GetOrInsert(const String& event_type, bool interruptible, bool bubbles, DefaultActionPhase default_action_phase)
 {
 	auto it = type_lookup.find(event_type);
 
 	if (it != type_lookup.end())
-		return it->second;
+		return Get(it->second);
 
 	// No specification found for this name, insert a new entry with default values
 	EventId new_id = static_cast<EventId>(specifications.size());
-	specifications.push_back(EventSpecification{ new_id, event_type, true, true, DefaultActionPhase::None });
+	specifications.push_back(EventSpecification{ new_id, event_type, interruptible, bubbles, default_action_phase });
 	type_lookup.emplace(event_type, new_id);
-	return new_id;
+	return specifications.back();
 }
 
+EventId GetIdOrInsert(const String& event_type)
+{
+	auto it = type_lookup.find(event_type);
+	if (it != type_lookup.end())
+		return it->second;
 
+	return GetOrInsert(event_type).id;
+}
 
 
 }

+ 10 - 2
Source/Core/EventSpecification.h

@@ -52,9 +52,17 @@ namespace EventSpecificationInterface {
 	// Returns the 'invalid' event type if no specification exists for id.
 	const EventSpecification& Get(EventId id);
 
+	// Get event specification for the given type.
+	// If not found: Inserts a new entry with given values.
+	const EventSpecification& GetOrInsert(const String& event_type, bool interruptible, bool bubbles, DefaultActionPhase default_action_phase);
+
+	// Get event specification for the given type.
+	// If not found: Inserts a new entry with default values.
+	const EventSpecification& GetOrInsert(const String& event_type);
+
 	// Get event id for the given name.
-	// Inserts a new entry with default values if event type is not already specified.
-	EventId GetIdOrDefineDefault(const String& event_type);
+	// If not found: Inserts a new entry with default values.
+	EventId GetIdOrInsert(const String& event_type);
 
 }
 

+ 2 - 2
Source/Core/Factory.cpp

@@ -547,9 +547,9 @@ EventInstancer* Factory::RegisterEventInstancer(EventInstancer* instancer)
 }
 
 // Instance an event object.
-Event* Factory::InstanceEvent(Element* target, EventId id, const Dictionary& parameters)
+Event* Factory::InstanceEvent(Element* target, EventId id, const String& type, const Dictionary& parameters, bool interruptible)
 {
-	Event* event = event_instancer->InstanceEvent(target, id, parameters);
+	Event* event = event_instancer->InstanceEvent(target, id, type, parameters, interruptible);
 	if (event != NULL)
 		event->instancer = event_instancer;