垂直水平容器布局
This commit is contained in:
parent
934dd653ee
commit
b5fc6a9a26
@ -79,18 +79,22 @@ int main(int argc, char* argv[]) {
|
||||
const auto button2 = std::make_shared<mbutton>();
|
||||
button2->push_slot(
|
||||
mslot(mbutton)
|
||||
.margin({10})
|
||||
.visibility(visibility_t::visible)
|
||||
(text_block2)
|
||||
);
|
||||
|
||||
const auto& window = mwindow::create({ 800, 600 }, L"Hello, World!");
|
||||
window->set_content(
|
||||
mnew(mborder)
|
||||
mnew(mv_box)
|
||||
[
|
||||
mslot(mborder)
|
||||
.h_alignment(horizontal_alignment_t::center)
|
||||
.v_alignment(vertical_alignment_t::center)
|
||||
(button)
|
||||
mslot(mv_box)
|
||||
.horizontal_alignment(horizontal_alignment_t::left)
|
||||
(button),
|
||||
|
||||
mslot(mv_box)
|
||||
.horizontal_alignment(horizontal_alignment_t::right)
|
||||
(button2)
|
||||
]
|
||||
);
|
||||
|
||||
|
@ -4,9 +4,9 @@
|
||||
|
||||
void mh_box::arrange_children(const geometry_t& in_allotted_geometry) {
|
||||
arrange_box_children<orientation_t::horizontal>(in_allotted_geometry,
|
||||
get_dpi_scale(),
|
||||
visibility_t::any_visible,
|
||||
get_slots());
|
||||
get_dpi_scale(),
|
||||
visibility_t::any_visible,
|
||||
get_slots());
|
||||
}
|
||||
|
||||
Eigen::Vector2f mh_box::compute_desired_size(float in_layout_scale_multiplier) const {
|
||||
@ -16,9 +16,9 @@ Eigen::Vector2f mh_box::compute_desired_size(float in_layout_scale_multiplier) c
|
||||
|
||||
void mv_box::arrange_children(const geometry_t& in_allotted_geometry) {
|
||||
arrange_box_children<orientation_t::vertical>(in_allotted_geometry,
|
||||
get_dpi_scale(),
|
||||
visibility_t::any_visible,
|
||||
get_slots());
|
||||
get_dpi_scale(),
|
||||
visibility_t::any_visible,
|
||||
get_slots());
|
||||
}
|
||||
|
||||
Eigen::Vector2f mv_box::compute_desired_size(float in_layout_scale_multiplier) const {
|
||||
|
@ -23,6 +23,7 @@ struct hbox_slot : mpanel_widget_slot<hbox_slot> {
|
||||
SLOT_SIZE()
|
||||
/** 定义边距属性,控制子组件周围的空间 */
|
||||
SLOT_ATTRIBUTE(margin_t, margin)
|
||||
SLOT_ATTRIBUTE(vertical_alignment_t, vertical_alignment)
|
||||
};
|
||||
|
||||
/**
|
||||
@ -68,6 +69,7 @@ struct vbox_slot : mpanel_widget_slot<vbox_slot> {
|
||||
SLOT_SIZE()
|
||||
/** 定义边距属性,控制子组件周围的空间 */
|
||||
SLOT_ATTRIBUTE(margin_t, margin)
|
||||
SLOT_ATTRIBUTE(horizontal_alignment_t, horizontal_alignment)
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -20,6 +20,15 @@ void arrange_single_child(
|
||||
const margin_t& margin = margin_t() // 默认为空边距
|
||||
);
|
||||
|
||||
template<typename T>
|
||||
concept has_vertical_alignment = requires {
|
||||
T().vertical_alignment();
|
||||
};
|
||||
template<typename T>
|
||||
concept has_horizontal_alignment = requires {
|
||||
T().horizontal_alignment();
|
||||
};
|
||||
|
||||
template<orientation_t LayoutOrientation, typename SlotType>
|
||||
void arrange_box_children(
|
||||
const geometry_t& in_allotted_geometry,
|
||||
@ -41,11 +50,11 @@ void arrange_box_children(
|
||||
struct slot_widget_info {
|
||||
std::shared_ptr<mwidget> widget;
|
||||
const SlotType* slot;
|
||||
float size;
|
||||
float margin_start; // 主轴起始边缘的margin
|
||||
float margin_end; // 主轴结束边缘的margin
|
||||
float margin_cross_start; // 交叉轴起始边缘的margin
|
||||
float margin_cross_end; // 交叉轴结束边缘的margin
|
||||
float size{};
|
||||
float margin_start{}; // 主轴起始边缘的margin
|
||||
float margin_end{}; // 主轴结束边缘的margin
|
||||
float margin_cross_start{}; // 交叉轴起始边缘的margin
|
||||
float margin_cross_end{}; // 交叉轴结束边缘的margin
|
||||
};
|
||||
|
||||
std::vector<slot_widget_info> visible_widgets;
|
||||
@ -126,7 +135,7 @@ void arrange_box_children(
|
||||
}
|
||||
}
|
||||
|
||||
// 第三轮:排列部件
|
||||
// 第三轮:排列部件
|
||||
float position = 0.0f;
|
||||
|
||||
if (is_reversed)
|
||||
@ -135,32 +144,101 @@ void arrange_box_children(
|
||||
for (const auto& info : visible_widgets) {
|
||||
position += info.margin_start;
|
||||
|
||||
// 获取部件期望的大小(需要同时考虑主轴和交叉轴)
|
||||
// 确保获取最新的期望尺寸,因为布局可能会嵌套调用
|
||||
info.widget->cache_desired_size(in_layout_scale_multiplier);
|
||||
const auto& desired_size = info.widget->get_desired_size().value();
|
||||
|
||||
Eigen::Vector2f pos = Eigen::Vector2f::Zero();
|
||||
Eigen::Vector2f size = container_size;
|
||||
Eigen::Vector2f size = Eigen::Vector2f::Zero(); // 初始化为0
|
||||
|
||||
if (is_horizontal) {
|
||||
// --- 主轴 (X) ---
|
||||
size.x() = info.size; // 主轴尺寸由之前的计算确定 (Auto 或 Stretch)
|
||||
if (is_reversed)
|
||||
pos.x() = container_primary_size - position - info.size;
|
||||
else
|
||||
pos.x() = position;
|
||||
|
||||
pos.y() += info.margin_cross_start;
|
||||
size.x() = info.size;
|
||||
size.y() -= info.margin_start + info.margin_end;
|
||||
} else {
|
||||
// --- 交叉轴 (Y) ---
|
||||
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; // 默认拉伸交叉轴
|
||||
|
||||
if constexpr (has_vertical_alignment<SlotType>) {
|
||||
const auto& v_alignment = info.slot->vertical_alignment();
|
||||
// **如果指定了具体的对齐方式(非拉伸),则使用控件期望的高度**
|
||||
// (这里假设 Top/Center/Bottom 意味着不拉伸,需要根据你的枚举定义调整)
|
||||
bool use_desired_height = (v_alignment == vertical_alignment_t::top ||
|
||||
v_alignment == vertical_alignment_t::center ||
|
||||
v_alignment == vertical_alignment_t::bottom);
|
||||
|
||||
if (use_desired_height) {
|
||||
final_height = std::min(widget_height, available_height); // 使用期望高度,但不超过可用空间
|
||||
if (available_height > widget_height) { // 只有在有剩余空间时才需要调整对齐位置
|
||||
if (v_alignment == vertical_alignment_t::center) {
|
||||
pos.y() += (available_height - widget_height) / 2.0f;
|
||||
} else if (v_alignment == vertical_alignment_t::bottom) {
|
||||
pos.y() += (available_height - widget_height);
|
||||
}
|
||||
// Top 对齐: pos.y() 初始值就是正确的
|
||||
}
|
||||
}
|
||||
// else: 拉伸对齐,保持 final_height = available_height
|
||||
}
|
||||
// else (SlotType 没有垂直对齐属性): 默认行为是拉伸,final_height = available_height
|
||||
|
||||
size.y() = final_height; // **传递给子控件的最终高度**
|
||||
|
||||
} else { // 垂直布局
|
||||
// --- 主轴 (Y) ---
|
||||
size.y() = info.size; // 主轴尺寸由之前的计算确定 (Auto 或 Stretch)
|
||||
if (is_reversed)
|
||||
pos.y() = container_primary_size - position - info.size;
|
||||
else
|
||||
pos.y() = position;
|
||||
|
||||
pos.x() += info.margin_cross_start;
|
||||
size.x() -= info.margin_start + info.margin_end;
|
||||
size.y() = info.size;
|
||||
// --- 交叉轴 (X) ---
|
||||
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; // 默认拉伸交叉轴
|
||||
|
||||
if constexpr (has_horizontal_alignment<SlotType>) {
|
||||
const auto& h_alignment = info.slot->horizontal_alignment();
|
||||
// **如果指定了具体的对齐方式(非拉伸),则使用控件期望的宽度**
|
||||
// (这里假设 Left/Center/Right 意味着不拉伸)
|
||||
bool use_desired_width = (h_alignment == horizontal_alignment_t::left ||
|
||||
h_alignment == horizontal_alignment_t::center ||
|
||||
h_alignment == horizontal_alignment_t::right);
|
||||
|
||||
if (use_desired_width) {
|
||||
final_width = std::min(widget_width, available_width); // 使用期望宽度,但不超过可用空间
|
||||
if (available_width > widget_width) { // 只有在有剩余空间时才需要调整对齐位置
|
||||
if (h_alignment == horizontal_alignment_t::center) {
|
||||
pos.x() += (available_width - widget_width) / 2.0f;
|
||||
} else if (h_alignment == horizontal_alignment_t::right) {
|
||||
pos.x() += (available_width - widget_width);
|
||||
}
|
||||
// **Left 对齐**: pos.x() 初始值就是正确的
|
||||
}
|
||||
}
|
||||
// else: 拉伸对齐,保持 final_width = available_width
|
||||
}
|
||||
// else (SlotType 没有水平对齐属性): 默认行为是拉伸,final_width = available_width
|
||||
|
||||
size.x() = final_width; // **传递给子控件的最终宽度**
|
||||
}
|
||||
|
||||
// 确保尺寸不为负
|
||||
size.x() = std::max(0.0f, size.x());
|
||||
size.y() = std::max(0.0f, size.y());
|
||||
|
||||
// 使用计算好的位置和尺寸创建子控件的几何信息
|
||||
const auto& child_geometry = in_allotted_geometry.make_child(pos, size);
|
||||
info.widget->set_geometry(child_geometry);
|
||||
info.widget->arrange_children(child_geometry);
|
||||
info.widget->arrange_children(child_geometry); // 子控件在其分配到的几何区域内进行布局
|
||||
|
||||
position += info.size + info.margin_end;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user