#include "pch.h" #include "log.h" #include "util.h" #include "asset.h" #include "node.h" #include "node_border.h" #include "layout.h" void LayoutManager::unload() { for (auto& l : m_layouts) l.second->destroy(); m_layouts.clear(); } void LayoutManager::create() { m_layouts[const_hash("main")] = std::make_unique(); m_layouts[const_hash("main")]->m_manager = this; } bool LayoutManager::load(const char* path) { auto abs_path = Asset::absolute(path); #if _WIN32 || __OSX__ struct stat tmp_info; if (stat(abs_path.c_str(), &tmp_info) != 0) return false; if (tmp_info.st_mtime <= m_file_info.st_mtime) return false; m_file_info = tmp_info; #else if (m_loaded) return true; // already loaded #endif // __ANDROID__ if (!m_layouts.empty() && on_reloading) on_reloading(); m_path = path; Asset file; if (!(file.open(path) && file.read_all())) return false; auto xml_string = std::string((char*)file.m_data, (size_t)file.m_len); file.close(); if (!parse(xml_string)) return false; if (on_loaded) on_loaded(m_loaded); m_loaded = true; return true; } bool LayoutManager::parse(const std::string& xml_string) noexcept { auto old = std::move(m_layouts); tinyxml2::XMLDocument xml(true, tinyxml2::COLLAPSE_WHITESPACE); auto ret = xml.Parse(xml_string.c_str(), xml_string.size()); if (ret != tinyxml2::XMLError::XML_SUCCESS) { return false; LOG("parsing xml failed"); } tinyxml2::XMLElement* current = xml.RootElement()->FirstChildElement(); while (current) { auto id_str = current->Attribute("id"); if (!id_str) { LOG("Layout node without id"); return false; } if (auto os = current->Attribute("os")) { auto osv = split(os, ','); if (std::find(osv.begin(), osv.end(), PP_OS) == osv.end()) { LOG("Layout %s not for this os(%s), skipping", id_str, PP_OS) current = current->NextSiblingElement("layout"); continue; } } //LOG("Parsing layout: %s", id_str); uint16_t id = const_hash(id_str); auto p = m_layouts.find(id); if (p == m_layouts.end()) { auto& node = m_layouts[id]; std::string node_name = current->Name(); node.reset(node_name == "border" ? new NodeBorder : new Node); node->set_manager(this); // try to copy the old size values if (old.count(id)) { const auto& old_node = *old[id]; YGNodeCopyStyle(node->y_node, old_node.y_node); } node->load_internal(current); } else { LOG("Layout id \"%s\" duplicated", id_str); } current = current->NextSiblingElement("layout"); } return true; } bool LayoutManager::reload() { // avoid conflict when assigning the same string from c_str std::string path_copy = m_path; return load(path_copy.c_str()); } void LayoutManager::restore_context() { for (auto& node : m_layouts) node.second->restore_context(); } void LayoutManager::clear_context() { for (auto& node : m_layouts) node.second->clear_context(); }