#pragma once /** * @file mpanel_widget.h * @brief 定义可容纳多个子组件的面板组件基类 * * 本文件定义了mpanel_widget模板类,这是一种可以容纳多个子组件的面板组件。 * 通过模板参数SlotType可以自定义子组件插槽的具体行为。 */ #include "mwidget.h" #include "slot_util.h" /** * @struct mpanel_widget_slot * @brief 面板组件的插槽结构,管理子组件 * * @tparam T 插槽的具体类型,通常是派生自此模板的类 * * 提供了对子组件的内容管理功能。 * 使用SLOT宏来定义插槽的标准功能。 */ template struct mpanel_widget_slot { /** * @brief 获取当前实例的引用,转换为具体类型T * @return 当前实例的引用,类型为T& */ auto& me() { return static_cast(*this); } std::weak_ptr slot_owner; // 插槽功能宏 - 定义内容管理 SLOT_CONTENT() }; /** * @class mpanel_widget * @brief 可布局多个子组件的面板组件基类 * * @tparam SlotType 插槽类型,控制如何管理子组件 * * 这个类是所有需要容纳多个子组件的面板组件的基类。 * 它提供了子组件的管理和查询功能。 */ template class mpanel_widget : public mwidget { public: //-------------- 绘制 -------------- /** * @brief 绘制组件 * @param in_context 绘制上下文 * * 基类实现为空,因为面板组件通常不需要自己绘制,而是依赖子组件的绘制。 */ void on_paint(mirage_paint_context& in_context) override {} void cache_all_children_desired_size(float in_layout_scale_multiplier, bool in_force = false) const; //-------------- 子项管理 -------------- // 1. 创建一个新的entity // 2. 给entity添加一个slot component // 3. 更新父子关系 // 4. 通知父组件需要重新计算布局 // 5. 返回slot component的引用,便于链式调用设置属性 /** * @brief 添加新的子组件插槽 * @return 新添加的插槽引用,允许链式调用设置插槽属性 * * 创建并添加一个新的子组件插槽到面板中。 */ auto add_slot() -> SlotType& { auto& slot = slots_.emplace_back(); slot.slot_owner = shared_from_this(); invalidate(invalidate_reason::all); return slot; } template auto add_child(Args&&... in_args) -> SlotType& { auto& slot = slots_.emplace_back(std::forward(in_args)...); slot.slot_owner = shared_from_this(); invalidate(invalidate_reason::all); return slot; } const auto& get_slots() const { return slots_; } private: std::vector slots_; }; 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); } }