diff options
-rw-r--r-- | CMakeLists.txt | 3 | ||||
-rw-r--r-- | assets/cru/ui/DefaultResources.xml | 58 | ||||
-rw-r--r-- | include/cru/ui/ThemeManager.hpp | 33 | ||||
-rw-r--r-- | include/cru/ui/UiManager.hpp | 5 | ||||
-rw-r--r-- | include/cru/ui/controls/Control.hpp | 4 | ||||
-rw-r--r-- | include/cru/ui/mapper/Mapper.hpp | 4 | ||||
-rw-r--r-- | include/cru/ui/style/StyleRuleSet.hpp | 13 | ||||
-rw-r--r-- | src/ui/ThemeManager.cpp | 87 | ||||
-rw-r--r-- | src/ui/UiManager.cpp | 46 | ||||
-rw-r--r-- | src/ui/components/Menu.cpp | 3 | ||||
-rw-r--r-- | src/ui/controls/Button.cpp | 5 | ||||
-rw-r--r-- | src/ui/controls/Control.cpp | 8 | ||||
-rw-r--r-- | src/ui/controls/TextBox.cpp | 5 | ||||
-rw-r--r-- | src/ui/mapper/ColorMapper.cpp | 13 | ||||
-rw-r--r-- | src/ui/mapper/MapperRegistry.cpp | 2 | ||||
-rw-r--r-- | src/ui/render/ScrollBar.cpp | 11 | ||||
-rw-r--r-- | src/ui/style/StyleRuleSet.cpp | 34 |
17 files changed, 196 insertions, 138 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 4040df29..6d07ecdd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,8 @@ function(target_add_resources target res_dir) target_sources(${target} PUBLIC ${RES_SOURCES}) foreach (RES_FILE ${RES_SOURCES}) file(RELATIVE_PATH RES_PATH ${CRU_ASSETS_DIR} ${RES_FILE}) - set_property(SOURCE ${RES_FILE} PROPERTY MACOSX_PACKAGE_LOCATION "Resources/${RES_PATH}/..") + cmake_path(GET RES_PATH PARENT_PATH RES_PATH) + set_property(SOURCE ${RES_FILE} PROPERTY MACOSX_PACKAGE_LOCATION "Resources/${RES_PATH}") endforeach(RES_FILE) endfunction() diff --git a/assets/cru/ui/DefaultResources.xml b/assets/cru/ui/DefaultResources.xml index b831be2c..68b7a31a 100644 --- a/assets/cru/ui/DefaultResources.xml +++ b/assets/cru/ui/DefaultResources.xml @@ -1,9 +1,57 @@ <Theme> <Resource key="scrollbar.collapse-thumb.color"> - <Color value="gray" /> + <Color value="gray" alpha="0.5" /> + </Resource> + <Resource key="scrollbar.arrow.normal.color"> + <Color value="#505050" /> + </Resource> + <Resource key="scrollbar.arrow.hover.color"> + <Color value="#505050" /> + </Resource> + <Resource key="scrollbar.arrow.press.color"> + <Color value="#ffffff" /> + </Resource> + <Resource key="scrollbar.arrow.disable.color"> + <Color value="#a3a3a3" /> + </Resource> + <Resource key="scrollbar.arrow-background.normal.color"> + <Color value="#f1f1f1" /> + </Resource> + <Resource key="scrollbar.arrow-background.hover.color"> + <Color value="#d2d2d2" /> + </Resource> + <Resource key="scrollbar.arrow-background.press.color"> + <Color value="#787878" /> + </Resource> + <Resource key="scrollbar.arrow-background.disable.color"> + <Color value="#f1f1f1" /> + </Resource> + <Resource key="scrollbar.slot.normal.color"> + <Color value="#f1f1f1" /> + </Resource> + <Resource key="scrollbar.slot.hover.color"> + <Color value="#f1f1f1" /> + </Resource> + <Resource key="scrollbar.slot.press.color"> + <Color value="#f1f1f1" /> + </Resource> + <Resource key="scrollbar.slot.disable.color"> + <Color value="#f1f1f1" /> + </Resource> + <Resource key="scrollbar.thumb.normal.color"> + <Color value="#c1c1c1" /> + </Resource> + <Resource key="scrollbar.thumb.hover.color"> + <Color value="#a8a8a8" /> + </Resource> + <Resource key="scrollbar.thumb.press.color"> + <Color value="#787878" /> + </Resource> + <Resource key="scrollbar.thumb.disable.color"> + <Color value="#c1c1c1" /> </Resource> - <Resource key="button-style"> + <Resource key="button.style"> <StyleRuleSet> <StyleRule> <NoCondition /> @@ -61,7 +109,7 @@ </StyleRuleSet> </Resource> - <Resource key="text-box-style"> + <Resource key="textbox.style"> <StyleRuleSet> <StyleRule> <NoCondition /> @@ -98,4 +146,8 @@ </StyleRule> </StyleRuleSet> </Resource> + + <Resource key="menuitem.style"> + <StyleRuleSet></StyleRuleSet> + </Resource> </Theme> diff --git a/include/cru/ui/ThemeManager.hpp b/include/cru/ui/ThemeManager.hpp index 07b5f57b..7d52fa48 100644 --- a/include/cru/ui/ThemeManager.hpp +++ b/include/cru/ui/ThemeManager.hpp @@ -4,6 +4,9 @@ #include "cru/common/Event.hpp" #include "cru/common/Exception.hpp" #include "cru/platform/graphics/Brush.hpp" +#include "cru/ui/mapper/MapperRegistry.hpp" +#include "cru/ui/style/StyleRuleSet.hpp" +#include "cru/xml/XmlNode.hpp" #include <unordered_map> @@ -29,22 +32,36 @@ class CRU_UI_API ThemeManager : public Object { CRU_DELETE_COPY(ThemeManager) CRU_DELETE_MOVE(ThemeManager) - ~ThemeManager() override = default; + ~ThemeManager() override; IEvent<std::nullptr_t>* ThemeResourceChangeEvent() { return &theme_resource_change_event_; } - gsl::not_null<std::shared_ptr<platform::graphics::IBrush>> GetBrush( - StringView key); + void ReadResourcesFile(const String& file_path); - private: - void Init(); + template <typename T> + T GetResource(const String& key) { + auto find_result = theme_resource_map_.find(key); + if (find_result == theme_resource_map_.cend()) { + throw ThemeResourceKeyNotExistException( + Format(u"Theme resource key \"%s\" not exist.", key)); + } + + auto mapper_registry = mapper::MapperRegistry::GetInstance(); + auto mapper = mapper_registry->GetMapper<T>(); + return mapper->MapFromXml(find_result->second); + } + + std::shared_ptr<platform::graphics::IBrush> GetResourceBrush( + const String& key); + + std::shared_ptr<style::StyleRuleSet> GetResourceStyleRuleSet( + const String& key); private: Event<std::nullptr_t> theme_resource_change_event_; - std::unordered_map<String, String> theme_resource_map_; - std::unordered_map<String, std::shared_ptr<platform::graphics::IBrush>> - brushes_; + std::unique_ptr<xml::XmlElementNode> theme_resource_xml_root_; + std::unordered_map<String, xml::XmlElementNode*> theme_resource_map_; }; } // namespace cru::ui diff --git a/include/cru/ui/UiManager.hpp b/include/cru/ui/UiManager.hpp index d16adc4f..9ac7f416 100644 --- a/include/cru/ui/UiManager.hpp +++ b/include/cru/ui/UiManager.hpp @@ -18,11 +18,6 @@ struct ThemeResources { std::shared_ptr<platform::graphics::IBrush> text_brush; std::shared_ptr<platform::graphics::IBrush> text_selection_brush; std::shared_ptr<platform::graphics::IBrush> caret_brush; - - std::shared_ptr<style::StyleRuleSet> button_style; - std::shared_ptr<style::StyleRuleSet> text_box_style; - - style::StyleRuleSet menu_item_style; }; class CRU_UI_API UiManager : public Object { diff --git a/include/cru/ui/controls/Control.hpp b/include/cru/ui/controls/Control.hpp index ed6233a9..c51643be 100644 --- a/include/cru/ui/controls/Control.hpp +++ b/include/cru/ui/controls/Control.hpp @@ -67,7 +67,7 @@ class CRU_UI_API Control : public Object { void SetCursor(std::shared_ptr<platform::gui::ICursor> cursor); public: - style::StyleRuleSet* GetStyleRuleSet(); + std::shared_ptr<style::StyleRuleSet> GetStyleRuleSet(); //*************** region: events *************** public: @@ -151,7 +151,7 @@ class CRU_UI_API Control : public Object { std::shared_ptr<platform::gui::ICursor> cursor_ = nullptr; - std::unique_ptr<style::StyleRuleSet> style_rule_set_; + std::shared_ptr<style::StyleRuleSet> style_rule_set_; std::unique_ptr<style::StyleRuleSetBind> style_rule_set_bind_; }; } // namespace cru::ui::controls diff --git a/include/cru/ui/mapper/Mapper.hpp b/include/cru/ui/mapper/Mapper.hpp index ceda8e0f..c52bec70 100644 --- a/include/cru/ui/mapper/Mapper.hpp +++ b/include/cru/ui/mapper/Mapper.hpp @@ -69,11 +69,11 @@ class CRU_UI_API BasicMapper : public MapperBase { T MapFromXml(xml::XmlElementNode* node) { if (!SupportMapFromXml()) { - throw new Exception(u"This mapper does not support map from xml."); + throw Exception(u"This mapper does not support map from xml."); } if (!XmlElementIsOfThisType(node)) { - throw new Exception(u"This xml element is not of mapping type."); + throw Exception(u"This xml element is not of mapping type."); } return DoMapFromXml(node); diff --git a/include/cru/ui/style/StyleRuleSet.hpp b/include/cru/ui/style/StyleRuleSet.hpp index b3c4f683..32b02d78 100644 --- a/include/cru/ui/style/StyleRuleSet.hpp +++ b/include/cru/ui/style/StyleRuleSet.hpp @@ -9,7 +9,7 @@ namespace cru::ui::style { class StyleRuleSet : public Object { public: StyleRuleSet() = default; - explicit StyleRuleSet(StyleRuleSet* parent); + explicit StyleRuleSet(std::shared_ptr<StyleRuleSet> parent); CRU_DELETE_COPY(StyleRuleSet) CRU_DELETE_MOVE(StyleRuleSet) @@ -17,8 +17,8 @@ class StyleRuleSet : public Object { ~StyleRuleSet() override = default; public: - StyleRuleSet* GetParent() const { return parent_; } - void SetParent(StyleRuleSet* parent); + std::shared_ptr<StyleRuleSet> GetParent() const { return parent_; } + void SetParent(std::shared_ptr<StyleRuleSet> parent); gsl::index GetSize() const { return static_cast<gsl::index>(rules_.size()); } const std::vector<StyleRule>& GetRules() const { return rules_; } @@ -47,7 +47,7 @@ class StyleRuleSet : public Object { private: Event<std::nullptr_t> change_event_; - StyleRuleSet* parent_ = nullptr; + std::shared_ptr<StyleRuleSet> parent_ = nullptr; EventRevokerGuard parent_change_event_guard_; std::vector<StyleRule> rules_; @@ -55,7 +55,8 @@ class StyleRuleSet : public Object { class StyleRuleSetBind { public: - StyleRuleSetBind(controls::Control* control, StyleRuleSet* ruleset); + StyleRuleSetBind(controls::Control* control, + std::shared_ptr<StyleRuleSet> ruleset); CRU_DELETE_COPY(StyleRuleSetBind) CRU_DELETE_MOVE(StyleRuleSetBind) @@ -69,7 +70,7 @@ class StyleRuleSetBind { private: controls::Control* control_; - StyleRuleSet* ruleset_; + std::shared_ptr<StyleRuleSet> ruleset_; // child first, parent last. std::vector<StyleRuleSet*> ruleset_chain_cache_; diff --git a/src/ui/ThemeManager.cpp b/src/ui/ThemeManager.cpp index e26da3fb..4ed5c5b6 100644 --- a/src/ui/ThemeManager.cpp +++ b/src/ui/ThemeManager.cpp @@ -1,10 +1,15 @@ #include "cru/ui/ThemeManager.hpp" +#include <memory> #include "Helper.hpp" #include "cru/common/StringUtil.hpp" +#include "cru/common/io/FileStream.hpp" +#include "cru/common/io/Resource.hpp" #include "cru/platform/graphics/Brush.hpp" #include "cru/platform/graphics/Factory.hpp" #include "cru/platform/gui/UiApplication.hpp" +#include "cru/ui/style/StyleRuleSet.hpp" +#include "cru/xml/XmlParser.hpp" namespace cru::ui { ThemeManager* ThemeManager::GetInstance() { @@ -12,52 +17,52 @@ ThemeManager* ThemeManager::GetInstance() { return &instance; } -ThemeManager::ThemeManager() { Init(); } - -void ThemeManager::Init() { - theme_resource_map_.emplace(u"scrollbar.collapse-thumb.color", - colors::gray.WithAlpha(128).ToString()); - theme_resource_map_.emplace(u"scrollbar.arrow.normal.color", u"#505050"); - theme_resource_map_.emplace(u"scrollbar.arrow.hover.color", u"#505050"); - theme_resource_map_.emplace(u"scrollbar.arrow.press.color", u"#ffffff"); - theme_resource_map_.emplace(u"scrollbar.arrow.disable.color", u"#a3a3a3"); - theme_resource_map_.emplace(u"scrollbar.arrow-background.normal.color", - u"#f1f1f1"); - theme_resource_map_.emplace(u"scrollbar.arrow-background.hover.color", - u"#d2d2d2"); - theme_resource_map_.emplace(u"scrollbar.arrow-background.press.color", - u"#787878"); - theme_resource_map_.emplace(u"scrollbar.arrow-background.disable.color", - u"#f1f1f1"); - theme_resource_map_.emplace(u"scrollbar.slot.normal.color", u"#f1f1f1"); - theme_resource_map_.emplace(u"scrollbar.slot.hover.color", u"#f1f1f1"); - theme_resource_map_.emplace(u"scrollbar.slot.press.color", u"#f1f1f1"); - theme_resource_map_.emplace(u"scrollbar.slot.disable.color", u"#f1f1f1"); - theme_resource_map_.emplace(u"scrollbar.thumb.normal.color", u"#c1c1c1"); - theme_resource_map_.emplace(u"scrollbar.thumb.hover.color", u"#a8a8a8"); - theme_resource_map_.emplace(u"scrollbar.thumb.press.color", u"#787878"); - theme_resource_map_.emplace(u"scrollbar.thumb.disable.color", u"#c1c1c1"); -} +ThemeManager::ThemeManager() { + std::filesystem::path resourses_file = + cru::io::GetResourceDir() / "cru/ui/DefaultResources.xml"; -gsl::not_null<std::shared_ptr<platform::graphics::IBrush>> -ThemeManager::GetBrush(StringView key) { - auto k = key.ToString(); - auto cached_brush_iter = brushes_.find(k); - if (cached_brush_iter != brushes_.cend()) { - return cached_brush_iter->second; + if (!std::filesystem::exists(resourses_file)) { + throw Exception(u"Default resources file not found."); } - auto color_string_iter = theme_resource_map_.find(k); - if (color_string_iter == theme_resource_map_.cend()) { - throw ThemeResourceKeyNotExistException(u"Key do not exist."); + ReadResourcesFile(String::FromStdPath(resourses_file)); +} + +ThemeManager::~ThemeManager() {} + +std::shared_ptr<platform::graphics::IBrush> ThemeManager::GetResourceBrush( + const String& key) { + return GetResource<std::shared_ptr<platform::graphics::IBrush>>(key); +} + +std::shared_ptr<style::StyleRuleSet> ThemeManager::GetResourceStyleRuleSet( + const String& key) { + return GetResource<std::shared_ptr<style::StyleRuleSet>>(key); +} + +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()); + 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\"."); } - auto color = Color::Parse(color_string_iter->second); - if (!color) throw BadThemeResourceException(u"Value is not a valid color."); - std::shared_ptr<platform::graphics::IBrush> brush = - GetUiApplication()->GetGraphicsFactory()->CreateSolidColorBrush(*color); - brushes_[k] = brush; - return brush; + for (auto child : theme_resource_xml_root_->GetChildren()) { + if (child->IsElementNode()) { + auto c = child->AsElement(); + if (c->GetTag().CaseInsensitiveEqual(u"Resource")) { + auto key_attr = c->GetOptionalAttributeCaseInsensitive(u"key"); + if (!key_attr) { + throw Exception(u"\"key\" attribute is required for resource."); + } + theme_resource_map_[*key_attr] = c->GetFirstChildElement(); + } + } + } } } // namespace cru::ui diff --git a/src/ui/UiManager.cpp b/src/ui/UiManager.cpp index 62dce6a7..0c8f258d 100644 --- a/src/ui/UiManager.cpp +++ b/src/ui/UiManager.cpp @@ -1,9 +1,6 @@ #include "cru/ui/UiManager.hpp" #include "Helper.hpp" -#include "cru/common/io/FileStream.hpp" -#include "cru/common/io/OpenFileFlag.hpp" -#include "cru/common/io/Resource.hpp" #include "cru/platform/graphics/Brush.hpp" #include "cru/platform/graphics/Factory.hpp" #include "cru/platform/graphics/Font.hpp" @@ -38,15 +35,6 @@ UiManager* UiManager::GetInstance() { UiManager::UiManager() { const auto factory = GetGraphicsFactory(); - std::filesystem::path resourses_file = - cru::io::GetResourceDir() / "cru/ui/DefaultResources.xml"; - - if (!std::filesystem::exists(resourses_file)) { - throw Exception(u"Default resources file not found."); - } - - ReadResourcesFile(String::FromStdPath(resourses_file)); - theme_resource_.default_font_family = u""; theme_resource_.default_font = @@ -59,42 +47,8 @@ UiManager::UiManager() { theme_resource_.text_selection_brush = factory->CreateSolidColorBrush(colors::skyblue); theme_resource_.caret_brush = black_brush; - - theme_resource_.menu_item_style.AddStyleRule( - {NoCondition::Create(), - BorderStyler::Create( - ApplyBorderStyleInfo{std::nullopt, Thickness{0}, CornerRadius{0}}), - u"DefaultMenuItem"}); } UiManager::~UiManager() = default; -void UiManager::ReadResourcesFile(const String& file_path) { - io::FileStream stream(file_path, io::OpenFileFlags::Read); - auto xml_string = stream.ReadAllAsString(); - auto parser = xml::XmlParser(xml_string); - auto xml_root = parser.Parse(); - - for (auto child : xml_root->GetChildren()) { - if (child->GetType() == xml::XmlNode::Type::Element) { - auto c = child->AsElement(); - if (c->GetTag().CaseInsensitiveEqual(u"Resource")) { - auto key = c->GetAttributeCaseInsensitive(u"key"); - if (key.CaseInsensitiveEqual(u"button-style")) { - auto style_rule_set_mapper = mapper::MapperRegistry::GetInstance() - ->GetRefMapper<StyleRuleSet>(); - auto style_rule_set = - style_rule_set_mapper->MapFromXml(c->GetFirstChildElement()); - theme_resource_.button_style = style_rule_set; - } else if (key.CaseInsensitiveEqual(u"text-box-style")) { - auto style_rule_set_mapper = mapper::MapperRegistry::GetInstance() - ->GetRefMapper<StyleRuleSet>(); - auto style_rule_set = - style_rule_set_mapper->MapFromXml(c->GetFirstChildElement()); - theme_resource_.text_box_style = style_rule_set; - } - } - } - } -} } // namespace cru::ui diff --git a/src/ui/components/Menu.cpp b/src/ui/components/Menu.cpp index 05324865..7405b23c 100644 --- a/src/ui/components/Menu.cpp +++ b/src/ui/components/Menu.cpp @@ -1,6 +1,7 @@ #include "cru/ui/components/Menu.hpp" #include <functional> #include "cru/platform/gui/Window.hpp" +#include "cru/ui/ThemeManager.hpp" #include "cru/ui/UiManager.hpp" #include "cru/ui/controls/Button.hpp" #include "cru/ui/controls/Control.hpp" @@ -16,7 +17,7 @@ MenuItem::MenuItem() { text_ = controls::TextBlock::Create(); container_->SetChild(text_); container_->GetStyleRuleSet()->SetParent( - &UiManager::GetInstance()->GetThemeResources()->menu_item_style); + ThemeManager::GetInstance()->GetResourceStyleRuleSet(u"menuitem.style")); container_->ClickEvent()->AddHandler([this](const helper::ClickEventArgs&) { if (this->on_click_) this->on_click_(); }); diff --git a/src/ui/controls/Button.cpp b/src/ui/controls/Button.cpp index 0f122650..887bcae6 100644 --- a/src/ui/controls/Button.cpp +++ b/src/ui/controls/Button.cpp @@ -4,6 +4,7 @@ #include "cru/platform/graphics/Brush.hpp" #include "cru/platform/gui/Cursor.hpp" #include "cru/platform/gui/UiApplication.hpp" +#include "cru/ui/ThemeManager.hpp" #include "cru/ui/UiManager.hpp" #include "cru/ui/helper/ClickDetector.hpp" #include "cru/ui/render/BorderRenderObject.hpp" @@ -16,8 +17,8 @@ Button::Button() : click_detector_(this) { render_object_->SetBorderEnabled(true); auto default_button_style = - UiManager::GetInstance()->GetThemeResources()->button_style.get(); - GetStyleRuleSet()->SetParent(default_button_style); + ThemeManager::GetInstance()->GetResourceStyleRuleSet(u"button.style"); + GetStyleRuleSet()->SetParent(std::move(default_button_style)); } Button::~Button() = default; diff --git a/src/ui/controls/Control.cpp b/src/ui/controls/Control.cpp index 44da7f6f..04199d1d 100644 --- a/src/ui/controls/Control.cpp +++ b/src/ui/controls/Control.cpp @@ -16,9 +16,9 @@ using platform::gui::IUiApplication; using platform::gui::SystemCursorType; Control::Control() { - style_rule_set_ = std::make_unique<style::StyleRuleSet>(); + style_rule_set_ = std::make_shared<style::StyleRuleSet>(); style_rule_set_bind_ = - std::make_unique<style::StyleRuleSetBind>(this, style_rule_set_.get()); + std::make_unique<style::StyleRuleSetBind>(this, style_rule_set_); MouseEnterEvent()->Direct()->AddHandler([this](events::MouseEventArgs&) { this->is_mouse_over_ = true; @@ -99,8 +99,8 @@ void Control::SetCursor(std::shared_ptr<ICursor> cursor) { } } -style::StyleRuleSet* Control::GetStyleRuleSet() { - return style_rule_set_.get(); +std::shared_ptr<style::StyleRuleSet> Control::GetStyleRuleSet() { + return style_rule_set_; } void Control::AddChild(Control* control, const Index position) { diff --git a/src/ui/controls/TextBox.cpp b/src/ui/controls/TextBox.cpp index bf72b494..20e89028 100644 --- a/src/ui/controls/TextBox.cpp +++ b/src/ui/controls/TextBox.cpp @@ -1,5 +1,6 @@ #include "cru/ui/controls/TextBox.hpp" +#include "cru/ui/ThemeManager.hpp" #include "cru/ui/UiManager.hpp" #include "cru/ui/render/BorderRenderObject.hpp" #include "cru/ui/render/CanvasRenderObject.hpp" @@ -16,6 +17,7 @@ TextBox::TextBox() : border_render_object_(new BorderRenderObject()), scroll_render_object_(new ScrollRenderObject()) { const auto theme_resources = UiManager::GetInstance()->GetThemeResources(); + auto theme_manager = ThemeManager::GetInstance(); text_render_object_ = std::make_unique<TextRenderObject>( theme_resources->text_brush, theme_resources->default_font, @@ -37,7 +39,8 @@ TextBox::TextBox() border_render_object_->SetBorderEnabled(true); - GetStyleRuleSet()->SetParent(theme_resources->text_box_style.get()); + GetStyleRuleSet()->SetParent( + theme_manager->GetResourceStyleRuleSet(u"textbox.style")); } TextBox::~TextBox() {} diff --git a/src/ui/mapper/ColorMapper.cpp b/src/ui/mapper/ColorMapper.cpp index ddfa6b9b..063b2359 100644 --- a/src/ui/mapper/ColorMapper.cpp +++ b/src/ui/mapper/ColorMapper.cpp @@ -15,9 +15,16 @@ Color ColorMapper::DoMapFromString(String str) { Color ColorMapper::DoMapFromXml(xml::XmlElementNode* node) { auto value_attr = node->GetOptionalAttributeCaseInsensitive(u"value"); - if (!value_attr) { - return colors::transparent; + Color result = colors::transparent; + if (value_attr) { + result = DoMapFromString(*value_attr); } - return DoMapFromString(*value_attr); + + auto alpha_value_attr = node->GetOptionalAttributeCaseInsensitive(u"alpha"); + if (alpha_value_attr) { + result.alpha = alpha_value_attr->ParseToDouble() * 255; + } + + return result; } } // namespace cru::ui::mapper diff --git a/src/ui/mapper/MapperRegistry.cpp b/src/ui/mapper/MapperRegistry.cpp index a9c53129..97c5cf21 100644 --- a/src/ui/mapper/MapperRegistry.cpp +++ b/src/ui/mapper/MapperRegistry.cpp @@ -1,5 +1,6 @@ #include "cru/ui/mapper/MapperRegistry.hpp" #include "cru/ui/mapper/BorderStyleMapper.hpp" +#include "cru/ui/mapper/BrushMapper.hpp" #include "cru/ui/mapper/ColorMapper.hpp" #include "cru/ui/mapper/CornerRadiusMapper.hpp" #include "cru/ui/mapper/CursorMapper.hpp" @@ -26,6 +27,7 @@ MapperRegistry *MapperRegistry::GetInstance() { MapperRegistry::MapperRegistry() { using namespace style; + RegisterMapper(new BrushMapper()); RegisterMapper(new CornerRadiusMapper()); RegisterMapper(new PointMapper()); RegisterMapper(new SizeMapper()); diff --git a/src/ui/render/ScrollBar.cpp b/src/ui/render/ScrollBar.cpp index 8e16862f..8676de61 100644 --- a/src/ui/render/ScrollBar.cpp +++ b/src/ui/render/ScrollBar.cpp @@ -264,9 +264,10 @@ void ScrollBar::InstallHandlers(controls::Control* control) { gsl::not_null<std::shared_ptr<platform::graphics::IBrush>> ScrollBar::GetCollapsedThumbBrush() { - return collapsed_thumb_brush_ ? gsl::not_null(collapsed_thumb_brush_) - : ThemeManager::GetInstance()->GetBrush( - u"scrollbar.collapse-thumb.color"); + return collapsed_thumb_brush_ + ? gsl::not_null(collapsed_thumb_brush_) + : gsl::not_null(ThemeManager::GetInstance()->GetResourceBrush( + u"scrollbar.collapse-thumb.color")); } void ScrollBar::SetCollapsedThumbBrush( @@ -280,8 +281,8 @@ gsl::not_null<std::shared_ptr<platform::graphics::IBrush>> ScrollBar::GetBrush( ScrollBarBrushUsageKind usage, ScrollBarBrushStateKind state) { auto b = brushes_[usage][state]; return b ? gsl::not_null(b) - : ThemeManager::GetInstance()->GetBrush( - GenerateScrollBarThemeColorKey(usage, state)); + : gsl::not_null(ThemeManager::GetInstance()->GetResourceBrush( + GenerateScrollBarThemeColorKey(usage, state))); } // Brush could be nullptr to use the theme brush. diff --git a/src/ui/style/StyleRuleSet.cpp b/src/ui/style/StyleRuleSet.cpp index 537d1956..88109350 100644 --- a/src/ui/style/StyleRuleSet.cpp +++ b/src/ui/style/StyleRuleSet.cpp @@ -6,12 +6,30 @@ #include <unordered_set> namespace cru::ui::style { -StyleRuleSet::StyleRuleSet(StyleRuleSet* parent) { SetParent(parent); } +namespace { +bool CheckCycle(StyleRuleSet* t, StyleRuleSet* p) { + while (p != nullptr) { + if (p == t) { + return true; + } + p = p->GetParent().get(); + } + + return false; +} +} // namespace -void StyleRuleSet::SetParent(StyleRuleSet* parent) { +StyleRuleSet::StyleRuleSet(std::shared_ptr<StyleRuleSet> parent) { + SetParent(std::move(parent)); +} + +void StyleRuleSet::SetParent(std::shared_ptr<StyleRuleSet> parent) { if (parent == parent_) return; + if (CheckCycle(this, parent.get())) { + throw Exception(u"Cycle detected in StyleRuleSet parent."); + } parent_change_event_guard_.Reset(); - parent_ = parent; + parent_ = std::move(parent); if (parent != nullptr) { parent_change_event_guard_.Reset(parent->ChangeEvent()->AddSpyOnlyHandler( [this] { this->RaiseChangeEvent(); })); @@ -44,12 +62,12 @@ void StyleRuleSet::Set(const StyleRuleSet& other, bool set_parent) { } StyleRuleSetBind::StyleRuleSetBind(controls::Control* control, - StyleRuleSet* ruleset) - : control_(control), ruleset_(ruleset) { + std::shared_ptr<StyleRuleSet> ruleset) + : control_(control), ruleset_(std::move(ruleset)) { Expects(control); - Expects(ruleset); + Expects(ruleset_); - ruleset->ChangeEvent()->AddSpyOnlyHandler([this] { + ruleset_->ChangeEvent()->AddSpyOnlyHandler([this] { UpdateRuleSetChainCache(); UpdateChangeListener(); UpdateStyle(); @@ -60,7 +78,7 @@ void StyleRuleSetBind::UpdateRuleSetChainCache() { ruleset_chain_cache_.clear(); auto parent = ruleset_; while (parent != nullptr) { - ruleset_chain_cache_.push_back(parent); + ruleset_chain_cache_.push_back(parent.get()); parent = parent->GetParent(); } } |