Browse Source

Allow specifying a value for parameters passed to property parsers

Michael Ragazzon 3 years ago
parent
commit
a7e7d0ace8

+ 22 - 6
Source/Core/PropertyDefinition.cpp

@@ -62,8 +62,24 @@ PropertyDefinition& PropertyDefinition::AddParser(const String& parser_name, con
 	{
 		StringList parameter_list;
 		StringUtilities::ExpandString(parameter_list, parser_parameters);
-		for (size_t i = 0; i < parameter_list.size(); i++)
-			new_parser.parameters[parameter_list[i]] = (int) i;
+
+		int parameter_value = 0;
+		for (const String& parameter : parameter_list)
+		{
+			// Look for an optional parameter value such as in "normal=400".
+			const size_t i_equal = parameter.find('=');
+			if (i_equal != String::npos)
+			{
+				if (!TypeConverter<String, int>::Convert(parameter.substr(i_equal + 1), parameter_value))
+				{
+					Log::Message(Log::LT_ERROR, "Parser was added with invalid parameter '%s'.", parameter.c_str());
+					return *this;
+				}
+			}
+
+			new_parser.parameters[parameter.substr(0, i_equal)] = parameter_value;
+			parameter_value += 1;
+		}
 	}
 
 	const int parser_index = (int)parsers.size();
@@ -131,12 +147,12 @@ bool PropertyDefinition::GetValue(String& value, const Property& property) const
 					return false;
 			}
 
-			int keyword = property.value.Get< int >();
-			for (ParameterMap::const_iterator i = parsers[parser_index].parameters.begin(); i != parsers[parser_index].parameters.end(); ++i)
+			int keyword = property.value.Get<int>();
+			for (const auto& name_keyword : parsers[parser_index].parameters)
 			{
-				if ((*i).second == keyword)
+				if (name_keyword.second == keyword)
 				{
-					value = (*i).first;
+					value = name_keyword.first;
 					break;
 				}
 			}

+ 59 - 0
Tests/Source/UnitTests/PropertySpecification.cpp

@@ -32,6 +32,7 @@
 #include <RmlUi/Core/PropertyDictionary.h>
 #include <RmlUi/Core/PropertySpecification.h>
 #include <doctest.h>
+#include <limits.h>
 
 using namespace Rml;
 
@@ -97,3 +98,61 @@ TEST_CASE("PropertySpecification")
 
 	Rml::Shutdown();
 }
+
+TEST_CASE("PropertyParser.Keyword")
+{
+	TestsSystemInterface system_interface;
+	TestsRenderInterface render_interface;
+	SetRenderInterface(&render_interface);
+	SetSystemInterface(&system_interface);
+	Rml::Initialise();
+
+	PropertySpecification specification(20, 0);
+
+	auto Parse = [&](const PropertyId id, const String& test_value, int expected_value) {
+		PropertyDictionary properties;
+		const bool parse_success = specification.ParsePropertyDeclaration(properties, id, test_value);
+		if (expected_value == INT_MAX)
+		{
+			CHECK(!parse_success);
+		}
+		else
+		{
+			CHECK(parse_success);
+			CHECK(properties.GetProperties().size() == 1);
+			const int parsed_value = properties.GetProperty(id)->Get<int>();
+			CHECK_MESSAGE(parsed_value == expected_value, "Test value: ", test_value);
+
+			const String parsed_value_str = properties.GetProperty(id)->ToString();
+			CHECK(parsed_value_str == test_value);
+		}
+	};
+
+	const PropertyId simple = specification.RegisterProperty("simple", "", false, false).AddParser("keyword", "a, b, c").GetId();
+	Parse(simple, "a", 0);
+	Parse(simple, "b", 1);
+	Parse(simple, "c", 2);
+	Parse(simple, "d", INT_MAX);
+	Parse(simple, "0", INT_MAX);
+	Parse(simple, "2", INT_MAX);
+
+	const PropertyId values = specification.RegisterProperty("values", "", false, false).AddParser("keyword", "a=50, b, c=-200").GetId();
+	Parse(values, "a", 50);
+	Parse(values, "b", 51);
+	Parse(values, "c", -200);
+	Parse(values, "d", INT_MAX);
+	Parse(values, "0", INT_MAX);
+	Parse(values, "2", INT_MAX);
+
+	const PropertyId numbers =
+		specification.RegisterProperty("numbers", "", false, false).AddParser("keyword", "a=10, b=20, c=30").AddParser("number").GetId();
+	Parse(numbers, "a", 10);
+	Parse(numbers, "b", 20);
+	Parse(numbers, "c", 30);
+	Parse(numbers, "d", INT_MAX);
+	Parse(numbers, "0", 0);
+	Parse(numbers, "2", 2);
+	Parse(numbers, "20", 20);
+
+	Rml::Shutdown();
+}