Browse Source

Implement it_index in data view for. Rename some functions.

Michael Ragazzon 5 years ago
parent
commit
7e3bb8942f

+ 5 - 5
Include/RmlUi/Core/DataTypeRegister.h

@@ -54,9 +54,9 @@ public:
 	StructHandle(DataTypeRegister* type_register, StructDefinition* struct_definition) : type_register(type_register), struct_definition(struct_definition) {}
 	StructHandle(DataTypeRegister* type_register, StructDefinition* struct_definition) : type_register(type_register), struct_definition(struct_definition) {}
 	
 	
 	template <typename MemberType>
 	template <typename MemberType>
-	StructHandle<Object>& AddMember(const String& name, MemberType Object::* member_ptr);
+	StructHandle<Object>& RegisterMember(const String& name, MemberType Object::* member_ptr);
 
 
-	StructHandle<Object>& AddMemberFunc(const String& name, MemberGetFunc<Object> get_func, MemberSetFunc<Object> set_func = nullptr);
+	StructHandle<Object>& RegisterMemberFunc(const String& name, MemberGetFunc<Object> get_func, MemberSetFunc<Object> set_func = nullptr);
 
 
 	explicit operator bool() const {
 	explicit operator bool() const {
 		return type_register && struct_definition;
 		return type_register && struct_definition;
@@ -191,13 +191,13 @@ private:
 
 
 template<typename Object>
 template<typename Object>
 template<typename MemberType>
 template<typename MemberType>
-inline StructHandle<Object>& StructHandle<Object>::AddMember(const String& name, MemberType Object::* member_ptr) {
+inline StructHandle<Object>& StructHandle<Object>::RegisterMember(const String& name, MemberType Object::* member_ptr) {
 	VariableDefinition* member_type = type_register->GetOrAddScalar<MemberType>();
 	VariableDefinition* member_type = type_register->GetOrAddScalar<MemberType>();
-	struct_definition->AddMember(name, std::make_unique<StructMemberDefault<Object, MemberType>>(member_type, member_ptr));
+	struct_definition->AddMember(name, std::make_unique<StructMemberObject<Object, MemberType>>(member_type, member_ptr));
 	return *this;
 	return *this;
 }
 }
 template<typename Object>
 template<typename Object>
-inline StructHandle<Object>& StructHandle<Object>::AddMemberFunc(const String& name, MemberGetFunc<Object> get_func, MemberSetFunc<Object> set_func) {
+inline StructHandle<Object>& StructHandle<Object>::RegisterMemberFunc(const String& name, MemberGetFunc<Object> get_func, MemberSetFunc<Object> set_func) {
 	VariableDefinition* definition = type_register->RegisterMemberFunc<Object>(get_func, set_func);
 	VariableDefinition* definition = type_register->RegisterMemberFunc<Object>(get_func, set_func);
 	struct_definition->AddMember(name, std::make_unique<StructMemberFunc>(definition));
 	struct_definition->AddMember(name, std::make_unique<StructMemberFunc>(definition));
 	return *this;
 	return *this;

+ 5 - 13
Include/RmlUi/Core/DataVariable.h

@@ -82,6 +82,8 @@ private:
 };
 };
 
 
 
 
+RMLUICORE_API DataVariable MakeLiteralIntVariable(int value);
+
 
 
 template<typename T>
 template<typename T>
 class ScalarDefinition final : public VariableDefinition {
 class ScalarDefinition final : public VariableDefinition {
@@ -134,8 +136,6 @@ public:
 		return int(static_cast<Container*>(ptr)->size());
 		return int(static_cast<Container*>(ptr)->size());
 	}
 	}
 
 
-	DataVariable MakeSizeVariable(int container_size);
-
 protected:
 protected:
 	DataVariable Child(void* void_ptr, const DataAddressEntry& address) override
 	DataVariable Child(void* void_ptr, const DataAddressEntry& address) override
 	{
 	{
@@ -146,7 +146,7 @@ protected:
 		if (index < 0 || index >= container_size)
 		if (index < 0 || index >= container_size)
 		{
 		{
 			if (address.name == "size")
 			if (address.name == "size")
-				return MakeSizeVariable(container_size);
+				return MakeLiteralIntVariable(container_size);
 
 
 			Log::Message(Log::LT_WARNING, "Data array index out of bounds.");
 			Log::Message(Log::LT_WARNING, "Data array index out of bounds.");
 			return DataVariable();
 			return DataVariable();
@@ -178,9 +178,9 @@ private:
 };
 };
 
 
 template <typename Object, typename MemberType>
 template <typename Object, typename MemberType>
-class StructMemberDefault final : public StructMember {
+class StructMemberObject final : public StructMember {
 public:
 public:
-	StructMemberDefault(VariableDefinition* definition, MemberType Object::* member_ptr) : StructMember(definition), member_ptr(member_ptr) {}
+	StructMemberObject(VariableDefinition* definition, MemberType Object::* member_ptr) : StructMember(definition), member_ptr(member_ptr) {}
 
 
 	void* GetPointer(void* base_ptr) override {
 	void* GetPointer(void* base_ptr) override {
 		return &(static_cast<Object*>(base_ptr)->*member_ptr);
 		return &(static_cast<Object*>(base_ptr)->*member_ptr);
@@ -263,14 +263,6 @@ private:
 	MemberSetFunc<T> set;
 	MemberSetFunc<T> set;
 };
 };
 
 
-
-RMLUICORE_API VariableDefinition* GetArraySizeDefinition();
-
-template<typename Container>
-inline DataVariable ArrayDefinition<Container>::MakeSizeVariable(int container_size) {
-	return DataVariable(GetArraySizeDefinition(), reinterpret_cast<void*>(static_cast<intptr_t>(container_size)));
-}
-
 }
 }
 }
 }
 
 

+ 5 - 4
Samples/basic/databinding/data/databinding.rml

@@ -198,7 +198,7 @@ form h2
 	</p>
 	</p>
 	<div data-for="invader : invaders">
 	<div data-for="invader : invaders">
 		<h1 data-class-red="rating < 30" data-class-big="rating == 0">{{invader.name}}</h1>
 		<h1 data-class-red="rating < 30" data-class-big="rating == 0">{{invader.name}}</h1>
-		<p>Invader {{'it_index '+ 1}} of {{ invaders.size }}.</p>
+		<p>Invader {{it_index + 1}} of {{ invaders.size }}.</p>
 		<img data-attr-sprite="invader.sprite" data-style-image-color="invader.color"/>
 		<img data-attr-sprite="invader.sprite" data-style-image-color="invader.color"/>
 		<p>
 		<p>
 			Damage: <span data-for="invader.damage"> {{it}} </span>
 			Damage: <span data-for="invader.damage"> {{it}} </span>
@@ -207,17 +207,18 @@ form h2
 </panel>
 </panel>
 <tab>Invaders</tab>
 <tab>Invaders</tab>
 <panel id="invaders" data-model="invaders">
 <panel id="invaders" data-model="invaders">
-	<p>Incoming invaders:
+	<p>
+		Incoming invaders:
 		<input type="range" name="rating" min="0" max="20" step="5" data-value="incoming_invaders_rate"/>
 		<input type="range" name="rating" min="0" max="20" step="5" data-value="incoming_invaders_rate"/>
 		{{ incoming_invaders_rate }} / min.
 		{{ incoming_invaders_rate }} / min.
 	</p>
 	</p>
 	<button data-event-click="launch_weapons">Launch weapons!</button>
 	<button data-event-click="launch_weapons">Launch weapons!</button>
 	<div data-for="invader : invaders">
 	<div data-for="invader : invaders">
 		<h1 data-class-red="invader.danger_rating > 70">{{invader.name}}</h1>
 		<h1 data-class-red="invader.danger_rating > 70">{{invader.name}}</h1>
-		<p>Invader {{'it_index' + 1}} of {{ invaders.size }}.</p>
+		<p>Invader {{it_index + 1}} of {{ invaders.size }}.</p>
 		<img data-attr-sprite="invader.sprite" data-style-image-color="invader.color"/>
 		<img data-attr-sprite="invader.sprite" data-style-image-color="invader.color"/>
 		<p>
 		<p>
-			Damage per shot: <span data-for="invader.damage"> {{it}} </span>
+			Shots fired (damage): <span data-for="invader.damage"> {{it}} </span>
 		</p>
 		</p>
 	</div>
 	</div>
 	<h1 data-if="invaders.size == 0">It's all safe and sound, sir!</h1>
 	<h1 data-if="invaders.size == 0">It's all safe and sound, sir!</h1>

+ 17 - 11
Samples/basic/databinding/src/main.cpp

@@ -114,6 +114,13 @@ struct Invader {
 	void GetColor(Rml::Core::Variant& variant) {
 	void GetColor(Rml::Core::Variant& variant) {
 		variant = "rgba(" + Rml::Core::ToString(color) + ')';
 		variant = "rgba(" + Rml::Core::ToString(color) + ')';
 	}
 	}
+	void SetColor(const Rml::Core::Variant& variant) {
+		using namespace Rml::Core;
+		String str = variant.Get<String>();
+		if (str.size() > 6)
+			str = str.substr(5, str.size() - 6);
+		color = Rml::Core::FromString<Colourb>(variant.Get<String>());
+	}
 };
 };
 
 
 
 
@@ -156,7 +163,7 @@ void HasGoodRating(Rml::Core::Variant& variant) {
 
 
 struct InvaderModelData {
 struct InvaderModelData {
 	double time_last_invader_spawn = 0;
 	double time_last_invader_spawn = 0;
-	double time_last_invader_shot = 0;
+	double time_last_weapons_launched = 0;
 
 
 	float incoming_invaders_rate = 10; // Per minute
 	float incoming_invaders_rate = 10; // Per minute
 
 
@@ -178,7 +185,6 @@ Rml::Core::DataModelHandle invaders_model, my_model;
 
 
 bool SetupDataBinding(Rml::Core::Context* context)
 bool SetupDataBinding(Rml::Core::Context* context)
 {
 {
-
 	// The invaders model
 	// The invaders model
 	{
 	{
 		Rml::Core::DataModelConstructor constructor = context->CreateDataModel("invaders");
 		Rml::Core::DataModelConstructor constructor = context->CreateDataModel("invaders");
@@ -191,11 +197,11 @@ bool SetupDataBinding(Rml::Core::Context* context)
 
 
 		if (auto invader_handle = constructor.RegisterStruct<Invader>())
 		if (auto invader_handle = constructor.RegisterStruct<Invader>())
 		{
 		{
-			invader_handle.AddMember("name", &Invader::name);
-			invader_handle.AddMember("sprite", &Invader::sprite);
-			invader_handle.AddMember("damage", &Invader::damage);
-			invader_handle.AddMember("danger_rating", &Invader::danger_rating);
-			invader_handle.AddMemberFunc("color", &Invader::GetColor);
+			invader_handle.RegisterMember("name", &Invader::name);
+			invader_handle.RegisterMember("sprite", &Invader::sprite);
+			invader_handle.RegisterMember("damage", &Invader::damage);
+			invader_handle.RegisterMember("danger_rating", &Invader::danger_rating);
+			invader_handle.RegisterMemberFunc("color", &Invader::GetColor, &Invader::SetColor);
 		}
 		}
 
 
 		constructor.RegisterArray<std::vector<Invader>>();
 		constructor.RegisterArray<std::vector<Invader>>();
@@ -230,8 +236,8 @@ bool SetupDataBinding(Rml::Core::Context* context)
 
 
 		if (auto vec2_handle = constructor.RegisterStruct<Rml::Core::Vector2f>())
 		if (auto vec2_handle = constructor.RegisterStruct<Rml::Core::Vector2f>())
 		{
 		{
-			vec2_handle.AddMember("x", &Rml::Core::Vector2f::x);
-			vec2_handle.AddMember("y", &Rml::Core::Vector2f::y);
+			vec2_handle.RegisterMember("x", &Rml::Core::Vector2f::x);
+			vec2_handle.RegisterMember("y", &Rml::Core::Vector2f::y);
 		}
 		}
 
 
 		constructor.RegisterArray<std::vector<Rml::Core::Vector2f>>();
 		constructor.RegisterArray<std::vector<Rml::Core::Vector2f>>();
@@ -290,7 +296,7 @@ void GameLoop()
 		invaders_data.time_last_invader_spawn = t;
 		invaders_data.time_last_invader_spawn = t;
 	}
 	}
 
 
-	if (t >= invaders_data.time_last_invader_shot + 1.0)
+	if (t >= invaders_data.time_last_weapons_launched + 1.0)
 	{
 	{
 		if (!invaders_data.invaders.empty())
 		if (!invaders_data.invaders.empty())
 		{
 		{
@@ -301,7 +307,7 @@ void GameLoop()
 
 
 			invaders_model.DirtyVariable("invaders");
 			invaders_model.DirtyVariable("invaders");
 		}
 		}
-		invaders_data.time_last_invader_shot = t;
+		invaders_data.time_last_weapons_launched = t;
 	}
 	}
 
 
 	my_model.Update();
 	my_model.Update();

+ 24 - 16
Source/Core/DataModel.cpp

@@ -77,7 +77,7 @@ static DataAddress ParseAddress(const String& address_str)
 // Returns an error string on error, or nullptr on success.
 // Returns an error string on error, or nullptr on success.
 static const char* LegalVariableName(const String& name)
 static const char* LegalVariableName(const String& name)
 {
 {
-	static SmallUnorderedSet<String> reserved_names{ "it", "ev", "true", "false", "size" };
+	static SmallUnorderedSet<String> reserved_names{ "it", "ev", "true", "false", "size", "literal" };
 	
 	
 	if (name.empty())
 	if (name.empty())
 		return "Name cannot be empty.";
 		return "Name cannot be empty.";
@@ -269,23 +269,31 @@ DataAddress DataModel::ResolveAddress(const String& address_str, Element* elemen
 
 
 DataVariable DataModel::GetVariable(const DataAddress& address) const
 DataVariable DataModel::GetVariable(const DataAddress& address) const
 {
 {
-	if (address.empty() || address.front().name.empty())
+	if (address.empty())
 		return DataVariable();
 		return DataVariable();
 
 
 	auto it = variables.find(address.front().name);
 	auto it = variables.find(address.front().name);
-	if (it == variables.end())
-		return DataVariable();
+	if (it != variables.end())
+	{
+		DataVariable variable = it->second;
 
 
-	DataVariable variable = it->second;
+		for (int i = 1; i < (int)address.size() && variable; i++)
+		{
+			variable = variable.Child(address[i]);
+			if (!variable)
+				return DataVariable();
+		}
+
+		return variable;
+	}
 
 
-	for (int i = 1; i < (int)address.size() && variable; i++)
+	if (address[0].name == "literal")
 	{
 	{
-		variable = variable.Child(address[i]);
-		if (!variable)
-			return DataVariable();
+		if (address.size() > 2 && address[1].name == "int")
+			return MakeLiteralIntVariable(address[2].index);
 	}
 	}
 
 
-	return variable;
+	return DataVariable();
 }
 }
 
 
 const DataEventFunc* DataModel::GetEventCallback(const String& name)
 const DataEventFunc* DataModel::GetEventCallback(const String& name)
@@ -375,18 +383,18 @@ static struct TestDataVariables {
 
 
 			if (auto fun_handle = handle.RegisterStruct<FunData>())
 			if (auto fun_handle = handle.RegisterStruct<FunData>())
 			{
 			{
-				fun_handle.AddMember("i", &FunData::i);
-				fun_handle.AddMember("x", &FunData::x);
-				fun_handle.AddMember("magic", &FunData::magic);
+				fun_handle.RegisterMember("i", &FunData::i);
+				fun_handle.RegisterMember("x", &FunData::x);
+				fun_handle.RegisterMember("magic", &FunData::magic);
 			}
 			}
 
 
 			handle.RegisterArray<FunArray>();
 			handle.RegisterArray<FunArray>();
 
 
 			if (auto smart_handle = handle.RegisterStruct<SmartData>())
 			if (auto smart_handle = handle.RegisterStruct<SmartData>())
 			{
 			{
-				smart_handle.AddMember("valid", &SmartData::valid);
-				smart_handle.AddMember("fun", &SmartData::fun);
-				smart_handle.AddMember("more_fun", &SmartData::more_fun);
+				smart_handle.RegisterMember("valid", &SmartData::valid);
+				smart_handle.RegisterMember("fun", &SmartData::fun);
+				smart_handle.RegisterMember("more_fun", &SmartData::more_fun);
 			}
 			}
 		}
 		}
 
 

+ 3 - 3
Source/Core/DataParser.cpp

@@ -990,7 +990,7 @@ struct TestParser {
 		result = TestExpression("true != false",  "1");
 		result = TestExpression("true != false",  "1");
 		result = TestExpression("true",           "1");
 		result = TestExpression("true",           "1");
 
 
-		result = TestExpression("true || false ? (true && 3==1+2 ? 'Absolutely!' : 'well..') : 'no'",  "Absolutely!");
+		result = TestExpression("true || false ? true && 3==1+2 ? 'Absolutely!' : 'well..' : 'no'",  "Absolutely!");
 		result = TestExpression(R"('It\'s a fit')",  R"(It's a fit)");
 		result = TestExpression(R"('It\'s a fit')",  R"(It's a fit)");
 		result = TestExpression("2 * 2",           "4");
 		result = TestExpression("2 * 2",           "4");
 		result = TestExpression("50000 / 1500",    "33.333");
 		result = TestExpression("50000 / 1500",    "33.333");
@@ -999,7 +999,7 @@ struct TestParser {
 		result = TestExpression("2*(-2)/4",        "-1");
 		result = TestExpression("2*(-2)/4",        "-1");
 		result = TestExpression("5.2 + 19 + 'px'", "24.2px");
 		result = TestExpression("5.2 + 19 + 'px'", "24.2px");
 
 
-		result = TestExpression("radius + 'm'",    "8.7m");
+		result = TestExpression("(radius | format(2)) + 'm'",    "8.70m");
 		result = TestExpression("radius < 10.5 ? 'smaller' : 'larger'",  "smaller");
 		result = TestExpression("radius < 10.5 ? 'smaller' : 'larger'",  "smaller");
 		TestAssignment("radius = 15");
 		TestAssignment("radius = 15");
 		result = TestExpression("radius < 10.5 ? 'smaller' : 'larger'",  "larger");
 		result = TestExpression("radius < 10.5 ? 'smaller' : 'larger'",  "larger");
@@ -1018,7 +1018,7 @@ struct TestParser {
 		result = TestExpression("3.62345 | format(10, true)", "3.62345");
 		result = TestExpression("3.62345 | format(10, true)", "3.62345");
 		result = TestExpression("3.62345 | round | format(2)", "4.00");
 		result = TestExpression("3.62345 | round | format(2)", "4.00");
 		result = TestExpression("3.0001 | format(2, false)", "3.00");
 		result = TestExpression("3.0001 | format(2, false)", "3.00");
-		result = TestExpression("3.0001 | format(2, true)"), "3";
+		result = TestExpression("3.0001 | format(2, true)", "3");
 
 
 		result = TestExpression("0.2 + 3.42345 | round", "4");
 		result = TestExpression("0.2 + 3.42345 | round", "4");
 		result = TestExpression("(3.42345 | round) + 0.2", "3.2");
 		result = TestExpression("(3.42345 | round) + 0.2", "3.2");

+ 5 - 5
Source/Core/DataVariable.cpp

@@ -70,9 +70,9 @@ DataVariable VariableDefinition::Child(void* ptr, const DataAddressEntry& addres
     return DataVariable();
     return DataVariable();
 }
 }
 
 
-class ArraySizeDefinition final : public VariableDefinition {
+class LiteralIntDefinition final : public VariableDefinition {
 public:
 public:
-    ArraySizeDefinition() : VariableDefinition(DataVariableType::Scalar) {}
+    LiteralIntDefinition() : VariableDefinition(DataVariableType::Scalar) {}
 
 
     bool Get(void* ptr, Variant& variant) override
     bool Get(void* ptr, Variant& variant) override
     {
     {
@@ -81,10 +81,10 @@ public:
     }
     }
 };
 };
 
 
-VariableDefinition* GetArraySizeDefinition()
+DataVariable MakeLiteralIntVariable(int value)
 {
 {
-    static ArraySizeDefinition size_definition;
-    return &size_definition;
+    static LiteralIntDefinition literal_int_definition;
+    return DataVariable(&literal_int_definition, reinterpret_cast<void*>(static_cast<intptr_t>(value)));
 }
 }
 
 
 }
 }

+ 29 - 2
Source/Core/DataViewDefault.cpp

@@ -366,10 +366,32 @@ bool DataViewFor::Initialize(DataModel& model, Element* element, const String& i
 	}
 	}
 
 
 	if (iterator_container_pair.size() == 2)
 	if (iterator_container_pair.size() == 2)
-		iterator_name = iterator_container_pair.front();
-	else
+	{
+		StringList iterator_index_pair;
+		StringUtilities::ExpandString(iterator_index_pair, iterator_container_pair.front(), ',');
+
+		if (iterator_index_pair.empty())
+		{
+			Log::Message(Log::LT_WARNING, "Invalid syntax in data-for '%s'", in_expression.c_str());
+			return false;
+		}
+		else if (iterator_index_pair.size() == 1)
+		{
+			iterator_name = iterator_index_pair.front();
+		}
+		else if (iterator_index_pair.size() == 2)
+		{
+			iterator_name = iterator_index_pair.front();
+			iterator_index_name = iterator_index_pair.back();
+		}
+	}
+
+	if (iterator_name.empty())
 		iterator_name = "it";
 		iterator_name = "it";
 
 
+	if (iterator_index_name.empty())
+		iterator_index_name = "it_index";
+
 	const String& container_name = iterator_container_pair.back();
 	const String& container_name = iterator_container_pair.back();
 
 
 	container_address = model.ResolveAddress(container_name, element);
 	container_address = model.ResolveAddress(container_name, element);
@@ -404,7 +426,12 @@ bool DataViewFor::Update(DataModel& model)
 			iterator_address = container_address;
 			iterator_address = container_address;
 			iterator_address.push_back(DataAddressEntry(i));
 			iterator_address.push_back(DataAddressEntry(i));
 
 
+			DataAddress iterator_index_address = {
+				{"literal"}, {"int"}, {i}
+			};
+
 			model.InsertAlias(new_element_ptr.get(), iterator_name, std::move(iterator_address));
 			model.InsertAlias(new_element_ptr.get(), iterator_name, std::move(iterator_address));
+			model.InsertAlias(new_element_ptr.get(), iterator_index_name, std::move(iterator_index_address));
 
 
 			Element* new_element = element->GetParentNode()->InsertBefore(std::move(new_element_ptr), element);
 			Element* new_element = element->GetParentNode()->InsertBefore(std::move(new_element_ptr), element);
 			elements.push_back(new_element);
 			elements.push_back(new_element);

+ 1 - 0
Source/Core/DataViewDefault.h

@@ -154,6 +154,7 @@ protected:
 private:
 private:
 	DataAddress container_address;
 	DataAddress container_address;
 	String iterator_name;
 	String iterator_name;
+	String iterator_index_name;
 	String rml_contents;
 	String rml_contents;
 	ElementAttributes attributes;
 	ElementAttributes attributes;