diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 8edbbd8..175f3bc 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -50,6 +50,7 @@ add_executable(geopro_desktop WIN32 panels/chart/ContourPlotItem.cpp panels/chart/LivePanner.cpp panels/chart/ScatterHoverTip.cpp + panels/columns/Column3DDataset.cpp panels/AnomalyTablePanel.cpp panels/LoadingOverlay.cpp panels/DatasetDetailPage.cpp diff --git a/src/app/panels/columns/Column3DDataset.cpp b/src/app/panels/columns/Column3DDataset.cpp new file mode 100644 index 0000000..f237826 --- /dev/null +++ b/src/app/panels/columns/Column3DDataset.cpp @@ -0,0 +1,140 @@ +#include "panels/columns/Column3DDataset.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Theme.hpp" +#include "panels/DatasetListPanel.hpp" + +using geopro::controller::AxesMode; +using geopro::controller::AxesUnit; +using geopro::controller::ViewDir; + +namespace geopro::app { + +Column3DDataset::Column3DDataset(QWidget* parent) : QWidget(parent) { + auto* root = new QVBoxLayout(this); + root->setContentsMargins(space::kMd, space::kMd, space::kMd, space::kMd); + root->setSpacing(space::kMd); + + // 坐标轴设置 + { + auto* form = new QFormLayout(); + auto* mode = new QComboBox(); + mode->addItem(QStringLiteral("标准"), static_cast(AxesMode::Standard)); + mode->addItem(QStringLiteral("三维立体"), static_cast(AxesMode::Stereo)); + mode->addItem(QStringLiteral("不显示"), static_cast(AxesMode::None)); + connect(mode, qOverload(&QComboBox::currentIndexChanged), this, + [this, mode](int) { emit axesModeChanged(static_cast(mode->currentData().toInt())); }); + auto* oPoint = new QPushButton(QStringLiteral("设置…")); + connect(oPoint, &QPushButton::clicked, this, &Column3DDataset::oPointClicked); + auto* unit = new QComboBox(); + unit->addItem(QStringLiteral("无刻度"), static_cast(AxesUnit::None)); + unit->addItem(QStringLiteral("米"), static_cast(AxesUnit::Meter)); + unit->addItem(QStringLiteral("英尺"), static_cast(AxesUnit::Feet)); + unit->addItem(QStringLiteral("经纬度"), static_cast(AxesUnit::LatLon)); + unit->setCurrentIndex(1); + connect(unit, qOverload(&QComboBox::currentIndexChanged), this, + [this, unit](int) { emit axesUnitChanged(static_cast(unit->currentData().toInt())); }); + auto* font = new QPushButton(QStringLiteral("设置…")); + connect(font, &QPushButton::clicked, this, &Column3DDataset::fontClicked); + form->addRow(QStringLiteral("显示方式"), mode); + form->addRow(QStringLiteral("O点位置"), oPoint); + form->addRow(QStringLiteral("刻度"), unit); + form->addRow(QStringLiteral("字体"), font); + root->addWidget(new QLabel(QStringLiteral("坐标轴设置"))); + root->addLayout(form); + } + + // 水平/垂直比例(单滑块 + 数值) + { + auto* row = new QHBoxLayout(); + auto* slider = new QSlider(Qt::Horizontal); + slider->setMinimum(1); + slider->setMaximum(10); + slider->setValue(2); + auto* val = new QLabel(QStringLiteral("2.0\xc3\x97")); // × + connect(slider, &QSlider::valueChanged, this, [this, val](int v) { + val->setText(QStringLiteral("%1.0\xc3\x97").arg(v)); + emit verticalExaggerationChanged(static_cast(v)); + }); + row->addWidget(slider, 1); + row->addWidget(val); + root->addWidget(new QLabel(QStringLiteral("水平/垂直比例"))); + root->addLayout(row); + } + + // 快捷视图 + { + auto* row = new QHBoxLayout(); + struct V { + const char* t; + ViewDir d; + }; + const V views[] = { + {"\xe5\x89\x8d", ViewDir::Front}, // 前 + {"\xe5\x90\x8e", ViewDir::Back}, // 后 + {"\xe5\xb7\xa6", ViewDir::Left}, // 左 + {"\xe5\x8f\xb3", ViewDir::Right}, // 右 + {"\xe4\xb8\x8a", ViewDir::Top}, // 上 + {"\xe4\xb8\x8b", ViewDir::Bottom}, // 下 + }; + for (const V& v : views) { + auto* b = new QPushButton(QString::fromUtf8(v.t)); + ViewDir d = v.d; + connect(b, &QPushButton::clicked, this, [this, d] { emit viewRequested(d); }); + row->addWidget(b); + } + root->addWidget(new QLabel(QStringLiteral("快捷视图"))); + root->addLayout(row); + } + + // 缩放 + { + auto* row = new QHBoxLayout(); + auto* in = new QPushButton(QStringLiteral("放大")); + auto* out = new QPushButton(QStringLiteral("缩小")); + auto* fit = new QPushButton(QStringLiteral("适配")); + connect(in, &QPushButton::clicked, this, &Column3DDataset::zoomInRequested); + connect(out, &QPushButton::clicked, this, &Column3DDataset::zoomOutRequested); + connect(fit, &QPushButton::clicked, this, &Column3DDataset::fitRequested); + row->addWidget(in); + row->addWidget(out); + row->addWidget(fit); + root->addWidget(new QLabel(QStringLiteral("缩放"))); + root->addLayout(row); + } + + // 数据集列表(可勾选) + list_ = new QTreeWidget(); + list_->setHeaderHidden(true); + list_->setRootIsDecorated(true); + applyDatasetCardDelegate(list_); + connect(list_, &QTreeWidget::itemChanged, this, [this](QTreeWidgetItem*, int) { + QStringList ids; + for (QTreeWidgetItemIterator it(list_); *it; ++it) { + if ((*it)->checkState(0) == Qt::Checked) + ids << (*it)->data(0, kDsIdRole).toString(); + } + emit checkedDatasetsChanged(ids); + }); + root->addWidget(list_, 1); +} + +void Column3DDataset::setDatasets(const std::vector& rows) { + populateDatasetList(list_, rows, /*append=*/false); + for (QTreeWidgetItemIterator it(list_); *it; ++it) { + (*it)->setFlags((*it)->flags() | Qt::ItemIsUserCheckable); + if ((*it)->checkState(0) != Qt::Checked) + (*it)->setCheckState(0, Qt::Unchecked); + } +} + +} // namespace geopro::app diff --git a/src/app/panels/columns/Column3DDataset.hpp b/src/app/panels/columns/Column3DDataset.hpp new file mode 100644 index 0000000..d0d8ead --- /dev/null +++ b/src/app/panels/columns/Column3DDataset.hpp @@ -0,0 +1,35 @@ +#pragma once +#include +#include +#include +#include "I3dSceneView.hpp" // AxesMode/AxesUnit/ViewDir +#include "repo/RepoTypes.hpp" + +class QTreeWidget; + +namespace geopro::app { + +// 三维数据集栏:坐标轴设置 + 水平/垂直比例 + 快捷视图 + 缩放 + 3D 数据集列表。 +class Column3DDataset : public QWidget { + Q_OBJECT +public: + explicit Column3DDataset(QWidget* parent = nullptr); + void setDatasets(const std::vector& rows); + +signals: + void axesModeChanged(geopro::controller::AxesMode mode); + void axesUnitChanged(geopro::controller::AxesUnit unit); + void verticalExaggerationChanged(double ve); + void viewRequested(geopro::controller::ViewDir dir); + void zoomInRequested(); + void zoomOutRequested(); + void fitRequested(); + void oPointClicked(); + void fontClicked(); + void checkedDatasetsChanged(const QStringList& dsIds); + +private: + QTreeWidget* list_ = nullptr; +}; + +} // namespace geopro::app