From 542949e9f5c690292af6faf9a61671bf1e2263eb Mon Sep 17 00:00:00 2001 From: daiqingshuang Date: Mon, 21 Apr 2025 14:30:01 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=8E=A7=E4=BB=B6=E5=B8=83?= =?UTF-8?q?=E5=B1=80=E8=AF=AD=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- example/src/main.cpp | 63 ++++++++++--------- src/mirage_core/src/misc/mirage_type.h | 9 +-- .../src/widget/compound_widget/mborder.h | 9 +-- .../src/widget/compound_widget/mbutton.cpp | 4 ++ .../src/widget/compound_widget/mbutton.h | 8 ++- .../src/widget/leaf_widget/mimage.cpp | 9 +++ .../src/widget/leaf_widget/mimage.h | 11 +++- .../src/widget/leaf_widget/mtext_block.cpp | 9 +++ .../src/widget/leaf_widget/mtext_block.h | 34 +++++----- .../src/widget/mcompound_widget.h | 24 +++---- src/mirage_widget/src/widget/mleaf_widget.h | 3 +- src/mirage_widget/src/widget/mpanel_widget.h | 24 +++---- src/mirage_widget/src/widget/mwidget.cpp | 24 +++---- src/mirage_widget/src/widget/mwidget.h | 57 ++++++++++++----- src/mirage_widget/src/widget/slot_util.h | 8 +-- src/mirage_widget/src/widget/widget_new.h | 14 +++-- .../src/widget_tree/hit_test_result.h | 4 +- .../src/widget_utils/layout_utils.cpp | 2 +- .../src/widget_utils/layout_utils.h | 48 +++++++------- src/mirage_widget/src/window/mwindow.cpp | 4 +- src/mirage_widget/src/window/mwindow.h | 6 +- src/mirage_widget/src/window/mwindow_impl.cpp | 42 ++++++------- 22 files changed, 245 insertions(+), 171 deletions(-) diff --git a/example/src/main.cpp b/example/src/main.cpp index 63624f6..ee6924e 100644 --- a/example/src/main.cpp +++ b/example/src/main.cpp @@ -47,11 +47,11 @@ int main(int argc, char* argv[]) { font_manager::instance().load_default_font(); - auto name = mirage_style::get().name(); - auto version = mirage_style::get().version(); - auto author = mirage_style::get().author(); + auto name = mirage_style::get().name(); + auto version = mirage_style::get().version(); + auto author = mirage_style::get().author(); auto description = mirage_style::get().description(); - auto license = mirage_style::get().license(); + auto license = mirage_style::get().license(); std::stringstream ss; ss << "name: " << name << "\n"; @@ -59,39 +59,46 @@ int main(int argc, char* argv[]) { ss << "author: " << author << "\n"; ss << "description: " << description << "\n"; ss << "license: " << license << "\n"; + // const char*转换为std::u32string const auto& config_info_str = utf8::utf8to32(ss.str()); - const auto& text_block = std::make_shared(); - text_block->set_text(config_info_str); // text_block->set_text(U"Hello, World! 你好,世界!\n换行测试1111,测试测试测试测试,测试测试😀🐵🙏 😃🐵🙏"); const auto& window = mwindow::create({ 800, 600 }, L"Hello, World!"); window->set_content( - mnew(mv_box) - [ - mslot(mv_box) - .horizontal_alignment(horizontal_alignment_t::left) - +mnew(mbutton) + mnew(mv_box) [ - mslot(mbutton) - .margin({ 10 }) - .visibility(visibility_t::visible) - +text_block - ], + mslot(mv_box) + .horizontal_alignment(horizontal_alignment_t::left) + +mnew(mbutton) + [ + mslot(mbutton) + .margin({ 10 }) + .visibility(visibility_t::visible) + [ + mnew(mtext_block, + .text(config_info_str) + .font_size(24) + ) + ] + ], - mslot(mv_box) - .horizontal_alignment(horizontal_alignment_t::right) - +mnew(mbutton) - [ - mslot(mbutton) - .margin({ 10 }) - .visibility(visibility_t::visible) - +mnew(mtext_block) - ->set_text(U"Hello, World!") - ->set_font_size(24) + mslot(mv_box) + .horizontal_alignment(horizontal_alignment_t::right) + +mnew(mbutton) + [ + mslot(mbutton) + .margin({ 10 }) + .visibility(visibility_t::visible) + [ + mnew(mtext_block, + .text(U"Hello, World!") + .font_size(24) + ) + ] + ] ] - ] - ); + ); mirage_app::get().run(); return 0; diff --git a/src/mirage_core/src/misc/mirage_type.h b/src/mirage_core/src/misc/mirage_type.h index 2839db5..83b700c 100644 --- a/src/mirage_core/src/misc/mirage_type.h +++ b/src/mirage_core/src/misc/mirage_type.h @@ -70,10 +70,11 @@ enum class visibility_t : uint32_t { hit_test_invisible = 1 << 4, ///< 整个组件树不可点击 // 常用组合 - all = 0xFFFFFFFF, ///< 所有可见性标志 - any_visible = visible | self_hit_test_invisible | hit_test_invisible, ///< 任何可见状态 - any_invisible = collapsed | hidden, ///< 任何不可见状态 - any_hit_testable = visible, ///< 任何可命中测试状态 + all = 0xFFFFFFFF, ///< 所有可见性标志 + any_visible = visible | self_hit_test_invisible | hit_test_invisible, ///< 任何可见状态 + any_invisible = collapsed | hidden, ///< 任何不可见状态 + any_hit_testable = visible, ///< 任何可命中测试状态 + any_layout = any_visible | hidden, ///< 任何布局状态 }; // 为visibility枚举启用位标志功能 DEFINE_ENUM_FLAGS(visibility_t) diff --git a/src/mirage_widget/src/widget/compound_widget/mborder.h b/src/mirage_widget/src/widget/compound_widget/mborder.h index 4717746..860eb2e 100644 --- a/src/mirage_widget/src/widget/compound_widget/mborder.h +++ b/src/mirage_widget/src/widget/compound_widget/mborder.h @@ -41,7 +41,8 @@ struct mborder_slot : mcompound_widget_slot { * mborder是一个容器组件,只能包含一个子组件,并在其周围添加可配置的边距。 * 通过调整margin属性可以控制子组件与边框之间的距离。 */ -class mborder : public mcompound_widget { +template +class mborder : public mcompound_widget { public: /** * @brief 排列子组件 @@ -51,7 +52,7 @@ public: * 子组件将根据对齐方式和设置的边距进行布局。 */ virtual void arrange_children(const geometry_t& in_allotted_geometry) override { - const auto& slot = get_child_slot(); + const auto& slot = this->get_child_slot(); if (const auto child_widget = slot.get()) arrange_single_child(in_allotted_geometry, child_widget, @@ -61,10 +62,10 @@ public: } Eigen::Vector2f compute_desired_size(float in_layout_scale_multiplier) const override { - if (const auto& child = get_child_slot().get()) { + if (const auto& child = this->get_child_slot().get()) { // 获取子部件的期望大小 const auto& child_size = child->compute_desired_size(in_layout_scale_multiplier); - const auto& margin = slot_.margin(); + const auto& margin = this->slot_.margin(); // 添加边距的贡献 // return child_size + Eigen::Vector2f(margin.horizontal(), margin.vertical()); diff --git a/src/mirage_widget/src/widget/compound_widget/mbutton.cpp b/src/mirage_widget/src/widget/compound_widget/mbutton.cpp index 9b9d0f6..60defde 100644 --- a/src/mirage_widget/src/widget/compound_widget/mbutton.cpp +++ b/src/mirage_widget/src/widget/compound_widget/mbutton.cpp @@ -16,6 +16,10 @@ void mbutton::init() { set_visibility(visibility_t::visible); } +void mbutton::setup_widget(const button_args& in_args) { + mborder::setup_widget(in_args); +} + void mbutton::on_paint(mirage_paint_context& in_context) { in_context.drawer().make_rounded_rect( { 0, 0 }, diff --git a/src/mirage_widget/src/widget/compound_widget/mbutton.h b/src/mirage_widget/src/widget/compound_widget/mbutton.h index 0eb6d10..a69c104 100644 --- a/src/mirage_widget/src/widget/compound_widget/mbutton.h +++ b/src/mirage_widget/src/widget/compound_widget/mbutton.h @@ -1,11 +1,15 @@ #pragma once #include "mborder.h" -class mbutton : public mborder { +struct button_args { + WARG(linear_color, color) +}; + +class mbutton : public mborder { public: mbutton(); virtual void init() override; - + void setup_widget(const button_args& in_args) override; virtual void on_paint(mirage_paint_context& in_context) override; virtual void on_click(const Eigen::Vector2f& in_position, mouse_button in_button) override; diff --git a/src/mirage_widget/src/widget/leaf_widget/mimage.cpp b/src/mirage_widget/src/widget/leaf_widget/mimage.cpp index 3a5e861..ae566d4 100644 --- a/src/mirage_widget/src/widget/leaf_widget/mimage.cpp +++ b/src/mirage_widget/src/widget/leaf_widget/mimage.cpp @@ -2,6 +2,15 @@ #include "texture/texture.h" +void mimage::setup_widget(const image_args& in_args) { + set_color(in_args.color()); + set_image(in_args.image()); + if (in_args.sampler()) + set_sampler(in_args.sampler()); + else + set_sampler(texture_sampler_builder::get_sampler(sampler_type::default_)); +} + void mimage::on_paint(mirage_paint_context& in_context) { if (!image_) { return; diff --git a/src/mirage_widget/src/widget/leaf_widget/mimage.h b/src/mirage_widget/src/widget/leaf_widget/mimage.h index 135171f..6d0b855 100644 --- a/src/mirage_widget/src/widget/leaf_widget/mimage.h +++ b/src/mirage_widget/src/widget/leaf_widget/mimage.h @@ -4,8 +4,15 @@ class texture; -class mimage : public mleaf_widget { +struct image_args { + WARG(std::shared_ptr, image) + WARG(linear_color, color) + WARG(std::shared_ptr, sampler) +}; + +class mimage : public mleaf_widget { public: + void setup_widget(const image_args& in_args) override; void on_paint(mirage_paint_context& in_context) override; Eigen::Vector2f compute_desired_size(float in_layout_scale_multiplier) const override; @@ -19,6 +26,6 @@ public: void set_sampler(sampler_type in_type); private: std::shared_ptr image_; - std::shared_ptr sampler_ = texture_sampler_builder::get_sampler(sampler_type::default_); + std::shared_ptr sampler_; linear_color color_ = { 1, 1, 1, 1 }; }; diff --git a/src/mirage_widget/src/widget/leaf_widget/mtext_block.cpp b/src/mirage_widget/src/widget/leaf_widget/mtext_block.cpp index abd86a5..49744bd 100644 --- a/src/mirage_widget/src/widget/leaf_widget/mtext_block.cpp +++ b/src/mirage_widget/src/widget/leaf_widget/mtext_block.cpp @@ -6,6 +6,15 @@ #include "font/font_system.h" +void mtext_block::setup_widget(const text_block_args& in_args) { + text_ = in_args.text(); + font_ = in_args.font(); + font_size_ = in_args.font_size().value_or(15.f); + line_spacing_ = in_args.line_spacing().value_or(1.2f); + max_width_ = in_args.max_width().value_or(0.f); + update_layout(); +} + void mtext_block::on_paint(mirage_paint_context& in_context) { // 绘制文本 in_context.drawer().make_text( diff --git a/src/mirage_widget/src/widget/leaf_widget/mtext_block.h b/src/mirage_widget/src/widget/leaf_widget/mtext_block.h index 4b85045..1ff0227 100644 --- a/src/mirage_widget/src/widget/leaf_widget/mtext_block.h +++ b/src/mirage_widget/src/widget/leaf_widget/mtext_block.h @@ -4,44 +4,42 @@ class font_face_interface; -class mtext_block : public mleaf_widget { -public: +struct text_block_args { + WARG(std::u32string, text) + WARG(std::shared_ptr, font) + WARG(std::optional, font_size) + WARG(std::optional, line_spacing) + WARG(std::optional, max_width) +}; +class mtext_block : public mleaf_widget { +public: + void setup_widget(const text_block_args& in_args) override; void on_paint(mirage_paint_context& in_context) override; - auto set_text(const std::u32string& in_text) { + void set_text(const std::u32string& in_text) { text_ = in_text; update_layout(); - using this_type = std::remove_reference_t; - return std::static_pointer_cast(shared_from_this()); } - auto set_font(const std::shared_ptr& in_font) { + void set_font(const std::shared_ptr& in_font) { font_ = in_font; update_layout(); - using this_type = std::remove_reference_t; - return std::static_pointer_cast(shared_from_this()); } - auto set_font_size(float in_font_size) { + void set_font_size(float in_font_size) { font_size_ = in_font_size; update_layout(); - using this_type = std::remove_reference_t; - return std::static_pointer_cast(shared_from_this()); } - auto set_line_spacing(float in_line_spacing) { + void set_line_spacing(float in_line_spacing) { line_spacing_ = in_line_spacing; update_layout(); - using this_type = std::remove_reference_t; - return std::static_pointer_cast(shared_from_this()); } - auto set_max_width(float in_max_width) { + void set_max_width(float in_max_width) { max_width_ = in_max_width; update_layout(); - using this_type = std::remove_reference_t; - return std::static_pointer_cast(shared_from_this()); } const auto& get_text() const { return text_; } @@ -58,7 +56,7 @@ private: std::u32string text_; text_layout_t layout_{}; - float font_size_ = 15.0f; + float font_size_ = .0f; float line_spacing_ = 1.2f; float max_width_ = 0.0f; std::shared_ptr font_; diff --git a/src/mirage_widget/src/widget/mcompound_widget.h b/src/mirage_widget/src/widget/mcompound_widget.h index 937432f..23550fd 100644 --- a/src/mirage_widget/src/widget/mcompound_widget.h +++ b/src/mirage_widget/src/widget/mcompound_widget.h @@ -29,9 +29,9 @@ struct mcompound_widget_slot { auto& me() { return static_cast(*this); } - std::weak_ptr slot_owner; + std::weak_ptr slot_owner; - operator std::shared_ptr() const { return slot_owner.lock(); } + operator std::shared_ptr() const { return slot_owner.lock(); } // 插槽功能宏 - 定义内容管理和对齐属性 SLOT_CONTENT() @@ -49,8 +49,8 @@ struct mcompound_widget_slot { * 这个类是所有只需要单个子组件的组件的基类。它处理子组件的 * 尺寸计算、布局和绘制等常见任务。 */ -template -class mcompound_widget : public mwidget { +template +class mcompound_widget : public mwidget { public: using slot_type = SlotType; //-------------- 内容设置 -------------- @@ -58,8 +58,8 @@ public: auto& push_slot(const SlotType& in_slot) { const auto& child_widget = in_slot.get(); on_set_content(child_widget); - invalidate(invalidate_reason::layout); - auto shared_this = shared_from_this(); + this->invalidate(invalidate_reason::layout); + auto shared_this = this->shared_from_this(); slot_ = in_slot; @@ -73,7 +73,7 @@ public: } auto operator[](const SlotType& in_slot) { push_slot(in_slot); - return shared_from_this(); + return this->shared_from_this(); } //-------------- 尺寸计算 -------------- @@ -116,7 +116,7 @@ protected: * 派生类可以重写此函数来处理子组件设置时的特殊逻辑。 * 基类实现为空。 */ - virtual void on_set_content(const std::shared_ptr& in_widget) {} + virtual void on_set_content(const std::shared_ptr& in_widget) {} SlotType slot_; }; @@ -126,8 +126,8 @@ protected: * * 如果有子组件且不是collapsed状态,则返回子组件的期望大小,否则返回零大小。 */ -template -Eigen::Vector2f mcompound_widget::compute_desired_size(float in_layout_scale_multiplier) const { +template +Eigen::Vector2f mcompound_widget::compute_desired_size(float in_layout_scale_multiplier) const { if (const auto& child_widget = get_child_slot().get()) { if (has_any_flag(child_widget->get_visibility(), visibility_t::any_visible)) { return child_widget->compute_desired_size(in_layout_scale_multiplier); @@ -141,8 +141,8 @@ Eigen::Vector2f mcompound_widget::compute_desired_size(float in_layout * * 使用layout_utils中的arrange_single_child函数根据对齐属性排列单个子组件。 */ -template -void mcompound_widget::arrange_children(const geometry_t& in_allotted_geometry) { +template +void mcompound_widget::arrange_children(const geometry_t& in_allotted_geometry) { const auto& slot = get_child_slot(); if (const auto& child_widget = slot.get()) { arrange_single_child(in_allotted_geometry, child_widget, slot.h_alignment(), slot.v_alignment(), {}); diff --git a/src/mirage_widget/src/widget/mleaf_widget.h b/src/mirage_widget/src/widget/mleaf_widget.h index aa6d00d..066a510 100644 --- a/src/mirage_widget/src/widget/mleaf_widget.h +++ b/src/mirage_widget/src/widget/mleaf_widget.h @@ -5,7 +5,8 @@ * @class mleaf_widget * @brief 不允许任何子组件的叶子组件基类 */ -class mleaf_widget : public mwidget { +template +class mleaf_widget : public mwidget { public: void arrange_children(const geometry_t& in_allotted_geometry) override { (void)in_allotted_geometry; } }; diff --git a/src/mirage_widget/src/widget/mpanel_widget.h b/src/mirage_widget/src/widget/mpanel_widget.h index 79ec0c5..a955ddc 100644 --- a/src/mirage_widget/src/widget/mpanel_widget.h +++ b/src/mirage_widget/src/widget/mpanel_widget.h @@ -28,7 +28,7 @@ struct mpanel_widget_slot { auto& me() { return static_cast(*this); } - std::weak_ptr slot_owner; + std::weak_ptr slot_owner; operator auto() const { return slot_owner.lock(); } @@ -47,8 +47,8 @@ struct mpanel_widget_slot { * 这个类是所有需要容纳多个子组件的面板组件的基类。 * 它提供了子组件的管理和查询功能。 */ -template -class mpanel_widget : public mwidget { +template +class mpanel_widget : public mwidget { public: using slot_type = SlotType; @@ -74,7 +74,7 @@ public: */ auto& add_slot() { auto& slot = slots_.emplace_back(); - auto shared_this = shared_from_this(); + auto shared_this = this->shared_from_this(); slot.slot_owner = shared_this; @@ -84,14 +84,14 @@ public: if (slot.has_visibility()) { child_widget->set_visibility(slot.visibility()); } - invalidate(invalidate_reason::all); + this->invalidate(invalidate_reason::all); return slot; } template auto& add_slot(Args&&... in_args) { auto& slot = slots_.emplace_back(std::forward(in_args)...); - auto shared_this = shared_from_this(); + auto shared_this = this->shared_from_this(); slot.slot_owner = shared_this; @@ -101,12 +101,12 @@ public: if (slot.has_visibility()) { child_widget->set_visibility(slot.visibility()); } - invalidate(invalidate_reason::all); + this->invalidate(invalidate_reason::all); return slot; } auto& push_slot(const SlotType& in_slot) { auto& slot = slots_.emplace_back(in_slot); - auto shared_this = shared_from_this(); + auto shared_this = this->shared_from_this(); slot.slot_owner = shared_this; @@ -116,7 +116,7 @@ public: if (slot.has_visibility()) { child_widget->set_visibility(slot.visibility()); } - invalidate(invalidate_reason::all); + this->invalidate(invalidate_reason::all); return slot; } @@ -126,14 +126,14 @@ public: auto operator[](auto... in_slot) { for (const auto& slot: { in_slot... }) { add_slot(slot); } - return shared_from_this(); + return this->shared_from_this(); } private: std::vector slots_; }; -template -void mpanel_widget::cache_all_children_desired_size(float in_layout_scale_multiplier, bool in_force) const { +template +void mpanel_widget::cache_all_children_desired_size(float in_layout_scale_multiplier, bool in_force) const { for (const auto& slot: slots_) { const auto& ptr = slot.get(); ptr->cache_desired_size(in_layout_scale_multiplier, in_force); diff --git a/src/mirage_widget/src/widget/mwidget.cpp b/src/mirage_widget/src/widget/mwidget.cpp index 8b77742..c1dfec0 100644 --- a/src/mirage_widget/src/widget/mwidget.cpp +++ b/src/mirage_widget/src/widget/mwidget.cpp @@ -3,41 +3,41 @@ #include "window/mwindow.h" #include "geometry/dpi_helper.h" -mwidget::~mwidget() { +mwidget_interface::~mwidget_interface() { remove_from_parent(); } -const mwindow* mwidget::get_window() const { +const mwindow* mwidget_interface::get_window() const { if (const auto parent = get_parent()) { return parent->get_window(); } return nullptr; } -mwindow* mwidget::get_window() { +mwindow* mwidget_interface::get_window() { if (const auto parent = get_parent()) { return parent->get_window(); } return nullptr; } -void mwidget::set_geometry(const geometry_t& in_geometry) { +void mwidget_interface::set_geometry(const geometry_t& in_geometry) { geometry_ = in_geometry; } -void mwidget::cache_desired_size(float in_layout_scale_multiplier, bool in_force) { +void mwidget_interface::cache_desired_size(float in_layout_scale_multiplier, bool in_force) { if (!in_force && desired_size_.has_value()) return; desired_size_ = compute_desired_size(in_layout_scale_multiplier); } -auto mwidget::get_dpi_scale() const -> float { +auto mwidget_interface::get_dpi_scale() const -> float { if (const auto window = get_window()) return window->get_dpi_scale(); return 1.f; } -void mwidget::set_parent(const std::shared_ptr& in_parent) { +void mwidget_interface::set_parent(const std::shared_ptr& in_parent) { // 先从原父节点中移除 remove_from_parent(); @@ -46,7 +46,7 @@ void mwidget::set_parent(const std::shared_ptr& in_parent) { in_parent->add_child(shared_from_this()); } -void mwidget::remove_from_parent() { +void mwidget_interface::remove_from_parent() { const auto parent = get_parent(); if (!parent) return; @@ -54,7 +54,7 @@ void mwidget::remove_from_parent() { parent->remove_child(shared_from_this()); } -void mwidget::add_child(const std::shared_ptr& in_child) { +void mwidget_interface::add_child(const std::shared_ptr& in_child) { #if DEBUG // 避免重复添加 const auto& it = std::ranges::find_if(children_, [&](const auto& child) { return child == in_child; }); @@ -64,7 +64,7 @@ void mwidget::add_child(const std::shared_ptr& in_child) { invalidate(invalidate_reason::layout); } -void mwidget::remove_child(const std::shared_ptr& in_child) { +void mwidget_interface::remove_child(const std::shared_ptr& in_child) { const auto& it = std::ranges::find_if(children_, [&](const auto& child) { return child == in_child; }); @@ -74,7 +74,7 @@ void mwidget::remove_child(const std::shared_ptr& in_child) { invalidate(invalidate_reason::layout); } -void mwidget::invalidate(invalidate_reason in_reason) { +void mwidget_interface::invalidate(invalidate_reason in_reason) { // 设置失效标记 set_flag(invalidate_, in_reason); @@ -89,7 +89,7 @@ void mwidget::invalidate(invalidate_reason in_reason) { } } -bool mwidget::can_hit_test() const { +bool mwidget_interface::can_hit_test() const { // 不可见组件不参与命中测试 if (has_any_flag(visibility_, visibility_t::any_invisible)) { return false; diff --git a/src/mirage_widget/src/widget/mwidget.h b/src/mirage_widget/src/widget/mwidget.h index b285864..f512416 100644 --- a/src/mirage_widget/src/widget/mwidget.h +++ b/src/mirage_widget/src/widget/mwidget.h @@ -7,12 +7,12 @@ class mwindow; /** - * @class mwidget + * @class mwidget_interface * @brief UI组件的基类 */ -class mwidget : public std::enable_shared_from_this { +class mwidget_interface : public std::enable_shared_from_this { public: - virtual ~mwidget(); + virtual ~mwidget_interface(); virtual const mwindow* get_window() const; virtual mwindow* get_window(); @@ -32,11 +32,11 @@ public: auto get_parent() const { return parent_.lock(); } const auto& get_children() const { return children_; } - void set_parent(const std::shared_ptr& in_parent); + void set_parent(const std::shared_ptr& in_parent); void remove_from_parent(); - void add_child(const std::shared_ptr& in_child); - void remove_child(const std::shared_ptr& in_child); + void add_child(const std::shared_ptr& in_child); + void remove_child(const std::shared_ptr& in_child); virtual void invalidate(invalidate_reason in_reason); auto has_invalidate_reason(invalidate_reason in_reason) const { return has_any_flag(invalidate_, in_reason); } @@ -113,12 +113,41 @@ public: virtual hit_test_handle on_mouse_wheel(const Eigen::Vector2f& in_position, const wheel_event& in_delta) { return hit_test_handle::unhandled(); } protected: - bool enabled_ = true; - invalidate_reason invalidate_{}; - visibility_t visibility_ = visibility_t::self_hit_test_invisible; - std::optional desired_size_{}; - std::weak_ptr parent_; - std::vector> children_; - geometry_t geometry_{}; - std::string tag{}; // 风格标签 + bool enabled_ = true; + invalidate_reason invalidate_{}; + visibility_t visibility_ = visibility_t::self_hit_test_invisible; + std::optional desired_size_{}; + std::weak_ptr parent_; + std::vector> children_; + geometry_t geometry_{}; + std::string tag{}; // 风格标签 }; + +struct null_args { + +}; + +template +class mwidget : public mwidget_interface { +public: + using construct_args = ConstructArgs; + virtual void setup_widget(const ConstructArgs& in_args) {} +}; + +#define WARG(type, name) \ + protected: \ + type name##_{}; \ + public: \ + const auto& name() const { return name##_; } \ + auto& name(const type& in_value) { \ + name##_ = in_value; \ + return *this; \ + } \ + auto& name(type&& in_value) { \ + name##_ = std::move(in_value); \ + return *this; \ + } \ + auto& name(const type* in_value) { \ + name##_ = *in_value; \ + return *this; \ + } \ diff --git a/src/mirage_widget/src/widget/slot_util.h b/src/mirage_widget/src/widget/slot_util.h index 1855558..b9cb8b9 100644 --- a/src/mirage_widget/src/widget/slot_util.h +++ b/src/mirage_widget/src/widget/slot_util.h @@ -26,21 +26,21 @@ #define SLOT_CONTENT() \ public: \ - auto& set(const std::shared_ptr& in_widget) { \ + auto& set(const std::shared_ptr& in_widget) { \ widget_ = in_widget; \ return me(); \ } \ const auto& get() const { return widget_; } \ - auto& operator()(const std::shared_ptr& in_widget) { \ + auto& operator[](const std::shared_ptr& in_widget) { \ set(in_widget); \ return me(); \ } \ - auto& operator+(const std::shared_ptr& in_widget) { \ + auto& operator+(const std::shared_ptr& in_widget) { \ set(in_widget); \ return me(); \ } \ protected: \ - std::shared_ptr widget_{}; + std::shared_ptr widget_{}; #define SLOT_SIZE() \ public: \ diff --git a/src/mirage_widget/src/widget/widget_new.h b/src/mirage_widget/src/widget/widget_new.h index ad809ac..1bb2fd9 100644 --- a/src/mirage_widget/src/widget/widget_new.h +++ b/src/mirage_widget/src/widget/widget_new.h @@ -13,6 +13,7 @@ */ template struct mwidget_decl { + using construct_args = typename WidgetType::construct_args; mwidget_decl() { widget_ = std::make_shared(); } @@ -30,12 +31,13 @@ struct mwidget_decl { auto operator[](Args&&... in_args) { return std::static_pointer_cast((*widget_)[std::forward(in_args)...]); } - auto operator->() { - return widget_.get(); + auto& setup(const construct_args& in_args) { + widget_->setup_widget(in_args); + return *this; } - operator std::shared_ptr() const { return widget_; } - std::shared_ptr widget_; + operator std::shared_ptr() const { return widget_; } + std::shared_ptr widget_; }; /** @@ -56,6 +58,8 @@ button->push_slot( */ #define mslot(type) type::slot_type() +#define margs(type) type::construct_args() + /** * @param type 组件类型 * @code @@ -75,4 +79,4 @@ mnew(mv_box) * @endcode * @note 对于简单的创建控件也可以不使用mnew方式,而是使用std::make_shared(),然后使用布局容器的成员函数来管理布局,具体可以看mcompound_widget和mpanel_widget */ -#define mnew(type, ...) mwidget_decl(__VA_ARGS__) +#define mnew(type, ...) mwidget_decl().setup(type::construct_args()__VA_ARGS__) diff --git a/src/mirage_widget/src/widget_tree/hit_test_result.h b/src/mirage_widget/src/widget_tree/hit_test_result.h index a00c12f..ed48169 100644 --- a/src/mirage_widget/src/widget_tree/hit_test_result.h +++ b/src/mirage_widget/src/widget_tree/hit_test_result.h @@ -7,7 +7,7 @@ #include #include -class mwidget; +class mwidget_interface; /** * @enum hit_test_result_behavior * @brief 定义命中测试结果的行为 @@ -42,7 +42,7 @@ private: }; struct hit_test_result { - std::shared_ptr widget; + std::shared_ptr widget; Eigen::Vector2f widget_space_pos; operator bool() const { diff --git a/src/mirage_widget/src/widget_utils/layout_utils.cpp b/src/mirage_widget/src/widget_utils/layout_utils.cpp index f4a26be..51a0095 100644 --- a/src/mirage_widget/src/widget_utils/layout_utils.cpp +++ b/src/mirage_widget/src/widget_utils/layout_utils.cpp @@ -3,7 +3,7 @@ // #include "layout_utils.h" -void arrange_single_child(const geometry_t& in_allotted_geometry, const std::shared_ptr& child_widget, +void arrange_single_child(const geometry_t& in_allotted_geometry, const std::shared_ptr& child_widget, horizontal_alignment_t h_alignment, vertical_alignment_t v_alignment, const margin_t& margin) { if (!child_widget) return; diff --git a/src/mirage_widget/src/widget_utils/layout_utils.h b/src/mirage_widget/src/widget_utils/layout_utils.h index 1efba40..7de44c9 100644 --- a/src/mirage_widget/src/widget_utils/layout_utils.h +++ b/src/mirage_widget/src/widget_utils/layout_utils.h @@ -14,7 +14,7 @@ */ void arrange_single_child( const geometry_t& in_allotted_geometry, - const std::shared_ptr& child_widget, + const std::shared_ptr& child_widget, horizontal_alignment_t h_alignment, vertical_alignment_t v_alignment, const margin_t& margin = margin_t() // 默认为空边距 @@ -48,13 +48,13 @@ void arrange_box_children( // 第一轮:收集可见部件信息并计算自动尺寸 struct slot_widget_info { - std::shared_ptr widget; - const SlotType* slot; - float size{}; - float margin_start{}; // 主轴起始边缘的margin - float margin_end{}; // 主轴结束边缘的margin - float margin_cross_start{}; // 交叉轴起始边缘的margin - float margin_cross_end{}; // 交叉轴结束边缘的margin + std::shared_ptr widget; + const SlotType* slot; + float size{}; + float margin_start{}; // 主轴起始边缘的margin + float margin_end{}; // 主轴结束边缘的margin + float margin_cross_start{}; // 交叉轴起始边缘的margin + float margin_cross_end{}; // 交叉轴结束边缘的margin }; std::vector visible_widgets; @@ -71,23 +71,23 @@ void arrange_box_children( if (!has_any_flag(widget->get_visibility(), in_visibility_filter)) continue; - const auto& margin = child_slot.margin(); - const float margin_left = margin.left; - const float margin_right = margin.right; - const float margin_top = margin.top; + const auto& margin = child_slot.margin(); + const float margin_left = margin.left; + const float margin_right = margin.right; + const float margin_top = margin.top; const float margin_bottom = margin.bottom; float margin_start, margin_end, margin_cross_start, margin_cross_end; if (is_horizontal) { - margin_start = margin_left; - margin_end = margin_right; + margin_start = margin_left; + margin_end = margin_right; margin_cross_start = margin_top; - margin_cross_end = margin_bottom; + margin_cross_end = margin_bottom; } else { - margin_start = margin_top; - margin_end = margin_bottom; + margin_start = margin_top; + margin_end = margin_bottom; margin_cross_start = margin_left; - margin_cross_end = margin_right; + margin_cross_end = margin_right; } total_margins += margin_start + margin_end; @@ -161,10 +161,10 @@ void arrange_box_children( pos.x() = position; // --- 交叉轴 (Y) --- - pos.y() = info.margin_cross_start; + pos.y() = info.margin_cross_start; const float available_height = container_size.y() - (info.margin_cross_start + info.margin_cross_end); - const float widget_height = desired_size.y(); // 控件期望的高度 - float final_height = available_height; // 默认拉伸交叉轴 + const float widget_height = desired_size.y(); // 控件期望的高度 + float final_height = available_height; // 默认拉伸交叉轴 if constexpr (has_vertical_alignment) { const auto& v_alignment = info.slot->vertical_alignment(); @@ -200,10 +200,10 @@ void arrange_box_children( pos.y() = position; // --- 交叉轴 (X) --- - pos.x() = info.margin_cross_start; + pos.x() = info.margin_cross_start; const float available_width = container_size.x() - (info.margin_cross_start + info.margin_cross_end); - const float widget_width = desired_size.x(); // 控件期望的宽度 - float final_width = available_width; // 默认拉伸交叉轴 + const float widget_width = desired_size.x(); // 控件期望的宽度 + float final_width = available_width; // 默认拉伸交叉轴 if constexpr (has_horizontal_alignment) { const auto& h_alignment = info.slot->horizontal_alignment(); diff --git a/src/mirage_widget/src/window/mwindow.cpp b/src/mirage_widget/src/window/mwindow.cpp index 4b89d3a..9b17342 100644 --- a/src/mirage_widget/src/window/mwindow.cpp +++ b/src/mirage_widget/src/window/mwindow.cpp @@ -52,11 +52,11 @@ platform_window* mwindow::get_platform_window() const { return pimpl_->get_platform_window(); } -void mwindow::set_content(const std::shared_ptr& content) { +void mwindow::set_content(const std::shared_ptr& content) { pimpl_->set_content(content); } -std::shared_ptr mwindow::get_content() const { +std::shared_ptr mwindow::get_content() const { return pimpl_->get_content(); } diff --git a/src/mirage_widget/src/window/mwindow.h b/src/mirage_widget/src/window/mwindow.h index 3b64d08..1f0f2a2 100644 --- a/src/mirage_widget/src/window/mwindow.h +++ b/src/mirage_widget/src/window/mwindow.h @@ -28,7 +28,7 @@ struct wheel_event; * 表示一个可以包含UI组件的窗口。提供窗口创建、操作、样式设置和内容布局等功能。 * 作为一个组件容器,窗口本身也是一个UI组件。 */ -class mwindow : public mwidget { +class mwindow : public mwidget { public: /** @@ -68,13 +68,13 @@ public: * @brief 设置窗口内容 * @param content 要设置为内容的组件 */ - void set_content(const std::shared_ptr& content); + void set_content(const std::shared_ptr& content); /** * @brief 获取窗口内容 * @return 窗口内容组件 */ - [[nodiscard]] auto get_content() const -> std::shared_ptr; + [[nodiscard]] auto get_content() const -> std::shared_ptr; //-------------- 几何与变换 -------------- /** diff --git a/src/mirage_widget/src/window/mwindow_impl.cpp b/src/mirage_widget/src/window/mwindow_impl.cpp index 69af71d..19318bb 100644 --- a/src/mirage_widget/src/window/mwindow_impl.cpp +++ b/src/mirage_widget/src/window/mwindow_impl.cpp @@ -11,8 +11,8 @@ struct mouse_state { Eigen::Vector2f press_position = Eigen::Vector2f::Zero(); time_type press_time{}; time_type last_click_time{}; - std::weak_ptr hover_widget; - std::weak_ptr hit_widget; + std::weak_ptr hover_widget; + std::weak_ptr hit_widget; void reset() { position = Eigen::Vector2f::Zero(); @@ -172,7 +172,7 @@ public: } // 内容管理 - void set_content(const std::shared_ptr& widget) { + void set_content(const std::shared_ptr& widget) { content_widget_ = widget; if (widget) { widget->init(); @@ -181,7 +181,7 @@ public: } } - std::shared_ptr get_content() const { + std::shared_ptr get_content() const { return content_widget_; } @@ -198,7 +198,7 @@ public: } // 辅助函数 - void invalidate_recursive(mwidget* widget, invalidate_reason reason) { + void invalidate_recursive(mwidget_interface* widget, invalidate_reason reason) { if (!widget) return; widget->invalidate(reason); @@ -213,7 +213,7 @@ public: } // 布局与绘制 - void paint_all(mwidget* widget) { + void paint_all(mwidget_interface* widget) { if (!widget || !is_visible_in_viewport(widget)) { return; } @@ -228,7 +228,7 @@ public: } } - bool is_visible_in_viewport(mwidget* widget) { + bool is_visible_in_viewport(mwidget_interface* widget) { if (!widget) return false; // 简化版视口测试,实际实现应检查裁剪区域重叠 @@ -245,7 +245,7 @@ public: pos.y() + size.y() <= 0.0f); } - void layout_all(mwidget* widget) { + void layout_all(mwidget_interface* widget) { if (!widget) return; if (widget->has_invalidate_reason(invalidate_reason::layout)) { @@ -288,13 +288,13 @@ public: mouse_.position = window_pos; // 执行命中测试,查找鼠标位置下的控件 - const auto& result = perform_hit_test(window_pos, [](mwidget* widget, const Eigen::Vector2f& local_pos) { + const auto& result = perform_hit_test(window_pos, [](mwidget_interface* widget, const Eigen::Vector2f& local_pos) { return widget->on_mouse_move(local_pos); }); // 如果悬停控件没有变化,直接返回 - std::shared_ptr hover_widget = result.widget; - std::shared_ptr last_hover = mouse_.hover_widget.lock(); + std::shared_ptr hover_widget = result.widget; + std::shared_ptr last_hover = mouse_.hover_widget.lock(); if (last_hover == hover_widget) { return; @@ -314,7 +314,7 @@ public: void process_mouse_button_down(const Eigen::Vector2f& window_pos, mouse_button button) { // 执行命中测试,找出鼠标位置下的控件 - const auto& result = perform_hit_test(window_pos, [button](mwidget* widget, const Eigen::Vector2f& local_pos) { + const auto& result = perform_hit_test(window_pos, [button](mwidget_interface* widget, const Eigen::Vector2f& local_pos) { return widget->on_mouse_button_down(local_pos, button); }); @@ -326,14 +326,14 @@ public: void process_mouse_button_up(const Eigen::Vector2f& window_pos, mouse_button button) { // 执行命中测试,找出鼠标位置下的控件 - const auto& hit_result = perform_hit_test(window_pos, [button](mwidget* widget, const Eigen::Vector2f& local_pos) { + const auto& hit_result = perform_hit_test(window_pos, [button](mwidget_interface* widget, const Eigen::Vector2f& local_pos) { return widget->on_mouse_button_up(local_pos, button); }); const auto& widget_local_pos = hit_result.widget_space_pos; // 获取之前点击的控件 - std::shared_ptr pressed_widget = mouse_.hit_widget.lock(); + std::shared_ptr pressed_widget = mouse_.hit_widget.lock(); // 如果没有点击到任何控件,重置状态并返回 if (!pressed_widget) { @@ -359,20 +359,20 @@ public: } void process_mouse_button_dbl(const Eigen::Vector2f& window_pos, mouse_button button) { - std::shared_ptr hover_widget = mouse_.hover_widget.lock(); + std::shared_ptr hover_widget = mouse_.hover_widget.lock(); if (hover_widget) { hover_widget->on_double_click(window_pos, button); } } void process_mouse_wheel(const Eigen::Vector2f& window_pos, wheel_event wheel_event) { - perform_hit_test(window_pos, [&](mwidget* widget, const Eigen::Vector2f& local_pos) { + perform_hit_test(window_pos, [&](mwidget_interface* widget, const Eigen::Vector2f& local_pos) { return widget->on_mouse_wheel(local_pos, wheel_event); }); } void process_mouse_leave() { - std::shared_ptr hover_widget = mouse_.hover_widget.lock(); + std::shared_ptr hover_widget = mouse_.hover_widget.lock(); if (hover_widget) { hover_widget->on_mouse_leave(); } @@ -382,7 +382,7 @@ public: // 命中测试 hit_test_result perform_hit_test( const Eigen::Vector2f& window_pos, - const std::function& hit_func) const + const std::function& hit_func) const { if (!content_widget_) { return {}; @@ -391,9 +391,9 @@ public: } hit_test_result perform_hit_test( - mwidget* widget, + mwidget_interface* widget, const Eigen::Vector2f& window_pos, - const std::function& hit_func) const + const std::function& hit_func) const { if (!widget) { return {}; @@ -439,7 +439,7 @@ private: mwindow* owner_; std::unique_ptr platform_window_; std::unique_ptr window_state_; - std::shared_ptr content_widget_; + std::shared_ptr content_widget_; mirage_paint_context paint_context_; render_state render_state_; mouse_state mouse_;