aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/cru/ui/ThemeManager.hpp27
-rw-r--r--include/cru/xml/XmlNode.hpp1
-rw-r--r--src/ui/ThemeManager.cpp22
-rw-r--r--src/xml/XmlNode.cpp7
4 files changed, 51 insertions, 6 deletions
diff --git a/include/cru/ui/ThemeManager.hpp b/include/cru/ui/ThemeManager.hpp
index be9daa47..68c2b121 100644
--- a/include/cru/ui/ThemeManager.hpp
+++ b/include/cru/ui/ThemeManager.hpp
@@ -8,6 +8,9 @@
#include "cru/ui/style/StyleRuleSet.hpp"
#include "cru/xml/XmlNode.hpp"
+#include <any>
+#include <typeindex>
+#include <typeinfo>
#include <unordered_map>
namespace cru::ui {
@@ -40,6 +43,8 @@ class CRU_UI_API ThemeManager : public Object {
void ReadResourcesFile(const String& file_path);
+ void SetThemeXml(xml::XmlElementNode* root);
+
template <typename T>
T GetResource(const String& key) {
auto find_result = theme_resource_map_.find(key);
@@ -48,9 +53,17 @@ class CRU_UI_API ThemeManager : public Object {
Format(u"Theme resource key \"%s\" not exist.", key));
}
+ auto& cache = find_result->second.cache;
+ auto cache_find_result = cache.find(typeid(T));
+ if (cache_find_result != cache.cend()) {
+ return std::any_cast<T>(cache_find_result->second);
+ }
+
auto mapper_registry = mapper::MapperRegistry::GetInstance();
auto mapper = mapper_registry->GetMapper<T>();
- return mapper->MapFromXml(find_result->second);
+ auto resource = mapper->MapFromXml(find_result->second.xml_node);
+ cache[typeid(T)] = resource;
+ return resource;
}
std::shared_ptr<platform::graphics::IBrush> GetResourceBrush(
@@ -62,8 +75,18 @@ class CRU_UI_API ThemeManager : public Object {
const String& key);
private:
+ struct ResourceEntry {
+ CRU_DEFAULT_CONSTRUCTOR_DESTRUCTOR(ResourceEntry)
+ CRU_DEFAULT_COPY(ResourceEntry)
+ CRU_DEFAULT_MOVE(ResourceEntry)
+
+ String name;
+ xml::XmlElementNode* xml_node;
+ std::unordered_map<std::type_index, std::any> cache;
+ };
+
Event<std::nullptr_t> theme_resource_change_event_;
std::unique_ptr<xml::XmlElementNode> theme_resource_xml_root_;
- std::unordered_map<String, xml::XmlElementNode*> theme_resource_map_;
+ std::unordered_map<String, ResourceEntry> theme_resource_map_;
};
} // namespace cru::ui
diff --git a/include/cru/xml/XmlNode.hpp b/include/cru/xml/XmlNode.hpp
index d1cb9430..cfe6e155 100644
--- a/include/cru/xml/XmlNode.hpp
+++ b/include/cru/xml/XmlNode.hpp
@@ -121,6 +121,7 @@ class CRU_XML_API XmlElementNode : public XmlNode {
void AddAttribute(String key, String value);
void AddChild(XmlNode* child);
+ Index GetChildElementCount() const;
XmlElementNode* GetFirstChildElement() const;
XmlNode* Clone() const override;
diff --git a/src/ui/ThemeManager.cpp b/src/ui/ThemeManager.cpp
index dc08edb3..be980e8c 100644
--- a/src/ui/ThemeManager.cpp
+++ b/src/ui/ThemeManager.cpp
@@ -49,11 +49,15 @@ void ThemeManager::ReadResourcesFile(const String& file_path) {
io::FileStream stream(file_path, io::OpenFileFlags::Read);
auto xml_string = stream.ReadAllAsString();
auto parser = xml::XmlParser(xml_string);
- theme_resource_xml_root_.reset(parser.Parse());
+ SetThemeXml(parser.Parse());
+}
+
+void ThemeManager::SetThemeXml(xml::XmlElementNode* root) {
+ theme_resource_xml_root_.reset(root);
theme_resource_map_.clear();
if (!theme_resource_xml_root_->GetTag().CaseInsensitiveEqual(u"Theme")) {
- throw Exception(u"Root tag of theme resource file must be \"Theme\".");
+ throw Exception(u"Root tag of theme must be \"Theme\".");
}
for (auto child : theme_resource_xml_root_->GetChildren()) {
@@ -64,10 +68,20 @@ void ThemeManager::ReadResourcesFile(const String& file_path) {
if (!key_attr) {
throw Exception(u"\"key\" attribute is required for resource.");
}
- theme_resource_map_[*key_attr] = c->GetFirstChildElement();
+ if (!c->GetChildElementCount()) {
+ throw Exception(u"Resource must have only one child element.");
+ }
+
+ ResourceEntry entry;
+
+ entry.name = *key_attr;
+ entry.xml_node = c->GetFirstChildElement();
+
+ theme_resource_map_[entry.name] = std::move(entry);
}
}
}
-}
+ theme_resource_change_event_.Raise(nullptr);
+}
} // namespace cru::ui
diff --git a/src/xml/XmlNode.cpp b/src/xml/XmlNode.cpp
index 79847544..00437f9b 100644
--- a/src/xml/XmlNode.cpp
+++ b/src/xml/XmlNode.cpp
@@ -1,4 +1,5 @@
#include "cru/xml/XmlNode.hpp"
+#include <algorithm>
namespace cru::xml {
@@ -32,6 +33,12 @@ void XmlElementNode::AddChild(XmlNode* child) {
child->parent_ = this;
}
+Index XmlElementNode::GetChildElementCount() const {
+ return std::count_if(
+ children_.cbegin(), children_.cend(),
+ [](xml::XmlNode* node) { return node->IsElementNode(); });
+}
+
XmlElementNode* XmlElementNode::GetFirstChildElement() const {
for (auto child : children_) {
if (child->GetType() == XmlNode::Type::Element) {