#pragma once #include "widget.h" #include "render_command.h" #include "dynamic_list.h" #include "culling_config.h" #include "event_target.h" #include "modifiers/modifiers.h" #include #include #include namespace mirage { // ============================================================================ // 辅助函数:统一的属性提取 // ============================================================================ namespace stack_detail { /// @brief 从子控件中提取 stretch 信息 template std::optional extract_stretch_factor(const Child& child) { // 新系统:检测 stretch_modifier if constexpr (modifier::is_stretch_modifier) { return modifier::get_flex_factor(child); } return std::nullopt; } /// @brief 判断子控件是否应该 stretch template bool should_stretch(const Child& child) { // 新系统:检测 stretch_modifier if constexpr (modifier::is_stretch_modifier) { return true; } // 旧系统 return extract_stretch_factor(child).has_value(); } /// @brief 获取 stretch 的 flex 因子 template float get_flex_factor(const Child& child) { // 新系统:检测 stretch_modifier if constexpr (modifier::is_stretch_modifier) { return modifier::get_flex_factor(child); } // 旧系统 if (auto factor = extract_stretch_factor(child)) { return *factor; } return 0.0f; } /// @brief 检测是否为布局修饰器 template constexpr bool is_layout_modifier() { return modifier::is_layout_modifier; } } // ============================================================================ // v_stack 实现 // ============================================================================ template class v_stack : public event_target, public z_order_mixin> { public: constexpr explicit v_stack(children&&... in_children) : children_(std::forward(in_children)...) { } auto measure(const vec2f_t& available_size) const -> vec2f_t { float max_width = 0.0f; float total_height = 0.0f; std::apply([&](const auto&... child) { (process_child_measure(child, available_size, max_width, total_height), ...); }, children_); return vec2f_t{max_width, total_height}; } void arrange(const layout_state& state) { // 保存布局状态用于事件处理 m_layout_state = state; // 第一遍:计算固定尺寸和stretch总权重 float fixed_height = 0.0f; float total_flex = 0.0f; std::apply([&](const auto&... child) { (calculate_flex_info(child, state.size(), fixed_height, total_flex), ...); }, children_); // 计算可用于stretch的剩余空间 const float available_stretch_height = std::max(0.0f, state.size().y() - fixed_height); // 第二遍:实际布局 float current_y = 0.0f; std::apply([&](auto&... child) { (process_child_arrange_with_stretch(child, state, current_y, available_stretch_height, total_flex), ... ); }, children_); } void build_render_commands(render_command_builder& builder) const { // 应用 z_order 到构建器 this->apply_z_order_to_builder(builder); std::apply([&builder](const auto&... child) { (child.build_render_commands(builder), ...); }, children_); } void build_render_commands(render_command_builder& builder, const culling_context& context) const { // 应用 z_order 到构建器 this->apply_z_order_to_builder(builder); std::apply([&builder, &context](const auto&... child) { (invoke_build_render_commands(child, builder, context), ...); }, children_); } const auto& get_children() const { return children_; } // event_target 接口实现 bool contains_point(double global_x, double global_y) const override { return m_layout_state. contains_global_point(vec2f_t(static_cast(global_x), static_cast(global_y))); } std::pair global_to_local(double global_x, double global_y) const override { auto local = m_layout_state.to_local(vec2f_t(static_cast(global_x), static_cast(global_y))); return {local.x(), local.y()}; } std::vector get_event_children() const override { std::vector event_children; std::apply([&](T&... child) { ( [&]() { using ChildType = std::remove_cvref_t; // 情况 1: dynamic_list if constexpr (std::is_same_v) { event_children.push_back(const_cast(&child)); } // 情况 2: 布局修饰器 - 穿透获取内部事件目标 else if constexpr (modifier::is_layout_modifier) { if (auto* target = modifier::get_inner_event_target(const_cast(child))) { event_children.push_back(target); } } // 情况 3: 继承自 event_target 的普通 widget else if constexpr (std::is_base_of_v) { event_children.push_back(const_cast(&child)); } }() , ...); }, children_); return event_children; } private: /// @brief 计算flex布局信息(第一遍) template void calculate_flex_info(const Child& child, const vec2f_t& available_size, float& fixed_height, float& total_flex) const { if constexpr (std::is_same_v, dynamic_list>) { // dynamic_list 的子组件都按固定尺寸处理 for (const auto& sub_child : child.get_children()) { const auto child_size = sub_child.measure(available_size); fixed_height += child_size.y(); } } else if constexpr (modifier::is_stretch_modifier) { // 新系统:stretch_modifier total_flex += modifier::get_flex_factor(child); } else if constexpr (modifier::is_layout_modifier) { // 其他布局修饰器(padding, align):按固定尺寸处理 const auto child_size = child.measure(available_size); fixed_height += child_size.y(); } else { // 直接处理普通 widget(总是固定尺寸) const auto child_size = child.measure(available_size); fixed_height += child_size.y(); } } // 辅助函数:处理单个子组件的测量 template void process_child_measure(const Child& child, const vec2f_t& available_size, float& max_width, float& total_height) const { if constexpr (std::is_same_v, dynamic_list>) { // 展开 dynamic_list 的子组件 for (const auto& sub_child : child.get_children()) { const auto child_size = sub_child.measure(available_size); max_width = std::max(max_width, child_size.x()); total_height += child_size.y(); } } else if constexpr (modifier::is_stretch_modifier) { // stretch 子组件在 measure 时不贡献高度 // 但仍需测量宽度 const auto child_size = child.measure(available_size); max_width = std::max(max_width, child_size.x()); } else { // 直接处理普通 widget 或其他修饰器 const auto child_size = child.measure(available_size); max_width = std::max(max_width, child_size.x()); total_height += child_size.y(); } } // 辅助函数:处理单个子组件的布局(支持stretch) template void process_child_arrange_with_stretch(Child& child, const layout_state& state, float& current_y, float available_stretch_height, float total_flex) const { if constexpr (std::is_same_v, dynamic_list>) { // 展开 dynamic_list 的子组件 for (auto& sub_child : child.get_children()) { const auto child_size = sub_child.measure(state.size()); const auto child_state = state.derive_child(vec2f_t{0.0f, current_y}, child_size); sub_child.arrange(child_state); current_y += child_size.y(); } } else if constexpr (modifier::is_stretch_modifier) { // 新系统:stretch_modifier vec2f_t child_size; if (total_flex > 0.0f) { const float flex_factor = modifier::get_flex_factor(child); const float stretch_height = (flex_factor / total_flex) * available_stretch_height; const auto measured_size = child.measure(state.size()); child_size = vec2f_t{measured_size.x(), stretch_height}; } else { child_size = child.measure(state.size()); } const auto child_state = state.derive_child(vec2f_t{0.0f, current_y}, child_size); child.arrange(child_state); current_y += child_size.y(); } else { // 直接处理普通 widget 或其他修饰器 const auto child_size = child.measure(state.size()); const auto child_state = state.derive_child(vec2f_t{0.0f, current_y}, child_size); child.arrange(child_state); current_y += child_size.y(); } } std::tuple children_; layout_state m_layout_state; }; // ============================================================================ // h_stack 实现 // ============================================================================ template class h_stack : public event_target, public z_order_mixin> { public: explicit constexpr h_stack(children&&... in_children) : children_(std::forward(in_children)...) { } [[nodiscard]] auto measure(const vec2f_t& available_size) const -> vec2f_t { float total_width = 0.0f; float max_height = 0.0f; std::apply([&](const auto&... child) { (process_child_measure(child, available_size, total_width, max_height), ...); }, children_); return vec2f_t{total_width, max_height}; } void arrange(const layout_state& state) { m_layout_state = state; // 第一遍:计算固定尺寸和stretch总权重 float fixed_width = 0.0f; float total_flex = 0.0f; std::apply([&](const auto&... child) { (calculate_flex_info(child, state.size(), fixed_width, total_flex), ...); }, children_); // 计算可用于stretch的剩余空间 const float available_stretch_width = std::max(0.0f, state.size().x() - fixed_width); // 第二遍:实际布局 float current_x = 0.0f; std::apply([&](auto&... child) { (process_child_arrange_with_stretch(child, state, current_x, available_stretch_width, total_flex), ...); }, children_); } void build_render_commands(render_command_builder& builder) const { // 应用 z_order 到构建器 this->apply_z_order_to_builder(builder); std::apply([&builder](const auto&... child) { (child.build_render_commands(builder), ...); }, children_); } void build_render_commands(render_command_builder& builder, const culling_context& context) const { // 应用 z_order 到构建器 this->apply_z_order_to_builder(builder); std::apply([&builder, &context](const auto&... child) { (invoke_build_render_commands(child, builder, context), ...); }, children_); } [[nodiscard]] const auto& get_children() const { return children_; } // event_target 接口实现 bool contains_point(double global_x, double global_y) const override { return m_layout_state. contains_global_point(vec2f_t(static_cast(global_x), static_cast(global_y))); } std::pair global_to_local(double global_x, double global_y) const override { auto local = m_layout_state.to_local(vec2f_t(static_cast(global_x), static_cast(global_y))); return {local.x(), local.y()}; } std::vector get_event_children() const override { std::vector event_children; auto func = [&](auto&... child) { ( [&]() { using ChildType = std::remove_cvref_t; // 情况 1: dynamic_list if constexpr (std::is_same_v) { event_children.push_back(const_cast(&child)); } // 情况 2: 布局修饰器 - 穿透获取内部事件目标 else if constexpr (modifier::is_layout_modifier) { if (auto* target = modifier::get_inner_event_target(const_cast(child))) { event_children.push_back(target); } } // 情况 3: 继承自 event_target 的普通 widget else if constexpr (std::is_base_of_v) { event_children.push_back(const_cast(&child)); } }() , ...); }; std::apply(func, children_); return event_children; } private: /// @brief 计算flex布局信息(第一遍) template void calculate_flex_info(const Child& child, const vec2f_t& available_size, float& fixed_width, float& total_flex) const { if constexpr (std::is_same_v, dynamic_list>) { // dynamic_list 的子组件都按固定尺寸处理 for (const auto& sub_child : child.get_children()) { const auto child_size = sub_child.measure(available_size); fixed_width += child_size.x(); } } else if constexpr (modifier::is_stretch_modifier) { // 新系统:stretch_modifier total_flex += modifier::get_flex_factor(child); } else if constexpr (modifier::is_layout_modifier) { // 其他布局修饰器(padding, align):按固定尺寸处理 const auto child_size = child.measure(available_size); fixed_width += child_size.x(); } else { // 直接处理普通 widget(总是固定尺寸) const auto child_size = child.measure(available_size); fixed_width += child_size.x(); } } // 辅助函数:处理单个子组件的测量 template void process_child_measure(const Child& child, const vec2f_t& available_size, float& total_width, float& max_height) const { if constexpr (std::is_same_v, dynamic_list>) { // 展开 dynamic_list 的子组件 for (const auto& sub_child : child.get_children()) { const auto child_size = sub_child.measure(available_size); total_width += child_size.x(); max_height = std::max(max_height, child_size.y()); } } else if constexpr (modifier::is_stretch_modifier) { // stretch 子组件在 measure 时不贡献宽度 // 但仍需测量高度 const auto child_size = child.measure(available_size); max_height = std::max(max_height, child_size.y()); } else { // 直接处理普通 widget 或其他修饰器 const auto child_size = child.measure(available_size); total_width += child_size.x(); max_height = std::max(max_height, child_size.y()); } } // 辅助函数:处理单个子组件的布局(支持stretch) template void process_child_arrange_with_stretch(Child& child, const layout_state& state, float& current_x, float available_stretch_width, float total_flex) const { if constexpr (std::is_same_v, dynamic_list>) { // 展开 dynamic_list 的子组件 for (auto& sub_child : child.get_children()) { const auto child_size = sub_child.measure(state.size()); const auto child_state = state.derive_child(vec2f_t{current_x, 0.0f}, child_size); sub_child.arrange(child_state); current_x += child_size.x(); } } else if constexpr (modifier::is_stretch_modifier) { // 新系统:stretch_modifier vec2f_t child_size; if (total_flex > 0.0f) { const float flex_factor = modifier::get_flex_factor(child); const float stretch_width = (flex_factor / total_flex) * available_stretch_width; const auto measured_size = child.measure(state.size()); child_size = vec2f_t{stretch_width, measured_size.y()}; } else { child_size = child.measure(state.size()); } const auto child_state = state.derive_child(vec2f_t{current_x, 0.0f}, child_size); child.arrange(child_state); current_x += child_size.x(); } else { // 直接处理普通 widget 或其他修饰器 const auto child_size = child.measure(state.size()); const auto child_state = state.derive_child(vec2f_t{current_x, 0.0f}, child_size); child.arrange(child_state); current_x += child_size.x(); } } std::tuple children_; layout_state m_layout_state; }; }