Przeglądaj źródła

Use kind-of-factory approach for widget builders

nordsoft 2 lat temu
rodzic
commit
e245dbaf9d

+ 19 - 47
client/gui/InterfaceObjectConfigurable.cpp

@@ -35,6 +35,21 @@ InterfaceObjectConfigurable::InterfaceObjectConfigurable(const JsonNode & config
 InterfaceObjectConfigurable::InterfaceObjectConfigurable(int used, Point offset):
 	CIntObject(used, offset)
 {
+	REGISTER_BUILDER("picture", &InterfaceObjectConfigurable::buildPicture);
+	REGISTER_BUILDER("image", &InterfaceObjectConfigurable::buildImage);
+	REGISTER_BUILDER("texture", &InterfaceObjectConfigurable::buildTexture);
+	REGISTER_BUILDER("animation", &InterfaceObjectConfigurable::buildAnimation);
+	REGISTER_BUILDER("label", &InterfaceObjectConfigurable::buildLabel);
+	REGISTER_BUILDER("toggleGroup", &InterfaceObjectConfigurable::buildToggleGroup);
+	REGISTER_BUILDER("toggleButton", &InterfaceObjectConfigurable::buildToggleButton);
+	REGISTER_BUILDER("button", &InterfaceObjectConfigurable::buildButton);
+	REGISTER_BUILDER("labelGroup", &InterfaceObjectConfigurable::buildLabelGroup);
+	REGISTER_BUILDER("slider", &InterfaceObjectConfigurable::buildSlider);
+}
+
+void InterfaceObjectConfigurable::registerBuilder(const std::string & type, BuilderFunction f)
+{
+	builders[type] = f;
 }
 
 void InterfaceObjectConfigurable::addCallback(const std::string & callbackName, std::function<void(int)> callback)
@@ -365,53 +380,10 @@ std::shared_ptr<CIntObject> InterfaceObjectConfigurable::buildWidget(JsonNode co
 	}
 	
 	auto type = config["type"].String();
-	if(type == "picture")
-	{
-		return buildPicture(config);
-	}
-	if(type == "image")
-	{
-		return buildImage(config);
-	}
-	if(type == "texture")
-	{
-		return buildTexture(config);
-	}
-	if(type == "animation")
-	{
-		return buildAnimation(config);
-	}
-	if(type == "label")
-	{
-		return buildLabel(config);
-	}
-	if(type == "toggleGroup")
-	{
-		return buildToggleGroup(config);
-	}
-	if(type == "toggleButton")
-	{
-		return buildToggleButton(config);
-	}
-	if(type == "button")
-	{
-		return buildButton(config);
-	}
-	if(type == "labelGroup")
-	{
-		return buildLabelGroup(config);
-	}
-	if(type == "slider")
-	{
-		return buildSlider(config);
-	}
+	auto buildIterator = builders.find(type);
+	if(buildIterator != builders.end())
+		return (buildIterator->second)(config);
 
-	logGlobal->debug("Calling custom widget building function");
-	return const_cast<InterfaceObjectConfigurable*>(this)->buildCustomWidget(config);
-}
-
-std::shared_ptr<CIntObject> InterfaceObjectConfigurable::buildCustomWidget(const JsonNode & config)
-{
-	logGlobal->error("Default custom widget builder called");
+	logGlobal->error("Builder with type %s is not registered", type);
 	return nullptr;
 }

+ 8 - 3
client/gui/InterfaceObjectConfigurable.h

@@ -25,6 +25,8 @@ class CAnimImage;
 class CShowableAnim;
 class CFilledTexture;
 
+#define REGISTER_BUILDER(type, method) registerBuilder(type, std::bind(method, this, std::placeholders::_1))
+
 class InterfaceObjectConfigurable: public CIntObject
 {
 public:
@@ -32,6 +34,10 @@ public:
 	InterfaceObjectConfigurable(const JsonNode & config, int used=0, Point offset=Point());
 
 protected:
+	
+	using BuilderFunction = std::function<std::shared_ptr<CIntObject>(const JsonNode &)>;
+	void registerBuilder(const std::string &, BuilderFunction);
+	
 	//must be called after adding callbacks
 	void init(const JsonNode & config);
 	
@@ -67,14 +73,13 @@ protected:
 	std::shared_ptr<CAnimImage> buildImage(const JsonNode &) const;
 	std::shared_ptr<CShowableAnim> buildAnimation(const JsonNode &) const;
 	std::shared_ptr<CFilledTexture> buildTexture(const JsonNode &) const;
-	
-	
+		
 	//composite widgets
-	virtual std::shared_ptr<CIntObject> buildCustomWidget(const JsonNode & config);
 	std::shared_ptr<CIntObject> buildWidget(JsonNode config) const;
 	
 private:
 	
+	std::map<std::string, BuilderFunction> builders;
 	std::map<std::string, std::shared_ptr<CIntObject>> widgets;
 	std::map<std::string, std::function<void(int)>> callbacks;
 };

+ 6 - 9
client/lobby/RandomMapTab.cpp

@@ -399,6 +399,8 @@ TemplatesDropBox::TemplatesDropBox(RandomMapTab & randomMapTab, int3 size):
 	InterfaceObjectConfigurable(LCLICK | HOVER),
 	randomMapTab(randomMapTab)
 {
+	REGISTER_BUILDER("templateListItem", &TemplatesDropBox::buildListItem);
+	
 	curItems = VLC->tplh->getTemplates();
 	vstd::erase_if(curItems, [size](const CRmgTemplate * t){return !t->matchesSize(size);});
 	curItems.insert(curItems.begin(), nullptr); //default template
@@ -422,16 +424,11 @@ TemplatesDropBox::TemplatesDropBox(RandomMapTab & randomMapTab, int3 size):
 	updateListItems();
 }
 
-std::shared_ptr<CIntObject> TemplatesDropBox::buildCustomWidget(const JsonNode & config)
+std::shared_ptr<CIntObject> TemplatesDropBox::buildListItem(const JsonNode & config)
 {
-	if(config["type"].String() == "templateListItem")
-	{
-		auto position = readPosition(config["position"]);
-		listItems.push_back(std::make_shared<ListItem>(config, *this, position));
-		return listItems.back();
-	}
-	
-	return InterfaceObjectConfigurable::buildCustomWidget(config);
+	auto position = readPosition(config["position"]);
+	listItems.push_back(std::make_shared<ListItem>(config, *this, position));
+	return listItems.back();
 }
 
 void TemplatesDropBox::sliderMove(int slidPos)

+ 1 - 3
client/lobby/RandomMapTab.h

@@ -72,10 +72,8 @@ public:
 	void clickLeft(tribool down, bool previousState) override;
 	void setTemplate(const CRmgTemplate *);
 	
-protected:
-	std::shared_ptr<CIntObject> buildCustomWidget(const JsonNode & config) override;
-	
 private:
+	std::shared_ptr<CIntObject> buildListItem(const JsonNode & config);
 	
 	void sliderMove(int slidPos);
 	void updateListItems();