186 lines
6.7 KiB
C++
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>();
|
|
}
|
|
}
|