Browse Source

Add DataViewIf

Michael Ragazzon 6 years ago
parent
commit
cd0b24b18d

+ 22 - 1
Include/RmlUi/Core/DataBinding.h

@@ -84,16 +84,33 @@ private:
 };
 };
 
 
 
 
+class DataViewIf {
+public:
+	DataViewIf(const DataModel& model, Element* element, const String& binding_name);
+
+	inline operator bool() const {
+		return !binding_name.empty() && element;
+	}
+	bool Update(const DataModel& model);
+
+private:
+	ObserverPtr<Element> element;
+	String binding_name;
+};
+
+
 class DataViews {
 class DataViews {
 public:
 public:
 
 
 	void AddView(DataViewText&& view) {
 	void AddView(DataViewText&& view) {
 		text_views.push_back(std::move(view));
 		text_views.push_back(std::move(view));
 	}
 	}
-
 	void AddView(DataViewAttribute&& view) {
 	void AddView(DataViewAttribute&& view) {
 		attribute_views.push_back(std::move(view));
 		attribute_views.push_back(std::move(view));
 	}
 	}
+	void AddView(DataViewIf&& view) {
+		if_views.push_back(std::move(view));
+	}
 
 
 	bool Update(const DataModel& model)
 	bool Update(const DataModel& model)
 	{
 	{
@@ -102,12 +119,15 @@ public:
 			result |= view.Update(model);
 			result |= view.Update(model);
 		for (auto& view : attribute_views)
 		for (auto& view : attribute_views)
 			result |= view.Update(model);
 			result |= view.Update(model);
+		for (auto& view : if_views)
+			result |= view.Update(model);
 		return result;
 		return result;
 	}
 	}
 
 
 private:
 private:
 	std::vector<DataViewText> text_views;
 	std::vector<DataViewText> text_views;
 	std::vector<DataViewAttribute> attribute_views;
 	std::vector<DataViewAttribute> attribute_views;
+	std::vector<DataViewIf> if_views;
 };
 };
 
 
 
 
@@ -183,6 +203,7 @@ public:
 	};
 	};
 
 
 	bool GetValue(const String& name, String& out_value) const;
 	bool GetValue(const String& name, String& out_value) const;
+	bool GetValue(const String& name, bool& out_value) const;
 	bool SetValue(const String& name, const String& value) const;
 	bool SetValue(const String& name, const String& value) const;
 	bool IsWritable(const String& name) const;
 	bool IsWritable(const String& name) const;
 
 

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

@@ -166,6 +166,7 @@ form h2
 	<p class="title" style="margin-top: 1.8em;">{{hello_world}}<span style="color: blue;"> Rated: {{rating}}</span></p>
 	<p class="title" style="margin-top: 1.8em;">{{hello_world}}<span style="color: blue;"> Rated: {{rating}}</span></p>
 	<p>Data binding demo. We rate this a good old {{rating}}!</p>
 	<p>Data binding demo. We rate this a good old {{rating}}!</p>
 	<input type="range" name="rating" min="0" max="100" step="1" value="50" data-attr-value="rating"/>
 	<input type="range" name="rating" min="0" max="100" step="1" value="50" data-attr-value="rating"/>
+	<div data-if="good_rating">Thanks for the awesome rating!</div>
 </panel>
 </panel>
 <tab>Decorators</tab>
 <tab>Decorators</tab>
 <panel id="decorators">
 <panel id="decorators">

+ 3 - 0
Samples/basic/databinding/src/main.cpp

@@ -106,6 +106,7 @@ private:
 struct MyData {
 struct MyData {
 	Rml::Core::String hello_world = "Hello World!";
 	Rml::Core::String hello_world = "Hello World!";
 	int rating = 99;
 	int rating = 99;
+	int good_rating = 1;
 } my_data;
 } my_data;
 
 
 Rml::Core::DataModelHandle my_model;
 Rml::Core::DataModelHandle my_model;
@@ -120,6 +121,7 @@ bool SetupDataBinding(Rml::Core::Context* context)
 
 
 	my_model.BindData("hello_world", Type::STRING, &my_data.hello_world);
 	my_model.BindData("hello_world", Type::STRING, &my_data.hello_world);
 	my_model.BindData("rating", Type::INT, &my_data.rating, true);
 	my_model.BindData("rating", Type::INT, &my_data.rating, true);
+	my_model.BindData("good_rating", Type::INT, &my_data.good_rating);
 
 
 	return true;
 	return true;
 }
 }
@@ -133,6 +135,7 @@ std::unique_ptr<DemoWindow> demo_window;
 void GameLoop()
 void GameLoop()
 {
 {
 	my_model.UpdateControllers();
 	my_model.UpdateControllers();
+	my_data.good_rating = int(my_data.rating > 50);
 	my_model.UpdateViews();
 	my_model.UpdateViews();
 
 
 	demo_window->Update();
 	demo_window->Update();

+ 60 - 5
Source/Core/DataBinding.cpp

@@ -167,6 +167,32 @@ bool DataViewAttribute::Update(const DataModel& model)
 }
 }
 
 
 
 
+
+DataViewIf::DataViewIf(const DataModel& model, Element* element, const String& binding_name) : element(element->GetObserverPtr()), binding_name(binding_name)
+{
+	Update(model);
+}
+
+
+bool DataViewIf::Update(const DataModel& model)
+{
+	bool result = false;
+	bool value = false;
+	if (model.GetValue(binding_name, value))
+	{
+		bool is_visible = (element->GetLocalStyleProperties().count(PropertyId::Display) == 0);
+		if(is_visible != value)
+		{
+			if (value)
+				element->RemoveProperty(PropertyId::Display);
+			else
+				element->SetProperty(PropertyId::Display, Property(Style::Display::None));
+			result = true;
+		}
+	}
+	return result;
+}
+
 DataControllerAttribute::DataControllerAttribute(const DataModel& model, const String& in_attribute_name, const String& in_value_name) : attribute_name(in_attribute_name), value_name(in_value_name)
 DataControllerAttribute::DataControllerAttribute(const DataModel& model, const String& in_attribute_name, const String& in_value_name) : attribute_name(in_attribute_name), value_name(in_value_name)
 {
 {
 	String value;
 	String value;
@@ -192,7 +218,7 @@ bool DataControllerAttribute::Update(Element* element, const DataModel& model)
 
 
 bool DataModel::GetValue(const String& name, String& out_value) const
 bool DataModel::GetValue(const String& name, String& out_value) const
 {
 {
-	bool result = true;
+	bool success = true;
 
 
 	auto it = bindings.find(name);
 	auto it = bindings.find(name);
 	if (it != bindings.end())
 	if (it != bindings.end())
@@ -202,22 +228,51 @@ bool DataModel::GetValue(const String& name, String& out_value) const
 		if (binding.type == Type::STRING)
 		if (binding.type == Type::STRING)
 			out_value = *static_cast<const String*>(binding.ptr);
 			out_value = *static_cast<const String*>(binding.ptr);
 		else if (binding.type == Type::INT)
 		else if (binding.type == Type::INT)
-			result = TypeConverter<int, String>::Convert(*static_cast<const int*>(binding.ptr), out_value);
+			success = TypeConverter<int, String>::Convert(*static_cast<const int*>(binding.ptr), out_value);
 		else
 		else
 		{
 		{
 			RMLUI_ERRORMSG("TODO: Implementation for the provided binding type has not been made yet.");
 			RMLUI_ERRORMSG("TODO: Implementation for the provided binding type has not been made yet.");
-			result = false;
+			success = false;
 		}
 		}
 	}
 	}
 	else
 	else
 	{
 	{
 		Log::Message(Log::LT_WARNING, "Could not find value named '%s' in data model.", name.c_str());
 		Log::Message(Log::LT_WARNING, "Could not find value named '%s' in data model.", name.c_str());
-		result = false;
+		success = false;
 	}
 	}
 
 
-	return result;
+	return success;
 }
 }
 
 
+bool DataModel::GetValue(const String& name, bool& out_value) const
+{
+	bool success = true;
+
+	auto it = bindings.find(name);
+	if (it != bindings.end())
+	{
+		const Binding& binding = it->second;
+
+		if (binding.type == Type::STRING)
+			success = TypeConverter<String, bool>::Convert(*static_cast<const String*>(binding.ptr), out_value);
+		else if (binding.type == Type::INT)
+			success = TypeConverter<int, bool>::Convert(*static_cast<const int*>(binding.ptr), out_value);
+		else
+		{
+			RMLUI_ERRORMSG("TODO: Implementation for the provided binding type has not been made yet.");
+			success = false;
+		}
+	}
+	else
+	{
+		Log::Message(Log::LT_WARNING, "Could not find value named '%s' in data model.", name.c_str());
+		success = false;
+	}
+
+	return success;
+}
+
+
 bool DataModel::SetValue(const String& name, const String& value) const
 bool DataModel::SetValue(const String& name, const String& value) const
 {
 {
 	bool result = true;
 	bool result = true;

+ 26 - 20
Source/Core/Factory.cpp

@@ -275,27 +275,33 @@ ElementPtr Factory::InstanceElement(Element* parent, const String& instancer_nam
 						if (name.size() > 5 && name[0] == 'd' && name[1] == 'a' && name[2] == 't' && name[3] == 'a' && name[4] == '-')
 						if (name.size() > 5 && name[0] == 'd' && name[1] == 'a' && name[2] == 't' && name[3] == 'a' && name[4] == '-')
 						{
 						{
 							const size_t data_type_end = name.find('-', 5);
 							const size_t data_type_end = name.find('-', 5);
-							if (data_type_end != String::npos)
+							const size_t count = (data_type_end == String::npos ? String::npos : data_type_end - 5);
+							const String data_type = name.substr(5, count);
+							const String value_bind_name = attribute.second.Get<String>();
+
+							if (data_type == "attr")
+							{
+								const String attr_bind_name = name.substr(5 + data_type.size() + 1);
+
+								DataViewAttribute data_view(*data_model, element.get(), attr_bind_name, value_bind_name);
+								if (data_view)
+									data_model->views.AddView(std::move(data_view));
+								else
+									Log::Message(Log::LT_WARNING, "Could not add data-attr view to element '%s'.", parent->GetAddress().c_str());
+
+								DataControllerAttribute data_controller(*data_model, attr_bind_name, value_bind_name);
+								if (data_controller)
+									data_model->controllers.AddController(element.get(), std::move(data_controller));
+								else
+									Log::Message(Log::LT_WARNING, "Could not add data-attr controller to element '%s'.", parent->GetAddress().c_str());
+							}
+							else if (data_type == "if")
 							{
 							{
-								const String data_type = name.substr(5, data_type_end - 5);
-
-								if (data_type == "attr")
-								{
-									const String attr_bind_name = name.substr(5 + data_type.size() + 1);
-									const String value_bind_name = attribute.second.Get<String>();
-
-									DataViewAttribute data_view(*data_model, element.get(), attr_bind_name, value_bind_name);
-									if (data_view)
-										data_model->views.AddView(std::move(data_view));
-									else
-										Log::Message(Log::LT_WARNING, "Could not add data binding view to element '%s'.", parent->GetAddress().c_str());
-
-									DataControllerAttribute data_controller(*data_model, attr_bind_name, value_bind_name);
-									if (data_controller)
-										data_model->controllers.AddController(element.get(), std::move(data_controller));
-									else
-										Log::Message(Log::LT_WARNING, "Could not add data binding controller to element '%s'.", parent->GetAddress().c_str());
-								}
+								DataViewIf view(*data_model, element.get(), value_bind_name);
+								if (view)
+									data_model->views.AddView(std::move(view));
+								else
+									Log::Message(Log::LT_WARNING, "Could not add data-if view to element '%s'.", parent->GetAddress().c_str());
 							}
 							}
 						}
 						}
 					}
 					}