fix(ui): 分段树修复(批2)-选中高亮统一对象树+结构还原TM挂载+缩进一致

- #2 DatasetCardDelegate 选中/hover 改与对象树(ObjectRowDelegate)一致:整行方角填充
     (去圆角卡)+左2px accent竖条满高+选中标题加粗;保留双行卡片(创建时间·类型副标题)
- #4 CategorySection 树结构:派生 ds(反演剖面)带派生父指向已被筛掉/属别段的原始 ds 时,
     按 parentId 挂载失败→ds 浮到根平铺。改:派生父在本段保留嵌套(体>切片),否则回退挂
     结构容器 structParentId(TM),还原 项目/GS/TM/DS 真实层级
- #6 三维体段体相对TM缩进过大:容器节点(项目/GS/TM)不画复选框但保留同宽复选框列,使
     各级缩进只差一个树级(原先容器无列宽→子级带框缩进多撑出复选框列宽),与对象树一致

构建:app 链接通过
This commit is contained in:
gaozheng 2026-06-25 16:46:32 +08:00
parent a2770ba49d
commit b497fe547c
2 changed files with 24 additions and 13 deletions

View File

@ -70,25 +70,27 @@ public:
return; return;
} }
// 卡片 // 选中/hover与对象树ObjectRowDelegate完全一致——整行方角填充非圆角卡+ 左 2px
// accent 竖条贴行左缘满高 + 选中标题加粗。保留双行卡片内容(标题 + 创建时间·类型副标题)。
const QRect r = opt.rect.adjusted(4, 2, -4, -2); const QRect r = opt.rect.adjusted(4, 2, -4, -2);
const bool selected = opt.state & QStyle::State_Selected; const bool selected = opt.state & QStyle::State_Selected;
const bool hover = opt.state & QStyle::State_MouseOver; const bool hover = opt.state & QStyle::State_MouseOver;
if (selected || hover) { if (selected || hover)
QPainterPath path; p->fillRect(opt.rect, geopro::app::tokenColor(selected ? "bg/selected" : "bg/hover"));
path.addRoundedRect(r, 6, 6); if (selected)
p->fillPath(path, geopro::app::tokenColor(selected ? "bg/selected" : "bg/hover")); p->fillRect(QRect(opt.rect.left(), opt.rect.top(), 2, opt.rect.height()),
}
if (selected) { // 左 2px 强调竖条规范§6.2
p->fillRect(QRect(r.left(), r.top() + 4, 2, r.height() - 8),
geopro::app::tokenColor("accent/primary")); geopro::app::tokenColor("accent/primary"));
}
// 可勾选项:左侧画复选框(用当前 style 的指示器),文本整体右移。无复选框项(容器节点)左留白小。 // 可勾选项:左侧画复选框(用当前 style 的指示器),文本整体右移。
// 容器节点(项目/GS/TM)虽不画复选框,也保留同宽复选框列——否则其子级(带复选框)相对容器的
// 视觉缩进 = 树级缩进 + 复选框列宽,比「子带框→孙带框」的缩进大一截(用户实测 #6三维体段
// 体相对 TM 缩进过大)。保留同宽列后各级缩进只差一个树级,与对象树一致。
const int box = 16;
const int checkColPad = 12 + box + 8; // 复选框列总宽(复选框 + 两侧留白)
int textLeftPad = 6; int textLeftPad = 6;
const bool checkable = (idx.flags() & Qt::ItemIsUserCheckable); const bool checkable = (idx.flags() & Qt::ItemIsUserCheckable);
const bool isContainer = idx.data(kDsDdCodeRole).toString() == QStringLiteral("container");
if (checkable) { if (checkable) {
const int box = 16;
QRect checkRect(r.left() + 12, r.top() + (r.height() - box) / 2, box, box); QRect checkRect(r.left() + 12, r.top() + (r.height() - box) / 2, box, box);
const auto cs = static_cast<Qt::CheckState>(idx.data(Qt::CheckStateRole).toInt()); const auto cs = static_cast<Qt::CheckState>(idx.data(Qt::CheckStateRole).toInt());
QStyleOptionViewItem o(opt); QStyleOptionViewItem o(opt);
@ -98,7 +100,9 @@ public:
const QWidget* w = opt.widget; const QWidget* w = opt.widget;
QStyle* st = w ? w->style() : QApplication::style(); QStyle* st = w ? w->style() : QApplication::style();
st->drawPrimitive(QStyle::PE_IndicatorItemViewItemCheck, &o, p, w); st->drawPrimitive(QStyle::PE_IndicatorItemViewItemCheck, &o, p, w);
textLeftPad = 12 + box + 8; // 复选框右侧留白后再放文本 textLeftPad = checkColPad; // 复选框右侧留白后再放文本
} else if (isContainer) {
textLeftPad = checkColPad; // 容器保留同宽列(不画框),使子级缩进与对象树一致
} }
QString title = disp, meta; QString title = disp, meta;
@ -111,6 +115,7 @@ public:
const QRect textR = r.adjusted(textLeftPad, 4, -12, -4); const QRect textR = r.adjusted(textLeftPad, 4, -12, -4);
QFont tf = opt.font; QFont tf = opt.font;
tf.setPixelSize(geopro::app::scaledPx(13)); tf.setPixelSize(geopro::app::scaledPx(13));
if (selected) tf.setWeight(QFont::DemiBold); // 选中加粗,与对象树一致
p->setFont(tf); p->setFont(tf);
p->setPen(geopro::app::tokenColor("text/primary")); p->setPen(geopro::app::tokenColor("text/primary"));
if (meta.isEmpty()) { if (meta.isEmpty()) {

View File

@ -194,9 +194,15 @@ void CategorySection::rebuildList() {
display.push_back(std::move(c)); display.push_back(std::move(c));
} }
} }
// 分段树是「项目/GS/TM」组织树ds 应挂到其结构容器(TM)下。但派生 ds(如反演剖面)带派生父
// parentId指向原始 ds若该原始 ds 不在本段(被筛掉/属别类型段),按 parentId 挂载会失败 →
// ds 浮到树根平铺(用户实测 bugds 没挂在 tm 下)。故:派生父在本段则保留派生嵌套(如 体>切片)
// 否则回退挂到结构容器 structParentId(TM)。
std::set<std::string> presentIds;
for (const auto& d : filtered) presentIds.insert(d.id);
for (const auto& d : filtered) { for (const auto& d : filtered) {
DsRow x = d; DsRow x = d;
if (x.parentId.empty()) x.parentId = x.structParentId; // 源 ds / 体 → 挂结构容器 if (x.parentId.empty() || !presentIds.count(x.parentId)) x.parentId = x.structParentId;
display.push_back(std::move(x)); display.push_back(std::move(x));
} }