Files
Renderive/YSGraphic_Core/component/Base/Layout.cpp
T
2026-06-16 13:33:27 +08:00

186 lines
6.7 KiB
C++

#include "Layout.h"
#include <iostream>
#include "3rd/magic_enum/export.h"
#include "Core/Base/global_include.h"
#include "Core/spdlog/export.h"
namespace Psc {
struct HorizontalTraits {
static int get_main(const Layout_Item* i) { return i->x(); }
static void set_main(Layout_Item* i, int v) { i->set_x(v); }
static int get_cros(const Layout_Item* i) { return i->y(); }
static void set_cros(Layout_Item* i, int v) { i->set_y(v); }
static int get_main_len(const Layout_Item* i) { return i->w(); }
static void set_main_len(Layout_Item* i, int v) { i->set_w(v); }
static int get_cros_len(const Layout_Item* i) { return i->h(); }
static void set_cros_len(Layout_Item* i, int v) { i->set_h(v); }
static int main_prefix(const QMargins& m) { return m.left(); }
static int main_suffix(const QMargins& m) { return m.right(); }
static int cros_prefix(const QMargins& m) { return m.top(); }
static int cros_suffix(const QMargins& m) { return m.bottom(); }
static int main_length(const Layout* l) { return l->w(); }
static int cros_length(const Layout* l) { return l->h(); }
};
struct VerticalTraits {
static int get_main(const Layout_Item* i) { return i->y(); }
static void set_main(Layout_Item* i, int v) { i->set_y(v); }
static int get_cros(const Layout_Item* i) { return i->x(); }
static void set_cros(Layout_Item* i, int v) { i->set_x(v); }
static int get_main_len(const Layout_Item* i) { return i->h(); }
static void set_main_len(Layout_Item* i, int v) { i->set_h(v); }
static int get_cros_len(const Layout_Item* i) { return i->w(); }
static void set_cros_len(Layout_Item* i, int v) { i->set_w(v); }
static int main_prefix(const QMargins& m) { return m.top(); }
static int main_suffix(const QMargins& m) { return m.bottom(); }
static int cros_prefix(const QMargins& m) { return m.left(); }
static int cros_suffix(const QMargins& m) { return m.right(); }
static int main_length(const Layout* l) { return l->h(); }
static int cros_length(const Layout* l) { return l->w(); }
};
// TODO: maxsize mainsize 不知道怎么和 grow shrink 合并处理
template<typename T>
void Layout::layout_impl() {
int main_prefix = T::main_prefix(margins);
int main_suffix = T::main_suffix(margins);
int cros_prefix = T::cros_prefix(margins);
int cros_suffix = T::cros_suffix(margins);
int main_length = T::main_length(this);
int cros_length = T::cros_length(this);
int cros_max = cros_length - cros_prefix - cros_suffix;
int total_main = main_prefix + main_suffix;
QVector<Layout_Item*> grow_items;
QVector<Layout_Item*> shrink_items;
// ---------- 第一遍:初始化尺寸 & 收集 grow / shrink ----------
for (auto* item : items) {
auto size = item->sizeHint();
auto& flags = item->size_policy;
item->set_size(size);
if (flags.testFlag(Cross_Expand)) {
T::set_cros_len(item, cros_max);
}
if (flags.testFlag(Get_Main_By_Cross)) {
int cros_len = T::get_cros_len(item);
int main_len = item->get_main_by_cros(cros_len);
T::set_main_len(item, main_len);
}
total_main += T::get_main_len(item);
// 明确语义:Grow / Shrink 不允许同时生效
if (flags.testFlag(Grow) && !flags.testFlag(Shrink)) {
grow_items.push_back(item);
} else if (flags.testFlag(Shrink)) {
shrink_items.push_back(item);
}
}
int available = main_length - total_main;
// ---------- Grow ----------
if (available > 0 && !grow_items.isEmpty()) {
int count = grow_items.size();
int each = available / count;
int remain = available % count;
for (int i = 0; i < grow_items.size(); ++i) {
auto* item = grow_items[i];
int delta = each + (i < remain ? 1 : 0);
int len = T::get_main_len(item);
T::set_main_len(item, len + delta);
}
available = 0;
}
// ---------- Shrink(按比例,修正版本) ----------
if (available < 0 && !shrink_items.isEmpty()) {
int deficit = -available;
int shrink_cap = 0;
for (auto* item : shrink_items) {
shrink_cap += T::get_main_len(item);
}
if (shrink_cap > 0) {
int actual_shrink = std::min(deficit, shrink_cap);
int remain = actual_shrink;
for (int i = 0; i < shrink_items.size(); ++i) {
auto* item = shrink_items[i];
int cur = T::get_main_len(item);
int delta = actual_shrink * cur / shrink_cap;
if (i == shrink_items.size() - 1)
delta = remain; // 吃掉误差
delta = std::min(delta, cur);
T::set_main_len(item, cur - delta);
remain -= delta;
}
available += actual_shrink;
}
}
// ---------- 最后一步:设置每个 item 的位置 ----------
int main_pos = main_prefix;
for (Layout_Item * item : items) {
auto dr = item->direction;
if (dr == Direction::Default) {
dr = direction;
if (dr == Direction::Default) {
dr = Direction::Middle;
}
}
if (dr == Direction::Middle) {
int cur = T::get_cros_len(item);
auto middle = cros_prefix + (cros_length - cros_prefix - cros_suffix)/2;
auto pos = middle - cur/2;
T::set_cros(item, pos);
} else if (dr == Direction::First) {
T::set_cros(item, cros_prefix);
} else if (dr == Direction::Last) {
int cur = T::get_cros_len(item);
auto last = cros_length - cros_suffix;
auto pos = last - cur;
T::set_cros(item, pos);
} else {
std::cout << "未知的类型 " << VAR_STR_1(dr) << LOG_POS << std::endl;
std::terminate();
}
T::set_main(item, main_pos);
main_pos += T::get_main_len(item) + space;
}
}
void Layout::layout() {
if (orientation == Qt::Horizontal)
layout_impl<HorizontalTraits>();
else
layout_impl<VerticalTraits>();
}
}