aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2022-03-02 22:07:33 +0800
committercrupest <crupest@outlook.com>2022-03-02 22:07:33 +0800
commit57353bd3acd97957cb5f970016fec52977cc6e95 (patch)
tree6e47a50f33466f7bcdce7c7aa9bf15b82fe4a58a
parent7adfe813c23d20abe936aa0624fd68e0112717b3 (diff)
downloadcru-57353bd3acd97957cb5f970016fec52977cc6e95.tar.gz
cru-57353bd3acd97957cb5f970016fec52977cc6e95.tar.bz2
cru-57353bd3acd97957cb5f970016fec52977cc6e95.zip
...
-rw-r--r--assets/cru/ui/DefaultResources.xml66
-rw-r--r--include/cru/platform/GraphicsBase.h4
-rw-r--r--include/cru/platform/graphics/Geometry.h5
-rw-r--r--include/cru/ui/ThemeManager.h2
-rw-r--r--include/cru/ui/ThemeResourceDictionary.h8
-rw-r--r--include/cru/ui/components/PopupButton.h22
-rw-r--r--include/cru/ui/controls/Button.h1
-rw-r--r--include/cru/ui/controls/IconButton.h93
-rw-r--r--include/cru/ui/mapper/StringMapper.h18
-rw-r--r--include/cru/ui/render/BorderRenderObject.h3
-rw-r--r--include/cru/ui/render/GeometryRenderObject.h50
-rw-r--r--include/cru/ui/render/RenderObject.h9
-rw-r--r--src/platform/graphics/Geometry.cpp11
-rw-r--r--src/theme_builder/components/conditions/CompoundConditionEditor.cpp16
-rw-r--r--src/theme_builder/components/conditions/CompoundConditionEditor.h5
-rw-r--r--src/ui/CMakeLists.txt3
-rw-r--r--src/ui/ThemeManager.cpp4
-rw-r--r--src/ui/components/PopupButton.cpp17
-rw-r--r--src/ui/controls/IconButton.cpp50
-rw-r--r--src/ui/mapper/MapperRegistry.cpp2
-rw-r--r--src/ui/mapper/StringMapper.cpp16
-rw-r--r--src/ui/render/BorderRenderObject.cpp12
-rw-r--r--src/ui/render/GeometryRenderObject.cpp110
-rw-r--r--src/ui/render/RenderObject.cpp13
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()};