diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index c7b9579..9dbc572 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -24,6 +24,7 @@ add_executable(geopro_desktop WIN32 panels/AnomalyListPanel.cpp panels/DatasetListPanel.cpp panels/ObjectTreePanel.cpp + panels/DynamicFormView.cpp CentralScene.cpp ProjectListDialog.cpp SettingsDialog.cpp) diff --git a/src/app/panels/DynamicFormView.cpp b/src/app/panels/DynamicFormView.cpp new file mode 100644 index 0000000..c5af31d --- /dev/null +++ b/src/app/panels/DynamicFormView.cpp @@ -0,0 +1,81 @@ +#include "panels/DynamicFormView.hpp" + +#include +#include +#include +#include + +#include "Theme.hpp" + +namespace geopro::app { + +DynamicFormView::DynamicFormView(QWidget* parent) : QWidget(parent) { + auto* outer = new QVBoxLayout(this); + outer->setContentsMargins(0, 0, 0, 0); + outer->setSpacing(0); + + auto* scroll = new QScrollArea(this); + scroll->setWidgetResizable(true); + scroll->setFrameShape(QFrame::NoFrame); + auto* host = new QWidget(); + content_ = new QVBoxLayout(host); + content_->setContentsMargins(geopro::app::space::kLg, geopro::app::space::kMd, + geopro::app::space::kLg, geopro::app::space::kMd); + content_->setSpacing(geopro::app::space::kSm); + content_->addStretch(); + scroll->setWidget(host); + outer->addWidget(scroll); + + showMessage(QStringLiteral("(选中后显示属性详情)")); +} + +void DynamicFormView::clear() { + while (content_->count() > 0) { + QLayoutItem* it = content_->takeAt(0); + if (it->widget()) it->widget()->deleteLater(); + delete it; + } +} + +void DynamicFormView::showMessage(const QString& message) { + clear(); + auto* hint = new QLabel(message); + hint->setAlignment(Qt::AlignCenter); + geopro::app::applyTokenizedStyleSheet(hint, + QStringLiteral("color:{{text/disabled}}; padding:16px;")); + content_->addWidget(hint); + content_->addStretch(); +} + +void DynamicFormView::setForm(const geopro::data::DynamicForm& form) { + clear(); + if (form.groups.empty()) { + showMessage(QStringLiteral("(暂无属性)")); + return; + } + for (const auto& group : form.groups) { + auto* title = new QLabel(QString::fromStdString(group.name)); + geopro::app::applyTokenizedStyleSheet( + title, QStringLiteral("color:{{text/secondary}}; font-weight:%1; padding-top:6px;") + .arg(geopro::app::type::kWeightSemibold)); + content_->addWidget(title); + + auto* form_w = new QWidget(); + auto* fl = new QFormLayout(form_w); + fl->setContentsMargins(0, 0, 0, 0); + fl->setLabelAlignment(Qt::AlignLeft | Qt::AlignTop); + fl->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); + for (const auto& f : group.fields) { + auto* k = new QLabel(QString::fromStdString(f.name)); + geopro::app::applyTokenizedStyleSheet(k, QStringLiteral("color:{{text/secondary}};")); + auto* v = new QLabel(QString::fromStdString(f.value)); + v->setWordWrap(true); + geopro::app::applyTokenizedStyleSheet(v, QStringLiteral("color:{{text/primary}};")); + fl->addRow(k, v); + } + content_->addWidget(form_w); + } + content_->addStretch(); +} + +} // namespace geopro::app diff --git a/src/app/panels/DynamicFormView.hpp b/src/app/panels/DynamicFormView.hpp new file mode 100644 index 0000000..c3c6cd3 --- /dev/null +++ b/src/app/panels/DynamicFormView.hpp @@ -0,0 +1,21 @@ +#pragma once +#include +#include "repo/RepoTypes.hpp" + +class QVBoxLayout; + +namespace geopro::app { + +// 被动:渲染 DynamicForm(分组键值)。对象属性 / 数据集属性两面板共用。 +class DynamicFormView : public QWidget { +public: + explicit DynamicFormView(QWidget* parent = nullptr); + void setForm(const geopro::data::DynamicForm& form); + void showMessage(const QString& message); // 空/错占位 + +private: + void clear(); + QVBoxLayout* content_ = nullptr; // 滚动区内容布局 +}; + +} // namespace geopro::app