Refactor layout system: Replace slot and property_slot with layout modifiers
- Removed the slot and property_slot classes, consolidating their functionality into a new modifier system. - Introduced align_modifier, padding_modifier, and stretch_modifier to handle layout properties. - Updated overlay and stack classes to utilize the new modifier system for layout management. - Simplified event handling by integrating layout modifiers directly into the event target retrieval process. - Removed unused includes and cleaned up code for better readability and maintainability.
This commit is contained in:
@@ -20,7 +20,7 @@
|
||||
#include "post_effect.h"
|
||||
#include "layout/stack.h"
|
||||
#include "fill_box.h"
|
||||
#include "layout/slot.h"
|
||||
#include "layout/modifiers/modifiers.h" // 新的布局修饰器
|
||||
#include "image/texture_manager.h"
|
||||
|
||||
using namespace mirage;
|
||||
@@ -408,31 +408,51 @@ private:
|
||||
std::cout << "clicked" << std::endl;
|
||||
};
|
||||
|
||||
// 使用 slot 系统演示
|
||||
// slot 允许在不修改子控件的情况下附加布局参数
|
||||
// ===================================================================
|
||||
// 布局修饰器管道语法示例
|
||||
// ===================================================================
|
||||
//
|
||||
// ===== 旧写法(已弃用)=====
|
||||
// slot{
|
||||
// imager{}.texture_id(id_)
|
||||
// }.align(alignment::CENTER).padding(10.f)
|
||||
//
|
||||
// slot{
|
||||
// overlay{...}
|
||||
// } | stretch()
|
||||
//
|
||||
// ===== 新写法(推荐)=====
|
||||
// imager{}.texture_id(id_)
|
||||
// | align(alignment::CENTER)
|
||||
// | padding(10.f)
|
||||
//
|
||||
// overlay{...} | stretch()
|
||||
//
|
||||
// ===================================================================
|
||||
|
||||
// 使用新的布局修饰器管道语法
|
||||
v_stack v{
|
||||
// 普通方式:直接放置控件
|
||||
button{
|
||||
"Hello",
|
||||
on_click
|
||||
},
|
||||
// 使用 slot 方式:通过 slot 包装控件并设置对齐和边距
|
||||
slot{
|
||||
overlay{
|
||||
// 使用 slot 设置图片居中对齐
|
||||
slot{
|
||||
imager{}
|
||||
.texture_id(texture_id_)
|
||||
.fit(image_fit::contain)
|
||||
.set_texture_size(texture_size_)
|
||||
}.align(alignment::CENTER).padding(10.f),
|
||||
// 普通后效控件(不使用 slot)
|
||||
post_effect_widget{
|
||||
fill_box{},
|
||||
blur_effect{20.f}
|
||||
},
|
||||
}
|
||||
} | stretch()
|
||||
// 新的管道语法:通过修饰器添加布局属性
|
||||
// 不再需要 slot{} 包装,直接使用 | 管道操作符
|
||||
overlay{
|
||||
// 使用管道语法设置图片居中对齐和边距
|
||||
imager{}
|
||||
.texture_id(texture_id_)
|
||||
.fit(image_fit::contain)
|
||||
.set_texture_size(texture_size_)
|
||||
| align(alignment::CENTER)
|
||||
| padding(10.f),
|
||||
// 普通后效控件
|
||||
post_effect_widget{
|
||||
fill_box{},
|
||||
blur_effect{20.f}
|
||||
},
|
||||
} | stretch() // 直接对 overlay 应用 stretch,无需 slot 包装
|
||||
};
|
||||
|
||||
layout_state state;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "widget.h"
|
||||
#include "render_command.h"
|
||||
#include "event_target.h"
|
||||
#include "layout/modifiers/modifier_traits.h"
|
||||
#include <memory>
|
||||
|
||||
using mirage::event_target;
|
||||
@@ -41,7 +42,12 @@ class any_widget {
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_event_target() -> event_target* override {
|
||||
if constexpr (std::is_base_of_v<event_target, T>) {
|
||||
// 情况 1: 布局修饰器 - 穿透获取内部事件目标
|
||||
if constexpr (mirage::modifier::is_layout_modifier<T>) {
|
||||
return mirage::modifier::get_inner_event_target(data);
|
||||
}
|
||||
// 情况 2: 继承自 event_target 的普通 widget
|
||||
else if constexpr (std::is_base_of_v<event_target, T>) {
|
||||
return &data;
|
||||
}
|
||||
else {
|
||||
@@ -50,7 +56,12 @@ class any_widget {
|
||||
}
|
||||
|
||||
[[nodiscard]] auto get_event_target() const -> const event_target* override {
|
||||
if constexpr (std::is_base_of_v<event_target, T>) {
|
||||
// 情况 1: 布局修饰器 - 穿透获取内部事件目标
|
||||
if constexpr (mirage::modifier::is_layout_modifier<T>) {
|
||||
return mirage::modifier::get_inner_event_target(const_cast<T&>(data));
|
||||
}
|
||||
// 情况 2: 继承自 event_target 的普通 widget
|
||||
else if constexpr (std::is_base_of_v<event_target, T>) {
|
||||
return &data;
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -3,14 +3,12 @@
|
||||
#include "render_command.h"
|
||||
#include "event_target.h"
|
||||
#include "any_widget.h"
|
||||
#include "slot.h"
|
||||
#include "layout_types.h"
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
|
||||
namespace mirage {
|
||||
// anchors 已在 slot.h 中定义
|
||||
|
||||
/// @brief Canvas槽位 - 存储子Widget及其布局信息
|
||||
struct canvas_slot {
|
||||
any_widget child; // 子Widget(使用类型擦除)
|
||||
@@ -74,69 +72,21 @@ namespace mirage {
|
||||
/// @brief 添加子Widget(默认锚点:左上角)
|
||||
template <typename W>
|
||||
auto&& add_child(this auto&& self, W&& child, vec2f_t position = vec2f_t::Zero()) {
|
||||
using ChildType = std::remove_cvref_t<W>;
|
||||
|
||||
// 情况 1: property_slot 类型(新系统)
|
||||
if constexpr (layout::is_property_slot_v<ChildType>) {
|
||||
anchors anch = anchors::top_left();
|
||||
vec2f_t pos = position;
|
||||
vec2f_t sz = vec2f_t::Zero();
|
||||
int32_t z = 0;
|
||||
|
||||
// 从 property_slot 中提取属性
|
||||
if (auto anchor_p = child.template get_property<layout::anchor_tag>()) {
|
||||
anch = anchor_p->value;
|
||||
}
|
||||
if (auto pos_p = child.template get_property<layout::position_tag>()) {
|
||||
pos = pos_p->value;
|
||||
}
|
||||
if (auto size_p = child.template get_property<layout::size_tag>()) {
|
||||
sz = size_p->value;
|
||||
}
|
||||
if (auto z_p = child.template get_property<layout::z_order_tag>()) {
|
||||
z = z_p->value;
|
||||
}
|
||||
|
||||
// property_slot 内部包含 slot,slot 会处理 padding 和 alignment
|
||||
self.slots_.emplace_back(std::forward<W>(child), anch, pos, sz, z);
|
||||
}
|
||||
// 情况 2: slot 类型(新系统,没有容器属性)
|
||||
else if constexpr (layout::is_slot_v<ChildType>) {
|
||||
// slot 会处理 padding 和 alignment,直接添加
|
||||
self.slots_.emplace_back(std::forward<W>(child), anchors::top_left(), position);
|
||||
}
|
||||
// 情况 3: 普通 widget
|
||||
else {
|
||||
self.slots_.emplace_back(std::forward<W>(child), anchors::top_left(), position);
|
||||
}
|
||||
self.slots_.emplace_back(std::forward<W>(child), anchors::top_left(), position);
|
||||
return std::forward<decltype(self)>(self);
|
||||
}
|
||||
|
||||
/// @brief 添加子Widget(指定锚点)
|
||||
template <typename W>
|
||||
auto&& add_child(this auto&& self, W&& child, anchors anchor, vec2f_t position = vec2f_t::Zero()) {
|
||||
using ChildType = std::remove_cvref_t<W>;
|
||||
|
||||
if constexpr (layout::is_property_slot_v<ChildType> || layout::is_slot_v<ChildType>) {
|
||||
self.slots_.emplace_back(std::forward<W>(child), anchor, position);
|
||||
}
|
||||
else {
|
||||
self.slots_.emplace_back(std::forward<W>(child), anchor, position);
|
||||
}
|
||||
self.slots_.emplace_back(std::forward<W>(child), anchor, position);
|
||||
return std::forward<decltype(self)>(self);
|
||||
}
|
||||
|
||||
/// @brief 添加拉伸子Widget
|
||||
template <typename W>
|
||||
auto&& add_stretched_child(this auto&& self, W&& child, anchors anchor, vec2f_t position, vec2f_t size) {
|
||||
using ChildType = std::remove_cvref_t<W>;
|
||||
|
||||
if constexpr (layout::is_property_slot_v<ChildType> || layout::is_slot_v<ChildType>) {
|
||||
self.slots_.emplace_back(std::forward<W>(child), anchor, position, size);
|
||||
}
|
||||
else {
|
||||
self.slots_.emplace_back(std::forward<W>(child), anchor, position, size);
|
||||
}
|
||||
self.slots_.emplace_back(std::forward<W>(child), anchor, position, size);
|
||||
return std::forward<decltype(self)>(self);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
#include "container_properties.h"
|
||||
#include "slot_traits.h"
|
||||
#include "widget.h"
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
|
||||
@@ -57,34 +57,4 @@ namespace mirage {
|
||||
inline constexpr bool container_supports_property_v =
|
||||
detail::tuple_contains_v<Property, typename container_capabilities<Container>::supported_properties>;
|
||||
|
||||
// ============================================================================
|
||||
// 编译期属性验证工具
|
||||
// ============================================================================
|
||||
|
||||
namespace detail {
|
||||
/// @brief 检查 property_slot 的所有属性是否都被容器支持
|
||||
template <typename Container, typename PropertySlot>
|
||||
struct all_properties_supported_impl;
|
||||
|
||||
template <typename Container, typename SlotType, typename... Properties>
|
||||
struct all_properties_supported_impl<Container, mirage::property_slot<SlotType, Properties...>> {
|
||||
static constexpr bool value = (container_supports_property_v<Container, Properties> && ...);
|
||||
};
|
||||
|
||||
template <typename Container, typename T>
|
||||
struct all_properties_supported {
|
||||
static constexpr bool value = true; // 非 property_slot 类型,默认支持
|
||||
};
|
||||
|
||||
template <typename Container, typename SlotType, typename... Properties>
|
||||
struct all_properties_supported<Container, mirage::property_slot<SlotType, Properties...>>
|
||||
: all_properties_supported_impl<Container, mirage::property_slot<SlotType, Properties...>> {
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
/// @brief 检查子控件的所有属性是否都被容器支持
|
||||
template <typename Container, typename Child>
|
||||
inline constexpr bool all_properties_supported_v =
|
||||
detail::all_properties_supported<Container, std::remove_cvref_t<Child>>::value;
|
||||
|
||||
} // namespace mirage
|
||||
@@ -61,7 +61,7 @@ namespace mirage {
|
||||
// 属性工厂函数
|
||||
// ============================================================================
|
||||
|
||||
inline constexpr auto stretch(float factor = 1.0f) { return stretch_tag{factor}; }
|
||||
// inline constexpr auto stretch(float factor = 1.0f) { return stretch_tag{factor}; }
|
||||
inline auto anchor(const anchors& a) { return anchor_tag{a}; }
|
||||
inline auto at(const vec2f_t& pos) { return position_tag{pos}; }
|
||||
inline auto at(float x, float y) { return position_tag{x, y}; }
|
||||
|
||||
69
src/widget/layout/modifiers/align_modifier.h
Normal file
69
src/widget/layout/modifiers/align_modifier.h
Normal file
@@ -0,0 +1,69 @@
|
||||
#pragma once
|
||||
|
||||
#include "layout/layout_types.h"
|
||||
#include "layout/alignment_utils.h"
|
||||
#include "widget.h"
|
||||
#include "layout_state.h"
|
||||
|
||||
namespace mirage {
|
||||
namespace modifier {
|
||||
// align 配置类
|
||||
struct align_config {
|
||||
alignment value;
|
||||
|
||||
constexpr explicit align_config(alignment a) : value(a) {
|
||||
}
|
||||
};
|
||||
|
||||
// align 修饰器类
|
||||
template <widget Child>
|
||||
class align_modifier {
|
||||
Child child_;
|
||||
alignment alignment_;
|
||||
|
||||
public:
|
||||
explicit align_modifier(Child child, alignment a) : child_(std::move(child)), alignment_(a) {
|
||||
}
|
||||
|
||||
// ===== widget concept 实现 =====
|
||||
|
||||
[[nodiscard]] auto measure(const vec2f_t& available_size) const -> vec2f_t {
|
||||
// 对于 FILL 对齐,返回可用空间;否则返回子控件测量尺寸
|
||||
if (alignment_ == alignment::FILL) {
|
||||
return available_size;
|
||||
}
|
||||
return child_.measure(available_size);
|
||||
}
|
||||
|
||||
void arrange(const layout_state& state) {
|
||||
const vec2f_t child_size = (alignment_ == alignment::FILL)
|
||||
? state.size()
|
||||
: child_.measure(state.size());
|
||||
|
||||
const vec2f_t pos = calculate_aligned_position(child_size, state.size(), alignment_);
|
||||
child_.arrange(state.derive_child(pos, child_size));
|
||||
}
|
||||
|
||||
template <typename Builder>
|
||||
void build_render_commands(Builder& builder) const {
|
||||
child_.build_render_commands(builder);
|
||||
}
|
||||
|
||||
// 访问内部子控件
|
||||
[[nodiscard]] const Child& child() const { return child_; }
|
||||
[[nodiscard]] Child& child() { return child_; }
|
||||
|
||||
// 访问对齐值
|
||||
[[nodiscard]] alignment get_alignment() const { return alignment_; }
|
||||
};
|
||||
|
||||
// 管道操作符
|
||||
template <widget W>
|
||||
auto operator|(W&& w, align_config cfg) -> align_modifier<std::remove_cvref_t<W>> {
|
||||
return align_modifier<std::remove_cvref_t<W>>(std::forward<W>(w), cfg.value);
|
||||
}
|
||||
} // namespace mirage::modifier
|
||||
|
||||
// 便捷工厂函数
|
||||
constexpr auto align(alignment a) { return modifier::align_config{a}; }
|
||||
} // namespace mirage
|
||||
79
src/widget/layout/modifiers/modifier_traits.h
Normal file
79
src/widget/layout/modifiers/modifier_traits.h
Normal file
@@ -0,0 +1,79 @@
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace mirage {
|
||||
// 前向声明 event_target(在 mirage 命名空间)
|
||||
class event_target;
|
||||
}
|
||||
|
||||
namespace mirage::modifier {
|
||||
// 前向声明
|
||||
template <widget Child>
|
||||
class padding_modifier;
|
||||
template <widget Child>
|
||||
class align_modifier;
|
||||
template <widget Child>
|
||||
class stretch_modifier;
|
||||
|
||||
// ===== 修饰器类型萃取 =====
|
||||
|
||||
// 检测是否为 stretch_modifier
|
||||
template<typename T>
|
||||
concept is_stretch_modifier = std::is_base_of_v<stretch_modifier<T>, T>;
|
||||
|
||||
// 检测是否为 padding_modifier
|
||||
template<typename T>
|
||||
concept is_padding_modifier = std::is_base_of_v<padding_modifier<std::remove_cvref_t<T>>, std::remove_cvref_t<T>>;
|
||||
|
||||
// 检测是否为 align_modifier
|
||||
template<typename T>
|
||||
concept is_align_modifier = std::is_base_of_v<align_modifier<std::remove_cvref_t<T>>, std::remove_cvref_t<T>>;
|
||||
|
||||
// 检测是否为任意布局修饰器
|
||||
template <typename T>
|
||||
concept is_layout_modifier = is_stretch_modifier<T> || is_padding_modifier<T> || is_align_modifier<T>;
|
||||
|
||||
template<typename T>
|
||||
concept has_child = requires(T t) {
|
||||
{ t.child() } -> std::same_as<typename T::child_type>;
|
||||
};
|
||||
|
||||
// 获取 flex_factor(用于 stretch)
|
||||
template <typename T>
|
||||
constexpr float get_flex_factor([[maybe_unused]] const T& widget) {
|
||||
if constexpr (is_stretch_modifier<T>) {
|
||||
return widget.flex_factor();
|
||||
}
|
||||
else {
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// 检测是否应该 stretch
|
||||
template <typename T>
|
||||
constexpr bool should_stretch([[maybe_unused]] const T& widget) {
|
||||
return is_stretch_modifier<T>;
|
||||
}
|
||||
|
||||
// ===== 事件穿透辅助函数 =====
|
||||
|
||||
/// @brief 递归获取修饰器内部的实际事件目标
|
||||
/// 如果子控件是布局修饰器,则继续向下查找
|
||||
/// 否则,如果子控件继承自 event_target,则返回该子控件的指针
|
||||
template <typename Child>
|
||||
auto get_inner_event_target(Child& child) -> event_target* {
|
||||
if constexpr (is_layout_modifier<std::remove_cvref_t<Child>>) {
|
||||
// 布局修饰器:递归获取内部子控件
|
||||
return get_inner_event_target(child.child());
|
||||
}
|
||||
else if constexpr (std::is_base_of_v<event_target, std::remove_cvref_t<Child>>) {
|
||||
// 继承自 event_target 的子控件
|
||||
return &child;
|
||||
}
|
||||
else {
|
||||
// 非 event_target 子控件
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
} // namespace mirage::modifier
|
||||
8
src/widget/layout/modifiers/modifiers.h
Normal file
8
src/widget/layout/modifiers/modifiers.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
// 布局修饰器统一入口
|
||||
|
||||
#include "modifier_traits.h"
|
||||
#include "padding_modifier.h"
|
||||
#include "align_modifier.h"
|
||||
#include "stretch_modifier.h"
|
||||
100
src/widget/layout/modifiers/padding_modifier.h
Normal file
100
src/widget/layout/modifiers/padding_modifier.h
Normal file
@@ -0,0 +1,100 @@
|
||||
#pragma once
|
||||
|
||||
#include "layout/layout_types.h"
|
||||
#include "widget.h"
|
||||
#include "layout_state.h"
|
||||
|
||||
namespace mirage {
|
||||
namespace modifier {
|
||||
// padding 配置类
|
||||
struct padding_config {
|
||||
margin value;
|
||||
|
||||
constexpr explicit padding_config(float all) : value{all, all, all, all} {
|
||||
}
|
||||
|
||||
constexpr padding_config(float horizontal, float vertical) : value{
|
||||
horizontal, vertical, horizontal, vertical
|
||||
} {
|
||||
}
|
||||
|
||||
constexpr padding_config(float left, float top, float right, float bottom) : value{
|
||||
left, top, right, bottom
|
||||
} {
|
||||
}
|
||||
|
||||
constexpr explicit padding_config(margin m) : value(m) {
|
||||
}
|
||||
};
|
||||
|
||||
// padding 修饰器类
|
||||
template <widget Child>
|
||||
class padding_modifier {
|
||||
Child child_;
|
||||
margin padding_;
|
||||
|
||||
public:
|
||||
explicit padding_modifier(Child child, margin p) : child_(std::move(child)), padding_(p) {
|
||||
}
|
||||
|
||||
// ===== widget concept 实现 =====
|
||||
|
||||
[[nodiscard]] auto measure(const vec2f_t& available_size) const -> vec2f_t {
|
||||
const float h_padding = padding_.left + padding_.right;
|
||||
const float v_padding = padding_.top + padding_.bottom;
|
||||
|
||||
// 减去 padding 后传给子控件
|
||||
const vec2f_t inner_size{
|
||||
available_size.x() > h_padding ? available_size.x() - h_padding : 0.0f,
|
||||
available_size.y() > v_padding ? available_size.y() - v_padding : 0.0f
|
||||
};
|
||||
|
||||
const vec2f_t child_size = child_.measure(inner_size);
|
||||
|
||||
// 加上 padding 返回
|
||||
return vec2f_t{child_size.x() + h_padding, child_size.y() + v_padding};
|
||||
}
|
||||
|
||||
void arrange(const layout_state& state) {
|
||||
const float h_padding = padding_.left + padding_.right;
|
||||
const float v_padding = padding_.top + padding_.bottom;
|
||||
|
||||
const vec2f_t inner_size{
|
||||
state.size().x() > h_padding ? state.size().x() - h_padding : 0.0f,
|
||||
state.size().y() > v_padding ? state.size().y() - v_padding : 0.0f
|
||||
};
|
||||
const vec2f_t offset{padding_.left, padding_.top};
|
||||
|
||||
child_.arrange(state.derive_child(offset, inner_size));
|
||||
}
|
||||
|
||||
template <typename Builder>
|
||||
void build_render_commands(Builder& builder) const {
|
||||
child_.build_render_commands(builder);
|
||||
}
|
||||
|
||||
// 访问内部子控件
|
||||
[[nodiscard]] const Child& child() const { return child_; }
|
||||
[[nodiscard]] Child& child() { return child_; }
|
||||
|
||||
// 访问 padding 值
|
||||
[[nodiscard]] const margin& get_padding() const { return padding_; }
|
||||
};
|
||||
|
||||
// 管道操作符
|
||||
template <widget W>
|
||||
auto operator|(W&& w, padding_config cfg) -> padding_modifier<std::remove_cvref_t<W>> {
|
||||
return padding_modifier<std::remove_cvref_t<W>>(std::forward<W>(w), cfg.value);
|
||||
}
|
||||
}
|
||||
|
||||
// 便捷工厂函数
|
||||
constexpr auto padding(float all) { return modifier::padding_config{all}; }
|
||||
constexpr auto padding(float horizontal, float vertical) { return modifier::padding_config{horizontal, vertical}; }
|
||||
|
||||
constexpr auto padding(float left, float top, float right, float bottom) {
|
||||
return modifier::padding_config{left, top, right, bottom};
|
||||
}
|
||||
|
||||
constexpr auto padding(margin m) { return modifier::padding_config{m}; }
|
||||
} // namespace mirage::modifier
|
||||
60
src/widget/layout/modifiers/stretch_modifier.h
Normal file
60
src/widget/layout/modifiers/stretch_modifier.h
Normal file
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
#include "widget.h"
|
||||
#include "layout_state.h"
|
||||
|
||||
namespace mirage {
|
||||
namespace modifier {
|
||||
// stretch 配置类
|
||||
struct stretch_config {
|
||||
float flex_factor = 1.0f;
|
||||
|
||||
constexpr explicit stretch_config(float f = 1.0f) : flex_factor(f) {
|
||||
}
|
||||
};
|
||||
|
||||
// stretch 修饰器类 - 作为容器属性的标记
|
||||
template <widget Child>
|
||||
class stretch_modifier {
|
||||
Child child_;
|
||||
float flex_factor_;
|
||||
|
||||
public:
|
||||
// 标记:表明这是一个 stretch 类型
|
||||
static constexpr bool is_stretch = true;
|
||||
|
||||
explicit stretch_modifier(Child child, float flex = 1.0f) : child_(std::move(child)), flex_factor_(flex) {
|
||||
}
|
||||
|
||||
[[nodiscard]] float flex_factor() const { return flex_factor_; }
|
||||
|
||||
// ===== widget concept 转发 =====
|
||||
|
||||
[[nodiscard]] auto measure(const vec2f_t& available_size) const -> vec2f_t {
|
||||
return child_.measure(available_size);
|
||||
}
|
||||
|
||||
void arrange(const layout_state& state) {
|
||||
child_.arrange(state);
|
||||
}
|
||||
|
||||
template <typename Builder>
|
||||
void build_render_commands(Builder& builder) const {
|
||||
child_.build_render_commands(builder);
|
||||
}
|
||||
|
||||
// 访问内部子控件
|
||||
[[nodiscard]] const Child& child() const { return child_; }
|
||||
[[nodiscard]] Child& child() { return child_; }
|
||||
};
|
||||
|
||||
// 管道操作符
|
||||
template <widget W>
|
||||
auto operator|(W&& w, stretch_config cfg) -> stretch_modifier<std::remove_cvref_t<W>> {
|
||||
return stretch_modifier<std::remove_cvref_t<W>>(std::forward<W>(w), cfg.flex_factor);
|
||||
}
|
||||
}
|
||||
|
||||
// 便捷工厂函数
|
||||
constexpr auto stretch(float factor = 1.0f) { return modifier::stretch_config{factor}; }
|
||||
} // namespace mirage::modifier
|
||||
@@ -4,14 +4,13 @@
|
||||
#include "event_target.h"
|
||||
#include "dynamic_list.h"
|
||||
#include "culling_config.h"
|
||||
#include "slot.h"
|
||||
#include "modifiers/modifiers.h"
|
||||
#include "layout_types.h"
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
namespace mirage {
|
||||
// alignment 和 margin 已在 slot.h 中定义
|
||||
|
||||
/// @brief Overlay容器模板
|
||||
template <widget... Children>
|
||||
class overlay : public event_target, public z_order_mixin<overlay<Children...>> {
|
||||
@@ -123,34 +122,28 @@ namespace mirage {
|
||||
|
||||
std::vector<event_target*> get_event_children() const override {
|
||||
std::vector<event_target*> event_children;
|
||||
|
||||
std::apply([&](auto&... child) {
|
||||
auto func = [&](auto&... child) {
|
||||
(
|
||||
[&]() {
|
||||
[&] {
|
||||
using ChildType = std::remove_cvref_t<decltype(child)>;
|
||||
// 情况 1: dynamic_list
|
||||
if constexpr (std::is_same_v<ChildType, dynamic_list>) {
|
||||
event_children.push_back(const_cast<dynamic_list*>(&child));
|
||||
}
|
||||
// 情况 2: property_slot 类型(新系统)
|
||||
else if constexpr (is_property_slot_v<ChildType>) {
|
||||
using SlotChildType = slot_child_type_t<ChildType>;
|
||||
if constexpr (std::is_base_of_v<event_target, SlotChildType>) {
|
||||
event_children.push_back(const_cast<SlotChildType*>(&child.child()));
|
||||
}
|
||||
}
|
||||
// 情况 3: slot 类型(新系统)
|
||||
else if constexpr (is_slot_v<ChildType>) {
|
||||
using SlotChildType = slot_child_type_t<ChildType>;
|
||||
if constexpr (std::is_base_of_v<event_target, SlotChildType>) {
|
||||
event_children.push_back(const_cast<SlotChildType*>(&child.child()));
|
||||
// 情况 2: 布局修饰器 - 穿透获取内部事件目标
|
||||
else if constexpr (modifier::is_layout_modifier<ChildType>) {
|
||||
if (auto* target = modifier::get_inner_event_target(const_cast<ChildType&>(child))) {
|
||||
event_children.push_back(target);
|
||||
}
|
||||
}
|
||||
// 情况 3: 继承自 event_target 的普通 widget
|
||||
else if constexpr (std::is_base_of_v<event_target, ChildType>) {
|
||||
event_children.push_back(const_cast<ChildType*>(&child));
|
||||
}
|
||||
}()
|
||||
, ...);
|
||||
}, children_);
|
||||
}(),
|
||||
...);
|
||||
};
|
||||
std::apply(func, children_);
|
||||
|
||||
return event_children;
|
||||
}
|
||||
@@ -174,9 +167,9 @@ namespace mirage {
|
||||
max_size = max_size.cwiseMax(child_size);
|
||||
}
|
||||
}
|
||||
else if constexpr (is_property_slot_v<Child> || is_slot_v<Child>) {
|
||||
// 新系统:slot/property_slot 直接处理 padding 和 alignment
|
||||
// 直接测量 slot,它会处理内部的 padding
|
||||
else if constexpr (modifier::is_layout_modifier<Child>) {
|
||||
// 新系统:布局修饰器(padding, align, stretch)
|
||||
// 修饰器内部已封装布局逻辑,直接调用 measure
|
||||
auto child_size = child.measure(available_size);
|
||||
max_size = max_size.cwiseMax(child_size);
|
||||
}
|
||||
@@ -200,9 +193,10 @@ namespace mirage {
|
||||
arrange_single_widget(sub_child, parent_state, overlay_size);
|
||||
}
|
||||
}
|
||||
else if constexpr (is_property_slot_v<Child> || is_slot_v<Child>) {
|
||||
// 新系统:slot/property_slot 直接处理 padding 和 alignment
|
||||
// 给 slot 分配整个 overlay 空间,让它自己处理对齐
|
||||
else if constexpr (modifier::is_layout_modifier<Child>) {
|
||||
// 新系统:布局修饰器(padding, align, stretch)
|
||||
// 修饰器内部已封装布局逻辑(align计算对齐位置,padding计算偏移)
|
||||
// 给修饰器分配整个 overlay 空间,让它自己处理布局
|
||||
const auto child_state = parent_state.derive_child(vec2f_t::Zero(), overlay_size);
|
||||
child.arrange(child_state);
|
||||
}
|
||||
|
||||
@@ -1,311 +0,0 @@
|
||||
#pragma once
|
||||
#include "widget.h"
|
||||
#include "types.h"
|
||||
#include "layout_types.h"
|
||||
#include "container_properties.h"
|
||||
#include "slot_traits.h"
|
||||
#include "container_capabilities.h"
|
||||
#include "alignment_utils.h"
|
||||
#include <tuple>
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace mirage {
|
||||
// ============================================================================
|
||||
// 前向声明
|
||||
// ============================================================================
|
||||
|
||||
// 容器前向声明
|
||||
template <widget... Children>
|
||||
class v_stack;
|
||||
template <widget... Children>
|
||||
class h_stack;
|
||||
template <widget... Children>
|
||||
class overlay;
|
||||
class canvas;
|
||||
|
||||
// ============================================================================
|
||||
// Slot 类
|
||||
// ============================================================================
|
||||
|
||||
/// @brief Slot - 处理内部布局属性(padding、alignment)
|
||||
template <typename Child>
|
||||
class slot {
|
||||
public:
|
||||
explicit slot(Child child) : child_(std::move(child)) {
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 链式调用设置 padding
|
||||
// ============================================================================
|
||||
|
||||
auto&& padding(this auto&& self, const margin& m) {
|
||||
self.padding_ = m;
|
||||
return std::forward<decltype(self)>(self);
|
||||
}
|
||||
|
||||
auto&& padding(this auto&& self, float all) {
|
||||
self.padding_ = margin(all, all, all, all);
|
||||
return std::forward<decltype(self)>(self);
|
||||
}
|
||||
|
||||
auto&& padding(this auto&& self, float horizontal, float vertical) {
|
||||
self.padding_ = margin(horizontal, vertical, horizontal, vertical);
|
||||
return std::forward<decltype(self)>(self);
|
||||
}
|
||||
|
||||
auto&& padding(this auto&& self, float left, float top, float right, float bottom) {
|
||||
self.padding_ = margin(left, top, right, bottom);
|
||||
return std::forward<decltype(self)>(self);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 链式调用设置 alignment
|
||||
// ============================================================================
|
||||
|
||||
auto&& align(this auto&& self, alignment a) {
|
||||
self.alignment_ = a;
|
||||
return std::forward<decltype(self)>(self);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Widget concept 实现
|
||||
// ============================================================================
|
||||
|
||||
auto measure(const vec2f_t& available_size) const -> vec2f_t {
|
||||
const vec2f_t inner_available(
|
||||
std::max(0.0f, available_size.x() - padding_.left - padding_.right),
|
||||
std::max(0.0f, available_size.y() - padding_.top - padding_.bottom)
|
||||
);
|
||||
|
||||
vec2f_t child_size = child_.measure(inner_available);
|
||||
|
||||
return vec2f_t(
|
||||
child_size.x() + padding_.left + padding_.right,
|
||||
child_size.y() + padding_.top + padding_.bottom
|
||||
);
|
||||
}
|
||||
|
||||
void arrange(const layout_state& state) {
|
||||
const vec2f_t inner_size(
|
||||
std::max(0.0f, state.size().x() - padding_.left - padding_.right),
|
||||
std::max(0.0f, state.size().y() - padding_.top - padding_.bottom)
|
||||
);
|
||||
|
||||
const vec2f_t child_size = (alignment_ == alignment::FILL)
|
||||
? inner_size
|
||||
: child_.measure(inner_size);
|
||||
|
||||
const vec2f_t child_pos = calculate_aligned_position(child_size, inner_size, alignment_);
|
||||
|
||||
const vec2f_t final_offset(
|
||||
padding_.left + child_pos.x(),
|
||||
padding_.top + child_pos.y()
|
||||
);
|
||||
|
||||
const auto child_state = state.derive_child(final_offset, child_size);
|
||||
child_.arrange(child_state);
|
||||
}
|
||||
|
||||
void build_render_commands(mirage::render_command_builder& builder) const {
|
||||
child_.build_render_commands(builder);
|
||||
}
|
||||
|
||||
void build_render_commands(mirage::render_command_builder& builder,
|
||||
const mirage::culling_context& context) const {
|
||||
invoke_build_render_commands(child_, builder, context);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 访问器
|
||||
// ============================================================================
|
||||
|
||||
const Child& child() const { return child_; }
|
||||
Child& child() { return child_; }
|
||||
const margin& get_padding() const { return padding_; }
|
||||
alignment get_alignment() const { return alignment_; }
|
||||
|
||||
private:
|
||||
Child child_;
|
||||
margin padding_ = margin::zero();
|
||||
alignment alignment_ = alignment::TOP_LEFT;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// property_slot 包装器
|
||||
// ============================================================================
|
||||
|
||||
/// @brief 带容器属性的 Slot 包装器
|
||||
template <typename SlotType, typename... Properties>
|
||||
class property_slot {
|
||||
public:
|
||||
property_slot(SlotType slot, Properties... props) : slot_(std::move(slot)), properties_(std::move(props)...) {
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Widget concept 转发
|
||||
// ============================================================================
|
||||
|
||||
auto measure(const vec2f_t& available_size) const -> vec2f_t {
|
||||
return slot_.measure(available_size);
|
||||
}
|
||||
|
||||
void arrange(const layout_state& state) {
|
||||
slot_.arrange(state);
|
||||
}
|
||||
|
||||
void build_render_commands(mirage::render_command_builder& builder) const {
|
||||
// 应用 z_order(如果有)
|
||||
if constexpr (has_property<z_order_tag>()) {
|
||||
if (auto z = get_property<z_order_tag>()) {
|
||||
builder.set_z_order(z->value);
|
||||
}
|
||||
}
|
||||
slot_.build_render_commands(builder);
|
||||
}
|
||||
|
||||
void build_render_commands(mirage::render_command_builder& builder,
|
||||
const mirage::culling_context& context) const {
|
||||
// 应用 z_order(如果有)
|
||||
if constexpr (has_property<z_order_tag>()) {
|
||||
if (auto z = get_property<z_order_tag>()) {
|
||||
builder.set_z_order(z->value);
|
||||
}
|
||||
}
|
||||
invoke_build_render_commands(slot_, builder, context);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 属性检查和获取
|
||||
// ============================================================================
|
||||
|
||||
template <typename P>
|
||||
static constexpr bool has_property() {
|
||||
return detail::contains_type_v<P, Properties...>;
|
||||
}
|
||||
|
||||
template <typename P>
|
||||
std::optional<P> get_property() const {
|
||||
return detail::get_param<P>(properties_);
|
||||
}
|
||||
|
||||
template <typename P>
|
||||
P get_property_or(const P& default_value) const {
|
||||
auto opt = get_property<P>();
|
||||
return opt.has_value() ? opt.value() : default_value;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 访问器
|
||||
// ============================================================================
|
||||
|
||||
const SlotType& get_slot() const { return slot_; }
|
||||
SlotType& get_slot() { return slot_; }
|
||||
|
||||
// 便捷访问子控件
|
||||
const auto& child() const { return slot_.child(); }
|
||||
auto& child() { return slot_.child(); }
|
||||
|
||||
const std::tuple<Properties...>& properties() const { return properties_; }
|
||||
|
||||
private:
|
||||
SlotType slot_;
|
||||
std::tuple<Properties...> properties_;
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// 管道操作符
|
||||
// ============================================================================
|
||||
|
||||
/// @brief slot | property -> property_slot
|
||||
template <typename Child, typename Property> requires std::is_base_of_v<container_property_tag, Property>
|
||||
auto operator|(slot<Child>&& s, Property&& prop) {
|
||||
return property_slot<slot<Child>, std::remove_cvref_t<Property>>(
|
||||
std::move(s), std::forward<Property>(prop)
|
||||
);
|
||||
}
|
||||
|
||||
/// @brief slot | property -> property_slot (左值版本)
|
||||
template <typename Child, typename Property> requires std::is_base_of_v<container_property_tag, Property>
|
||||
auto operator|(slot<Child>& s, Property&& prop) {
|
||||
return property_slot<slot<Child>, std::remove_cvref_t<Property>>(
|
||||
std::move(s), std::forward<Property>(prop)
|
||||
);
|
||||
}
|
||||
|
||||
/// @brief property_slot | property -> property_slot (链式添加属性)
|
||||
template <typename SlotType, typename... ExistingProps, typename NewProperty> requires std::is_base_of_v<container_property_tag, NewProperty>
|
||||
auto operator|(property_slot<SlotType, ExistingProps...>&& ps, NewProperty&& prop) {
|
||||
// 创建新的 property_slot,包含所有现有属性和新属性
|
||||
auto func = [&](auto&&... existing_props) {
|
||||
return property_slot<SlotType, ExistingProps..., std::remove_cvref_t<NewProperty>>(
|
||||
std::move(ps.get_slot()),
|
||||
std::forward<decltype(existing_props)>(existing_props)...,
|
||||
std::forward<NewProperty>(prop)
|
||||
);
|
||||
};
|
||||
return std::apply(func, std::move(ps).properties());
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 辅助函数
|
||||
// ============================================================================
|
||||
|
||||
/// @brief 从 slot 或普通 widget 中提取子控件的引用
|
||||
template <typename T>
|
||||
decltype(auto) unwrap_slot(T&& item) {
|
||||
if constexpr (is_property_slot_v<T>) {
|
||||
return std::forward<T>(item).child();
|
||||
}
|
||||
else if constexpr (is_slot_v<T>) {
|
||||
return std::forward<T>(item).child();
|
||||
}
|
||||
else {
|
||||
return std::forward<T>(item);
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief 从 property_slot 中提取指定类型的属性
|
||||
template <typename PropertyType, typename T>
|
||||
std::optional<PropertyType> extract_property(const T& item) {
|
||||
if constexpr (is_property_slot_v<T>) {
|
||||
return item.template get_property<PropertyType>();
|
||||
}
|
||||
else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief 从 property_slot 中提取指定类型的属性,如果不存在则返回默认值
|
||||
template <typename PropertyType, typename T>
|
||||
PropertyType extract_property_or(const T& item, const PropertyType& default_value) {
|
||||
if constexpr (is_property_slot_v<T>) {
|
||||
return item.template get_property_or<PropertyType>(default_value);
|
||||
}
|
||||
else {
|
||||
return default_value;
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief 检查 property_slot 是否包含指定属性
|
||||
template <typename PropertyType, typename T>
|
||||
constexpr bool has_property() {
|
||||
if constexpr (is_property_slot_v<T>) {
|
||||
return T::template has_property<PropertyType>();
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 便捷构造函数
|
||||
// ============================================================================
|
||||
|
||||
/// @brief 创建 slot 的便捷函数
|
||||
template <widget W>
|
||||
auto make_slot(W&& child) {
|
||||
return slot<std::remove_cvref_t<W>>(std::forward<W>(child));
|
||||
}
|
||||
} // namespace mirage
|
||||
@@ -1,114 +0,0 @@
|
||||
#pragma once
|
||||
#include <tuple>
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace mirage {
|
||||
// ============================================================================
|
||||
// 前向声明
|
||||
// ============================================================================
|
||||
|
||||
template <typename Child>
|
||||
class slot;
|
||||
|
||||
template <typename SlotType, typename... Properties>
|
||||
class property_slot;
|
||||
|
||||
// ============================================================================
|
||||
// 类型萃取工具(detail 命名空间)
|
||||
// ============================================================================
|
||||
|
||||
namespace detail {
|
||||
/// @brief 检查类型T是否在参数包Params中
|
||||
template <typename T, typename... Params>
|
||||
struct contains_type : std::disjunction<std::is_same<T, Params>...> {
|
||||
};
|
||||
|
||||
template <typename T, typename... Params>
|
||||
inline constexpr bool contains_type_v = contains_type<T, Params...>::value;
|
||||
|
||||
/// @brief 从tuple中获取指定类型的值
|
||||
template <typename T, typename Tuple, std::size_t... Is>
|
||||
constexpr std::optional<T> get_param_impl(const Tuple& tuple, std::index_sequence<Is...>) {
|
||||
std::optional<T> result;
|
||||
(
|
||||
[&]() {
|
||||
using ElemType = std::tuple_element_t<Is, Tuple>;
|
||||
if constexpr (std::is_same_v<ElemType, T>) {
|
||||
result = std::get<Is>(tuple);
|
||||
}
|
||||
}()
|
||||
, ...);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, typename... Params>
|
||||
constexpr std::optional<T> get_param(const std::tuple<Params...>& tuple) {
|
||||
return get_param_impl<T>(tuple, std::index_sequence_for<Params...>{});
|
||||
}
|
||||
|
||||
/// @brief 检查tuple中是否包含指定类型
|
||||
template <typename T, typename Tuple>
|
||||
struct tuple_contains;
|
||||
|
||||
template <typename T, typename... Types>
|
||||
struct tuple_contains<T, std::tuple<Types...>> : contains_type<T, Types...> {
|
||||
};
|
||||
|
||||
template <typename T, typename Tuple>
|
||||
inline constexpr bool tuple_contains_v = tuple_contains<T, Tuple>::value;
|
||||
} // namespace detail
|
||||
|
||||
// ============================================================================
|
||||
// Slot 类型萃取
|
||||
// ============================================================================
|
||||
|
||||
/// @brief 检查类型是否为 slot
|
||||
template <typename T>
|
||||
struct is_slot : std::false_type {
|
||||
};
|
||||
|
||||
template <typename Child>
|
||||
struct is_slot<slot<Child>> : std::true_type {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline constexpr bool is_slot_v = is_slot<std::remove_cvref_t<T>>::value;
|
||||
|
||||
/// @brief 检查类型是否为 property_slot
|
||||
template <typename T>
|
||||
struct is_property_slot : std::false_type {
|
||||
};
|
||||
|
||||
template <typename SlotType, typename... Properties>
|
||||
struct is_property_slot<property_slot<SlotType, Properties...>> : std::true_type {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline constexpr bool is_property_slot_v = is_property_slot<std::remove_cvref_t<T>>::value;
|
||||
|
||||
/// @brief 检查类型是否为 slot 或 property_slot
|
||||
template <typename T>
|
||||
inline constexpr bool is_any_slot_v = is_slot_v<T> || is_property_slot_v<T>;
|
||||
|
||||
/// @brief 获取 slot 的子控件类型
|
||||
template <typename T>
|
||||
struct slot_child_type {
|
||||
using type = T; // 非 slot 类型,返回自身
|
||||
};
|
||||
|
||||
template <typename Child>
|
||||
struct slot_child_type<slot<Child>> {
|
||||
using type = Child;
|
||||
};
|
||||
|
||||
template <typename SlotType, typename... Properties>
|
||||
struct slot_child_type<property_slot<SlotType, Properties...>> {
|
||||
using type = slot_child_type<SlotType>::type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using slot_child_type_t = slot_child_type<std::remove_cvref_t<T>>::type;
|
||||
|
||||
} // namespace mirage
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "dynamic_list.h"
|
||||
#include "culling_config.h"
|
||||
#include "event_target.h"
|
||||
#include "slot.h"
|
||||
#include "modifiers/modifiers.h"
|
||||
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
@@ -16,32 +16,12 @@ namespace mirage {
|
||||
// ============================================================================
|
||||
|
||||
namespace stack_detail {
|
||||
/// @brief 从子控件中提取 padding/margin
|
||||
/// slot 直接处理 padding,这里返回 zero
|
||||
template <typename Child>
|
||||
margin extract_child_margin(const Child& child) {
|
||||
if constexpr (is_slot_v<Child>) {
|
||||
// slot 类型,padding 已经在 slot 内部处理
|
||||
return margin::zero();
|
||||
}
|
||||
else if constexpr (is_property_slot_v<Child>) {
|
||||
// property_slot 类型,padding 在内部 slot 处理
|
||||
return margin::zero();
|
||||
}
|
||||
else {
|
||||
// 普通 widget
|
||||
return margin::zero();
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief 从子控件中提取 stretch 信息
|
||||
template <typename Child>
|
||||
std::optional<float> extract_stretch_factor(const Child& child) {
|
||||
if constexpr (is_property_slot_v<Child>) {
|
||||
// 新系统:从 property_slot 提取 stretch_tag
|
||||
if (auto sp = child.template get_property<stretch_tag>()) {
|
||||
return sp->flex_factor;
|
||||
}
|
||||
// 新系统:检测 stretch_modifier
|
||||
if constexpr (modifier::is_stretch_modifier<Child>) {
|
||||
return modifier::get_flex_factor(child);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -49,17 +29,33 @@ namespace mirage {
|
||||
/// @brief 判断子控件是否应该 stretch
|
||||
template <typename Child>
|
||||
bool should_stretch(const Child& child) {
|
||||
// 新系统:检测 stretch_modifier
|
||||
if constexpr (modifier::is_stretch_modifier<Child>) {
|
||||
return true;
|
||||
}
|
||||
// 旧系统
|
||||
return extract_stretch_factor(child).has_value();
|
||||
}
|
||||
|
||||
/// @brief 获取 stretch 的 flex 因子
|
||||
template <typename Child>
|
||||
float get_flex_factor(const Child& child) {
|
||||
// 新系统:检测 stretch_modifier
|
||||
if constexpr (modifier::is_stretch_modifier<Child>) {
|
||||
return modifier::get_flex_factor(child);
|
||||
}
|
||||
// 旧系统
|
||||
if (auto factor = extract_stretch_factor(child)) {
|
||||
return *factor;
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
/// @brief 检测是否为布局修饰器
|
||||
template <typename Child>
|
||||
constexpr bool is_layout_modifier() {
|
||||
return modifier::is_layout_modifier<Child>;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
@@ -150,21 +146,13 @@ namespace mirage {
|
||||
if constexpr (std::is_same_v<ChildType, dynamic_list>) {
|
||||
event_children.push_back(const_cast<dynamic_list*>(&child));
|
||||
}
|
||||
// 情况 2: property_slot 类型(新系统)
|
||||
else if constexpr (is_property_slot_v<ChildType>) {
|
||||
using SlotChildType = slot_child_type_t<ChildType>;
|
||||
if constexpr (std::is_base_of_v<event_target, SlotChildType>) {
|
||||
event_children.push_back(const_cast<SlotChildType*>(&child.child()));
|
||||
// 情况 2: 布局修饰器 - 穿透获取内部事件目标
|
||||
else if constexpr (modifier::is_layout_modifier<ChildType>) {
|
||||
if (auto* target = modifier::get_inner_event_target(const_cast<ChildType&>(child))) {
|
||||
event_children.push_back(target);
|
||||
}
|
||||
}
|
||||
// 情况 3: slot 类型(新系统)
|
||||
else if constexpr (is_slot_v<ChildType>) {
|
||||
using SlotChildType = slot_child_type_t<ChildType>;
|
||||
if constexpr (std::is_base_of_v<event_target, SlotChildType>) {
|
||||
event_children.push_back(const_cast<SlotChildType*>(&child.child()));
|
||||
}
|
||||
}
|
||||
// 情况 4: 继承自 event_target 的普通 widget
|
||||
// 情况 3: 继承自 event_target 的普通 widget
|
||||
else if constexpr (std::is_base_of_v<event_target, ChildType>) {
|
||||
event_children.push_back(const_cast<ChildType*>(&child));
|
||||
}
|
||||
@@ -187,16 +175,14 @@ namespace mirage {
|
||||
fixed_height += child_size.y();
|
||||
}
|
||||
}
|
||||
else if constexpr (is_property_slot_v<Child> || is_slot_v<Child>) {
|
||||
if (stack_detail::should_stretch(child)) {
|
||||
// stretch 子组件:尺寸由 flex 分配
|
||||
total_flex += stack_detail::get_flex_factor(child);
|
||||
}
|
||||
else {
|
||||
// 固定尺寸子组件
|
||||
const auto child_size = child.measure(available_size);
|
||||
fixed_height += child_size.y();
|
||||
}
|
||||
else if constexpr (modifier::is_stretch_modifier<Child>) {
|
||||
// 新系统:stretch_modifier
|
||||
total_flex += modifier::get_flex_factor(child);
|
||||
}
|
||||
else if constexpr (modifier::is_layout_modifier<Child>) {
|
||||
// 其他布局修饰器(padding, align):按固定尺寸处理
|
||||
const auto child_size = child.measure(available_size);
|
||||
fixed_height += child_size.y();
|
||||
}
|
||||
else {
|
||||
// 直接处理普通 widget(总是固定尺寸)
|
||||
@@ -217,22 +203,14 @@ namespace mirage {
|
||||
total_height += child_size.y();
|
||||
}
|
||||
}
|
||||
else if constexpr (is_property_slot_v<Child> || is_slot_v<Child>) {
|
||||
if (stack_detail::should_stretch(child)) {
|
||||
// stretch 子组件在 measure 时不贡献高度
|
||||
// 但仍需测量宽度
|
||||
const auto child_size = child.measure(available_size);
|
||||
max_width = std::max(max_width, child_size.x());
|
||||
}
|
||||
else {
|
||||
// 固定尺寸子组件
|
||||
const auto child_size = 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<Child>) {
|
||||
// stretch 子组件在 measure 时不贡献高度
|
||||
// 但仍需测量宽度
|
||||
const auto child_size = child.measure(available_size);
|
||||
max_width = std::max(max_width, child_size.x());
|
||||
}
|
||||
else {
|
||||
// 直接处理普通 widget
|
||||
// 直接处理普通 widget 或其他修饰器
|
||||
const auto child_size = child.measure(available_size);
|
||||
max_width = std::max(max_width, child_size.x());
|
||||
total_height += child_size.y();
|
||||
@@ -252,27 +230,24 @@ namespace mirage {
|
||||
current_y += child_size.y();
|
||||
}
|
||||
}
|
||||
else if constexpr (is_property_slot_v<Child> || is_slot_v<Child>) {
|
||||
else if constexpr (modifier::is_stretch_modifier<Child>) {
|
||||
// 新系统:stretch_modifier
|
||||
vec2f_t child_size;
|
||||
if (stack_detail::should_stretch(child) && total_flex > 0.0f) {
|
||||
// stretch 子组件:根据 flex 比例分配高度
|
||||
const float flex_factor = stack_detail::get_flex_factor(child);
|
||||
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;
|
||||
// 测量得到宽度,使用 stretch 高度
|
||||
const auto measured_size = child.measure(state.size());
|
||||
child_size = vec2f_t{measured_size.x(), 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
|
||||
// 直接处理普通 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);
|
||||
@@ -363,33 +338,28 @@ namespace mirage {
|
||||
std::vector<event_target*> get_event_children() const override {
|
||||
std::vector<event_target*> event_children;
|
||||
|
||||
std::apply([&](auto&... child) {
|
||||
auto func = [&](auto&... child) {
|
||||
(
|
||||
[&]() {
|
||||
using ChildType = std::remove_cvref_t<decltype(child)>;
|
||||
// 情况 1: dynamic_list
|
||||
if constexpr (std::is_same_v<ChildType, dynamic_list>) {
|
||||
event_children.push_back(const_cast<dynamic_list*>(&child));
|
||||
}
|
||||
// 情况 2: property_slot 类型(新系统)
|
||||
else if constexpr (is_property_slot_v<ChildType>) {
|
||||
using SlotChildType = slot_child_type_t<ChildType>;
|
||||
if constexpr (std::is_base_of_v<event_target, SlotChildType>) {
|
||||
event_children.push_back(const_cast<SlotChildType*>(&child.child()));
|
||||
}
|
||||
}
|
||||
// 情况 3: slot 类型(新系统)
|
||||
else if constexpr (is_slot_v<ChildType>) {
|
||||
using SlotChildType = slot_child_type_t<ChildType>;
|
||||
if constexpr (std::is_base_of_v<event_target, SlotChildType>) {
|
||||
event_children.push_back(const_cast<SlotChildType*>(&child.child()));
|
||||
// 情况 2: 布局修饰器 - 穿透获取内部事件目标
|
||||
else if constexpr (modifier::is_layout_modifier<ChildType>) {
|
||||
if (auto* target = modifier::get_inner_event_target(const_cast<ChildType&>(child))) {
|
||||
event_children.push_back(target);
|
||||
}
|
||||
}
|
||||
// 情况 3: 继承自 event_target 的普通 widget
|
||||
else if constexpr (std::is_base_of_v<event_target, ChildType>) {
|
||||
event_children.push_back(const_cast<ChildType*>(&child));
|
||||
}
|
||||
}()
|
||||
, ...);
|
||||
}, children_);
|
||||
};
|
||||
std::apply(func, children_);
|
||||
|
||||
return event_children;
|
||||
}
|
||||
@@ -406,16 +376,14 @@ namespace mirage {
|
||||
fixed_width += child_size.x();
|
||||
}
|
||||
}
|
||||
else if constexpr (is_property_slot_v<Child> || is_slot_v<Child>) {
|
||||
if (stack_detail::should_stretch(child)) {
|
||||
// stretch 子组件:尺寸由 flex 分配
|
||||
total_flex += stack_detail::get_flex_factor(child);
|
||||
}
|
||||
else {
|
||||
// 固定尺寸子组件
|
||||
const auto child_size = child.measure(available_size);
|
||||
fixed_width += child_size.x();
|
||||
}
|
||||
else if constexpr (modifier::is_stretch_modifier<Child>) {
|
||||
// 新系统:stretch_modifier
|
||||
total_flex += modifier::get_flex_factor(child);
|
||||
}
|
||||
else if constexpr (modifier::is_layout_modifier<Child>) {
|
||||
// 其他布局修饰器(padding, align):按固定尺寸处理
|
||||
const auto child_size = child.measure(available_size);
|
||||
fixed_width += child_size.x();
|
||||
}
|
||||
else {
|
||||
// 直接处理普通 widget(总是固定尺寸)
|
||||
@@ -436,22 +404,14 @@ namespace mirage {
|
||||
max_height = std::max(max_height, child_size.y());
|
||||
}
|
||||
}
|
||||
else if constexpr (is_property_slot_v<Child> || is_slot_v<Child>) {
|
||||
if (stack_detail::should_stretch(child)) {
|
||||
// stretch 子组件在 measure 时不贡献宽度
|
||||
// 但仍需测量高度
|
||||
const auto child_size = child.measure(available_size);
|
||||
max_height = std::max(max_height, child_size.y());
|
||||
}
|
||||
else {
|
||||
// 固定尺寸子组件
|
||||
const auto child_size = 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<Child>) {
|
||||
// stretch 子组件在 measure 时不贡献宽度
|
||||
// 但仍需测量高度
|
||||
const auto child_size = child.measure(available_size);
|
||||
max_height = std::max(max_height, child_size.y());
|
||||
}
|
||||
else {
|
||||
// 直接处理普通 widget
|
||||
// 直接处理普通 widget 或其他修饰器
|
||||
const auto child_size = child.measure(available_size);
|
||||
total_width += child_size.x();
|
||||
max_height = std::max(max_height, child_size.y());
|
||||
@@ -471,27 +431,24 @@ namespace mirage {
|
||||
current_x += child_size.x();
|
||||
}
|
||||
}
|
||||
else if constexpr (is_property_slot_v<Child> || is_slot_v<Child>) {
|
||||
else if constexpr (modifier::is_stretch_modifier<Child>) {
|
||||
// 新系统:stretch_modifier
|
||||
vec2f_t child_size;
|
||||
if (stack_detail::should_stretch(child) && total_flex > 0.0f) {
|
||||
// stretch 子组件:根据 flex 比例分配宽度
|
||||
const float flex_factor = stack_detail::get_flex_factor(child);
|
||||
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;
|
||||
// 测量得到高度,使用 stretch 宽度
|
||||
const auto measured_size = child.measure(state.size());
|
||||
child_size = vec2f_t{stretch_width, measured_size.y()};
|
||||
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
|
||||
// 直接处理普通 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);
|
||||
|
||||
Reference in New Issue
Block a user