diff options
author | crupest <crupest@outlook.com> | 2022-03-02 22:07:33 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2022-03-02 22:07:33 +0800 |
commit | 57353bd3acd97957cb5f970016fec52977cc6e95 (patch) | |
tree | 6e47a50f33466f7bcdce7c7aa9bf15b82fe4a58a | |
parent | 7adfe813c23d20abe936aa0624fd68e0112717b3 (diff) | |
download | cru-57353bd3acd97957cb5f970016fec52977cc6e95.tar.gz cru-57353bd3acd97957cb5f970016fec52977cc6e95.tar.bz2 cru-57353bd3acd97957cb5f970016fec52977cc6e95.zip |
...
24 files changed, 510 insertions, 30 deletions
diff --git a/assets/cru/ui/DefaultResources.xml b/assets/cru/ui/DefaultResources.xml index 26f6e929..c779a5b9 100644 --- a/assets/cru/ui/DefaultResources.xml +++ b/assets/cru/ui/DefaultResources.xml @@ -1,4 +1,12 @@ <Theme> + <Resource key="icon.close"> + <String value="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z" /> + </Resource> + + <Resource key="icon.plus-square"> + <String value="M14 1a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1h12zM2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2z M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z"/> + </Resource> + <Resource key="text.font"> <Font /> </Resource> @@ -122,6 +130,64 @@ </StyleRuleSet> </Resource> + <Resource key="icon-button.style"> + <StyleRuleSet> + <StyleRule> + <NoCondition /> + <BorderStyler> + <BorderStyle> + <Thickness value="5" /> + <CornerRadius all="5" /> + </BorderStyle> + </BorderStyler> + </StyleRule> + <StyleRule> + <ClickStateCondition value="none" /> + <BorderStyler> + <BorderStyle> + <Color value="#00bfff" /> + </BorderStyle> + </BorderStyler> + <CursorStyler> + <Cursor value="arrow" /> + </CursorStyler> + </StyleRule> + <StyleRule> + <ClickStateCondition value="hover" /> + <BorderStyler> + <BorderStyle> + <Color value="#47d1ff" /> + </BorderStyle> + </BorderStyler> + <CursorStyler> + <Cursor value="hand" /> + </CursorStyler> + </StyleRule> + <StyleRule> + <ClickStateCondition value="press" /> + <BorderStyler> + <BorderStyle> + <Color value="#91e4ff" /> + </BorderStyle> + </BorderStyler> + <CursorStyler> + <Cursor value="hand" /> + </CursorStyler> + </StyleRule> + <StyleRule> + <ClickStateCondition value="pressinactive" /> + <BorderStyler> + <BorderStyle> + <Color value="#91e4ff" /> + </BorderStyle> + </BorderStyler> + <CursorStyler> + <Cursor value="arrow" /> + </CursorStyler> + </StyleRule> + </StyleRuleSet> + </Resource> + <Resource key="textbox.style"> <StyleRuleSet> <StyleRule> diff --git a/include/cru/platform/GraphicsBase.h b/include/cru/platform/GraphicsBase.h index 8fb9a3af..62a8bf29 100644 --- a/include/cru/platform/GraphicsBase.h +++ b/include/cru/platform/GraphicsBase.h @@ -1,9 +1,9 @@ #pragma once #include "cru/common/Base.h" +#include "cru/common/Format.h" #include "cru/common/Range.h" #include "cru/common/String.h" -#include "cru/common/Format.h" #include <cstdint> #include <limits> @@ -25,6 +25,8 @@ struct Point final { return *this; } + constexpr Point Negate() const { return Point(-x, -y); } + float x = 0; float y = 0; }; diff --git a/include/cru/platform/graphics/Geometry.h b/include/cru/platform/graphics/Geometry.h index 1c2bd1f7..19620789 100644 --- a/include/cru/platform/graphics/Geometry.h +++ b/include/cru/platform/graphics/Geometry.h @@ -1,6 +1,8 @@ #pragma once #include "Resource.h" +#include <memory> + namespace cru::platform::graphics { struct CRU_PLATFORM_GRAPHICS_API IGeometry : virtual IGraphicsResource { virtual bool FillContains(const Point& point) = 0; @@ -59,4 +61,7 @@ struct CRU_PLATFORM_GRAPHICS_API IGeometryBuilder : virtual IGraphicsResource { void ParseAndApplySvgPathData(StringView path_d); }; + +std::unique_ptr<IGeometry> CRU_PLATFORM_GRAPHICS_API +CreateGeometryFromSvgPathData(IGraphicsFactory* factory, StringView path_d); } // namespace cru::platform::graphics diff --git a/include/cru/ui/ThemeManager.h b/include/cru/ui/ThemeManager.h index 9917f219..faa8a1cf 100644 --- a/include/cru/ui/ThemeManager.h +++ b/include/cru/ui/ThemeManager.h @@ -37,6 +37,8 @@ class CRU_UI_API ThemeManager : public Object { Format(u"Theme resource key {} not exist.", key)); } + String GetResourceString(const String& key); + std::shared_ptr<platform::graphics::IBrush> GetResourceBrush( const String& key); diff --git a/include/cru/ui/ThemeResourceDictionary.h b/include/cru/ui/ThemeResourceDictionary.h index a303b466..7112ab27 100644 --- a/include/cru/ui/ThemeResourceDictionary.h +++ b/include/cru/ui/ThemeResourceDictionary.h @@ -63,14 +63,6 @@ class CRU_UI_API ThemeResourceDictionary : public Object { return resource; } - std::shared_ptr<platform::graphics::IBrush> GetResourceBrush( - const String& key); - - std::shared_ptr<platform::graphics::IFont> GetResourceFont(const String& key); - - std::shared_ptr<style::StyleRuleSet> GetResourceStyleRuleSet( - const String& key); - private: void UpdateResourceMap(xml::XmlElementNode* root_xml); diff --git a/include/cru/ui/components/PopupButton.h b/include/cru/ui/components/PopupButton.h index 37420ff6..c8ef9c50 100644 --- a/include/cru/ui/components/PopupButton.h +++ b/include/cru/ui/components/PopupButton.h @@ -3,6 +3,7 @@ #include "cru/ui/Base.h" #include "cru/ui/components/Menu.h" #include "cru/ui/controls/Button.h" +#include "cru/ui/controls/IconButton.h" #include "cru/ui/controls/Popup.h" #include "cru/ui/controls/TextBlock.h" @@ -35,4 +36,25 @@ class CRU_UI_API PopupMenuTextButton : public Component { Event<Index> menu_item_selected_event_; }; + +class CRU_UI_API PopupMenuIconButton : public Component { + public: + PopupMenuIconButton(); + ~PopupMenuIconButton() override; + + public: + ui::controls::Control* GetRootControl() override { return &button_; } + + ui::controls::IconButton* GetButton() { return &button_; } + + void SetMenuItems(std::vector<String> items); + + IEvent<Index>* MenuItemSelectedEvent() { return &menu_item_selected_event_; } + + private: + ui::controls::IconButton button_; + PopupMenu popup_menu_; + + Event<Index> menu_item_selected_event_; +}; } // namespace cru::ui::components diff --git a/include/cru/ui/controls/Button.h b/include/cru/ui/controls/Button.h index 1828dc57..6df23c62 100644 --- a/include/cru/ui/controls/Button.h +++ b/include/cru/ui/controls/Button.h @@ -1,7 +1,6 @@ #pragma once #include "SingleChildControl.h" -#include "../controls/SingleChildControl.h" #include "../helper/ClickDetector.h" #include "../render/BorderRenderObject.h" #include "IBorderControl.h" diff --git a/include/cru/ui/controls/IconButton.h b/include/cru/ui/controls/IconButton.h new file mode 100644 index 00000000..4f347b33 --- /dev/null +++ b/include/cru/ui/controls/IconButton.h @@ -0,0 +1,93 @@ +#pragma once +#include "NoChildControl.h" + +#include "../helper/ClickDetector.h" +#include "../render/BorderRenderObject.h" +#include "../render/GeometryRenderObject.h" +#include "IBorderControl.h" +#include "IClickableControl.h" +#include "cru/common/Event.h" + +namespace cru::ui::controls { +class CRU_UI_API IconButton : public NoChildControl, + public virtual IClickableControl, + public virtual IBorderControl { + public: + static constexpr StringView kControlType = u"IconButton"; + + public: + IconButton(); + IconButton(StringView icon_svg_path_data_string, const Rect& view_port); + ~IconButton() override; + + String GetControlType() const final { return kControlType.ToString(); } + + render::RenderObject* GetRenderObject() const override { + return container_render_object_.get(); + } + + public: + helper::ClickState GetClickState() override { + return click_detector_.GetState(); + } + + IEvent<helper::ClickState>* ClickStateChangeEvent() override { + return click_detector_.StateChangeEvent(); + } + + IEvent<helper::ClickEventArgs>* ClickEvent() { + return click_detector_.ClickEvent(); + } + + void ApplyBorderStyle(const style::ApplyBorderStyleInfo& style) override { + container_render_object_->ApplyBorderStyle(style); + } + + std::shared_ptr<platform::graphics::IGeometry> GetIconGeometry() const { + return geometry_render_object_->GetGeometry(); + } + void SetIconGeometry(std::shared_ptr<platform::graphics::IGeometry> geometry, + std::optional<Rect> view_port = std::nullopt) { + geometry_render_object_->SetGeometry(std::move(geometry), view_port); + } + + Rect GetIconViewPort() const { + return geometry_render_object_->GetViewPort(); + } + void SetIconViewPort(const Rect& view_port) { + geometry_render_object_->SetViewPort(view_port); + } + + std::shared_ptr<platform::graphics::IBrush> GetIconFillBrush() const { + return geometry_render_object_->GetFillBrush(); + } + void SetIconFillBrush(std::shared_ptr<platform::graphics::IBrush> brush) { + geometry_render_object_->SetFillBrush(std::move(brush)); + } + + std::shared_ptr<platform::graphics::IBrush> GetIconStrokeBrush() const { + return geometry_render_object_->GetStrokeBrush(); + } + void SetIconStrokeBrush(std::shared_ptr<platform::graphics::IBrush> brush) { + geometry_render_object_->SetStrokeBrush(std::move(brush)); + } + + float GetIconStrokeWidth() const { + return geometry_render_object_->GetStrokeWidth(); + } + void SetIconStrokeWidth(float width) { + geometry_render_object_->SetStrokeWidth(width); + } + + void SetIconFillColor(const Color& color); + void SetIconWithSvgPathDataString(StringView icon_svg_path_data_string, + const Rect& view_port); + void SetIconWithSvgPathDataStringResourceKey( + StringView icon_svg_path_data_string_resource_key, const Rect& view_port); + + private: + std::unique_ptr<render::BorderRenderObject> container_render_object_; + std::unique_ptr<render::GeometryRenderObject> geometry_render_object_; + helper::ClickDetector click_detector_; +}; +} // namespace cru::ui::controls diff --git a/include/cru/ui/mapper/StringMapper.h b/include/cru/ui/mapper/StringMapper.h new file mode 100644 index 00000000..8a907591 --- /dev/null +++ b/include/cru/ui/mapper/StringMapper.h @@ -0,0 +1,18 @@ +#pragma once +#include "Mapper.h" + +namespace cru::ui::mapper { +class CRU_UI_API StringMapper : public BasicMapper<String> { + public: + StringMapper(); + ~StringMapper(); + + public: + bool SupportMapFromString() override { return true; } + bool SupportMapFromXml() override { return true; } + + protected: + String DoMapFromString(String str) override; + String DoMapFromXml(xml::XmlElementNode* node) override; +}; +} // namespace cru::ui::mapper diff --git a/include/cru/ui/render/BorderRenderObject.h b/include/cru/ui/render/BorderRenderObject.h index a71cd6a0..8de0eea3 100644 --- a/include/cru/ui/render/BorderRenderObject.h +++ b/include/cru/ui/render/BorderRenderObject.h @@ -44,7 +44,8 @@ class CRU_UI_API BorderRenderObject : public SingleChildRenderObject { RenderObject* HitTest(const Point& point) override; void Draw(platform::graphics::IPainter* painter) override; - Thickness GetOuterSpaceThickness() const override; + Thickness GetTotalSpaceThickness() const override; + Thickness GetInnerSpaceThickness() const override; Rect GetPaddingRect() const override; Rect GetContentRect() const override; diff --git a/include/cru/ui/render/GeometryRenderObject.h b/include/cru/ui/render/GeometryRenderObject.h new file mode 100644 index 00000000..6c5702ae --- /dev/null +++ b/include/cru/ui/render/GeometryRenderObject.h @@ -0,0 +1,50 @@ +#pragma once +#include "RenderObject.h" +#include "cru/platform/graphics/Brush.h" +#include "cru/platform/graphics/Geometry.h" + +#include <optional> + +namespace cru::ui::render { +class GeometryRenderObject : public RenderObject { + public: + GeometryRenderObject(); + + CRU_DELETE_COPY(GeometryRenderObject) + CRU_DELETE_MOVE(GeometryRenderObject) + + ~GeometryRenderObject() override; + + public: + void Draw(platform::graphics::IPainter* painter) override; + RenderObject* HitTest(const Point& point) override; + + std::shared_ptr<platform::graphics::IGeometry> GetGeometry() const; + void SetGeometry(std::shared_ptr<platform::graphics::IGeometry> geometry, + std::optional<Rect> view_port = std::nullopt); + + Rect GetViewPort() const; + void SetViewPort(const Rect& view_port); + + std::shared_ptr<platform::graphics::IBrush> GetFillBrush() const; + void SetFillBrush(std::shared_ptr<platform::graphics::IBrush> brush); + + std::shared_ptr<platform::graphics::IBrush> GetStrokeBrush() const; + void SetStrokeBrush(std::shared_ptr<platform::graphics::IBrush> brush); + + float GetStrokeWidth() const; + void SetStrokeWidth(float width); + + protected: + Size OnMeasureContent(const MeasureRequirement& requirement, + const MeasureSize& preferred_size) override; + void OnLayoutContent(const Rect& content_rect) override; + + private: + std::shared_ptr<platform::graphics::IGeometry> geometry_ = nullptr; + Rect view_port_{}; + std::shared_ptr<platform::graphics::IBrush> fill_brush_ = nullptr; + std::shared_ptr<platform::graphics::IBrush> stroke_brush_ = nullptr; + float stroke_width_ = 0; +}; +} // namespace cru::ui::render diff --git a/include/cru/ui/render/RenderObject.h b/include/cru/ui/render/RenderObject.h index e8dc3b17..9f2b69d9 100644 --- a/include/cru/ui/render/RenderObject.h +++ b/include/cru/ui/render/RenderObject.h @@ -32,8 +32,9 @@ namespace cru::ui::render { * void Draw(platform::graphics::IPainter* painter) override; * RenderObject* HitTest(const Point& point) override; * protected: - * Size OnMeasureContent(const MeasureRequirement& requirement) override; - * void OnLayoutContent(const Rect& content_rect) override; + * Size OnMeasureContent(const MeasureRequirement& requirement, const + * MeasureSize& preferred_size) override; void OnLayoutContent(const Rect& + * content_rect) override; */ class CRU_UI_API RenderObject : public Object { CRU_DEFINE_CLASS_LOG_TAG(u"RenderObject") @@ -93,7 +94,9 @@ class CRU_UI_API RenderObject : public Object { // This will set offset of this render object and call OnLayoutCore. void Layout(const Point& offset); - virtual Thickness GetOuterSpaceThickness() const; + virtual Thickness GetTotalSpaceThickness() const; + virtual Thickness GetInnerSpaceThickness() const; + virtual Rect GetPaddingRect() const; virtual Rect GetContentRect() const; diff --git a/src/platform/graphics/Geometry.cpp b/src/platform/graphics/Geometry.cpp index d4d36eb4..389b97f5 100644 --- a/src/platform/graphics/Geometry.cpp +++ b/src/platform/graphics/Geometry.cpp @@ -1,8 +1,10 @@ #include "cru/platform/graphics/Geometry.h" +#include "cru/common/Exception.h" +#include "cru/platform/graphics/Factory.h" + #include <cmath> #include <unordered_set> -#include "cru/common/Exception.h" namespace cru::platform::graphics { constexpr float PI = 3.14159265358979323846f; @@ -365,4 +367,11 @@ void IGeometryBuilder::ParseAndApplySvgPathData(StringView path_d) { } } +std::unique_ptr<IGeometry> CreateGeometryFromSvgPathData( + IGraphicsFactory* factory, StringView path_d) { + auto builder = factory->CreateGeometryBuilder(); + builder->ParseAndApplySvgPathData(path_d); + return builder->Build(); +} + } // namespace cru::platform::graphics diff --git a/src/theme_builder/components/conditions/CompoundConditionEditor.cpp b/src/theme_builder/components/conditions/CompoundConditionEditor.cpp index beede667..a0985eff 100644 --- a/src/theme_builder/components/conditions/CompoundConditionEditor.cpp +++ b/src/theme_builder/components/conditions/CompoundConditionEditor.cpp @@ -6,6 +6,7 @@ #include "NoConditionEditor.h" #include "cru/common/ClonablePtr.h" #include "cru/platform/Color.h" +#include "cru/ui/Base.h" #include "cru/ui/ThemeManager.h" #include "cru/ui/controls/FlexLayout.h" #include "cru/ui/style/Condition.h" @@ -20,9 +21,11 @@ CompoundConditionEditorChild::CompoundConditionEditorChild( remove_button_.GetStyleRuleSet()->SetParent( ui::ThemeManager::GetInstance()->GetResourceStyleRuleSet( u"cru.theme_builder.icon-button.style")); - remove_button_.SetChild(&remove_button_text_); - remove_button_text_.SetText(u"x"); - remove_button_text_.SetTextColor(ui::colors::red); + remove_button_.SetIconWithSvgPathDataStringResourceKey(u"icon.close", + {0, 0, 16, 16}); + remove_button_.SetPreferredSize({24, 24}); + remove_button_.SetPadding(ui::Thickness(4)); + remove_button_.SetIconFillColor(ui::colors::red); container_.AddChild(condition_editor_->GetRootControl()); @@ -44,8 +47,11 @@ CompoundConditionEditor::CompoundConditionEditor() { add_child_button_.GetButton()->GetStyleRuleSet()->SetParent( ui::ThemeManager::GetInstance()->GetResourceStyleRuleSet( u"cru.theme_builder.icon-button.style")); - add_child_button_.SetButtonText(u"+"); - add_child_button_.SetButtonTextColor(ui::colors::green); + add_child_button_.GetButton()->SetIconWithSvgPathDataStringResourceKey( + u"icon.plus-square", {0, 0, 16, 16}); + add_child_button_.GetButton()->SetPreferredSize({24, 24}); + add_child_button_.GetButton()->SetPadding(ui::Thickness(4)); + add_child_button_.GetButton()->SetIconFillColor(ui::colors::green); add_child_button_.SetMenuItems({u"And Condition", u"Or Condition", u"Click State Condition", u"Focus Condition", u"Checked Condition", u"No Condition"}); diff --git a/src/theme_builder/components/conditions/CompoundConditionEditor.h b/src/theme_builder/components/conditions/CompoundConditionEditor.h index 471087ae..f80896c8 100644 --- a/src/theme_builder/components/conditions/CompoundConditionEditor.h +++ b/src/theme_builder/components/conditions/CompoundConditionEditor.h @@ -25,8 +25,7 @@ class CompoundConditionEditorChild : public ui::components::Component { private: ui::controls::FlexLayout container_; - ui::controls::Button remove_button_; - ui::controls::TextBlock remove_button_text_; + ui::controls::IconButton remove_button_; std::unique_ptr<ConditionEditor> condition_editor_; Event<std::nullptr_t> remove_event_; @@ -43,7 +42,7 @@ class CompoundConditionEditor : public ConditionEditor { bool trigger_change = true); private: - ui::components::PopupMenuTextButton add_child_button_; + ui::components::PopupMenuIconButton add_child_button_; ui::controls::FlexLayout children_container_; std::vector<std::unique_ptr<CompoundConditionEditorChild>> children_; }; diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index e3819800..ce67c12c 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -11,6 +11,7 @@ add_library(cru_ui SHARED controls/Container.cpp controls/Control.cpp controls/FlexLayout.cpp + controls/IconButton.cpp controls/NoChildControl.cpp controls/Popup.cpp controls/RootControl.cpp @@ -37,6 +38,7 @@ add_library(cru_ui SHARED mapper/MeasureLengthMapper.cpp mapper/PointMapper.cpp mapper/SizeMapper.cpp + mapper/StringMapper.cpp mapper/ThicknessMapper.cpp mapper/style/AndConditionMapper.cpp mapper/style/BorderStylerMapper.cpp @@ -55,6 +57,7 @@ add_library(cru_ui SHARED render/BorderRenderObject.cpp render/CanvasRenderObject.cpp render/FlexLayoutRenderObject.cpp + render/GeometryRenderObject.cpp render/LayoutHelper.cpp render/RenderObject.cpp render/ScrollBar.cpp diff --git a/src/ui/ThemeManager.cpp b/src/ui/ThemeManager.cpp index 1adbddaf..93dc9a9f 100644 --- a/src/ui/ThemeManager.cpp +++ b/src/ui/ThemeManager.cpp @@ -49,6 +49,10 @@ void ThemeManager::PrependThemeResourceDictionary( theme_resource_change_event_.Raise(nullptr); } +String ThemeManager::GetResourceString(const String& key) { + return GetResource<String>(key); +} + std::shared_ptr<platform::graphics::IBrush> ThemeManager::GetResourceBrush( const String& key) { return GetResource<std::shared_ptr<platform::graphics::IBrush>>(key); diff --git a/src/ui/components/PopupButton.cpp b/src/ui/components/PopupButton.cpp index f09bf2d1..41e0ad6c 100644 --- a/src/ui/components/PopupButton.cpp +++ b/src/ui/components/PopupButton.cpp @@ -21,4 +21,21 @@ void PopupMenuTextButton::SetMenuItems(std::vector<String> items) { std::move(items[i]), [this, i] { menu_item_selected_event_.Raise(i); }); } } + +PopupMenuIconButton::PopupMenuIconButton() : popup_menu_(&button_) { + button_.ClickEvent()->AddHandler([this](const helper::ClickEventArgs& args) { + popup_menu_.SetPosition(args.GetDownPointOfScreen()); + popup_menu_.Show(); + }); +} + +PopupMenuIconButton::~PopupMenuIconButton() {} + +void PopupMenuIconButton::SetMenuItems(std::vector<String> items) { + popup_menu_.GetMenu()->ClearItems(); + for (Index i = 0; i < items.size(); i++) { + popup_menu_.GetMenu()->AddTextItem( + std::move(items[i]), [this, i] { menu_item_selected_event_.Raise(i); }); + } +} } // namespace cru::ui::components diff --git a/src/ui/controls/IconButton.cpp b/src/ui/controls/IconButton.cpp new file mode 100644 index 00000000..01ecabdd --- /dev/null +++ b/src/ui/controls/IconButton.cpp @@ -0,0 +1,50 @@ +#include "cru/ui/controls/IconButton.h" + +#include "../Helper.h" +#include "cru/platform/graphics/Factory.h" +#include "cru/platform/graphics/Geometry.h" +#include "cru/ui/ThemeManager.h" + +namespace cru::ui::controls { +IconButton::IconButton() + : container_render_object_(new render::BorderRenderObject()), + geometry_render_object_(new render::GeometryRenderObject()), + click_detector_(this) { + container_render_object_->SetChild(geometry_render_object_.get()); + container_render_object_->SetAttachedControl(this); + geometry_render_object_->SetAttachedControl(this); + + container_render_object_->SetBorderEnabled(true); + GetStyleRuleSet()->SetParent( + ThemeManager::GetInstance()->GetResourceStyleRuleSet( + u"icon-button.style")); +} + +IconButton::IconButton(StringView icon_svg_path_data_string, + const Rect& view_port) + : IconButton() { + SetIconWithSvgPathDataString(icon_svg_path_data_string, view_port); +} + +IconButton::~IconButton() {} + +void IconButton::SetIconFillColor(const Color& color) { + SetIconFillBrush(GetGraphicsFactory()->CreateSolidColorBrush(color)); +} + +void IconButton::SetIconWithSvgPathDataString( + StringView icon_svg_path_data_string, const Rect& view_port) { + SetIconGeometry(platform::graphics::CreateGeometryFromSvgPathData( + GetGraphicsFactory(), icon_svg_path_data_string), + view_port); +} + +void IconButton::SetIconWithSvgPathDataStringResourceKey( + StringView icon_svg_path_data_string_resource_key, const Rect& view_port) { + SetIconWithSvgPathDataString( + ThemeManager::GetInstance()->GetResourceString( + icon_svg_path_data_string_resource_key.ToString()), + view_port); +} + +} // namespace cru::ui::controls diff --git a/src/ui/mapper/MapperRegistry.cpp b/src/ui/mapper/MapperRegistry.cpp index ad5b7e8d..f599c1ed 100644 --- a/src/ui/mapper/MapperRegistry.cpp +++ b/src/ui/mapper/MapperRegistry.cpp @@ -8,6 +8,7 @@ #include "cru/ui/mapper/MeasureLengthMapper.h" #include "cru/ui/mapper/PointMapper.h" #include "cru/ui/mapper/SizeMapper.h" +#include "cru/ui/mapper/StringMapper.h" #include "cru/ui/mapper/ThicknessMapper.h" #include "cru/ui/mapper/style/AndConditionMapper.h" #include "cru/ui/mapper/style/BorderStylerMapper.h" @@ -39,6 +40,7 @@ MapperRegistry::MapperRegistry() { RegisterMapper(new MeasureLengthMapper()); RegisterMapper(new PointMapper()); RegisterMapper(new SizeMapper()); + RegisterMapper(new StringMapper()); RegisterMapper(new ThicknessMapper()); RegisterMapper(new BorderStyleMapper()); RegisterMapper(new ColorMapper()); diff --git a/src/ui/mapper/StringMapper.cpp b/src/ui/mapper/StringMapper.cpp new file mode 100644 index 00000000..9e73b7f1 --- /dev/null +++ b/src/ui/mapper/StringMapper.cpp @@ -0,0 +1,16 @@ +#include "cru/ui/mapper/StringMapper.h" +#include "cru/xml/XmlNode.h" + +namespace cru::ui::mapper { +StringMapper::StringMapper() { SetAllowedTags({u"String"}); } + +StringMapper::~StringMapper() {} + +String StringMapper::DoMapFromString(String str) { return std::move(str); } + +String StringMapper::DoMapFromXml(xml::XmlElementNode* node) { + auto value_attr = node->GetOptionalAttributeCaseInsensitive(u"value"); + if (value_attr) return *value_attr; + return {}; +} +} // namespace cru::ui::mapper diff --git a/src/ui/render/BorderRenderObject.cpp b/src/ui/render/BorderRenderObject.cpp index 40ab506a..8e93e205 100644 --- a/src/ui/render/BorderRenderObject.cpp +++ b/src/ui/render/BorderRenderObject.cpp @@ -130,10 +130,16 @@ void BorderRenderObject::OnLayoutContent(const Rect& content_rect) { void BorderRenderObject::OnResize(const Size& new_size) { RecreateGeometry(); } -Thickness BorderRenderObject::GetOuterSpaceThickness() const { +Thickness BorderRenderObject::GetTotalSpaceThickness() const { return is_border_enabled_ - ? RenderObject::GetOuterSpaceThickness() + GetBorderThickness() - : RenderObject::GetOuterSpaceThickness(); + ? RenderObject::GetTotalSpaceThickness() + GetBorderThickness() + : RenderObject::GetTotalSpaceThickness(); +} + +Thickness BorderRenderObject::GetInnerSpaceThickness() const { + return is_border_enabled_ + ? RenderObject::GetInnerSpaceThickness() + GetBorderThickness() + : RenderObject::GetInnerSpaceThickness(); } Rect BorderRenderObject::GetPaddingRect() const { diff --git a/src/ui/render/GeometryRenderObject.cpp b/src/ui/render/GeometryRenderObject.cpp new file mode 100644 index 00000000..ea9b6e11 --- /dev/null +++ b/src/ui/render/GeometryRenderObject.cpp @@ -0,0 +1,110 @@ +#include "cru/ui/render/GeometryRenderObject.h" +#include "cru/platform/graphics/Brush.h" +#include "cru/platform/graphics/Geometry.h" +#include "cru/platform/graphics/Painter.h" +#include "cru/ui/render/RenderObject.h" + +namespace cru::ui::render { +GeometryRenderObject::GeometryRenderObject() {} + +GeometryRenderObject::~GeometryRenderObject() {} + +std::shared_ptr<platform::graphics::IGeometry> +GeometryRenderObject::GetGeometry() const { + return geometry_; +} + +void GeometryRenderObject::SetGeometry( + std::shared_ptr<platform::graphics::IGeometry> geometry, + std::optional<Rect> view_port) { + geometry_ = std::move(geometry); + if (view_port) { + view_port_ = *view_port; + } else { + view_port_ = geometry_ ? geometry_->GetBounds() : Rect{}; + } +} + +Rect GeometryRenderObject::GetViewPort() const { return view_port_; } + +void GeometryRenderObject::SetViewPort(const Rect& view_port) { + view_port_ = view_port; + InvalidatePaint(); +} + +std::shared_ptr<platform::graphics::IBrush> GeometryRenderObject::GetFillBrush() + const { + return fill_brush_; +} + +void GeometryRenderObject::SetFillBrush( + std::shared_ptr<platform::graphics::IBrush> brush) { + fill_brush_ = std::move(brush); + InvalidatePaint(); +} + +std::shared_ptr<platform::graphics::IBrush> +GeometryRenderObject::GetStrokeBrush() const { + return stroke_brush_; +} + +void GeometryRenderObject::SetStrokeBrush( + std::shared_ptr<platform::graphics::IBrush> brush) { + stroke_brush_ = std::move(brush); + InvalidatePaint(); +} + +float GeometryRenderObject::GetStrokeWidth() const { return stroke_width_; } + +void GeometryRenderObject::SetStrokeWidth(float width) { + stroke_width_ = width; + InvalidatePaint(); +} + +void GeometryRenderObject::Draw(platform::graphics::IPainter* painter) { + if (!geometry_) return; + + painter->PushState(); + + auto content_rect = GetContentRect(); + + painter->ConcatTransform(Matrix::Translation(content_rect.GetLeftTop())); + + painter->ConcatTransform( + Matrix::Translation(view_port_.GetLeftTop().Negate()) * + Matrix::Scale(content_rect.width / view_port_.width, + content_rect.height / view_port_.height)); + + if (fill_brush_) { + painter->FillGeometry(geometry_.get(), fill_brush_.get()); + } + + if (stroke_brush_ && stroke_width_) { + painter->StrokeGeometry(geometry_.get(), stroke_brush_.get(), + stroke_width_); + } + + painter->PopState(); +} + +RenderObject* GeometryRenderObject::HitTest(const Point& point) { + return GetPaddingRect().IsPointInside(point) ? this : nullptr; +} + +Size GeometryRenderObject::OnMeasureContent( + const MeasureRequirement& requirement, const MeasureSize& preferred_size) { + Size result = GetViewPort().GetSize(); + + if (preferred_size.width.IsSpecified()) { + result.width = preferred_size.width.GetLengthOrUndefined(); + } + + if (preferred_size.height.IsSpecified()) { + result.height = preferred_size.height.GetLengthOrUndefined(); + } + + return requirement.Coerce(result); +} + +void GeometryRenderObject::OnLayoutContent(const Rect& content_rect) {} +} // namespace cru::ui::render diff --git a/src/ui/render/RenderObject.cpp b/src/ui/render/RenderObject.cpp index b6de5782..a2ecab8b 100644 --- a/src/ui/render/RenderObject.cpp +++ b/src/ui/render/RenderObject.cpp @@ -1,6 +1,7 @@ #include "cru/ui/render/RenderObject.h" #include "cru/common/log/Logger.h" +#include "cru/platform/GraphicsBase.h" #include "cru/ui/DebugFlags.h" #include "cru/ui/controls/Control.h" #include "cru/ui/host/WindowHost.h" @@ -109,13 +110,15 @@ void RenderObject::Layout(const Point& offset) { OnLayoutCore(); } -Thickness RenderObject::GetOuterSpaceThickness() const { +Thickness RenderObject::GetTotalSpaceThickness() const { return margin_ + padding_; } +Thickness RenderObject::GetInnerSpaceThickness() const { return padding_; } + Size RenderObject::OnMeasureCore(const MeasureRequirement& requirement, const MeasureSize& preferred_size) { - const Thickness outer_space = GetOuterSpaceThickness(); + const Thickness outer_space = GetTotalSpaceThickness(); const Size space_size{outer_space.GetHorizontalTotal(), outer_space.GetVerticalTotal()}; @@ -124,8 +127,10 @@ Size RenderObject::OnMeasureCore(const MeasureRequirement& requirement, content_requirement.max = content_requirement.max.Minus(space_size); content_requirement.min = content_requirement.min.Minus(space_size); + auto inner_space = GetInnerSpaceThickness(); MeasureSize content_preferred_size = - content_requirement.Coerce(preferred_size.Minus(space_size)); + content_requirement.Coerce(preferred_size.Minus( + {inner_space.GetHorizontalTotal(), inner_space.GetVerticalTotal()})); const auto content_size = OnMeasureContent(content_requirement, content_preferred_size); @@ -135,7 +140,7 @@ Size RenderObject::OnMeasureCore(const MeasureRequirement& requirement, void RenderObject::OnLayoutCore() { Size total_size = GetDesiredSize(); - const Thickness outer_space = GetOuterSpaceThickness(); + const Thickness outer_space = GetTotalSpaceThickness(); const Size space_size{outer_space.GetHorizontalTotal(), outer_space.GetVerticalTotal()}; |