Files
panopainter/src/layout.cpp

133 lines
3.3 KiB
C++

#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<Node>();
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();
}