Browse Source

Add `Element::Contains` method

Michael Ragazzon 8 months ago
parent
commit
0e1215e794
3 changed files with 51 additions and 1 deletions
  1. 5 1
      Include/RmlUi/Core/Element.h
  2. 11 0
      Source/Core/Element.cpp
  3. 35 0
      Tests/Source/UnitTests/Selectors.cpp

+ 5 - 1
Include/RmlUi/Core/Element.h

@@ -572,10 +572,14 @@ public:
 	/// @param[in] selector The selector or comma-separated selectors to match against.
 	/// @param[in] selector The selector or comma-separated selectors to match against.
 	/// @performance Prefer GetElementById/TagName/ClassName whenever possible.
 	/// @performance Prefer GetElementById/TagName/ClassName whenever possible.
 	void QuerySelectorAll(ElementList& elements, const String& selector);
 	void QuerySelectorAll(ElementList& elements, const String& selector);
-	/// Check if the element matches the given RCSS selector query.
+	/// Checks if the element matches the given RCSS selector query.
 	/// @param[in] selector The selector or comma-separated selectors to match against.
 	/// @param[in] selector The selector or comma-separated selectors to match against.
 	/// @return True if the element matches the given RCSS selector query, false otherwise.
 	/// @return True if the element matches the given RCSS selector query, false otherwise.
 	bool Matches(const String& selector);
 	bool Matches(const String& selector);
+	/// Checks if the provided element is a descendant of the current element.
+	/// @param[in] element The element to test with.
+	/// @return True if the provided element is a descendant of this element, false otherwise.
+	bool Contains(Element* element) const;
 
 
 	//@}
 	//@}
 
 

+ 11 - 0
Source/Core/Element.cpp

@@ -1620,6 +1620,17 @@ bool Element::Matches(const String& selectors)
 	return false;
 	return false;
 }
 }
 
 
+bool Element::Contains(Element* element) const
+{
+	while (element)
+	{
+		if (element == this)
+			return true;
+		element = element->GetParentNode();
+	}
+	return false;
+}
+
 EventDispatcher* Element::GetEventDispatcher() const
 EventDispatcher* Element::GetEventDispatcher() const
 {
 {
 	return &meta->event_dispatcher;
 	return &meta->event_dispatcher;

+ 35 - 0
Tests/Source/UnitTests/Selectors.cpp

@@ -258,6 +258,23 @@ static const Vector<MatchesSelector> matches_selectors =
 	{ "G", "p#G[missing]",   false },
 	{ "G", "p#G[missing]",   false },
 	{ "B", "[unit='m']",     true }
 	{ "B", "[unit='m']",     true }
 };
 };
+
+struct ContainsSelector {
+	String element_id;
+	String target_id;
+	bool expected_result;
+};
+static const Vector<ContainsSelector> contains_selectors =
+{
+	{ "A",  "A",  true },
+	{ "P",  "A",  true },
+	{ "A",  "P",  false },
+	{ "P",  "D0", true },
+	{ "D0", "P",  false },
+	{ "X",  "P",  false },
+	{ "P",  "X",  false },
+};
+
 // clang-format on
 // clang-format on
 
 
 // Recursively iterate through 'element' and all of its descendants to find all
 // Recursively iterate through 'element' and all of its descendants to find all
@@ -456,5 +473,23 @@ TEST_CASE("Selectors")
 		context->UnloadDocument(document);
 		context->UnloadDocument(document);
 	}
 	}
 
 
+	SUBCASE("Contains")
+	{
+		const String document_string = doc_begin + doc_end;
+		ElementDocument* document = context->LoadDocumentFromMemory(document_string);
+		REQUIRE(document);
+
+		for (const ContainsSelector& selector : contains_selectors)
+		{
+			Element* element = document->GetElementById(selector.element_id);
+			Element* target = document->GetElementById(selector.target_id);
+			REQUIRE(element);
+			REQUIRE(target);
+			CHECK_MESSAGE(element->Contains(target) == selector.expected_result,
+				"'" << selector.element_id << "' contains '" << selector.target_id << "'");
+		}
+		context->UnloadDocument(document);
+	}
+
 	TestsShell::ShutdownShell();
 	TestsShell::ShutdownShell();
 }
 }