#include "gui_xml.hpp" #include "elements/Panel.hpp" #include "elements/Image.hpp" #include "elements/Menu.hpp" #include "elements/Button.hpp" #include "elements/CheckBox.hpp" #include "elements/TextBox.hpp" #include "elements/TrackBar.hpp" #include "elements/InputBindBox.hpp" #include "elements/InventoryView.hpp" #include "frontend/menu.hpp" #include "frontend/locale.hpp" #include "items/Inventory.hpp" #include "logic/scripting/scripting.hpp" #include "maths/voxmaths.hpp" #include "util/stringutil.hpp" #include "window/Events.hpp" #include #include using namespace gui; static Align align_from_string(const std::string& str, Align def) { if (str == "left") return Align::left; if (str == "center") return Align::center; if (str == "right") return Align::right; if (str == "top") return Align::top; if (str == "bottom") return Align::bottom; return def; } static Gravity gravity_from_string(const std::string& str) { static const std::unordered_map gravity_names { {"top-left", Gravity::top_left}, {"top-center", Gravity::top_center}, {"top-right", Gravity::top_right}, {"center-left", Gravity::center_left}, {"center-center", Gravity::center_center}, {"center-right", Gravity::center_right}, {"bottom-left", Gravity::bottom_left}, {"bottom-center", Gravity::bottom_center}, {"bottom-right", Gravity::bottom_right}, }; auto found = gravity_names.find(str); if (found != gravity_names.end()) { return found->second; } return Gravity::none; } static runnable create_runnable( const UiXmlReader& reader, const xml::xmlelement& element, const std::string& name ) { if (element.has(name)) { std::string text = element.attr(name).getText(); if (!text.empty()) { return scripting::create_runnable( reader.getEnvironment(), text, reader.getFilename() ); } } return nullptr; } static onaction create_action( const UiXmlReader& reader, const xml::xmlelement& element, const std::string& name ) { auto callback = create_runnable(reader, element, name); if (callback == nullptr) { return nullptr; } return [callback](GUI*) {callback();}; } /* Read basic UINode properties */ static void _readUINode( const UiXmlReader& reader, const xml::xmlelement& element, UINode& node ) { if (element.has("id")) { node.setId(element.attr("id").getText()); } if (element.has("pos")) { node.setPos(element.attr("pos").asVec2()); } if (element.has("size")) { node.setSize(element.attr("size").asVec2()); } if (element.has("color")) { glm::vec4 color = element.attr("color").asColor(); glm::vec4 hoverColor = color; glm::vec4 pressedColor = color; if (element.has("hover-color")) { hoverColor = node.getHoverColor(); } if (element.has("pressed-color")) { pressedColor = node.getPressedColor(); } node.setColor(color); node.setHoverColor(hoverColor); node.setPressedColor(pressedColor); } if (element.has("margin")) { node.setMargin(element.attr("margin").asVec4()); } if (element.has("z-index")) { node.setZIndex(element.attr("z-index").asInt()); } if (element.has("interactive")) { node.setInteractive(element.attr("interactive").asBool()); } if (element.has("visible")) { node.setVisible(element.attr("visible").asBool()); } if (element.has("enabled")) { node.setEnabled(element.attr("enabled").asBool()); } if (element.has("position-func")) { node.setPositionFunc(scripting::create_vec2_supplier( reader.getEnvironment(), element.attr("position-func").getText(), reader.getFilename() )); } if (element.has("size-func")) { node.setSizeFunc(scripting::create_vec2_supplier( reader.getEnvironment(), element.attr("size-func").getText(), reader.getFilename() )); } if (element.has("hover-color")) { node.setHoverColor(element.attr("hover-color").asColor()); } if (element.has("pressed-color")) { node.setPressedColor(element.attr("pressed-color").asColor()); } std::string alignName = element.attr("align", "").getText(); node.setAlign(align_from_string(alignName, node.getAlign())); if (element.has("gravity")) { node.setGravity(gravity_from_string( element.attr("gravity").getText() )); } if (element.has("tooltip")) { node.setTooltip(util::str2wstr_utf8(element.attr("tooltip").getText())); } if (element.has("tooltip-delay")) { node.setTooltipDelay(element.attr("tooltip-delay").asFloat()); } if (auto onclick = create_action(reader, element, "onclick")) { node.listenAction(onclick); } if (auto ondoubleclick = create_action(reader, element, "ondoubleclick")) { node.listenDoubleClick(ondoubleclick); } } static void _readContainer(UiXmlReader& reader, const xml::xmlelement& element, Container& container) { _readUINode(reader, element, container); if (element.has("scrollable")) { container.setScrollable(element.attr("scrollable").asBool()); } if (element.has("scroll-step")) { container.setScrollStep(element.attr("scroll-step").asInt()); } for (auto& sub : element.getElements()) { if (sub->isText()) continue; auto subnode = reader.readUINode(*sub); if (subnode) { container.add(subnode); } } } void UiXmlReader::readUINode(UiXmlReader& reader, const xml::xmlelement& element, Container& container) { _readContainer(reader, element, container); } void UiXmlReader::readUINode( const UiXmlReader& reader, const xml::xmlelement& element, UINode& node ) { _readUINode(reader, element, node); } static void _readPanel(UiXmlReader& reader, const xml::xmlelement& element, Panel& panel, bool subnodes=true) { _readUINode(reader, element, panel); if (element.has("padding")) { glm::vec4 padding = element.attr("padding").asVec4(); panel.setPadding(padding); glm::vec2 size = panel.getSize(); panel.setSize(glm::vec2( size.x + padding.x + padding.z, size.y + padding.y + padding.w )); } if (element.has("size")) { panel.setResizing(false); } if (element.has("max-length")) { panel.setMaxLength(element.attr("max-length").asInt()); } if (element.has("orientation")) { auto &oname = element.attr("orientation").getText(); if (oname == "horizontal") { panel.setOrientation(Orientation::horizontal); } } if (subnodes) { for (auto& sub : element.getElements()) { if (sub->isText()) continue; auto subnode = reader.readUINode(*sub); if (subnode) { panel.add(subnode); } } } } static std::wstring readAndProcessInnerText(const xml::xmlelement& element, const std::string& context) { std::wstring text = L""; if (element.size() == 1) { std::string source = element.sub(0).attr("#").getText(); util::trim(source); text = util::str2wstr_utf8(source); if (text[0] == '@') { if (context.empty()) { text = langs::get(text.substr(1)); } else { text = langs::get(text.substr(1), util::str2wstr_utf8(context)); } } } return text; } static std::shared_ptr readLabel( const UiXmlReader& reader, const xml::xmlelement& element ) { std::wstring text = readAndProcessInnerText(element, reader.getContext()); auto label = std::make_shared