feat(panels): 数据/文件列表卡片化(标题+元信息双行+选中竖条)(规范§6.2)
This commit is contained in:
parent
824e8bdf62
commit
b26dcc1ca7
|
|
@ -544,9 +544,11 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
|||
auto* datasetTabs = new QTabWidget();
|
||||
auto* datasetList = new QListWidget();
|
||||
applyListSelection(datasetList);
|
||||
geopro::app::applyDatasetCardDelegate(datasetList);
|
||||
datasetTabs->addTab(datasetList, QStringLiteral("数据"));
|
||||
auto* fileList = new QListWidget();
|
||||
applyListSelection(fileList);
|
||||
geopro::app::applyDatasetCardDelegate(fileList);
|
||||
datasetTabs->addTab(fileList, QStringLiteral("文件"));
|
||||
auto* datasetDock = new ads::CDockWidget(QStringLiteral("数据真实显示栏"));
|
||||
auto* datasetBox = wrapWithHeader(
|
||||
|
|
|
|||
|
|
@ -3,7 +3,13 @@
|
|||
#include <QColor>
|
||||
#include <QListWidget>
|
||||
#include <QListWidgetItem>
|
||||
#include <QObject>
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
#include <QString>
|
||||
#include <QStyledItemDelegate>
|
||||
|
||||
#include "Theme.hpp"
|
||||
|
||||
namespace geopro::app {
|
||||
|
||||
|
|
@ -14,6 +20,88 @@ QString humanSize(long long b) {
|
|||
if (kb < 1024.0) return QStringLiteral("%1 KB").arg(kb, 0, 'f', 1);
|
||||
return QStringLiteral("%1 MB").arg(kb / 1024.0, 0, 'f', 1);
|
||||
}
|
||||
|
||||
// 数据/文件列表卡片委托:标题+元信息双行、悬停/选中圆角高亮 + 选中左 2px 强调竖条(规范§6.2)。
|
||||
// 特殊行(加载更多 / 占位提示)退回为居中纯文本,不画卡片。
|
||||
class DatasetCardDelegate : public QStyledItemDelegate {
|
||||
public:
|
||||
using QStyledItemDelegate::QStyledItemDelegate;
|
||||
|
||||
QSize sizeHint(const QStyleOptionViewItem&, const QModelIndex& idx) const override {
|
||||
const bool special =
|
||||
idx.data(kDsLoadMoreRole).toBool() || !(idx.flags() & Qt::ItemIsSelectable);
|
||||
return QSize(0, special ? 34 : 52);
|
||||
}
|
||||
|
||||
void paint(QPainter* p, const QStyleOptionViewItem& opt, const QModelIndex& idx) const override {
|
||||
p->save();
|
||||
p->setRenderHint(QPainter::Antialiasing, true);
|
||||
const QString disp = idx.data(Qt::DisplayRole).toString();
|
||||
|
||||
// 「加载更多」:居中强调色文本(hover 时加底)。
|
||||
if (idx.data(kDsLoadMoreRole).toBool()) {
|
||||
if (opt.state & QStyle::State_MouseOver) {
|
||||
QPainterPath bgp;
|
||||
bgp.addRoundedRect(opt.rect.adjusted(4, 2, -4, -2), 6, 6);
|
||||
p->fillPath(bgp, geopro::app::tokenColor("bg/hover"));
|
||||
}
|
||||
p->setPen(geopro::app::tokenColor("accent/primary"));
|
||||
p->drawText(opt.rect, Qt::AlignCenter, disp);
|
||||
p->restore();
|
||||
return;
|
||||
}
|
||||
// 占位提示行(不可选):居中淡色文本。
|
||||
if (!(idx.flags() & Qt::ItemIsSelectable)) {
|
||||
p->setPen(geopro::app::tokenColor("text/disabled"));
|
||||
p->drawText(opt.rect, Qt::AlignCenter, disp);
|
||||
p->restore();
|
||||
return;
|
||||
}
|
||||
|
||||
// 卡片
|
||||
const QRect r = opt.rect.adjusted(4, 2, -4, -2);
|
||||
const bool selected = opt.state & QStyle::State_Selected;
|
||||
const bool hover = opt.state & QStyle::State_MouseOver;
|
||||
if (selected || hover) {
|
||||
QPainterPath path;
|
||||
path.addRoundedRect(r, 6, 6);
|
||||
p->fillPath(path, geopro::app::tokenColor(selected ? "bg/selected" : "bg/hover"));
|
||||
}
|
||||
if (selected) { // 左 2px 强调竖条(规范§6.2)
|
||||
p->fillRect(QRect(r.left(), r.top() + 4, 2, r.height() - 8),
|
||||
geopro::app::tokenColor("accent/primary"));
|
||||
}
|
||||
|
||||
QString title = disp, meta;
|
||||
const int nl = disp.indexOf(QLatin1Char('\n'));
|
||||
if (nl >= 0) {
|
||||
title = disp.left(nl);
|
||||
meta = disp.mid(nl + 1);
|
||||
}
|
||||
|
||||
const QRect textR = r.adjusted(14, 6, -12, -6);
|
||||
// 标题
|
||||
QFont tf = opt.font;
|
||||
tf.setPixelSize(geopro::app::scaledPx(13));
|
||||
p->setFont(tf);
|
||||
p->setPen(geopro::app::tokenColor("text/primary"));
|
||||
const QRect titleR(textR.left(), textR.top(), textR.width(), textR.height() / 2);
|
||||
p->drawText(titleR, Qt::AlignLeft | Qt::AlignVCenter,
|
||||
p->fontMetrics().elidedText(title, Qt::ElideRight, titleR.width()));
|
||||
// 元信息
|
||||
if (!meta.isEmpty()) {
|
||||
QFont mf = opt.font;
|
||||
mf.setPixelSize(geopro::app::scaledPx(11));
|
||||
p->setFont(mf);
|
||||
p->setPen(geopro::app::tokenColor("text/tertiary"));
|
||||
const QRect metaR(textR.left(), textR.center().y() + 1, textR.width(),
|
||||
textR.height() / 2);
|
||||
p->drawText(metaR, Qt::AlignLeft | Qt::AlignVCenter,
|
||||
p->fontMetrics().elidedText(meta, Qt::ElideRight, metaR.width()));
|
||||
}
|
||||
p->restore();
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
void populateDatasetList(QListWidget* list, const std::vector<geopro::data::DsRow>& rows, bool append) {
|
||||
|
|
@ -53,4 +141,13 @@ void populateFileList(QListWidget* list, const std::vector<geopro::data::DsRow>&
|
|||
}
|
||||
}
|
||||
|
||||
void applyDatasetCardDelegate(QListWidget* list) {
|
||||
if (!list) return;
|
||||
list->setItemDelegate(new DatasetCardDelegate(list));
|
||||
list->setMouseTracking(true); // 让委托收到 hover 状态
|
||||
list->setSpacing(0); // 卡间距由委托内边距控制
|
||||
QObject::connect(&ThemeManager::instance(), &ThemeManager::changed, list,
|
||||
[list]() { list->viewport()->update(); });
|
||||
}
|
||||
|
||||
} // namespace geopro::app
|
||||
|
|
|
|||
|
|
@ -18,4 +18,7 @@ void populateDatasetList(QListWidget* list, const std::vector<geopro::data::DsRo
|
|||
// 文件页签:每条 = 文件名 +(可读大小);UserRole 存 dsId、+2 存文件 url。空时显示占位。
|
||||
void populateFileList(QListWidget* list, const std::vector<geopro::data::DsRow>& rows, bool append);
|
||||
|
||||
// 给数据/文件列表套用卡片委托(标题+元信息双行、悬停/选中圆角高亮+左强调竖条,规范§6.2)。
|
||||
void applyDatasetCardDelegate(QListWidget* list);
|
||||
|
||||
} // namespace geopro::app
|
||||
|
|
|
|||
Loading…
Reference in New Issue