From b26dcc1ca7ae4ba17f67da6943607f91373f627f Mon Sep 17 00:00:00 2001 From: gaozheng Date: Wed, 10 Jun 2026 16:40:14 +0800 Subject: [PATCH] =?UTF-8?q?feat(panels):=20=E6=95=B0=E6=8D=AE/=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E5=88=97=E8=A1=A8=E5=8D=A1=E7=89=87=E5=8C=96(?= =?UTF-8?q?=E6=A0=87=E9=A2=98+=E5=85=83=E4=BF=A1=E6=81=AF=E5=8F=8C?= =?UTF-8?q?=E8=A1=8C+=E9=80=89=E4=B8=AD=E7=AB=96=E6=9D=A1)=EF=BC=88?= =?UTF-8?q?=E8=A7=84=E8=8C=83=C2=A76.2=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/main.cpp | 2 + src/app/panels/DatasetListPanel.cpp | 97 +++++++++++++++++++++++++++++ src/app/panels/DatasetListPanel.hpp | 3 + 3 files changed, 102 insertions(+) diff --git a/src/app/main.cpp b/src/app/main.cpp index bf6df1c..9d69a3a 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -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( diff --git a/src/app/panels/DatasetListPanel.cpp b/src/app/panels/DatasetListPanel.cpp index 2ca911f..1630a16 100644 --- a/src/app/panels/DatasetListPanel.cpp +++ b/src/app/panels/DatasetListPanel.cpp @@ -3,7 +3,13 @@ #include #include #include +#include +#include +#include #include +#include + +#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& rows, bool append) { @@ -53,4 +141,13 @@ void populateFileList(QListWidget* list, const std::vector& } } +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 diff --git a/src/app/panels/DatasetListPanel.hpp b/src/app/panels/DatasetListPanel.hpp index 0356760..8ac2887 100644 --- a/src/app/panels/DatasetListPanel.hpp +++ b/src/app/panels/DatasetListPanel.hpp @@ -18,4 +18,7 @@ void populateDatasetList(QListWidget* list, const std::vector& rows, bool append); +// 给数据/文件列表套用卡片委托(标题+元信息双行、悬停/选中圆角高亮+左强调竖条,规范§6.2)。 +void applyDatasetCardDelegate(QListWidget* list); + } // namespace geopro::app