Ver código fonte

Add a 'theme' media query for activating and deactivating media blocks

Michael Ragazzon 4 anos atrás
pai
commit
f9276da68a

+ 11 - 0
Include/RmlUi/Core/Context.h

@@ -115,6 +115,15 @@ public:
 	/// @param[in] show True to enable mouse cursor handling, false to disable.
 	void EnableMouseCursor(bool enable);
 
+	/// Activate or deactivate a media theme. Themes can be used in RCSS media queries.
+	/// @param theme_name[in] The name of the theme to (de)activate.
+	/// @param activate True to activate the given theme, false to deactivate.
+	void ActivateTheme(const String& theme_name, bool activate);
+	/// Check if a given media theme has been activated.
+	/// @param theme_name The name of the theme.
+	/// @return True if the theme is activated.
+	bool IsThemeActive(const String& theme_name) const;
+
 	/// Returns the first document in the context with the given id.
 	/// @param[in] id The id of the desired document.
 	/// @return The document (if it was found), or nullptr if no document exists with the ID.
@@ -265,6 +274,8 @@ private:
 	float density_independent_pixel_ratio;
 	String documents_base_tag = "body";
 
+	SmallUnorderedSet<String> active_themes;
+
 	ContextInstancer* instancer;
 
 	using ElementSet = SmallOrderedSet< Element* >;

+ 1 - 0
Include/RmlUi/Core/ID.h

@@ -183,6 +183,7 @@ enum class MediaQueryId : uint8_t
 	MinResolution,
 	MaxResolution,
 	Orientation,
+	Theme,
 
 	NumDefinedIds
 };

+ 3 - 4
Include/RmlUi/Core/StyleSheetContainer.h

@@ -53,12 +53,11 @@ public:
 	/// Loads a style from a CSS definition.
 	bool LoadStyleSheetContainer(Stream* stream, int begin_line_number = 1);
 
-	/// Compiles a single style sheet by combining all contained style sheets whose media queries match the provided parameters.
-	/// @param[in] dp_ratio The current context ratio of 'dp' units to 'px' units
-	/// @param[in] vp_dimensions The current context viewport dimensions
+	/// Compiles a single style sheet by combining all contained style sheets whose media queries match the current state of the context.
+	/// @param[in] context The current context used for evaluating media query parameters against.
 	/// @returns True when the compiled style sheet was changed, otherwise false.
 	/// @warning This operation invalidates all references to the previously compiled style sheet.
-	bool UpdateCompiledStyleSheet(float dp_ratio, Vector2f vp_dimensions);
+	bool UpdateCompiledStyleSheet(const Context* context);
 
 	/// Returns the previously compiled style sheet. 
 	StyleSheet* GetCompiledStyleSheet();

+ 24 - 0
Source/Core/Context.cpp

@@ -381,6 +381,30 @@ void Context::EnableMouseCursor(bool enable)
 	enable_cursor = enable;
 }
 
+void Context::ActivateTheme(const String& theme_name, bool activate)
+{
+	bool theme_changed = false;
+
+	if (activate)
+		theme_changed = active_themes.insert(theme_name).second;
+	else
+		theme_changed = (active_themes.erase(theme_name) > 0);
+
+	if (theme_changed)
+	{
+		for (int i = 0; i < root->GetNumChildren(true); ++i)
+		{
+			if (ElementDocument* document = root->GetChild(i)->GetOwnerDocument())
+				document->DirtyMediaQueries();
+		}
+	}
+}
+
+bool Context::IsThemeActive(const String& theme_name) const
+{
+	return active_themes.count(theme_name);
+}
+
 // Returns the first document found in the root with the given id.
 ElementDocument* Context::GetDocument(const String& id)
 {

+ 1 - 1
Source/Core/ElementDocument.cpp

@@ -235,7 +235,7 @@ void ElementDocument::DirtyMediaQueries()
 {
 	if (context && style_sheet_container)
 	{
-		const bool changed_style_sheet = style_sheet_container->UpdateCompiledStyleSheet(context->GetDensityIndependentPixelRatio(), Vector2f(context->GetDimensions()));
+		const bool changed_style_sheet = style_sheet_container->UpdateCompiledStyleSheet(context);
 
 		if (changed_style_sheet)
 		{

+ 9 - 1
Source/Core/StyleSheetContainer.cpp

@@ -27,6 +27,7 @@
  */
 
 #include "../../Include/RmlUi/Core/StyleSheetContainer.h"
+#include "../../Include/RmlUi/Core/Context.h"
 #include "../../Include/RmlUi/Core/PropertyDictionary.h"
 #include "../../Include/RmlUi/Core/Profiling.h"
 #include "../../Include/RmlUi/Core/StyleSheet.h"
@@ -51,10 +52,13 @@ bool StyleSheetContainer::LoadStyleSheetContainer(Stream* stream, int begin_line
 	return result;
 }
 
-bool StyleSheetContainer::UpdateCompiledStyleSheet(float dp_ratio, Vector2f vp_dimensions)
+bool StyleSheetContainer::UpdateCompiledStyleSheet(const Context* context)
 {
 	RMLUI_ZoneScoped;
 
+	const float dp_ratio = context->GetDensityIndependentPixelRatio();
+	const Vector2f vp_dimensions(context->GetDimensions());
+
 	Vector<int> new_active_media_block_indices;
 
 	const float font_size = DefaultComputedValues.font_size;
@@ -123,6 +127,10 @@ bool StyleSheetContainer::UpdateCompiledStyleSheet(float dp_ratio, Vector2f vp_d
 				if ((vp_dimensions.x <= vp_dimensions.y) != property.second.Get<bool>())
 					all_match = false;
 				break;
+			case MediaQueryId::Theme:
+				if (!context->IsThemeActive(property.second.Get<String>()))
+					all_match = false;
+				break;
 				// Invalid properties
 			case MediaQueryId::Invalid:
 			case MediaQueryId::NumDefinedIds:

+ 2 - 0
Source/Core/StyleSheetParser.cpp

@@ -194,6 +194,8 @@ public:
 		specification.RegisterProperty("max-resolution", "", false, false, CastId(MediaQueryId::MaxResolution)).AddParser("resolution");
 
 		specification.RegisterProperty("orientation", "", false, false, CastId(MediaQueryId::Orientation)).AddParser("keyword", "landscape, portrait");
+
+		specification.RegisterProperty("theme", "", false, false, CastId(MediaQueryId::Theme)).AddParser("string");
 	}
 
 	void SetTargetProperties(PropertyDictionary* _properties)

+ 90 - 0
Tests/Source/UnitTests/MediaQuery.cpp

@@ -163,6 +163,47 @@ static const String document_media_query3_rml = R"(
 </rml>
 )";
 
+static const String document_media_query4_rml = R"(
+<rml>
+<head>
+	<title>Test</title>
+	<link type="text/rcss" href="/assets/rml.rcss"/>
+	<style>
+		body {
+			left: 0;
+			top: 0;
+			right: 0;
+			bottom: 0;
+		}
+
+		div {
+			height: 48px;
+			width: 48px;
+			background: white;
+		}
+
+		@media (theme: big) {
+			div {
+				height: 96px;
+				width: 96px;
+			}
+		}
+
+		@media (theme: tiny) {
+			div {
+				height: 32px;
+				width: 32px;
+			}
+		}
+	</style>
+</head>
+
+<body>
+<div/>
+</body>
+</rml>
+)";
+
 
 TEST_CASE("mediaquery.basic")
 {
@@ -283,3 +324,52 @@ TEST_CASE("mediaquery.composite")
 
 	TestsShell::ShutdownShell();
 }
+
+TEST_CASE("mediaquery.theme")
+{
+	Context* context = TestsShell::GetContext();
+	REQUIRE(context);
+
+	ElementDocument* document = context->LoadDocumentFromMemory(document_media_query4_rml);
+	REQUIRE(document);
+	document->Show();
+
+	context->Update();
+	context->Render();
+
+	TestsShell::RenderLoop();
+
+	ElementList elems;
+	document->GetElementsByTagName(elems, "div");
+	CHECK(elems.size() == 1);
+
+	CHECK(elems[0]->GetBox().GetSize().x == 48.0f);
+
+	context->ActivateTheme("big", true);
+	context->Update();
+	context->Render();
+
+	CHECK(elems[0]->GetBox().GetSize().x == 96.0f);
+
+	context->ActivateTheme("big", false);
+	context->Update();
+	context->Render();
+
+	CHECK(elems[0]->GetBox().GetSize().x == 48.0f);
+
+	context->ActivateTheme("tiny", true);
+	context->Update();
+	context->Render();
+
+	CHECK(elems[0]->GetBox().GetSize().x == 32.0f);
+
+	context->ActivateTheme("big", true);
+	context->Update();
+	context->Render();
+
+	CHECK(elems[0]->GetBox().GetSize().x == 32.0f);
+
+	document->Close();
+
+	TestsShell::ShutdownShell();
+}