feat/vtk-3d-view #7
|
|
@ -3,7 +3,7 @@
|
|||
#include <utility>
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QFormLayout>
|
||||
#include <QFrame>
|
||||
#include <QHBoxLayout>
|
||||
#include <QHeaderView>
|
||||
#include <QHash>
|
||||
|
|
@ -20,16 +20,17 @@
|
|||
#include <QTreeWidget>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "FormKit.hpp"
|
||||
#include "Theme.hpp"
|
||||
#include "panels/chart/InversionProcessOps.hpp" // buildFilterApplyBody / buildNewFilterBody
|
||||
#include "repo/IDatasetCommandRepository.hpp"
|
||||
|
||||
namespace geopro::app {
|
||||
|
||||
namespace {
|
||||
constexpr double kFillRange = 1e9;
|
||||
constexpr int kDialogW = 900; // 原版弹窗宽 900px
|
||||
constexpr int kMatrixMin = 1, kMatrixMax = 21; // 矩阵行列范围(对照原版 1~21)
|
||||
constexpr int kDefaultDim = 3;
|
||||
constexpr int kSettingLabelW = 80; // 原版 .setting-label width:80px
|
||||
const char kDefaultCustomKey[] = "default-custom-filter"; // 默认自定义滤波器(不可删)
|
||||
const char kCustomGroupName[] = "自定义滤波器";
|
||||
|
||||
|
|
@ -40,86 +41,58 @@ double cellValue(const QTableWidgetItem* it) {
|
|||
const double v = it->text().toDouble(&ok);
|
||||
return ok ? v : 0.0;
|
||||
}
|
||||
|
||||
// 原版分组小标题(14px 半粗 + 标题下 1px divider)。
|
||||
void addSpecTitle(QVBoxLayout* into, const QString& title, QWidget* parent) {
|
||||
auto* lbl = new QLabel(title, parent);
|
||||
auto f = lbl->font();
|
||||
f.setBold(true);
|
||||
lbl->setFont(f);
|
||||
into->addWidget(lbl);
|
||||
auto* line = new QFrame(parent);
|
||||
line->setFrameShape(QFrame::HLine);
|
||||
line->setFrameShadow(QFrame::Plain);
|
||||
into->addWidget(line);
|
||||
}
|
||||
|
||||
// 原版带边框卡片(1px 边框 + 圆角 + 内距)。
|
||||
QFrame* cardFrame(QWidget* parent) {
|
||||
auto* card = new QFrame(parent);
|
||||
card->setFrameShape(QFrame::StyledPanel);
|
||||
return card;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
FilterDialog::FilterDialog(geopro::data::IDatasetCommandRepository* repo, QString dsId,
|
||||
QString projectId, QWidget* parent)
|
||||
: QDialog(parent), repo_(repo), dsId_(std::move(dsId)), projectId_(std::move(projectId)) {
|
||||
setWindowTitle(QStringLiteral("滤波处理"));
|
||||
setWindowTitle(QStringLiteral("滤波设置")); // 原版 filterSetting
|
||||
setModal(true);
|
||||
resize(820, 520);
|
||||
setFixedWidth(kDialogW);
|
||||
|
||||
auto* root = formkit::dialogRoot(this);
|
||||
auto* root = new QVBoxLayout(this);
|
||||
root->setContentsMargins(geopro::app::space::kLg, geopro::app::space::kLg,
|
||||
geopro::app::space::kLg, geopro::app::space::kLg);
|
||||
root->setSpacing(geopro::app::space::kMd);
|
||||
auto* body = new QHBoxLayout();
|
||||
body->setSpacing(geopro::app::space::kLg);
|
||||
root->addLayout(body, 1);
|
||||
|
||||
// ── 左:滤波器树 + 增删按钮 ─────────────────────────────────────────
|
||||
auto* leftLay = new QVBoxLayout();
|
||||
tree_ = new QTreeWidget(this);
|
||||
tree_->setHeaderHidden(true);
|
||||
leftLay->addWidget(tree_, 1);
|
||||
auto* treeBtnLay = new QHBoxLayout();
|
||||
auto* addBtn = new QPushButton(QStringLiteral("另存为"), this);
|
||||
auto* delBtn = new QPushButton(QStringLiteral("删除"), this);
|
||||
treeBtnLay->addWidget(addBtn);
|
||||
treeBtnLay->addWidget(delBtn);
|
||||
leftLay->addLayout(treeBtnLay);
|
||||
body->addLayout(leftLay, 1);
|
||||
buildLeft(body);
|
||||
buildRight(body);
|
||||
|
||||
// ── 右:配置面板 ────────────────────────────────────────────────────
|
||||
auto* rightLay = new QVBoxLayout();
|
||||
auto* form = formkit::makeEditForm();
|
||||
dataEdge_ = new QComboBox(this);
|
||||
dataEdge_->addItem(QStringLiteral("设为无效点"), QStringLiteral("whitening"));
|
||||
dataEdge_->addItem(QStringLiteral("忽略"), QStringLiteral("skip"));
|
||||
dataEdge_->addItem(QStringLiteral("复制边缘点"), QStringLiteral("edgePoint"));
|
||||
dataEdge_->addItem(QStringLiteral("填充"), QStringLiteral("filling"));
|
||||
dataEdgeValue_ = new QLineEdit(this);
|
||||
dataEdgeValue_->setEnabled(false);
|
||||
noDataPoints_ = new QComboBox(this);
|
||||
noDataPoints_->addItem(QStringLiteral("扩展"), QStringLiteral("expansion"));
|
||||
noDataPoints_->addItem(QStringLiteral("保留"), QStringLiteral("retain"));
|
||||
noDataPoints_->addItem(QStringLiteral("跳过"), QStringLiteral("skip"));
|
||||
noDataPoints_->addItem(QStringLiteral("填充"), QStringLiteral("filling"));
|
||||
noDataPoints_->setCurrentIndex(3); // 默认填充(对照原版)
|
||||
noDataValue_ = new QLineEdit(this);
|
||||
filterTimes_ = new QSpinBox(this);
|
||||
filterTimes_->setRange(1, 10);
|
||||
rows_ = new QSpinBox(this);
|
||||
rows_->setRange(kMatrixMin, kMatrixMax);
|
||||
rows_->setValue(kDefaultDim);
|
||||
cols_ = new QSpinBox(this);
|
||||
cols_->setRange(kMatrixMin, kMatrixMax);
|
||||
cols_->setValue(kDefaultDim);
|
||||
formkit::capField(dataEdge_);
|
||||
formkit::capField(dataEdgeValue_);
|
||||
formkit::capField(noDataPoints_);
|
||||
formkit::capField(noDataValue_);
|
||||
formkit::capField(filterTimes_);
|
||||
formkit::capField(rows_);
|
||||
formkit::capField(cols_);
|
||||
form->addRow(formkit::editLabel(QStringLiteral("数据边缘:")), dataEdge_);
|
||||
form->addRow(formkit::editLabel(QStringLiteral("数据边缘值:")), dataEdgeValue_);
|
||||
form->addRow(formkit::editLabel(QStringLiteral("无数据点:")), noDataPoints_);
|
||||
form->addRow(formkit::editLabel(QStringLiteral("无数据点值:")), noDataValue_);
|
||||
form->addRow(formkit::editLabel(QStringLiteral("滤波次数:")), filterTimes_);
|
||||
form->addRow(formkit::editLabel(QStringLiteral("行:")), rows_);
|
||||
form->addRow(formkit::editLabel(QStringLiteral("列:")), cols_);
|
||||
rightLay->addLayout(form);
|
||||
matrix_ = new QTableWidget(kDefaultDim, kDefaultDim, this);
|
||||
matrix_->horizontalHeader()->setVisible(false);
|
||||
matrix_->verticalHeader()->setVisible(false);
|
||||
rightLay->addWidget(matrix_, 1);
|
||||
body->addLayout(rightLay, 2);
|
||||
|
||||
// 底部按钮。
|
||||
// 底部按钮(原版三按钮各 ~30%:保存设置(主,左)/确认(主,中)/取消(右))。
|
||||
auto* btnLay = new QHBoxLayout();
|
||||
btnLay->addStretch();
|
||||
auto* cancelBtn = new QPushButton(QStringLiteral("取消"), this);
|
||||
okBtn_ = new QPushButton(QStringLiteral("应用"), this);
|
||||
btnLay->setSpacing(geopro::app::space::kMd);
|
||||
auto* saveSettingBtn = new QPushButton(QStringLiteral("保存设置"), this);
|
||||
okBtn_ = new QPushButton(QStringLiteral("确认"), this);
|
||||
okBtn_->setDefault(true);
|
||||
btnLay->addWidget(cancelBtn);
|
||||
btnLay->addWidget(okBtn_);
|
||||
auto* cancelBtn = new QPushButton(QStringLiteral("取消"), this);
|
||||
btnLay->addWidget(saveSettingBtn, 30);
|
||||
btnLay->addStretch(2);
|
||||
btnLay->addWidget(okBtn_, 30);
|
||||
btnLay->addStretch(2);
|
||||
btnLay->addWidget(cancelBtn, 30);
|
||||
root->addLayout(btnLay);
|
||||
|
||||
resizeMatrix(); // 默认 3x3 中心 1
|
||||
|
|
@ -127,14 +100,16 @@ FilterDialog::FilterDialog(geopro::data::IDatasetCommandRepository* repo, QStrin
|
|||
|
||||
connect(cancelBtn, &QPushButton::clicked, this, &QDialog::reject);
|
||||
connect(okBtn_, &QPushButton::clicked, this, &FilterDialog::onConfirm);
|
||||
connect(addBtn, &QPushButton::clicked, this, &FilterDialog::saveCustomFilter);
|
||||
connect(delBtn, &QPushButton::clicked, this, &FilterDialog::deleteSelectedFilter);
|
||||
connect(saveSettingBtn, &QPushButton::clicked, this, &FilterDialog::saveCustomFilter);
|
||||
connect(tree_, &QTreeWidget::itemSelectionChanged, this,
|
||||
&FilterDialog::onTreeSelectionChanged);
|
||||
// 行/列:仅奇数允许,偶数弹警告并回退旧值(对照原版 watch rows/cols)。
|
||||
prevRows_ = kDefaultDim;
|
||||
prevCols_ = kDefaultDim;
|
||||
connect(rows_, QOverload<int>::of(&QSpinBox::valueChanged), this,
|
||||
[this](int) { resizeMatrix(); });
|
||||
[this](int v) { onDimChanged(rows_, v, prevRows_, QStringLiteral("行")); });
|
||||
connect(cols_, QOverload<int>::of(&QSpinBox::valueChanged), this,
|
||||
[this](int) { resizeMatrix(); });
|
||||
[this](int v) { onDimChanged(cols_, v, prevCols_, QStringLiteral("列")); });
|
||||
// 数据边缘/无数据点:仅「填充」启用对应值输入框(对照原版 v-if=filling)。
|
||||
connect(dataEdge_, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int) {
|
||||
dataEdgeValue_->setEnabled(dataEdge_->currentData().toString() ==
|
||||
|
|
@ -149,6 +124,125 @@ FilterDialog::FilterDialog(geopro::data::IDatasetCommandRepository* repo, QStrin
|
|||
loadFilters();
|
||||
}
|
||||
|
||||
void FilterDialog::buildLeft(QHBoxLayout* body) {
|
||||
auto* card = cardFrame(this);
|
||||
card->setMinimumWidth(270); // 原版左卡片 min-width:270px
|
||||
auto* leftLay = new QVBoxLayout(card);
|
||||
leftLay->setContentsMargins(geopro::app::space::kLg, geopro::app::space::kLg,
|
||||
geopro::app::space::kLg, geopro::app::space::kLg);
|
||||
auto* title = new QLabel(QStringLiteral("滤波方式:"), card); // 原版 filterType:
|
||||
auto tf = title->font();
|
||||
tf.setBold(true);
|
||||
title->setFont(tf);
|
||||
leftLay->addWidget(title);
|
||||
tree_ = new QTreeWidget(card);
|
||||
tree_->setHeaderHidden(true);
|
||||
leftLay->addWidget(tree_, 1);
|
||||
auto* treeBtnLay = new QHBoxLayout();
|
||||
auto* addBtn = new QPushButton(QStringLiteral("另存为"), card);
|
||||
auto* delBtn = new QPushButton(QStringLiteral("删除"), card);
|
||||
treeBtnLay->addWidget(addBtn);
|
||||
treeBtnLay->addWidget(delBtn);
|
||||
leftLay->addLayout(treeBtnLay);
|
||||
body->addWidget(card, 3); // 左 ~30%
|
||||
|
||||
connect(addBtn, &QPushButton::clicked, this, &FilterDialog::saveCustomFilter);
|
||||
connect(delBtn, &QPushButton::clicked, this, &FilterDialog::deleteSelectedFilter);
|
||||
}
|
||||
|
||||
void FilterDialog::buildRight(QHBoxLayout* body) {
|
||||
auto* card = cardFrame(this);
|
||||
auto* rightLay = new QVBoxLayout(card);
|
||||
rightLay->setContentsMargins(geopro::app::space::kLg, geopro::app::space::kLg,
|
||||
geopro::app::space::kLg, geopro::app::space::kLg);
|
||||
rightLay->setSpacing(geopro::app::space::kMd);
|
||||
|
||||
// 滤波设置分组。
|
||||
addSpecTitle(rightLay, QStringLiteral("滤波设置"), card);
|
||||
dataEdge_ = new QComboBox(card);
|
||||
dataEdge_->addItem(QStringLiteral("设置为无效点"), QStringLiteral("whitening"));
|
||||
dataEdge_->addItem(QStringLiteral("忽略"), QStringLiteral("skip"));
|
||||
dataEdge_->addItem(QStringLiteral("复制边缘点"), QStringLiteral("edgePoint"));
|
||||
dataEdge_->addItem(QStringLiteral("填充"), QStringLiteral("filling"));
|
||||
dataEdgeValue_ = new QLineEdit(card);
|
||||
dataEdgeValue_->setEnabled(false);
|
||||
noDataPoints_ = new QComboBox(card);
|
||||
noDataPoints_->addItem(QStringLiteral("扩展"), QStringLiteral("expansion"));
|
||||
noDataPoints_->addItem(QStringLiteral("保留"), QStringLiteral("retain"));
|
||||
noDataPoints_->addItem(QStringLiteral("忽略"), QStringLiteral("skip")); // 原版 skip → 忽略
|
||||
noDataPoints_->addItem(QStringLiteral("填充"), QStringLiteral("filling"));
|
||||
noDataPoints_->setCurrentIndex(3); // 默认填充(对照原版)
|
||||
noDataValue_ = new QLineEdit(card);
|
||||
filterTimes_ = new QSpinBox(card);
|
||||
filterTimes_->setRange(1, 10);
|
||||
|
||||
rightLay->addLayout(settingRow(QStringLiteral("数据边缘:"), dataEdge_,
|
||||
QStringLiteral("值:"), dataEdgeValue_, card));
|
||||
rightLay->addLayout(settingRow(QStringLiteral("无数据点:"), noDataPoints_,
|
||||
QStringLiteral("值:"), noDataValue_, card));
|
||||
rightLay->addLayout(settingRow(QStringLiteral("滤波次数:"), filterTimes_,
|
||||
QString(), nullptr, card));
|
||||
|
||||
// 滤波器规格分组。
|
||||
addSpecTitle(rightLay, QStringLiteral("滤波器规格"), card);
|
||||
rows_ = new QSpinBox(card);
|
||||
rows_->setRange(kMatrixMin, kMatrixMax);
|
||||
rows_->setValue(kDefaultDim);
|
||||
cols_ = new QSpinBox(card);
|
||||
cols_->setRange(kMatrixMin, kMatrixMax);
|
||||
cols_->setValue(kDefaultDim);
|
||||
auto* specsRow = new QHBoxLayout();
|
||||
auto* rowLbl = new QLabel(QStringLiteral("行:"), card);
|
||||
rowLbl->setMinimumWidth(30);
|
||||
specsRow->addWidget(rowLbl);
|
||||
specsRow->addWidget(rows_);
|
||||
specsRow->addSpacing(geopro::app::space::kLg);
|
||||
auto* colLbl = new QLabel(QStringLiteral("列:"), card);
|
||||
colLbl->setMinimumWidth(30);
|
||||
specsRow->addWidget(colLbl);
|
||||
specsRow->addWidget(cols_);
|
||||
specsRow->addStretch();
|
||||
rightLay->addLayout(specsRow);
|
||||
|
||||
matrix_ = new QTableWidget(kDefaultDim, kDefaultDim, card);
|
||||
matrix_->horizontalHeader()->setVisible(true); // 原版矩阵带行列号表头
|
||||
matrix_->verticalHeader()->setVisible(true);
|
||||
rightLay->addWidget(matrix_, 1);
|
||||
body->addWidget(card, 6); // 右 ~60%
|
||||
}
|
||||
|
||||
// 原版 .setting-row:label(80px) + 主控件(30%) [+ 右侧 label「值:」+ 值框(30%)]。
|
||||
QHBoxLayout* FilterDialog::settingRow(const QString& label, QWidget* main, const QString& valLabel,
|
||||
QWidget* valField, QWidget* parent) {
|
||||
auto* row = new QHBoxLayout();
|
||||
row->setSpacing(geopro::app::space::kMd);
|
||||
auto* lbl = new QLabel(label, parent);
|
||||
lbl->setMinimumWidth(kSettingLabelW);
|
||||
row->addWidget(lbl);
|
||||
row->addWidget(main, 3);
|
||||
if (valField) {
|
||||
row->addSpacing(geopro::app::space::kLg);
|
||||
row->addWidget(new QLabel(valLabel, parent));
|
||||
row->addWidget(valField, 3);
|
||||
} else {
|
||||
row->addStretch(4);
|
||||
}
|
||||
return row;
|
||||
}
|
||||
|
||||
void FilterDialog::onDimChanged(QSpinBox* box, int newVal, int& prev, const QString& which) {
|
||||
if (newVal % 2 == 0) { // 偶数 → 警告并回退(对照原版 watch 回退旧值)
|
||||
QMessageBox::warning(
|
||||
this, windowTitle(),
|
||||
QStringLiteral("滤波矩阵%1数必须为奇数,以确保有唯一的中心点").arg(which));
|
||||
QSignalBlocker b(box);
|
||||
box->setValue(prev);
|
||||
return;
|
||||
}
|
||||
prev = newVal;
|
||||
resizeMatrix();
|
||||
}
|
||||
|
||||
void FilterDialog::loadFilters() {
|
||||
if (!repo_) return;
|
||||
QPointer<FilterDialog> self(this);
|
||||
|
|
@ -226,6 +320,12 @@ void FilterDialog::resizeMatrix() {
|
|||
std::vector<std::vector<double>> old = readMatrix();
|
||||
matrix_->setRowCount(r);
|
||||
matrix_->setColumnCount(c);
|
||||
// 行列号表头(1..n)。
|
||||
QStringList hh, vh;
|
||||
for (int j = 0; j < c; ++j) hh << QString::number(j + 1);
|
||||
for (int i = 0; i < r; ++i) vh << QString::number(i + 1);
|
||||
matrix_->setHorizontalHeaderLabels(hh);
|
||||
matrix_->setVerticalHeaderLabels(vh);
|
||||
for (int i = 0; i < r; ++i)
|
||||
for (int j = 0; j < c; ++j) {
|
||||
auto* it = matrix_->item(i, j);
|
||||
|
|
@ -272,8 +372,8 @@ void FilterDialog::saveCustomFilter() {
|
|||
return;
|
||||
}
|
||||
bool ok = false;
|
||||
const QString name = QInputDialog::getText(this, QStringLiteral("另存为新自定义滤波器"),
|
||||
QStringLiteral("名称:"), QLineEdit::Normal,
|
||||
const QString name = QInputDialog::getText(this, QStringLiteral("保存为新的自定义滤波器"),
|
||||
QStringLiteral("请输入滤波器名称"), QLineEdit::Normal,
|
||||
QStringLiteral("自定义滤波器1"), &ok);
|
||||
if (!ok || name.trimmed().isEmpty()) return;
|
||||
QPointer<FilterDialog> self(this);
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ class QTreeWidget;
|
|||
class QTreeWidgetItem;
|
||||
class QTableWidget;
|
||||
class QLineEdit;
|
||||
class QHBoxLayout;
|
||||
class QWidget;
|
||||
|
||||
namespace geopro::data {
|
||||
class IDatasetCommandRepository;
|
||||
|
|
@ -31,6 +33,11 @@ public:
|
|||
QWidget* parent = nullptr);
|
||||
|
||||
private:
|
||||
void buildLeft(QHBoxLayout* body); // 左:滤波方式树卡片
|
||||
void buildRight(QHBoxLayout* body); // 右:滤波设置 + 滤波器规格卡片
|
||||
QHBoxLayout* settingRow(const QString& label, QWidget* main, const QString& valLabel,
|
||||
QWidget* valField, QWidget* parent); // 原版 .setting-row
|
||||
void onDimChanged(QSpinBox* box, int newVal, int& prev, const QString& which); // 奇偶校验
|
||||
void loadFilters(); // 拉滤波器树
|
||||
void buildTree(); // 由 flatItems_ 建树
|
||||
void onTreeSelectionChanged(); // 选中叶节点 → 右侧回填
|
||||
|
|
@ -56,6 +63,8 @@ private:
|
|||
QSpinBox* filterTimes_ = nullptr;
|
||||
QSpinBox* rows_ = nullptr;
|
||||
QSpinBox* cols_ = nullptr;
|
||||
int prevRows_ = 3; // 奇偶校验回退用(上一合法行数)
|
||||
int prevCols_ = 3; // 上一合法列数
|
||||
QTableWidget* matrix_ = nullptr;
|
||||
|
||||
QPushButton* okBtn_ = nullptr;
|
||||
|
|
|
|||
|
|
@ -122,10 +122,11 @@ GridDataChartView::GridDataChartView(QWidget* parent) : QWidget(parent) {
|
|||
tbLay->addWidget(lblSimplify);
|
||||
tbLay->addWidget(simplifySlider_);
|
||||
tbLay->addWidget(simplifyValueLabel_);
|
||||
// 原版 .right-buttons margin-left:auto:异常标注/自动标注/另存为 右对齐。
|
||||
tbLay->addStretch();
|
||||
tbLay->addWidget(btnAnomalyLabel);
|
||||
tbLay->addWidget(btnAutoLabel);
|
||||
tbLay->addWidget(btnSaveAs);
|
||||
tbLay->addStretch();
|
||||
|
||||
lay->addWidget(toolbar);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
#include "panels/chart/GridWizardDialog.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <utility>
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QDoubleSpinBox>
|
||||
#include <QFormLayout>
|
||||
#include <QFrame>
|
||||
#include <QGridLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QListWidget>
|
||||
|
|
@ -15,96 +17,85 @@
|
|||
#include <QStackedWidget>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "FormKit.hpp"
|
||||
#include "Theme.hpp"
|
||||
#include "panels/chart/InversionProcessOps.hpp" // buildGridToBody
|
||||
#include "repo/IDatasetCommandRepository.hpp"
|
||||
|
||||
namespace geopro::app {
|
||||
|
||||
namespace {
|
||||
constexpr double kCoordRange = 1e9; // 坐标范围(足够宽)
|
||||
constexpr int kSizeMin = 1, kSizeMax = 300; // 点数范围(对照原版 1~300)
|
||||
constexpr int kDefaultXSize = 100; // 默认点数(原版 xPoints 默认 100)
|
||||
constexpr double kCoordRange = 1e9; // 坐标范围(足够宽)
|
||||
constexpr int kSizeMin = 1, kSizeMax = 300; // 点数范围(对照原版 1~300)
|
||||
constexpr int kDefaultXSize = 100; // 默认点数(原版 xPoints 默认 100)
|
||||
constexpr int kStep1W = 500, kStep2W = 800; // 原版步骤 1/2 弹窗宽
|
||||
constexpr int kParamLabelW = 60; // 原版 .param-group label min-width:60px
|
||||
constexpr int kParamFieldW = 100; // 原版输入框宽 100px
|
||||
|
||||
// 配一个坐标 spinbox(6 位小数,宽范围)。
|
||||
QDoubleSpinBox* makeCoordSpin(QWidget* parent) {
|
||||
auto* sp = new QDoubleSpinBox(parent);
|
||||
sp->setRange(-kCoordRange, kCoordRange);
|
||||
sp->setDecimals(6);
|
||||
sp->setFixedWidth(kParamFieldW);
|
||||
return sp;
|
||||
}
|
||||
|
||||
// 分组卡片标题(原版 .section-title:14px 半粗 + 标题下 1px divider)。
|
||||
void addSectionTitle(QVBoxLayout* into, const QString& title, QWidget* parent) {
|
||||
auto* lbl = new QLabel(title, parent);
|
||||
auto f = lbl->font();
|
||||
f.setBold(true);
|
||||
lbl->setFont(f);
|
||||
into->addWidget(lbl);
|
||||
auto* line = new QFrame(parent);
|
||||
line->setFrameShape(QFrame::HLine);
|
||||
line->setFrameShadow(QFrame::Plain);
|
||||
into->addWidget(line);
|
||||
}
|
||||
|
||||
// 原版 .param-group:定宽右标签 + 紧随输入框,多个并排成一行栅格。
|
||||
void addParamCell(QGridLayout* grid, int row, int col, const QString& label, QWidget* field,
|
||||
QWidget* parent) {
|
||||
auto* cell = new QHBoxLayout();
|
||||
cell->setSpacing(geopro::app::space::kSm);
|
||||
auto* lbl = new QLabel(label, parent);
|
||||
lbl->setMinimumWidth(kParamLabelW);
|
||||
lbl->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
||||
cell->addWidget(lbl);
|
||||
cell->addWidget(field);
|
||||
grid->addLayout(cell, row, col);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
GridWizardDialog::GridWizardDialog(geopro::data::IDatasetCommandRepository* repo, QString dsId,
|
||||
QWidget* parent)
|
||||
: QDialog(parent), repo_(repo), dsId_(std::move(dsId)) {
|
||||
setWindowTitle(QStringLiteral("网格化"));
|
||||
setWindowTitle(QStringLiteral("网格配置")); // 原版 gridSetting
|
||||
setModal(true);
|
||||
resize(560, 420);
|
||||
setFixedWidth(kStep1W);
|
||||
|
||||
auto* root = formkit::dialogRoot(this);
|
||||
auto* root = new QVBoxLayout(this);
|
||||
root->setContentsMargins(geopro::app::space::kLg, geopro::app::space::kLg,
|
||||
geopro::app::space::kLg, geopro::app::space::kLg);
|
||||
root->setSpacing(geopro::app::space::kMd);
|
||||
stack_ = new QStackedWidget(this);
|
||||
root->addWidget(stack_, 1);
|
||||
|
||||
// ── 步骤 1:算法选择(单选列表)──────────────────────────────────────
|
||||
auto* page1 = new QWidget(this);
|
||||
auto* p1Lay = new QVBoxLayout(page1);
|
||||
p1Lay->addWidget(new QLabel(QStringLiteral("请选择网格方法:"), page1));
|
||||
algoList_ = new QListWidget(page1);
|
||||
p1Lay->addWidget(algoList_, 1);
|
||||
stack_->addWidget(page1);
|
||||
buildStep1();
|
||||
buildStep2();
|
||||
|
||||
// ── 步骤 2:网格参数 + 数据值设置 ────────────────────────────────────
|
||||
auto* page2 = new QWidget(this);
|
||||
auto* p2Lay = new QVBoxLayout(page2);
|
||||
xMin_ = makeCoordSpin(page2); xMax_ = makeCoordSpin(page2);
|
||||
yMin_ = makeCoordSpin(page2); yMax_ = makeCoordSpin(page2);
|
||||
vMin_ = makeCoordSpin(page2); vMax_ = makeCoordSpin(page2);
|
||||
xSize_ = new QSpinBox(page2); xSize_->setRange(kSizeMin, kSizeMax); xSize_->setValue(kDefaultXSize);
|
||||
ySize_ = new QSpinBox(page2); ySize_->setRange(kSizeMin, kSizeMax); ySize_->setValue(kDefaultXSize);
|
||||
xSpacing_ = makeCoordSpin(page2); xSpacing_->setRange(0.0, kCoordRange);
|
||||
ySpacing_ = makeCoordSpin(page2); ySpacing_->setRange(0.0, kCoordRange);
|
||||
saveFormat_ = new QComboBox(page2);
|
||||
saveFormat_->addItem(QStringLiteral("线性"), QStringLiteral("linear"));
|
||||
saveFormat_->addItem(QStringLiteral("对数"), QStringLiteral("log"));
|
||||
|
||||
formkit::capField(xMin_);
|
||||
formkit::capField(xMax_);
|
||||
formkit::capField(xSpacing_);
|
||||
formkit::capField(yMin_);
|
||||
formkit::capField(yMax_);
|
||||
formkit::capField(ySpacing_);
|
||||
formkit::capField(vMin_);
|
||||
formkit::capField(vMax_);
|
||||
formkit::capField(xSize_);
|
||||
formkit::capField(ySize_);
|
||||
formkit::capField(saveFormat_);
|
||||
|
||||
auto* form = formkit::makeEditForm();
|
||||
form->addRow(formkit::editLabel(QStringLiteral("Xmin:")), xMin_);
|
||||
form->addRow(formkit::editLabel(QStringLiteral("Xmax:")), xMax_);
|
||||
form->addRow(formkit::editLabel(QStringLiteral("X点数:")), xSize_);
|
||||
form->addRow(formkit::editLabel(QStringLiteral("X间距:")), xSpacing_);
|
||||
form->addRow(formkit::editLabel(QStringLiteral("Ymin:")), yMin_);
|
||||
form->addRow(formkit::editLabel(QStringLiteral("Ymax:")), yMax_);
|
||||
form->addRow(formkit::editLabel(QStringLiteral("Y点数:")), ySize_);
|
||||
form->addRow(formkit::editLabel(QStringLiteral("Y间距:")), ySpacing_);
|
||||
form->addRow(formkit::editLabel(QStringLiteral("数据值min:")), vMin_);
|
||||
form->addRow(formkit::editLabel(QStringLiteral("数据值max:")), vMax_);
|
||||
form->addRow(formkit::editLabel(QStringLiteral("保存格式:")), saveFormat_);
|
||||
p2Lay->addLayout(form);
|
||||
stack_->addWidget(page2);
|
||||
|
||||
// ── 底部按钮(上一步 / 下一步 / 确认 / 取消)────────────────────────
|
||||
// ── 底部按钮(上一步 / 确认(主) / 取消,原版步骤 2 三按钮)────────────
|
||||
auto* btnLay = new QHBoxLayout();
|
||||
btnLay->setSpacing(geopro::app::space::kMd);
|
||||
btnLay->addStretch();
|
||||
prevBtn_ = new QPushButton(QStringLiteral("上一步"), this);
|
||||
nextBtn_ = new QPushButton(QStringLiteral("下一步"), this);
|
||||
okBtn_ = new QPushButton(QStringLiteral("确认"), this);
|
||||
okBtn_->setDefault(true);
|
||||
nextBtn_ = new QPushButton(QStringLiteral("下一步"), this);
|
||||
auto* cancelBtn = new QPushButton(QStringLiteral("取消"), this);
|
||||
btnLay->addWidget(prevBtn_);
|
||||
btnLay->addWidget(nextBtn_);
|
||||
btnLay->addWidget(okBtn_);
|
||||
btnLay->addWidget(nextBtn_);
|
||||
btnLay->addWidget(cancelBtn);
|
||||
root->addLayout(btnLay);
|
||||
prevBtn_->setVisible(false);
|
||||
|
|
@ -114,18 +105,108 @@ GridWizardDialog::GridWizardDialog(geopro::data::IDatasetCommandRepository* repo
|
|||
connect(nextBtn_, &QPushButton::clicked, this, &GridWizardDialog::goToStep2);
|
||||
connect(prevBtn_, &QPushButton::clicked, this, [this]() {
|
||||
stack_->setCurrentIndex(0);
|
||||
setFixedWidth(kStep1W);
|
||||
prevBtn_->setVisible(false); okBtn_->setVisible(false); nextBtn_->setVisible(true);
|
||||
});
|
||||
connect(okBtn_, &QPushButton::clicked, this, &GridWizardDialog::onConfirm);
|
||||
// 点数变化 → 重算间距(原版 calculateXInterval/calculateYInterval)。
|
||||
connect(xSize_, QOverload<int>::of(&QSpinBox::valueChanged), this,
|
||||
[this](int) { recalcXSpacing(); });
|
||||
connect(ySize_, QOverload<int>::of(&QSpinBox::valueChanged), this,
|
||||
[this](int) { recalcYSpacing(); });
|
||||
|
||||
loadAlgorithms();
|
||||
}
|
||||
|
||||
void GridWizardDialog::buildStep1() {
|
||||
auto* page1 = new QWidget(this);
|
||||
auto* p1Lay = new QVBoxLayout(page1);
|
||||
p1Lay->setContentsMargins(0, 0, 0, 0);
|
||||
p1Lay->setSpacing(geopro::app::space::kMd);
|
||||
p1Lay->addWidget(new QLabel(QStringLiteral("请选择网格方法:"), page1));
|
||||
algoList_ = new QListWidget(page1);
|
||||
p1Lay->addWidget(algoList_, 1);
|
||||
stack_->addWidget(page1);
|
||||
}
|
||||
|
||||
void GridWizardDialog::buildStep2() {
|
||||
auto* page2 = new QWidget(this);
|
||||
auto* p2Lay = new QVBoxLayout(page2);
|
||||
p2Lay->setContentsMargins(0, 0, 0, 0);
|
||||
p2Lay->setSpacing(geopro::app::space::kLg);
|
||||
|
||||
xMin_ = makeCoordSpin(page2); xMax_ = makeCoordSpin(page2);
|
||||
yMin_ = makeCoordSpin(page2); yMax_ = makeCoordSpin(page2);
|
||||
vMin_ = makeCoordSpin(page2); vMax_ = makeCoordSpin(page2);
|
||||
xSize_ = new QSpinBox(page2); xSize_->setRange(kSizeMin, kSizeMax);
|
||||
xSize_->setValue(kDefaultXSize); xSize_->setFixedWidth(100);
|
||||
ySize_ = new QSpinBox(page2); ySize_->setRange(kSizeMin, kSizeMax);
|
||||
ySize_->setValue(kDefaultXSize); ySize_->setFixedWidth(100);
|
||||
xSpacing_ = makeCoordSpin(page2); xSpacing_->setRange(0.0, kCoordRange);
|
||||
ySpacing_ = makeCoordSpin(page2); ySpacing_->setRange(0.0, kCoordRange);
|
||||
|
||||
// 分组 1:网格参数(栅格:Xmax→Xmin→X间距→X点数 同行;Y 同理)。
|
||||
addSectionTitle(p2Lay, QStringLiteral("网格参数"), page2);
|
||||
auto* grid = new QGridLayout();
|
||||
grid->setHorizontalSpacing(geopro::app::space::kMd);
|
||||
grid->setVerticalSpacing(geopro::app::space::kMd);
|
||||
addParamCell(grid, 0, 0, QStringLiteral("Xmax"), xMax_, page2);
|
||||
addParamCell(grid, 0, 1, QStringLiteral("Xmin"), xMin_, page2);
|
||||
addParamCell(grid, 0, 2, QStringLiteral("X间距"), xSpacing_, page2);
|
||||
addParamCell(grid, 0, 3, QStringLiteral("X点数"), xSize_, page2);
|
||||
addParamCell(grid, 1, 0, QStringLiteral("Ymax"), yMax_, page2);
|
||||
addParamCell(grid, 1, 1, QStringLiteral("Ymin"), yMin_, page2);
|
||||
addParamCell(grid, 1, 2, QStringLiteral("Y间距"), ySpacing_, page2);
|
||||
addParamCell(grid, 1, 3, QStringLiteral("Y点数"), ySize_, page2);
|
||||
grid->setColumnStretch(4, 1);
|
||||
p2Lay->addLayout(grid);
|
||||
|
||||
// 分组 2:数据值设置(数据值max/min + 恢复默认值 + 数据值保存为)。
|
||||
addSectionTitle(p2Lay, QStringLiteral("数据值设置"), page2);
|
||||
saveFormat_ = new QComboBox(page2);
|
||||
saveFormat_->addItem(QStringLiteral("线性"), QStringLiteral("linear"));
|
||||
saveFormat_->addItem(QStringLiteral("对数"), QStringLiteral("log"));
|
||||
saveFormat_->setFixedWidth(120);
|
||||
auto* restoreBtn = new QPushButton(QStringLiteral("恢复默认值"), page2);
|
||||
|
||||
auto* dv = new QGridLayout();
|
||||
dv->setHorizontalSpacing(geopro::app::space::kLg);
|
||||
dv->setVerticalSpacing(geopro::app::space::kMd);
|
||||
auto* vmaxLbl = new QLabel(QStringLiteral("数据值max"), page2);
|
||||
vmaxLbl->setMinimumWidth(kParamLabelW + 20);
|
||||
vmaxLbl->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
||||
dv->addWidget(vmaxLbl, 0, 0);
|
||||
dv->addWidget(vMax_, 0, 1);
|
||||
dv->addWidget(restoreBtn, 0, 3);
|
||||
auto* vminLbl = new QLabel(QStringLiteral("数据值min"), page2);
|
||||
vminLbl->setMinimumWidth(kParamLabelW + 20);
|
||||
vminLbl->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
||||
dv->addWidget(vminLbl, 1, 0);
|
||||
dv->addWidget(vMin_, 1, 1);
|
||||
auto* fmtLbl = new QLabel(QStringLiteral("数据值保存为"), page2); // 原版 saveFormat
|
||||
fmtLbl->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
||||
dv->addWidget(fmtLbl, 1, 2);
|
||||
dv->addWidget(saveFormat_, 1, 3);
|
||||
dv->setColumnStretch(4, 1);
|
||||
p2Lay->addLayout(dv);
|
||||
p2Lay->addStretch();
|
||||
stack_->addWidget(page2);
|
||||
|
||||
// 联动:Xmax/Xmin/X点数变 → 反算 X间距(round);X间距变 → 反算 X点数(round)。
|
||||
connect(xMax_, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this,
|
||||
[this](double) { calcXInterval(); });
|
||||
connect(xMin_, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this,
|
||||
[this](double) { calcXInterval(); });
|
||||
connect(xSize_, QOverload<int>::of(&QSpinBox::valueChanged), this,
|
||||
[this](int) { calcXInterval(); });
|
||||
connect(xSpacing_, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this,
|
||||
[this](double) { calcXPoints(); });
|
||||
connect(yMax_, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this,
|
||||
[this](double) { calcYInterval(); });
|
||||
connect(yMin_, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this,
|
||||
[this](double) { calcYInterval(); });
|
||||
connect(ySize_, QOverload<int>::of(&QSpinBox::valueChanged), this,
|
||||
[this](int) { calcYInterval(); });
|
||||
connect(ySpacing_, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this,
|
||||
[this](double) { calcYPoints(); });
|
||||
connect(restoreBtn, &QPushButton::clicked, this, &GridWizardDialog::loadParams);
|
||||
}
|
||||
|
||||
void GridWizardDialog::loadAlgorithms() {
|
||||
if (!repo_) return;
|
||||
QPointer<GridWizardDialog> self(this);
|
||||
|
|
@ -149,6 +230,7 @@ void GridWizardDialog::goToStep2() {
|
|||
return;
|
||||
}
|
||||
stack_->setCurrentIndex(1);
|
||||
setFixedWidth(kStep2W);
|
||||
nextBtn_->setVisible(false);
|
||||
prevBtn_->setVisible(true);
|
||||
okBtn_->setVisible(true);
|
||||
|
|
@ -166,28 +248,63 @@ void GridWizardDialog::loadParams() {
|
|||
self->yMax_->setValue(d.value(QStringLiteral("ymax")).toDouble());
|
||||
self->vMin_->setValue(d.value(QStringLiteral("vmin")).toDouble());
|
||||
self->vMax_->setValue(d.value(QStringLiteral("vmax")).toDouble());
|
||||
// 初始间距 = (xmax-xmin)/xSize,y 间距同 x(原版 onMounted 逻辑)。
|
||||
self->recalcXSpacing();
|
||||
// 原版 onMounted:X点数固定 100 → 算 X间距 → Y间距=X间距 → Y点数=ceil。
|
||||
self->xSize_->setValue(kDefaultXSize);
|
||||
self->calcXInterval();
|
||||
const double dx = self->xSpacing_->value();
|
||||
if (dx > 0) self->ySpacing_->setValue(dx);
|
||||
if (dx > 0) self->ySpacing_->setValue(dx); // 触发 calcYPoints
|
||||
});
|
||||
}
|
||||
|
||||
void GridWizardDialog::recalcXSpacing() {
|
||||
void GridWizardDialog::calcXInterval() {
|
||||
const int n = xSize_->value();
|
||||
if (n > 0) xSpacing_->setValue((xMax_->value() - xMin_->value()) / n);
|
||||
const double range = xMax_->value() - xMin_->value();
|
||||
if (n > 0 && range > 0) {
|
||||
QSignalBlocker b(xSpacing_); // 防与 calcXPoints 互触发
|
||||
xSpacing_->setValue(range / n);
|
||||
}
|
||||
}
|
||||
|
||||
void GridWizardDialog::recalcYSpacing() {
|
||||
void GridWizardDialog::calcXPoints() {
|
||||
const double iv = xSpacing_->value();
|
||||
const double range = xMax_->value() - xMin_->value();
|
||||
if (iv > 0 && range > 0) {
|
||||
QSignalBlocker b(xSize_);
|
||||
xSize_->setValue(static_cast<int>(std::lround(range / iv))); // 原版 round
|
||||
}
|
||||
}
|
||||
|
||||
void GridWizardDialog::calcYInterval() {
|
||||
const int n = ySize_->value();
|
||||
if (n > 0) ySpacing_->setValue((yMax_->value() - yMin_->value()) / n);
|
||||
const double range = yMax_->value() - yMin_->value();
|
||||
if (n > 0 && range > 0) {
|
||||
QSignalBlocker b(ySpacing_);
|
||||
ySpacing_->setValue(range / n);
|
||||
}
|
||||
}
|
||||
|
||||
void GridWizardDialog::calcYPoints() {
|
||||
const double iv = ySpacing_->value();
|
||||
const double range = yMax_->value() - yMin_->value();
|
||||
if (iv > 0 && range > 0) {
|
||||
QSignalBlocker b(ySize_);
|
||||
ySize_->setValue(static_cast<int>(std::ceil(range / iv))); // 原版 ceil(与 X 的 round 不同)
|
||||
}
|
||||
}
|
||||
|
||||
void GridWizardDialog::onConfirm() {
|
||||
if (!repo_ || !algoList_->currentItem()) { reject(); return; }
|
||||
if (xMax_->value() < xMin_->value() || yMax_->value() < yMin_->value() ||
|
||||
vMax_->value() < vMin_->value()) {
|
||||
QMessageBox::warning(this, windowTitle(), QStringLiteral("最大值不能小于最小值"));
|
||||
// 原版按 Xmax/Ymax/数据值分别提示。
|
||||
if (xMax_->value() < xMin_->value()) {
|
||||
QMessageBox::warning(this, windowTitle(), QStringLiteral("Xmax不能小于Xmin"));
|
||||
return;
|
||||
}
|
||||
if (yMax_->value() < yMin_->value()) {
|
||||
QMessageBox::warning(this, windowTitle(), QStringLiteral("Ymax不能小于Ymin"));
|
||||
return;
|
||||
}
|
||||
if (vMax_->value() < vMin_->value()) {
|
||||
QMessageBox::warning(this, windowTitle(), QStringLiteral("数据值max不能小于数据值min"));
|
||||
return;
|
||||
}
|
||||
GridToParams p;
|
||||
|
|
|
|||
|
|
@ -27,11 +27,15 @@ public:
|
|||
QWidget* parent = nullptr);
|
||||
|
||||
private:
|
||||
void buildStep1(); // 步骤 1:算法选择列表
|
||||
void buildStep2(); // 步骤 2:网格参数 + 数据值设置(两分组卡片)
|
||||
void loadAlgorithms(); // 步骤 1:拉算法列表
|
||||
void loadParams(); // 步骤 2:拉 x/y/v 默认参数
|
||||
void loadParams(); // 步骤 2:拉 x/y/v 默认参数(兼「恢复默认值」)
|
||||
void goToStep2(); // 下一步(校验算法已选)
|
||||
void recalcXSpacing(); // (xMax-xMin)/xSize → xSpacing(间距已有值时)
|
||||
void recalcYSpacing(); // (yMax-yMin)/ySize → ySpacing
|
||||
void calcXInterval(); // Xmax/Xmin/X点数变 → X间距=(xMax-xMin)/xSize
|
||||
void calcXPoints(); // X间距变 → X点数=round((xMax-xMin)/xSpacing)
|
||||
void calcYInterval(); // Ymax/Ymin/Y点数变 → Y间距=(yMax-yMin)/ySize
|
||||
void calcYPoints(); // Y间距变 → Y点数=ceil((yMax-yMin)/ySpacing)
|
||||
void onConfirm(); // 确认 → toGrid
|
||||
|
||||
geopro::data::IDatasetCommandRepository* repo_ = nullptr;
|
||||
|
|
|
|||
|
|
@ -87,8 +87,9 @@ RawDataChartView::RawDataChartView(QWidget* parent) : QWidget(parent) {
|
|||
tbLay->addWidget(btnColorScale);
|
||||
tbLay->addWidget(lblCurrentChart);
|
||||
tbLay->addWidget(chartTypeCombo_);
|
||||
tbLay->addWidget(btnSaveAs);
|
||||
// 原版 .right-buttons margin-left:auto:另存为 右对齐。
|
||||
tbLay->addStretch();
|
||||
tbLay->addWidget(btnSaveAs);
|
||||
|
||||
// 反演原数据默认工具条交互(O1 网格 / O2 色阶配置 / O3 另存为)。
|
||||
connect(btnGrid, &QToolButton::clicked, this, [this, btnGrid]() { openGridWizard(btnGrid); });
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
#include <utility>
|
||||
|
||||
#include <QButtonGroup>
|
||||
#include <QFormLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
|
|
@ -13,49 +12,68 @@
|
|||
#include <QRadioButton>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "FormKit.hpp"
|
||||
#include "Theme.hpp"
|
||||
#include "panels/chart/ScatterDataOps.hpp" // buildSaveRawDataBody(纯组装,便于单测)
|
||||
#include "repo/IDatasetCommandRepository.hpp"
|
||||
|
||||
namespace geopro::app {
|
||||
|
||||
namespace {
|
||||
constexpr int kInversionW = 400; // 原版 inversion 另存为弹窗宽 400px
|
||||
constexpr int kLabelW = 60; // 原版 .label width:60px
|
||||
} // namespace
|
||||
|
||||
SaveAsDialog::SaveAsDialog(Mode mode, geopro::data::IDatasetCommandRepository* repo, QString dsId,
|
||||
QWidget* parent)
|
||||
: QDialog(parent), mode_(mode), repo_(repo), dsId_(std::move(dsId)) {
|
||||
setWindowTitle(QStringLiteral("数据另存为"));
|
||||
setModal(true);
|
||||
|
||||
auto* root = formkit::dialogRoot(this);
|
||||
auto* root = new QVBoxLayout(this);
|
||||
root->setContentsMargins(geopro::app::space::kLg, geopro::app::space::kLg,
|
||||
geopro::app::space::kLg, geopro::app::space::kLg);
|
||||
root->setSpacing(geopro::app::space::kMd);
|
||||
|
||||
auto* card = formkit::formCard(this);
|
||||
auto* cardLay = formkit::cardBody(card);
|
||||
if (mode_ == Mode::Inversion) {
|
||||
// ── inversion:原版「另存为新的网格数据」400px,仅名称行 ──
|
||||
setWindowTitle(QStringLiteral("另存为新的网格数据"));
|
||||
setFixedWidth(kInversionW);
|
||||
|
||||
auto* nameRow = new QHBoxLayout();
|
||||
nameRow->setSpacing(geopro::app::space::kMd);
|
||||
nameLabel_ = new QLabel(QStringLiteral("名称:"), this); // 原版 label「名称:」
|
||||
nameLabel_->setMinimumWidth(kLabelW);
|
||||
nameEdit_ = new QLineEdit(this);
|
||||
nameEdit_->setPlaceholderText(QStringLiteral("请输入名称"));
|
||||
nameEdit_->setText(QStringLiteral("网格数据1")); // 原版默认值
|
||||
nameRow->addWidget(nameLabel_);
|
||||
nameRow->addWidget(nameEdit_, 1);
|
||||
root->addLayout(nameRow);
|
||||
} else {
|
||||
// ── RawData(measurement):新增/覆盖 + 名称(保持既有逻辑,不在本批返工范围)──
|
||||
setWindowTitle(QStringLiteral("数据另存为"));
|
||||
|
||||
if (mode_ == Mode::RawData) {
|
||||
// 新增/覆盖单选(复刻原版 a-radio-group:1=新增 0=覆盖)。
|
||||
auto* opLay = new QHBoxLayout();
|
||||
auto* rbNew = new QRadioButton(QStringLiteral("新增"), this);
|
||||
auto* rbOverwrite = new QRadioButton(QStringLiteral("覆盖"), this);
|
||||
opGroup_ = new QButtonGroup(this);
|
||||
opGroup_->addButton(rbNew, 1);
|
||||
opGroup_->addButton(rbOverwrite, 0);
|
||||
rbNew->setChecked(true); // 默认新增(与原版 dataStored 初值一致)
|
||||
rbNew->setChecked(true); // 默认新增
|
||||
opLay->addWidget(rbNew);
|
||||
opLay->addWidget(rbOverwrite);
|
||||
opLay->addStretch();
|
||||
cardLay->addLayout(opLay);
|
||||
}
|
||||
root->addLayout(opLay);
|
||||
|
||||
// 名称行:RawData 仅新增可见;Inversion 始终可见。
|
||||
auto* nameForm = formkit::makeEditForm();
|
||||
nameLabel_ = formkit::editLabel(QStringLiteral("数据名称"), this);
|
||||
nameEdit_ = new QLineEdit(this);
|
||||
formkit::capField(nameEdit_);
|
||||
nameForm->addRow(nameLabel_, nameEdit_);
|
||||
cardLay->addLayout(nameForm);
|
||||
root->addWidget(card);
|
||||
auto* nameRow = new QHBoxLayout();
|
||||
nameRow->setSpacing(geopro::app::space::kMd);
|
||||
nameLabel_ = new QLabel(QStringLiteral("数据名称"), this);
|
||||
nameLabel_->setMinimumWidth(kLabelW);
|
||||
nameEdit_ = new QLineEdit(this);
|
||||
nameRow->addWidget(nameLabel_);
|
||||
nameRow->addWidget(nameEdit_, 1);
|
||||
root->addLayout(nameRow);
|
||||
|
||||
if (mode_ == Mode::RawData && opGroup_) {
|
||||
// 切到覆盖隐藏名称框,切回新增显示(复刻原版 v-show=dataStored===1)。
|
||||
// 切到覆盖隐藏名称框,切回新增显示。
|
||||
connect(opGroup_, QOverload<int>::of(&QButtonGroup::idClicked), this, [this](int id) {
|
||||
const bool isNew = (id == 1);
|
||||
nameLabel_->setVisible(isNew);
|
||||
|
|
@ -63,13 +81,15 @@ SaveAsDialog::SaveAsDialog(Mode mode, geopro::data::IDatasetCommandRepository* r
|
|||
});
|
||||
}
|
||||
|
||||
// 底部按钮:原版右对齐,确认(主,左)/取消(右)。
|
||||
auto* btnLay = new QHBoxLayout();
|
||||
btnLay->setSpacing(geopro::app::space::kMd);
|
||||
btnLay->addStretch();
|
||||
auto* cancelBtn = new QPushButton(QStringLiteral("取消"), this);
|
||||
okBtn_ = new QPushButton(QStringLiteral("确定"), this);
|
||||
okBtn_ = new QPushButton(QStringLiteral("确认"), this);
|
||||
okBtn_->setDefault(true);
|
||||
btnLay->addWidget(cancelBtn);
|
||||
auto* cancelBtn = new QPushButton(QStringLiteral("取消"), this);
|
||||
btnLay->addWidget(okBtn_);
|
||||
btnLay->addWidget(cancelBtn);
|
||||
root->addLayout(btnLay);
|
||||
|
||||
connect(cancelBtn, &QPushButton::clicked, this, &QDialog::reject);
|
||||
|
|
@ -84,7 +104,7 @@ void SaveAsDialog::onConfirm() {
|
|||
const bool needName = (mode_ == Mode::Inversion) || (operationType == 1);
|
||||
const QString name = nameEdit_->text().trimmed();
|
||||
if (needName && name.isEmpty()) {
|
||||
QMessageBox::warning(this, windowTitle(), QStringLiteral("请输入数据名称"));
|
||||
QMessageBox::warning(this, windowTitle(), QStringLiteral("请输入名称"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,10 +4,9 @@
|
|||
|
||||
#include <QButtonGroup>
|
||||
#include <QComboBox>
|
||||
#include <QDoubleSpinBox>
|
||||
#include <QFormLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QMessageBox>
|
||||
#include <QPointer>
|
||||
#include <QPushButton>
|
||||
|
|
@ -15,14 +14,34 @@
|
|||
#include <QStackedWidget>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "FormKit.hpp"
|
||||
#include "Theme.hpp"
|
||||
#include "panels/chart/InversionProcessOps.hpp" // buildWhitenBody
|
||||
#include "repo/IDatasetCommandRepository.hpp"
|
||||
|
||||
namespace geopro::app {
|
||||
|
||||
namespace {
|
||||
constexpr double kExtRange = 1e6; // 边界扩展范围
|
||||
constexpr int kDialogW = 550; // 原版弹窗宽 550px
|
||||
constexpr int kLabelMinW = 120; // 原版 .field-label min-width:120px 右对齐
|
||||
constexpr double kCtrlRatio = 0.6; // 原版控件宽 60%
|
||||
|
||||
// 原版 .field-label:定宽右对齐标签。
|
||||
QLabel* fieldLabel(const QString& text, QWidget* parent) {
|
||||
auto* lbl = new QLabel(text, parent);
|
||||
lbl->setMinimumWidth(kLabelMinW);
|
||||
lbl->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
||||
return lbl;
|
||||
}
|
||||
|
||||
// 原版 .option-item:flex 行(标签右对齐 + 控件占 60%)。控件外裹一层以 60/40 拉伸。
|
||||
QHBoxLayout* optionRow(const QString& label, QWidget* ctrl, QWidget* parent) {
|
||||
auto* row = new QHBoxLayout();
|
||||
row->setSpacing(geopro::app::space::kLg);
|
||||
row->addWidget(fieldLabel(label, parent));
|
||||
row->addWidget(ctrl, 6); // 控件 60%
|
||||
row->addStretch(4); // 余 40% 留白
|
||||
return row;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
WhiteningDialog::WhiteningDialog(geopro::data::IDatasetCommandRepository* repo, QString dsId,
|
||||
|
|
@ -32,37 +51,37 @@ WhiteningDialog::WhiteningDialog(geopro::data::IDatasetCommandRepository* repo,
|
|||
dsId_(std::move(dsId)),
|
||||
projectId_(std::move(projectId)),
|
||||
tmObjectId_(std::move(tmObjectId)) {
|
||||
setWindowTitle(QStringLiteral("白化"));
|
||||
setWindowTitle(QStringLiteral("白化配置")); // 原版 whiteningSetting
|
||||
setModal(true);
|
||||
resize(460, 280);
|
||||
setFixedWidth(kDialogW);
|
||||
|
||||
auto* root = formkit::dialogRoot(this);
|
||||
auto* root = new QVBoxLayout(this);
|
||||
root->setContentsMargins(geopro::app::space::kLg, geopro::app::space::kLg,
|
||||
geopro::app::space::kLg, geopro::app::space::kLg);
|
||||
root->setSpacing(geopro::app::space::kMd);
|
||||
|
||||
// 白化方式下拉(数值对照原版 whiteningMethod 1/2/3)。
|
||||
auto* methodLay = formkit::makeEditForm();
|
||||
// 白化方式下拉(原版 3 项,数值对照 whiteningMethod 1/2/3)。
|
||||
methodCombo_ = new QComboBox(this);
|
||||
methodCombo_->addItem(QStringLiteral("数据边界自动白化"), 1);
|
||||
methodCombo_->addItem(QStringLiteral("白化模板"), 2);
|
||||
methodCombo_->addItem(QStringLiteral("白化文件"), 2);
|
||||
methodCombo_->addItem(QStringLiteral("模型白化"), 3);
|
||||
formkit::capField(methodCombo_);
|
||||
methodLay->addRow(formkit::editLabel(QStringLiteral("白化方式")), methodCombo_);
|
||||
root->addLayout(methodLay);
|
||||
root->addLayout(optionRow(QStringLiteral("白化方式"), methodCombo_, this));
|
||||
|
||||
stack_ = new QStackedWidget(this);
|
||||
root->addWidget(stack_, 1);
|
||||
root->addWidget(stack_);
|
||||
|
||||
// ── 方式 1:数据边界自动白化 ────────────────────────────────────────
|
||||
// ── 方式 1:数据边界自动白化(边界扩展文本框 + 内/外白化单选)────────────
|
||||
auto* page1 = new QWidget(this);
|
||||
auto* p1 = formkit::makeEditForm();
|
||||
page1->setLayout(p1);
|
||||
extension_ = new QDoubleSpinBox(page1);
|
||||
extension_->setRange(-kExtRange, kExtRange);
|
||||
extension_->setDecimals(3);
|
||||
formkit::capField(extension_);
|
||||
p1->addRow(formkit::editLabel(QStringLiteral("白化边界扩展")), extension_);
|
||||
auto* typeRow = new QHBoxLayout();
|
||||
auto* rbOuter = new QRadioButton(QStringLiteral("外部白化"), page1);
|
||||
auto* rbInner = new QRadioButton(QStringLiteral("内部白化"), page1);
|
||||
auto* p1 = new QVBoxLayout(page1);
|
||||
p1->setContentsMargins(0, 0, 0, 0);
|
||||
p1->setSpacing(geopro::app::space::kMd);
|
||||
extension_ = new QLineEdit(QStringLiteral("0"), page1); // 原版 AInput,默认 "0"
|
||||
p1->addLayout(optionRow(QStringLiteral("白化边界扩展"), extension_, page1));
|
||||
auto* typeWrap = new QWidget(page1);
|
||||
auto* typeRow = new QHBoxLayout(typeWrap);
|
||||
typeRow->setContentsMargins(0, 0, 0, 0);
|
||||
auto* rbOuter = new QRadioButton(QStringLiteral("外部白化"), typeWrap);
|
||||
auto* rbInner = new QRadioButton(QStringLiteral("内部白化"), typeWrap);
|
||||
rbOuter->setChecked(true);
|
||||
whiteningType_ = new QButtonGroup(this);
|
||||
whiteningType_->addButton(rbOuter, 0);
|
||||
|
|
@ -70,25 +89,26 @@ WhiteningDialog::WhiteningDialog(geopro::data::IDatasetCommandRepository* repo,
|
|||
typeRow->addWidget(rbOuter);
|
||||
typeRow->addWidget(rbInner);
|
||||
typeRow->addStretch();
|
||||
p1->addRow(formkit::editLabel(QStringLiteral("白化")), typeRow);
|
||||
p1->addLayout(optionRow(QStringLiteral("白化"), typeWrap, page1));
|
||||
stack_->addWidget(page1);
|
||||
|
||||
// ── 方式 2:白化模板(选文件)──────────────────────────────────────
|
||||
// ── 方式 2:白化文件(选文件)──────────────────────────────────────
|
||||
auto* page2 = new QWidget(this);
|
||||
auto* p2 = formkit::makeEditForm();
|
||||
page2->setLayout(p2);
|
||||
auto* p2 = new QVBoxLayout(page2);
|
||||
p2->setContentsMargins(0, 0, 0, 0);
|
||||
fileCombo_ = new QComboBox(page2);
|
||||
formkit::capField(fileCombo_);
|
||||
p2->addRow(formkit::editLabel(QStringLiteral("选择白化文件")), fileCombo_);
|
||||
p2->addLayout(optionRow(QStringLiteral("选择白化文件"), fileCombo_, page2));
|
||||
stack_->addWidget(page2);
|
||||
|
||||
// ── 方式 3:模型白化(梯形/矩形)───────────────────────────────────
|
||||
auto* page3 = new QWidget(this);
|
||||
auto* p3 = formkit::makeEditForm();
|
||||
page3->setLayout(p3);
|
||||
auto* subRow = new QHBoxLayout();
|
||||
auto* rbTrap = new QRadioButton(QStringLiteral("梯形白化"), page3);
|
||||
auto* rbRect = new QRadioButton(QStringLiteral("矩形白化"), page3);
|
||||
auto* p3 = new QVBoxLayout(page3);
|
||||
p3->setContentsMargins(0, 0, 0, 0);
|
||||
auto* subWrap = new QWidget(page3);
|
||||
auto* subRow = new QHBoxLayout(subWrap);
|
||||
subRow->setContentsMargins(0, 0, 0, 0);
|
||||
auto* rbTrap = new QRadioButton(QStringLiteral("梯形白化"), subWrap);
|
||||
auto* rbRect = new QRadioButton(QStringLiteral("矩形白化"), subWrap);
|
||||
rbTrap->setChecked(true);
|
||||
modelSubType_ = new QButtonGroup(this);
|
||||
modelSubType_->addButton(rbTrap, 2); // 2 梯形
|
||||
|
|
@ -96,17 +116,20 @@ WhiteningDialog::WhiteningDialog(geopro::data::IDatasetCommandRepository* repo,
|
|||
subRow->addWidget(rbTrap);
|
||||
subRow->addWidget(rbRect);
|
||||
subRow->addStretch();
|
||||
p3->addRow(formkit::editLabel(QStringLiteral("白化")), subRow);
|
||||
p3->addLayout(optionRow(QStringLiteral("白化"), subWrap, page3));
|
||||
stack_->addWidget(page3);
|
||||
|
||||
// 底部按钮。
|
||||
Q_UNUSED(kCtrlRatio);
|
||||
|
||||
// 底部按钮:原版 justify-content:space-between,确认(主,左)/取消(右) 各 45%。
|
||||
auto* btnLay = new QHBoxLayout();
|
||||
btnLay->addStretch();
|
||||
auto* cancelBtn = new QPushButton(QStringLiteral("取消"), this);
|
||||
okBtn_ = new QPushButton(QStringLiteral("确定"), this);
|
||||
btnLay->setSpacing(geopro::app::space::kMd);
|
||||
okBtn_ = new QPushButton(QStringLiteral("确认"), this);
|
||||
okBtn_->setDefault(true);
|
||||
btnLay->addWidget(cancelBtn);
|
||||
btnLay->addWidget(okBtn_);
|
||||
auto* cancelBtn = new QPushButton(QStringLiteral("取消"), this);
|
||||
btnLay->addWidget(okBtn_, 45);
|
||||
btnLay->addStretch(10);
|
||||
btnLay->addWidget(cancelBtn, 45);
|
||||
root->addLayout(btnLay);
|
||||
|
||||
connect(cancelBtn, &QPushButton::clicked, this, &QDialog::reject);
|
||||
|
|
@ -144,11 +167,11 @@ void WhiteningDialog::onConfirm() {
|
|||
p.dsObjectId = dsId_;
|
||||
p.whiteningMethod = methodCombo_->currentData().toInt();
|
||||
if (p.whiteningMethod == 1) {
|
||||
p.boundaryExtension = extension_->value();
|
||||
p.boundaryExtension = extension_->text().toDouble(); // 原版 Number(extension)||0
|
||||
p.whiteningType = whiteningType_->checkedId();
|
||||
} else if (p.whiteningMethod == 2) {
|
||||
if (fileCombo_->currentIndex() < 0) {
|
||||
QMessageBox::warning(this, windowTitle(), QStringLiteral("请选择白化文件"));
|
||||
QMessageBox::warning(this, windowTitle(), QStringLiteral("请选择一个白化文件"));
|
||||
return;
|
||||
}
|
||||
p.whitenedDataId = fileCombo_->currentData().toString();
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#include <QString>
|
||||
|
||||
class QComboBox;
|
||||
class QDoubleSpinBox;
|
||||
class QLineEdit;
|
||||
class QButtonGroup;
|
||||
class QStackedWidget;
|
||||
class QPushButton;
|
||||
|
|
@ -38,7 +38,7 @@ private:
|
|||
QComboBox* methodCombo_ = nullptr;
|
||||
QStackedWidget* stack_ = nullptr;
|
||||
// 方式 1:
|
||||
QDoubleSpinBox* extension_ = nullptr;
|
||||
QLineEdit* extension_ = nullptr; // 原版 AInput 文本框(默认 "0")
|
||||
QButtonGroup* whiteningType_ = nullptr; // 0 外部 / 1 内部
|
||||
// 方式 2:
|
||||
QComboBox* fileCombo_ = nullptr;
|
||||
|
|
|
|||
Loading…
Reference in New Issue