2
0
Эх сурвалжийг харах

Clean up element pointers in Context on detach. I think maybe we should use SharedPtr instead of UniquePtr for elements so we can extend its lifetime until the end of the next Update call.

Michael Ragazzon 6 жил өмнө
parent
commit
cb0ad4af19

+ 4 - 4
Samples/basic/animation/src/main.cpp

@@ -143,13 +143,13 @@ Rml::Core::Context* context = nullptr;
 ShellRenderInterfaceExtensions *shell_renderer;
 DemoWindow* window = nullptr;
 
-bool pause_loop = false;
+bool run_loop = true;
 bool single_loop = false;
 int nudge = 0;
 
 void GameLoop()
 {
-	if(!pause_loop || single_loop)
+	if(run_loop || single_loop)
 	{
 		context->Update();
 
@@ -211,11 +211,11 @@ public:
 
 			if (key_identifier == Rml::Core::Input::KI_SPACE)
 			{
-				pause_loop = !pause_loop;
+				run_loop = !run_loop;
 			}
 			else if (key_identifier == Rml::Core::Input::KI_RETURN)
 			{
-				pause_loop = true;
+				run_loop = false;
 				single_loop = true;
 			}
 			else if (key_identifier == Rml::Core::Input::KI_OEM_PLUS)

+ 1 - 0
Samples/basic/benchmark/data/benchmark.rml

@@ -66,6 +66,7 @@
 
 <body template="window">
 <div id="fps"/>
+<div id="click_test"/>
 <div id="performance"/>
 </body>
 </rml>

+ 50 - 10
Samples/basic/benchmark/src/main.cpp

@@ -133,6 +133,37 @@ public:
 			el->SetInnerRML(rml);
 	}
 
+	class SimpleEventListener : public Rml::Core::EventListener {
+	public:
+		void ProcessEvent(Rml::Core::Event& event) override {
+			static int i = 0;
+			event.GetTargetElement()->SetProperty("background-color", i++ % 2 == 0 ? "green" : "orange");
+		}
+	} simple_event_listener;
+
+	void click_test()
+	{
+		if (!document)
+			return;
+
+		Rml::Core::String rml;
+		
+		static int i = 0;
+		if(i++ % 2 == 0)
+			rml = Rml::Core::CreateString(1000, R"( <div style="width: 100px; height: 100px; background-color: #c33;"/> )");
+		else
+			rml = "<p>Wohooo!!!</p>";
+
+		if (auto el = document->GetElementById("click_test"))
+		{
+			el->SetInnerRML(rml);
+			if (auto child = el->GetChild(0))
+				child->AddEventListener(Rml::Core::EventId::Mouseup, &simple_event_listener);
+		}
+	}
+
+
+
 	~DemoWindow()
 	{
 		if (document)
@@ -154,19 +185,23 @@ Rml::Core::Context* context = nullptr;
 ShellRenderInterfaceExtensions *shell_renderer;
 DemoWindow* window = nullptr;
 
-bool pause_loop = false;
-bool single_loop = false;
+bool run_loop = true;
+bool single_loop = true;
 bool run_update = true;
+bool single_loop_update = true;
 
 void GameLoop()
 {
-	if (!pause_loop || single_loop)
+	if (run_update || single_loop_update)
 	{
-		if (run_update)
-		{
-			window->performance_test();
-		}
+		window->performance_test();
+		//window->click_test();
 
+		single_loop_update = false;
+	}
+
+	if (run_loop || single_loop)
+	{
 		context->Update();
 
 		shell_renderer->PrepareRenderBuffer();
@@ -224,13 +259,18 @@ public:
 
 			if (key_identifier == Rml::Core::Input::KI_SPACE)
 			{
-				pause_loop = !pause_loop;
+				run_loop = !run_loop;
 			}
-			else if (key_identifier == Rml::Core::Input::KI_OEM_PLUS)
+			else if (key_identifier == Rml::Core::Input::KI_DOWN)
 			{
-				pause_loop = true;
+				run_loop = false;
 				single_loop = true;
 			}
+			else if (key_identifier == Rml::Core::Input::KI_RIGHT)
+			{
+				run_update = false;
+				single_loop_update = true;
+			}
 			else if (key_identifier == Rml::Core::Input::KI_RETURN)
 			{
 				run_update = !run_update;

+ 44 - 29
Source/Core/Context.cpp

@@ -60,13 +60,10 @@ Context::Context(const String& name) : name(name), dimensions(0, 0), density_ind
 	else
 		cursor_proxy.reset();
 		
+	enable_cursor = true;
 
 	document_focus_history.push_back(root.get());
 	focus = root.get();
-
-	enable_cursor = true;
-
-	focus = nullptr;
 	hover = nullptr;
 	active = nullptr;
 	drag = nullptr;
@@ -709,11 +706,14 @@ void Context::ProcessMouseButtonUp(int button_index, int key_modifier_state)
 					if (drag_verbose)
 					{
 						drag_hover->DispatchEvent(EventId::Dragdrop, drag_parameters);
-						drag_hover->DispatchEvent(EventId::Dragout, drag_parameters);
+						// User may have removed the element, do an extra check.
+						if(drag_hover) 
+							drag_hover->DispatchEvent(EventId::Dragout, drag_parameters);
 					}
 				}
 
-				drag->DispatchEvent(EventId::Dragend, drag_parameters);
+				if(drag)
+					drag->DispatchEvent(EventId::Dragend, drag_parameters);
 
 				ReleaseDragClone();
 			}
@@ -796,39 +796,54 @@ void Context::SetInstancer(ContextInstancer* _instancer)
 // Internal callback for when an element is removed from the hierarchy.
 void Context::OnElementDetach(Element* element)
 {
-	ElementSet::iterator i = hover_chain.find(element);
-	if (i == hover_chain.end())
-		return;
+	auto it_hover = hover_chain.find(element);
+	if (it_hover != hover_chain.end())
+	{
+		Dictionary parameters;
+		GenerateMouseEventParameters(parameters, -1);
+		RmlEventFunctor send_event(EventId::Mouseout, parameters);
+		send_event(element);
 
-	ElementSet old_hover_chain = hover_chain;
-	hover_chain.erase(i);
+		hover_chain.erase(it_hover);
 
-	Element* hover_element = element;
-	while (hover_element != nullptr)
+		if (hover == element)
+			hover = nullptr;
+	}
+
+	auto it_active = std::find(active_chain.begin(), active_chain.end(), element);
+	if (it_active != active_chain.end())
 	{
-		Element* next_hover_element = nullptr;
+		active_chain.erase(it_active);
+
+		if (active == element)
+			active = nullptr;
+	}
 
-		// Look for a child on this element's children that is also hovered.
-		for (int j = 0; j < hover_element->GetNumChildren(true); ++j)
+	if (drag)
+	{
+		auto it = drag_hover_chain.find(element);
+		if (it != drag_hover_chain.end())
 		{
-			// Is this child also in the hover chain?
-			Element* hover_child_element = hover_element->GetChild(j);
-			ElementSet::iterator k = hover_chain.find(hover_child_element);
-			if (k != hover_chain.end())
-			{
-				next_hover_element = hover_child_element;
-				hover_chain.erase(k);
+			drag_hover_chain.erase(it);
 
-				break;
-			}
+			if (drag_hover == element)
+				drag_hover = nullptr;
 		}
 
-		hover_element = next_hover_element;
+		if (drag == element)
+		{
+			// The dragged element is being removed, silently cancel the drag operation
+			if (drag_started)
+				ReleaseDragClone();
+
+			drag = nullptr;
+			drag_hover = nullptr;
+			drag_hover_chain.clear();
+		}
 	}
 
-	Dictionary parameters;
-	GenerateMouseEventParameters(parameters, -1);
-	SendEvents(old_hover_chain, hover_chain, EventId::Mouseout, parameters);
+	// Focus already cleared by Element::RemoveChild
+	RMLUI_ASSERT(element != focus); 
 }
 
 // Internal callback for when a new element gains focus

+ 16 - 13
Source/Core/Element.cpp

@@ -1530,8 +1530,6 @@ ElementPtr Element::RemoveChild(Element* child)
 			ElementPtr detached_child = std::move(*itr);
 			children.erase(itr);
 
-			detached_child->SetParent(nullptr);
-
 			// Remove the child element as the focused child of this element.
 			if (child == focus)
 			{
@@ -1555,6 +1553,8 @@ ElementPtr Element::RemoveChild(Element* child)
 				}
 			}
 
+			detached_child->SetParent(nullptr);
+
 			DirtyLayout();
 			DirtyStackingContext();
 			DirtyStructure();
@@ -2087,19 +2087,22 @@ void Element::GetRML(String& content)
 
 void Element::SetOwnerDocument(ElementDocument* document)
 {
-	if (owner_document && !document)
+	// If this element is a document, then never change owner_document.
+	if (owner_document != this)
 	{
-		// We are detaching from the document and thereby also the context.
-		if (Context * context = owner_document->GetContext())
-			context->OnElementDetach(this);
-	}
+		if (owner_document && !document)
+		{
+			// We are detaching from the document and thereby also the context.
+			if (Context * context = owner_document->GetContext())
+				context->OnElementDetach(this);
+		}
 
-	// If this element is a document, then never change owner_document. Otherwise, this can happen when attaching to the root element.
-	if(owner_document != document && owner_document != this)
-	{
-		owner_document = document;
-		for (ElementPtr& child : children)
-			child->SetOwnerDocument(document);
+		if (owner_document != document)
+		{
+			owner_document = document;
+			for (ElementPtr& child : children)
+				child->SetOwnerDocument(document);
+		}
 	}
 }