Browse Source

Don't double create input elements

Michael Ragazzon 6 years ago
parent
commit
e1626379ee

+ 1 - 0
Samples/basic/animation/src/main.cpp

@@ -145,6 +145,7 @@ public:
 		  Replacing containers: 46.0  [c307140]
 		  Replace 'resize' event with virtual function call: 53.0  [7ad658f]
 		  Use all_properties_dirty flag when constructing elements: 55.0
+		  Don't double create input elements: 58.0
 		
 		*/
 

+ 45 - 33
Source/Controls/ElementFormControlInput.cpp

@@ -40,10 +40,10 @@ namespace Controls {
 // Constructs a new ElementFormControlInput.
 ElementFormControlInput::ElementFormControlInput(const Rocket::Core::String& tag) : ElementFormControl(tag)
 {
+	// OnAttributeChange will be called right after this, possible with a non-default type. Thus,
+	// creating the default InputTypeText here may result in it being destroyed in just a few moments.
+	// Instead, we create the InputTypeText in OnAttributeChange in the case where the type attribute has not been set.
 	type = NULL;
-	type = new InputTypeText(this);
-	type_name = "text";
-	SetClass(type_name, true);
 }
 
 ElementFormControlInput::~ElementFormControlInput()
@@ -91,39 +91,48 @@ void ElementFormControlInput::OnAttributeChange(const Core::AttributeNameList& c
 {
 	ElementFormControl::OnAttributeChange(changed_attributes);
 
+	Rocket::Core::String new_type_name;
+
 	if (changed_attributes.find("type") != changed_attributes.end())
 	{
-		Rocket::Core::String new_type_name = GetAttribute< Rocket::Core::String >("type", "text");
-		if (new_type_name != type_name)
+		new_type_name = GetAttribute< Rocket::Core::String >("type", "text");
+	}
+	else if (type == NULL)
+	{
+		// Ref. comment in constructor.
+		new_type_name = "text";
+	}
+
+	if (!new_type_name.empty() && new_type_name != type_name)
+	{
+		InputType* new_type = NULL;
+
+		if (new_type_name == "password")
+			new_type = new InputTypeText(this, Rocket::Controls::InputTypeText::OBSCURED);
+		else if (new_type_name == "radio")
+			new_type = new InputTypeRadio(this);
+		else if (new_type_name == "checkbox")
+			new_type = new InputTypeCheckbox(this);
+		else if (new_type_name == "range")
+			new_type = new InputTypeRange(this);
+		else if (new_type_name == "submit")
+			new_type = new InputTypeSubmit(this);
+		else if (new_type_name == "button")
+			new_type = new InputTypeButton(this);
+		else if (type_name == "text")
+			new_type = new InputTypeText(this);
+
+		if (new_type != NULL)
 		{
-			InputType* new_type = NULL;
-
-			if (new_type_name == "password")
-				new_type = new InputTypeText(this, Rocket::Controls::InputTypeText::OBSCURED);
-			else if (new_type_name == "radio")
-				new_type = new InputTypeRadio(this);
-			else if (new_type_name == "checkbox")
-				new_type = new InputTypeCheckbox(this);
-			else if (new_type_name == "range")
-				new_type = new InputTypeRange(this);
-			else if (new_type_name == "submit")
-				new_type = new InputTypeSubmit(this);
-			else if (new_type_name == "button")
-				new_type = new InputTypeButton(this);
-			else if (type_name == "text")
-				new_type = new InputTypeText(this);
-
-			if (new_type != NULL)
-			{
-				delete type;
-				type = new_type;
+			delete type;
+			type = new_type;
 
+			if(!type_name.empty())
 				SetClass(type_name, false);
-				SetClass(new_type_name, true);
-				type_name = new_type_name;
+			SetClass(new_type_name, true);
+			type_name = new_type_name;
 
-				DirtyLayout();
-			}
+			DirtyLayout();
 		}
 	}
 
@@ -143,14 +152,14 @@ void ElementFormControlInput::OnPropertyChange(const Core::PropertyNameList& cha
 // If we are the added element, this will pass the call onto our type handler.
 void ElementFormControlInput::OnChildAdd(Rocket::Core::Element* child)
 {
-	if (child == this)
+	if (child == this && type != NULL)
 		type->OnChildAdd();
 }
 
 // If we are the removed element, this will pass the call onto our type handler.
 void ElementFormControlInput::OnChildRemove(Rocket::Core::Element* child)
 {
-	if (child == this)
+	if (child == this && type != NULL)
 		type->OnChildRemove();
 }
 
@@ -158,11 +167,14 @@ void ElementFormControlInput::OnChildRemove(Rocket::Core::Element* child)
 void ElementFormControlInput::ProcessEvent(Core::Event& event)
 {
 	ElementFormControl::ProcessEvent(event);
-	type->ProcessEvent(event);
+	if(type != NULL)
+		type->ProcessEvent(event);
 }
 
 bool ElementFormControlInput::GetIntrinsicDimensions(Rocket::Core::Vector2f& dimensions)
 {
+	if (!type)
+		return false;
 	return type->GetIntrinsicDimensions(dimensions);
 }
 

+ 2 - 8
Source/Core/XMLParser.cpp

@@ -134,15 +134,9 @@ const XMLParser::ParseFrame* XMLParser::GetParseFrame() const
 }
 
 /// Called when the parser finds the beginning of an element tag.
-void XMLParser::HandleElementStart(const String& _name, const XMLAttributes& _attributes)
+void XMLParser::HandleElementStart(const String& _name, const XMLAttributes& attributes)
 {
-	String name = ToLower(_name);
-	XMLAttributes attributes;
-	
-	for (auto& [key, variant] : _attributes)
-	{
-		attributes[key] = variant.Get<String>();
-	}
+	const String name = ToLower(_name);
 
 	// Check for a specific handler that will override the child handler.
 	NodeHandlers::iterator itr = node_handlers.find(name);