mirror of
				https://github.com/luanti-org/luanti.git
				synced 2025-10-31 15:35:21 +01:00 
			
		
		
		
	Add styles to most elements
This commit is contained in:
		| @@ -55,17 +55,17 @@ with this program; if not, write to the Free Software Foundation, Inc., | ||||
| RenderingEngine *RenderingEngine::s_singleton = nullptr; | ||||
| 
 | ||||
| 
 | ||||
| static gui::GUISkin* createSkin(gui::IGUIEnvironment *environment, | ||||
| 								gui::EGUI_SKIN_TYPE type, video::IVideoDriver *driver) | ||||
| static gui::GUISkin *createSkin(gui::IGUIEnvironment *environment, | ||||
| 		gui::EGUI_SKIN_TYPE type, video::IVideoDriver *driver) | ||||
| { | ||||
| 	gui::GUISkin* skin = new gui::GUISkin(type, driver); | ||||
| 	gui::GUISkin *skin = new gui::GUISkin(type, driver); | ||||
| 
 | ||||
| 	gui::IGUIFont* builtinfont = environment->getBuiltInFont(); | ||||
| 	gui::IGUIFontBitmap* bitfont = 0; | ||||
| 	gui::IGUIFont *builtinfont = environment->getBuiltInFont(); | ||||
| 	gui::IGUIFontBitmap *bitfont = nullptr; | ||||
| 	if (builtinfont && builtinfont->getType() == gui::EGFT_BITMAP) | ||||
| 		bitfont = (gui::IGUIFontBitmap*)builtinfont; | ||||
| 
 | ||||
| 	gui::IGUISpriteBank* bank = 0; | ||||
| 	gui::IGUISpriteBank *bank = 0; | ||||
| 	skin->setFont(builtinfont); | ||||
| 
 | ||||
| 	if (bitfont) | ||||
| @@ -102,7 +102,7 @@ RenderingEngine::RenderingEngine(IEventReceiver *receiver) | ||||
| 	u32 i; | ||||
| 	for (i = 0; i != drivers.size(); i++) { | ||||
| 		if (!strcasecmp(driverstring.c_str(), | ||||
| 				    RenderingEngine::getVideoDriverName(drivers[i]))) { | ||||
| 				RenderingEngine::getVideoDriverName(drivers[i]))) { | ||||
| 			driverType = drivers[i]; | ||||
| 			break; | ||||
| 		} | ||||
| @@ -139,7 +139,7 @@ RenderingEngine::RenderingEngine(IEventReceiver *receiver) | ||||
| 	s_singleton = this; | ||||
| 
 | ||||
| 	auto skin = createSkin(m_device->getGUIEnvironment(), | ||||
| 						   gui::EGST_WINDOWS_METALLIC, driver); | ||||
| 			gui::EGST_WINDOWS_METALLIC, driver); | ||||
| 	m_device->getGUIEnvironment()->setSkin(skin); | ||||
| 	skin->drop(); | ||||
| } | ||||
|   | ||||
| @@ -18,85 +18,118 @@ with this program; if not, write to the Free Software Foundation, Inc., | ||||
| */ | ||||
| 
 | ||||
| #include "irrlichttypes_extrabloated.h" | ||||
| #include <array> | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| 
 | ||||
| class StyleSpec | ||||
| { | ||||
| public: | ||||
| 	enum Property { | ||||
| 		NONE = 0, | ||||
| 	enum Property | ||||
| 	{ | ||||
| 		TEXTCOLOR, | ||||
| 		BGCOLOR, | ||||
| 		NUM_PROPERTIES | ||||
| 		NOCLIP, | ||||
| 		BORDER, | ||||
| 		BGIMG, | ||||
| 		BGIMG_PRESSED, | ||||
| 		ALPHA, | ||||
| 		NUM_PROPERTIES, | ||||
| 		NONE | ||||
| 	}; | ||||
| 
 | ||||
| private: | ||||
| 	std::unordered_map<Property, std::string> properties; | ||||
| 	std::array<bool, NUM_PROPERTIES> property_set; | ||||
| 	std::array<std::string, NUM_PROPERTIES> properties; | ||||
| 
 | ||||
| public: | ||||
| 	static Property GetPropertyByName(const std::string &name) { | ||||
| 	static Property GetPropertyByName(const std::string &name) | ||||
| 	{ | ||||
| 		if (name == "textcolor") { | ||||
| 			return TEXTCOLOR; | ||||
| 		} else if (name == "bgcolor") { | ||||
| 			return BGCOLOR; | ||||
| 		} else if (name == "noclip") { | ||||
| 			return NOCLIP; | ||||
| 		} else if (name == "border") { | ||||
| 			return BORDER; | ||||
| 		} else if (name == "bgimg") { | ||||
| 			return BGIMG; | ||||
| 		} else if (name == "bgimg_pressed") { | ||||
| 			return BGIMG_PRESSED; | ||||
| 		} else if (name == "alpha") { | ||||
| 			return ALPHA; | ||||
| 		} else { | ||||
| 			return NONE; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	std::string get(Property prop, std::string def) const { | ||||
| 		auto it = properties.find(prop); | ||||
| 		if (it == properties.end()) { | ||||
| 	std::string get(Property prop, std::string def) const | ||||
| 	{ | ||||
| 		const auto &val = properties[prop]; | ||||
| 		return val.empty() ? def : val; | ||||
| 	} | ||||
| 
 | ||||
| 	void set(Property prop, const std::string &value) | ||||
| 	{ | ||||
| 		properties[prop] = value; | ||||
| 		property_set[prop] = true; | ||||
| 	} | ||||
| 
 | ||||
| 	video::SColor getColor(Property prop, video::SColor def) const | ||||
| 	{ | ||||
| 		const auto &val = properties[prop]; | ||||
| 		if (val.empty()) { | ||||
| 			return def; | ||||
| 		} | ||||
| 
 | ||||
| 		return it->second; | ||||
| 	} | ||||
| 
 | ||||
| 	void set(Property prop, std::string value) { | ||||
| 		properties[prop] = std::move(value); | ||||
| 	} | ||||
| 
 | ||||
| 	video::SColor getColor(Property prop, video::SColor def) const { | ||||
| 		auto it = properties.find(prop); | ||||
| 		if (it == properties.end()) { | ||||
| 			return def; | ||||
| 		} | ||||
| 
 | ||||
| 		parseColorString(it->second, def, false, 0xFF); | ||||
| 		parseColorString(val, def, false, 0xFF); | ||||
| 		return def; | ||||
| 	} | ||||
| 
 | ||||
| 	video::SColor getColor(Property prop) const { | ||||
| 		auto it = properties.find(prop); | ||||
| 		FATAL_ERROR_IF(it == properties.end(), "Unexpected missing property"); | ||||
| 	video::SColor getColor(Property prop) const | ||||
| 	{ | ||||
| 		const auto &val = properties[prop]; | ||||
| 		FATAL_ERROR_IF(val.empty(), "Unexpected missing property"); | ||||
| 
 | ||||
| 		video::SColor color; | ||||
| 		parseColorString(it->second, color, false, 0xFF); | ||||
| 		parseColorString(val, color, false, 0xFF); | ||||
| 		return color; | ||||
| 	} | ||||
| 
 | ||||
| 	bool hasProperty(Property prop) const { | ||||
| 		return properties.find(prop) != properties.end(); | ||||
| 	bool getBool(Property prop, bool def) const | ||||
| 	{ | ||||
| 		const auto &val = properties[prop]; | ||||
| 		if (val.empty()) { | ||||
| 			return def; | ||||
| 		} | ||||
| 
 | ||||
| 		return is_yes(val); | ||||
| 	} | ||||
| 
 | ||||
| 	StyleSpec &operator|=(const StyleSpec &other) { | ||||
| 		for (size_t i = 1; i < NUM_PROPERTIES; i++) { | ||||
| 	inline bool isNotDefault(Property prop) const | ||||
| 	{ | ||||
| 		return !properties[prop].empty(); | ||||
| 	} | ||||
| 
 | ||||
| 	inline bool hasProperty(Property prop) const { return property_set[prop]; } | ||||
| 
 | ||||
| 	StyleSpec &operator|=(const StyleSpec &other) | ||||
| 	{ | ||||
| 		for (size_t i = 0; i < NUM_PROPERTIES; i++) { | ||||
| 			auto prop = (Property)i; | ||||
| 			if (other.hasProperty(prop)) { | ||||
| 				properties[prop] = other.get(prop, ""); | ||||
| 				set(prop, other.get(prop, "")); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		return *this; | ||||
| 	} | ||||
| 
 | ||||
| 	StyleSpec operator|(const StyleSpec &other) const { | ||||
| 	StyleSpec operator|(const StyleSpec &other) const | ||||
| 	{ | ||||
| 		StyleSpec newspec = *this; | ||||
| 		newspec |= other; | ||||
| 		return newspec; | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
|   | ||||
| @@ -500,6 +500,9 @@ void GUIFormSpecMenu::parseCheckbox(parserData* data, const std::string &element | ||||
| 		gui::IGUICheckBox* e = Environment->addCheckBox(fselected, rect, this, | ||||
| 					spec.fid, spec.flabel.c_str()); | ||||
| 
 | ||||
| 		auto style = getStyleForElement("checkbox", name); | ||||
| 		e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false)); | ||||
| 
 | ||||
| 		if (spec.fname == data->focused_fieldname) { | ||||
| 			Environment->setFocus(e); | ||||
| 		} | ||||
| @@ -556,6 +559,9 @@ void GUIFormSpecMenu::parseScrollBar(parserData* data, const std::string &elemen | ||||
| 		gui::IGUIScrollBar* e = | ||||
| 				Environment->addScrollBar(is_horizontal,rect,this,spec.fid); | ||||
| 
 | ||||
| 		auto style = getStyleForElement("scrollbar", name); | ||||
| 		e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false)); | ||||
| 
 | ||||
| 		e->setMax(1000); | ||||
| 		e->setMin(0); | ||||
| 		e->setPos(stoi(parts[4])); | ||||
| @@ -702,15 +708,35 @@ void GUIFormSpecMenu::parseButton(parserData* data, const std::string &element, | ||||
| 
 | ||||
| 		GUIButton *e = GUIButton::addButton(Environment, rect, this, spec.fid, spec.flabel.c_str()); | ||||
| 
 | ||||
| 		auto style = getThemeForElement(type, name); | ||||
| 		if (style.hasProperty(StyleSpec::BGCOLOR)) { | ||||
| 		auto style = getStyleForElement(type, name, (type != "button") ? "button" : ""); | ||||
| 		if (style.isNotDefault(StyleSpec::BGCOLOR)) { | ||||
| 			e->setColor(style.getColor(StyleSpec::BGCOLOR)); | ||||
| 		} | ||||
| 		if (style.hasProperty(StyleSpec::TEXTCOLOR)) { | ||||
| 		if (style.isNotDefault(StyleSpec::TEXTCOLOR)) { | ||||
| 			e->setOverrideColor(style.getColor(StyleSpec::TEXTCOLOR)); | ||||
| 		} | ||||
| 		e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false)); | ||||
| 		e->setDrawBorder(style.getBool(StyleSpec::BORDER, true)); | ||||
| 
 | ||||
| //		e->setSprite();
 | ||||
| 		if (style.isNotDefault(StyleSpec::BGIMG)) { | ||||
| 			std::string image_name = style.get(StyleSpec::BGIMG, ""); | ||||
| 			std::string pressed_image_name = style.get(StyleSpec::BGIMG_PRESSED, ""); | ||||
| 
 | ||||
| 			video::ITexture *texture = 0; | ||||
| 			video::ITexture *pressed_texture = 0; | ||||
| 			texture = m_tsrc->getTexture(image_name); | ||||
| 			if (!pressed_image_name.empty()) | ||||
| 				pressed_texture = m_tsrc->getTexture(pressed_image_name); | ||||
| 			else | ||||
| 				pressed_texture = texture; | ||||
| 
 | ||||
| 			e->setUseAlphaChannel(style.getBool(StyleSpec::ALPHA, true)); | ||||
| 			e->setImage(guiScalingImageButton( | ||||
| 					Environment->getVideoDriver(), texture, geom.X, geom.Y)); | ||||
| 			e->setPressedImage(guiScalingImageButton( | ||||
| 					Environment->getVideoDriver(), pressed_texture, geom.X, geom.Y)); | ||||
| 			e->setScaleImage(true); | ||||
| 		} | ||||
| 
 | ||||
| 		if (spec.fname == data->focused_fieldname) { | ||||
| 			Environment->setFocus(e); | ||||
| @@ -889,6 +915,9 @@ void GUIFormSpecMenu::parseTable(parserData* data, const std::string &element) | ||||
| 		if (!str_initial_selection.empty() && str_initial_selection != "0") | ||||
| 			e->setSelected(stoi(str_initial_selection)); | ||||
| 
 | ||||
| 		auto style = getStyleForElement("table", name); | ||||
| 		e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false)); | ||||
| 
 | ||||
| 		m_tables.emplace_back(spec, e); | ||||
| 		m_fields.push_back(spec); | ||||
| 		return; | ||||
| @@ -963,6 +992,9 @@ void GUIFormSpecMenu::parseTextList(parserData* data, const std::string &element | ||||
| 		if (!str_initial_selection.empty() && str_initial_selection != "0") | ||||
| 			e->setSelected(stoi(str_initial_selection)); | ||||
| 
 | ||||
| 		auto style = getStyleForElement("textlist", name); | ||||
| 		e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false)); | ||||
| 
 | ||||
| 		m_tables.emplace_back(spec, e); | ||||
| 		m_fields.push_back(spec); | ||||
| 		return; | ||||
| @@ -1035,6 +1067,9 @@ void GUIFormSpecMenu::parseDropDown(parserData* data, const std::string &element | ||||
| 		if (!str_initial_selection.empty()) | ||||
| 			e->setSelected(stoi(str_initial_selection)-1); | ||||
| 
 | ||||
| 		auto style = getStyleForElement("dropdown", name); | ||||
| 		e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false)); | ||||
| 
 | ||||
| 		m_fields.push_back(spec); | ||||
| 
 | ||||
| 		m_dropdowns.emplace_back(spec, std::vector<std::string>()); | ||||
| @@ -1118,6 +1153,11 @@ void GUIFormSpecMenu::parsePwdField(parserData* data, const std::string &element | ||||
| 
 | ||||
| 		e->setPasswordBox(true,L'*'); | ||||
| 
 | ||||
| 		auto style = getStyleForElement("pwdfield", name, "field"); | ||||
| 		e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false)); | ||||
| 		e->setDrawBorder(style.getBool(StyleSpec::BORDER, true)); | ||||
| 		e->setOverrideColor(style.getColor(StyleSpec::TEXTCOLOR, video::SColor(0xFFFFFFFF))); | ||||
| 
 | ||||
| 		irr::SEvent evt; | ||||
| 		evt.EventType            = EET_KEY_INPUT_EVENT; | ||||
| 		evt.KeyInput.Key         = KEY_END; | ||||
| @@ -1194,6 +1234,14 @@ void GUIFormSpecMenu::createTextField(parserData *data, FieldSpec &spec, | ||||
| 			evt.KeyInput.PressedDown = true; | ||||
| 			e->OnEvent(evt); | ||||
| 		} | ||||
| 
 | ||||
| 		auto style = getStyleForElement(is_multiline ? "textarea" : "field", spec.fname); | ||||
| 		e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false)); | ||||
| 		e->setDrawBorder(style.getBool(StyleSpec::BORDER, true)); | ||||
| 		e->setOverrideColor(style.getColor(StyleSpec::TEXTCOLOR, video::SColor(0xFFFFFFFF))); | ||||
| 		if (style.get(StyleSpec::BGCOLOR, "") == "transparent") { | ||||
| 			e->setDrawBackground(false); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (!spec.flabel.empty()) { | ||||
| @@ -1407,6 +1455,15 @@ void GUIFormSpecMenu::parseLabel(parserData* data, const std::string &element) | ||||
| 			gui::IGUIStaticText *e = gui::StaticText::add(Environment, | ||||
| 				spec.flabel.c_str(), rect, false, false, this, spec.fid); | ||||
| 			e->setTextAlignment(gui::EGUIA_UPPERLEFT, gui::EGUIA_CENTER); | ||||
| 
 | ||||
| 			auto style = getStyleForElement("label", spec.fname); | ||||
| 			e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false)); | ||||
| 			e->setDrawBorder(style.getBool(StyleSpec::BORDER, false)); | ||||
| 			e->setOverrideColor(style.getColor(StyleSpec::TEXTCOLOR, video::SColor(0xFFFFFFFF))); | ||||
| 			if (style.isNotDefault(StyleSpec::BGCOLOR)) { | ||||
| 				e->setBackgroundColor(style.getColor(StyleSpec::BGCOLOR)); | ||||
| 			} | ||||
| 
 | ||||
| 			m_fields.push_back(spec); | ||||
| 		} | ||||
| 
 | ||||
| @@ -1475,9 +1532,18 @@ void GUIFormSpecMenu::parseVertLabel(parserData* data, const std::string &elemen | ||||
| 			L"", | ||||
| 			258+m_fields.size() | ||||
| 		); | ||||
| 		gui::IGUIStaticText *t = gui::StaticText::add(Environment, spec.flabel.c_str(), | ||||
| 		gui::IGUIStaticText *e = gui::StaticText::add(Environment, spec.flabel.c_str(), | ||||
| 			rect, false, false, this, spec.fid); | ||||
| 		t->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER); | ||||
| 		e->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER); | ||||
| 
 | ||||
| 		auto style = getStyleForElement("vertlabel", spec.fname, "label"); | ||||
| 		e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false)); | ||||
| 		e->setDrawBorder(style.getBool(StyleSpec::BORDER, false)); | ||||
| 		e->setOverrideColor(style.getColor(StyleSpec::TEXTCOLOR, video::SColor(0xFFFFFFFF))); | ||||
| 		if (style.isNotDefault(StyleSpec::BGCOLOR)) { | ||||
| 			e->setBackgroundColor(style.getColor(StyleSpec::BGCOLOR)); | ||||
| 		} | ||||
| 
 | ||||
| 		m_fields.push_back(spec); | ||||
| 		return; | ||||
| 	} | ||||
| @@ -1563,14 +1629,21 @@ void GUIFormSpecMenu::parseImageButton(parserData* data, const std::string &elem | ||||
| 			Environment->setFocus(e); | ||||
| 		} | ||||
| 
 | ||||
| 		e->setUseAlphaChannel(true); | ||||
| 		auto style = getStyleForElement("image_button", spec.fname); | ||||
| 
 | ||||
| 		e->setUseAlphaChannel(style.getBool(StyleSpec::ALPHA, true)); | ||||
| 		e->setImage(guiScalingImageButton( | ||||
| 			Environment->getVideoDriver(), texture, geom.X, geom.Y)); | ||||
| 		e->setPressedImage(guiScalingImageButton( | ||||
| 			Environment->getVideoDriver(), pressed_texture, geom.X, geom.Y)); | ||||
| 		e->setScaleImage(true); | ||||
| 		e->setNotClipped(noclip); | ||||
| 		e->setDrawBorder(drawborder); | ||||
| 		if (parts.size() >= 7) { | ||||
| 			e->setNotClipped(noclip); | ||||
| 			e->setDrawBorder(drawborder); | ||||
| 		} else { | ||||
| 			e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false)); | ||||
| 			e->setDrawBorder(style.getBool(StyleSpec::BORDER, true)); | ||||
| 		} | ||||
| 
 | ||||
| 		m_fields.push_back(spec); | ||||
| 		return; | ||||
| @@ -1656,7 +1729,7 @@ void GUIFormSpecMenu::parseTabHeader(parserData* data, const std::string &elemen | ||||
| 				pos.Y+geom.Y); | ||||
| 
 | ||||
| 		gui::IGUITabControl *e = Environment->addTabControl(rect, this, | ||||
| 				false, show_border, spec.fid); | ||||
| 				show_background, show_border, spec.fid); | ||||
| 		e->setAlignment(irr::gui::EGUIA_UPPERLEFT, irr::gui::EGUIA_UPPERLEFT, | ||||
| 				irr::gui::EGUIA_UPPERLEFT, irr::gui::EGUIA_LOWERRIGHT); | ||||
| 		e->setTabHeight(geom.Y); | ||||
| @@ -1665,16 +1738,13 @@ void GUIFormSpecMenu::parseTabHeader(parserData* data, const std::string &elemen | ||||
| 			Environment->setFocus(e); | ||||
| 		} | ||||
| 
 | ||||
| 		e->setNotClipped(true); | ||||
| 
 | ||||
| 		auto style = getThemeForElement("tabheader", name); | ||||
| 		auto style = getStyleForElement("tabheader", name); | ||||
| 		e->setNotClipped(style.getBool(StyleSpec::NOCLIP, true)); | ||||
| 
 | ||||
| 		for (const std::string &button : buttons) { | ||||
| 			auto tab = e->addTab(unescape_translate(unescape_string( | ||||
| 				utf8_to_wide(button))).c_str(), -1); | ||||
| 			tab->setDrawBackground(false); | ||||
| 			tab->setBackgroundColor(video::SColor(0xFFFF0000)); | ||||
| 			if (style.hasProperty(StyleSpec::BGCOLOR)) | ||||
| 			if (style.isNotDefault(StyleSpec::BGCOLOR)) | ||||
| 				tab->setBackgroundColor(style.getColor(StyleSpec::BGCOLOR)); | ||||
| 
 | ||||
| 			tab->setTextColor(style.getColor(StyleSpec::TEXTCOLOR, video::SColor(0xFFFFFFFF))); | ||||
| @@ -1753,6 +1823,10 @@ void GUIFormSpecMenu::parseItemImageButton(parserData* data, const std::string & | ||||
| 
 | ||||
| 		gui::IGUIButton *e = Environment->addButton(rect, this, spec.fid, L""); | ||||
| 
 | ||||
| 		auto style = getStyleForElement("item_image_button", spec.fname, "image_button"); | ||||
| 		e->setNotClipped(style.getBool(StyleSpec::NOCLIP, false)); | ||||
| 		e->setDrawBorder(style.getBool(StyleSpec::BORDER, true)); | ||||
| 
 | ||||
| 		if (spec.fname == data->focused_fieldname) { | ||||
| 			Environment->setFocus(e); | ||||
| 		} | ||||
| @@ -2043,30 +2117,46 @@ bool GUIFormSpecMenu::parseStyle(parserData *data, const std::string &element, b | ||||
| { | ||||
| 	std::vector<std::string> parts = split(element, ';'); | ||||
| 
 | ||||
| 	if (parts.size() != 3) { | ||||
| 	if (parts.size() < 2) { | ||||
| 		errorstream << "Invalid style element (" << parts.size() << "): '" << element | ||||
| 					<< "'" << std::endl; | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	std::string selector = trim(parts[0]); | ||||
| 	std::string propname = trim(parts[1]); | ||||
| 	std::string value    = trim(parts[2]); | ||||
| 
 | ||||
| 	StyleSpec::Property prop = StyleSpec::GetPropertyByName(propname); | ||||
| 	if (prop == StyleSpec::NONE) { | ||||
| 		errorstream << "Invalid style element (Unknown property " << prop << "): '" << element | ||||
| 	if (selector.empty()) { | ||||
| 		errorstream << "Invalid style element (Selector required): '" << element | ||||
| 					<< "'" << std::endl; | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	StyleSpec spec; | ||||
| 	spec.set(prop, value); | ||||
| 
 | ||||
| 	if (selector.empty()) { | ||||
| 		errorstream << "Invalid style element (Selector required): '" << element | ||||
| 					<< "'" << std::endl; | ||||
| 		return false; | ||||
| 	for (size_t i = 1; i < parts.size(); i++) { | ||||
| 		size_t equal_pos = parts[i].find('='); | ||||
| 		if (equal_pos == std::string::npos) { | ||||
| 			errorstream << "Invalid style element (Property missing value): '" << element | ||||
| 						<< "'" << std::endl; | ||||
| 			return false; | ||||
| 		} | ||||
| 
 | ||||
| 		std::string propname = trim(parts[i].substr(0, equal_pos)); | ||||
| 		std::string value    = trim(unescape_string(parts[i].substr(equal_pos + 1))); | ||||
| 
 | ||||
| 		std::transform(propname.begin(), propname.end(), propname.begin(), ::tolower); | ||||
| 
 | ||||
| 		StyleSpec::Property prop = StyleSpec::GetPropertyByName(propname); | ||||
| 		if (prop == StyleSpec::NONE) { | ||||
| 			if (property_warned.find(propname) != property_warned.end()) { | ||||
| 				warningstream << "Invalid style element (Unknown property " << propname << "): '" | ||||
| 						<< element | ||||
| 						<< "'" << std::endl; | ||||
| 				property_warned.insert(propname); | ||||
| 			} | ||||
| 			return false; | ||||
| 		} | ||||
| 
 | ||||
| 		spec.set(prop, value); | ||||
| 	} | ||||
| 
 | ||||
| 	if (style_type) { | ||||
| @@ -4115,9 +4205,17 @@ std::wstring GUIFormSpecMenu::getLabelByID(s32 id) | ||||
| 	return L""; | ||||
| } | ||||
| 
 | ||||
| StyleSpec GUIFormSpecMenu::getThemeForElement(const std::string &type, const std::string &name) { | ||||
| StyleSpec GUIFormSpecMenu::getStyleForElement(const std::string &type, | ||||
| 		const std::string &name, const std::string &parent_type) { | ||||
| 	StyleSpec ret; | ||||
| 
 | ||||
| 	if (!parent_type.empty()) { | ||||
| 		auto it = theme_by_type.find(parent_type); | ||||
| 		if (it != theme_by_type.end()) { | ||||
| 			ret |= it->second; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	auto it = theme_by_type.find(type); | ||||
| 	if (it != theme_by_type.end()) { | ||||
| 		ret |= it->second; | ||||
|   | ||||
| @@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc., | ||||
| 
 | ||||
| #include <utility> | ||||
| #include <stack> | ||||
| #include <unordered_set> | ||||
| 
 | ||||
| #include "irrlichttypes_extrabloated.h" | ||||
| #include "inventorymanager.h" | ||||
| @@ -404,8 +405,10 @@ protected: | ||||
| 
 | ||||
| 	std::unordered_map<std::string, StyleSpec> theme_by_type; | ||||
| 	std::unordered_map<std::string, StyleSpec> theme_by_name; | ||||
| 	std::unordered_set<std::string> property_warned; | ||||
| 
 | ||||
| 	StyleSpec getThemeForElement(const std::string &type, const std::string &name); | ||||
| 	StyleSpec getStyleForElement(const std::string &type, | ||||
| 			const std::string &name="", const std::string &parent_type=""); | ||||
| 
 | ||||
| 	v2s32 padding; | ||||
| 	v2f32 spacing; | ||||
| @@ -574,7 +577,6 @@ private: | ||||
| 	 * and the default value for the setting is true. | ||||
| 	 */ | ||||
| 	bool m_remap_dbl_click; | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| class FormspecFormSource: public IFormSource | ||||
|   | ||||
		Reference in New Issue
	
	Block a user