feat: 优化结果颜色设置对话框

- 使用颜色映射和越界值颜色分组重构对话框布局
- 统一范围输入、单位选择、重置按钮及底部按钮的尺寸与对齐
- 新增属性单位下拉框,复用全局单位表完成显示单位与基础单位双向换算
- 保持单位选择为对话框临时状态,避免纯单位切换改写手工范围
- 在单位换算失败时恢复原状态并阻止不完整的界面刷新
- 未启用越界专用颜色时显示当前色带端点色
- 独立保存用户自定义颜色,保持 Apply、OK 和 Cancel 的事务语义
- 更换属性范围重置图标并更新中文翻译资源
feature/nmNum-postprocessing-view-20260910
lh 2 weeks ago
parent 6ddbb17235
commit b565039240

Binary file not shown.

@ -2870,11 +2870,12 @@ Reason: %1</source>
<message><source>Below min</source><translation>低于最小值</translation></message>
<message><source>Above max</source><translation>高于最大值</translation></message>
<message><source>Color map</source><translation>色带</translation></message>
<message><source>Color mapping</source><translation>颜色映射</translation></message>
<message><source>Out-of-range colors</source><translation>越界值颜色</translation></message>
<message><source>Minimum</source><translation>最小值</translation></message>
<message><source>Maximum</source><translation>最大值</translation></message>
<message><source>Unit</source><translation>单位</translation></message>
<message><source>Dimensionless</source><translation>无量纲</translation></message>
<message><source>Minimum and maximum must be finite numbers.</source><translation>最小值和最大值必须是有限数。</translation></message>
<message><source>Unable to convert the range to the selected unit.</source><translation>无法将范围换算为所选单位。</translation></message>
<message><source>Minimum must be less than maximum.</source><translation>最小值必须小于最大值。</translation></message>
<message><source>Unable to read the committed color settings.</source><translation>无法读取已提交的颜色设置。</translation></message>
</context>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

@ -14,6 +14,7 @@ class QLabel;
class QLineEdit;
class QPushButton;
class QToolButton;
class iUnitGroup;
class nmPebiResultSceneController;
/**
@ -54,6 +55,10 @@ private slots:
void onRestorePropertyRangeClicked();
/** @brief 用户编辑任一上下限后显式进入手工范围模式。 */
void onManualRangeEdited(const QString& sText);
/** @brief 色带改变后刷新未启用越界颜色的端点预览。 */
void onColorMapChanged(int nIndex);
/** @brief 切换输入单位并保持两个输入值表示的物理量不变。 */
void onDisplayUnitChanged(int nIndex);
/** @brief 根据复选框同步低于范围颜色按钮状态。 */
void onBelowRangeToggled(bool bChecked);
/** @brief 根据复选框同步高于范围颜色按钮状态。 */
@ -72,8 +77,10 @@ private:
void createUi();
/** @brief 从 Scene 读取初值并记录不可变的预期身份。 */
bool initializeFromScene();
/** @brief 将设置和值域写入控件,不触发手工范围编辑状态。 */
void populateEditor(const nmPebiResultDisplaySettings& oSettings,
/** @brief 从属性目录和全局单位表初始化当前对话框的单位选择。 */
void initializeUnitEditor();
/** @brief 换算成功后将设置和值域写入控件,不触发手工编辑状态。 */
bool populateEditor(const nmPebiResultDisplaySettings& oSettings,
const double dVisibleRange[2]);
/** @brief 解析编辑值并构造待提交纯值设置。 */
bool collectEditedSettings(
@ -85,6 +92,18 @@ private:
QString formatValue(double dValue) const;
/** @brief 使用 C locale 严格解析有限 double。 */
bool parseFiniteValue(const QString& sText, double& dValue) const;
/** @brief 使用全局单位表换算单个有限值。 */
bool convertUnitValue(double dSourceValue,
const QString& sSourceUnit,
const QString& sDestinationUnit,
double& dDestinationValue) const;
/** @brief 将基础单位范围换算到当前对话框显示单位。 */
bool convertBaseRangeToDisplay(const double dBaseRange[2],
double dDisplayRange[2]) const;
/** @brief 根据当前单位刷新两个范围输入框的提示文字。 */
void refreshRangeToolTips();
/** @brief 根据色带、范围模式和启用状态刷新两个颜色按钮。 */
void refreshRangeColorButtons();
/** @brief 更新颜色按钮色块。 */
void updateColorButton(QPushButton* pButton,
const QColor& oColor);
@ -95,16 +114,21 @@ private:
quint64 m_nExpectedBindingRevision; ///< 打开时捕获的 Scene 成功绑定序号。
QString m_sExpectedSnapshotId; ///< 打开时捕获的快照稳定 ID。
QString m_sExpectedPropertyId; ///< 打开时捕获的属性稳定 ID。
QString m_sDisplayUnit; ///< 当前属性默认显示单位,仅用于标签。
QString m_sBaseUnit; ///< Catalog 中的数据层基础单位。
QString m_sDisplayUnit; ///< 当前对话框实例选择的输入显示单位。
iUnitGroup* m_pUnitGroup; ///< 全局单位框架拥有,未找到时为空。
double m_dPropertyRange[2]; ///< 快照完整业务范围,回退按钮使用。
nmPebiResultDisplaySettings m_oBaselineSettings; ///< 最近成功 Apply 的基线。
QColor m_oEditedBelowRangeColor; ///< 尚未提交的低于范围颜色。
QColor m_oEditedAboveRangeColor; ///< 尚未提交的高于范围颜色。
bool m_bManualRangeEdited; ///< 仅用户编辑或已有手工范围时为 true。
bool m_bRangeValuesEditedByUser; ///< 本次基线后用户是否亲自编辑过数值。
bool m_bInitialized; ///< Scene 初值是否完整读取成功。
QComboBox* m_pColorMapCombo; ///< 带渐变预览和稳定 ID 的色带框。
QLineEdit* m_pMinimumEdit; ///< 支持科学计数法的最小值文字框。
QLineEdit* m_pMaximumEdit; ///< 支持科学计数法的最大值文字框。
QLabel* m_pUnitLabel; ///< 当前属性默认显示单位;无量纲时显示“无量纲”。
QComboBox* m_pUnitCombo; ///< 两个范围输入框共用的临时显示单位。
QToolButton* m_pRestoreRangeButton; ///< 恢复完整业务范围按钮。
QCheckBox* m_pLogarithmicCheck; ///< Log10 映射开关。
QLabel* m_pLogReasonLabel; ///< Log 不可用时的明确原因。

@ -1,6 +1,8 @@
#include "nmWxPebiResultColorScaleSettingsDlg.h"
#include "nmPebiResultPropertyDisplayText.h"
#include "iUnitGroup.h"
#include "iUnitHelper.h"
#include "nmPebiResultPropertyCatalog.h"
#include "nmPebiResultSceneController.h"
#include "nmVTKColorMapCatalog.h"
@ -9,14 +11,17 @@
#include <QComboBox>
#include <QCoreApplication>
#include <QDialogButtonBox>
#include <QFormLayout>
#include <QGridLayout>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QIcon>
#include <QLabel>
#include <QLayout>
#include <QLineEdit>
#include <QLocale>
#include <QPushButton>
#include <QSize>
#include <QSizePolicy>
#include <QToolButton>
#include <QVariant>
#include <QVBoxLayout>
@ -80,12 +85,14 @@ nmWxPebiResultColorScaleSettingsDlg(
: QDialog(pParent),
m_pSceneController(pSceneController),
m_nExpectedBindingRevision(0),
m_pUnitGroup(nullptr),
m_bManualRangeEdited(false),
m_bRangeValuesEditedByUser(false),
m_bInitialized(false),
m_pColorMapCombo(nullptr),
m_pMinimumEdit(nullptr),
m_pMaximumEdit(nullptr),
m_pUnitLabel(nullptr),
m_pUnitCombo(nullptr),
m_pRestoreRangeButton(nullptr),
m_pLogarithmicCheck(nullptr),
m_pLogReasonLabel(nullptr),
@ -104,7 +111,7 @@ nmWxPebiResultColorScaleSettingsDlg(
m_bInitialized = initializeFromScene();
m_pApplyButton->setEnabled(m_bInitialized);
m_pOkButton->setEnabled(m_bInitialized);
if(!m_bInitialized) {
if(!m_bInitialized && m_pErrorLabel->text().isEmpty()) {
setErrorText(tr("The result color settings are unavailable."));
}
}
@ -128,10 +135,17 @@ void nmWxPebiResultColorScaleSettingsDlg::onOkClicked()
void nmWxPebiResultColorScaleSettingsDlg::onRestorePropertyRangeClicked()
{
double dDisplayRange[2] = { 0.0, 0.0 };
if(!convertBaseRangeToDisplay(m_dPropertyRange, dDisplayRange)) {
setErrorText(tr("Unable to convert the range to the selected unit."));
return;
}
m_bManualRangeEdited = false;
m_pMinimumEdit->setText(formatValue(m_dPropertyRange[0]));
m_pMaximumEdit->setText(formatValue(m_dPropertyRange[1]));
m_bRangeValuesEditedByUser = false;
m_pMinimumEdit->setText(formatValue(dDisplayRange[0]));
m_pMaximumEdit->setText(formatValue(dDisplayRange[1]));
refreshLogAvailability();
refreshRangeColorButtons();
setErrorText(QString());
}
@ -140,50 +154,114 @@ void nmWxPebiResultColorScaleSettingsDlg::onManualRangeEdited(
{
Q_UNUSED(sText);
m_bManualRangeEdited = true;
m_bRangeValuesEditedByUser = true;
refreshLogAvailability();
refreshRangeColorButtons();
}
void nmWxPebiResultColorScaleSettingsDlg::onColorMapChanged(int nIndex)
{
Q_UNUSED(nIndex);
refreshRangeColorButtons();
}
void nmWxPebiResultColorScaleSettingsDlg::onDisplayUnitChanged(int nIndex)
{
if(nIndex < 0) {
return;
}
const QString sNewUnit = m_pUnitCombo->itemText(nIndex);
if(sNewUnit == m_sDisplayUnit) {
return;
}
double dOldDisplayRange[2] = { 0.0, 0.0 };
double dBaseRange[2] = { 0.0, 0.0 };
double dNewDisplayRange[2] = { 0.0, 0.0 };
QString sError;
if(!parseFiniteValue(m_pMinimumEdit->text(), dOldDisplayRange[0]) ||
!parseFiniteValue(m_pMaximumEdit->text(), dOldDisplayRange[1])) {
sError = tr("Minimum and maximum must be finite numbers.");
} else if(!convertUnitValue(
dOldDisplayRange[0], m_sDisplayUnit,
m_sBaseUnit, dBaseRange[0]) ||
!convertUnitValue(
dOldDisplayRange[1], m_sDisplayUnit,
m_sBaseUnit, dBaseRange[1]) ||
!convertUnitValue(
dBaseRange[0], m_sBaseUnit,
sNewUnit, dNewDisplayRange[0]) ||
!convertUnitValue(
dBaseRange[1], m_sBaseUnit,
sNewUnit, dNewDisplayRange[1])) {
sError = tr("Unable to convert the range to the selected unit.");
}
if(!sError.isEmpty()) {
const bool bSignalsBlocked = m_pUnitCombo->blockSignals(true);
m_pUnitCombo->setCurrentIndex(
m_pUnitCombo->findText(m_sDisplayUnit));
m_pUnitCombo->blockSignals(bSignalsBlocked);
setErrorText(sError);
return;
}
m_sDisplayUnit = sNewUnit;
m_pMinimumEdit->setText(formatValue(dNewDisplayRange[0]));
m_pMaximumEdit->setText(formatValue(dNewDisplayRange[1]));
refreshRangeToolTips();
refreshLogAvailability();
setErrorText(QString());
}
void nmWxPebiResultColorScaleSettingsDlg::onBelowRangeToggled(bool bChecked)
{
m_pBelowColorButton->setEnabled(bChecked);
Q_UNUSED(bChecked);
refreshRangeColorButtons();
}
void nmWxPebiResultColorScaleSettingsDlg::onAboveRangeToggled(bool bChecked)
{
m_pAboveColorButton->setEnabled(bChecked);
Q_UNUSED(bChecked);
refreshRangeColorButtons();
}
void nmWxPebiResultColorScaleSettingsDlg::onChooseBelowRangeColor()
{
QColor oColor = QColorDialog::getColor(
m_oBaselineSettings.m_oBelowRangeColor, this,
m_oEditedBelowRangeColor, this,
tr("Below minimum color"));
if(oColor.isValid()) {
oColor.setAlpha(255);
m_oBaselineSettings.m_oBelowRangeColor = oColor;
updateColorButton(m_pBelowColorButton, oColor);
m_oEditedBelowRangeColor = oColor;
refreshRangeColorButtons();
}
}
void nmWxPebiResultColorScaleSettingsDlg::onChooseAboveRangeColor()
{
QColor oColor = QColorDialog::getColor(
m_oBaselineSettings.m_oAboveRangeColor, this,
m_oEditedAboveRangeColor, this,
tr("Above maximum color"));
if(oColor.isValid()) {
oColor.setAlpha(255);
m_oBaselineSettings.m_oAboveRangeColor = oColor;
updateColorButton(m_pAboveColorButton, oColor);
m_oEditedAboveRangeColor = oColor;
refreshRangeColorButtons();
}
}
void nmWxPebiResultColorScaleSettingsDlg::refreshLogAvailability()
{
double dMinimum = 0.0;
double dDisplayMinimum = 0.0;
double dBaseMinimum = 0.0;
const bool bMinimumValid =
parseFiniteValue(m_pMinimumEdit->text(), dMinimum);
parseFiniteValue(m_pMinimumEdit->text(), dDisplayMinimum);
const bool bMinimumConverted = bMinimumValid &&
convertUnitValue(dDisplayMinimum, m_sDisplayUnit,
m_sBaseUnit, dBaseMinimum);
const bool bPropertyPositive = m_dPropertyRange[0] > 0.0;
const bool bDisplayPositive = bMinimumValid && dMinimum > 0.0;
const bool bDisplayPositive =
bMinimumConverted && dBaseMinimum > 0.0;
const bool bAvailable = bPropertyPositive && bDisplayPositive;
if(!bAvailable && m_pLogarithmicCheck->isChecked()) {
// 禁用前先清除不可提交的 Log 状态,避免用户被锁在失败循环中。
@ -193,25 +271,27 @@ void nmWxPebiResultColorScaleSettingsDlg::refreshLogAvailability()
m_pLogarithmicCheck->blockSignals(bSignalsBlocked);
}
m_pLogarithmicCheck->setEnabled(bAvailable);
QString sReason;
if(!bPropertyPositive) {
m_pLogReasonLabel->setText(
tr("Logarithmic scale requires a positive property range."));
sReason = tr(
"Logarithmic scale requires a positive property range.");
} else if(!bDisplayPositive) {
m_pLogReasonLabel->setText(
tr("Logarithmic scale requires a positive minimum."));
} else {
m_pLogReasonLabel->clear();
sReason = tr(
"Logarithmic scale requires a positive minimum.");
}
m_pLogReasonLabel->setText(sReason);
m_pLogReasonLabel->setVisible(!sReason.isEmpty());
}
void nmWxPebiResultColorScaleSettingsDlg::createUi()
{
setWindowTitle(tr("Color settings for current property"));
setModal(true);
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
m_pColorMapCombo = new QComboBox(this);
m_pColorMapCombo->setIconSize(QSize(128, 16));
m_pColorMapCombo->setMinimumWidth(260);
m_pColorMapCombo->setMinimumWidth(280);
const QStringList listColorMapIds =
nmVTKColorMapCatalog::getColorMapIds();
for(int nIndex = 0; nIndex < listColorMapIds.size(); ++nIndex) {
@ -224,61 +304,92 @@ void nmWxPebiResultColorScaleSettingsDlg::createUi()
m_pMinimumEdit = new QLineEdit(this);
m_pMaximumEdit = new QLineEdit(this);
m_pUnitLabel = new QLabel(this);
m_pMinimumEdit->setMinimumWidth(220);
m_pMinimumEdit->setMaximumWidth(250);
m_pMaximumEdit->setMinimumWidth(220);
m_pMaximumEdit->setMaximumWidth(250);
m_pUnitCombo = new QComboBox(this);
m_pUnitCombo->setMinimumWidth(80);
m_pUnitCombo->setMaximumWidth(140);
m_pUnitCombo->hide();
m_pMinimumEdit->setAlignment(Qt::AlignRight);
m_pMaximumEdit->setAlignment(Qt::AlignRight);
m_pRestoreRangeButton = new QToolButton(this);
m_pRestoreRangeButton->setAutoRaise(true);
m_pRestoreRangeButton->setFixedSize(24, 24);
m_pRestoreRangeButton->setIconSize(QSize(16, 16));
m_pRestoreRangeButton->setFixedSize(36, 36);
m_pRestoreRangeButton->setIconSize(QSize(32, 32));
m_pRestoreRangeButton->setIcon(QIcon(resultColorIconPath(
QString::fromLatin1("Undo.png"))));
QString::fromLatin1("NmRestorePropertyRange.png"))));
m_pRestoreRangeButton->setToolTip(tr("Restore property range"));
QHBoxLayout* pMinimumLayout = new QHBoxLayout();
pMinimumLayout->setContentsMargins(0, 0, 0, 0);
pMinimumLayout->addWidget(m_pMinimumEdit, 1);
pMinimumLayout->addWidget(m_pRestoreRangeButton);
QWidget* pMinimumWidget = new QWidget(this);
pMinimumWidget->setLayout(pMinimumLayout);
m_pLogarithmicCheck = new QCheckBox(tr("Logarithmic scale"), this);
m_pLogReasonLabel = new QLabel(this);
m_pLogReasonLabel->setWordWrap(true);
m_pLogReasonLabel->setStyleSheet(
QString::fromLatin1("color: #666666;"));
m_pLogReasonLabel->hide();
m_pBelowRangeCheck = new QCheckBox(tr("Below min"), this);
m_pBelowColorButton = new QPushButton(this);
m_pBelowColorButton->setFixedSize(44, 22);
QHBoxLayout* pBelowLayout = new QHBoxLayout();
pBelowLayout->setContentsMargins(0, 0, 0, 0);
pBelowLayout->addWidget(m_pBelowRangeCheck);
pBelowLayout->addWidget(m_pBelowColorButton);
pBelowLayout->addStretch();
QWidget* pBelowWidget = new QWidget(this);
pBelowWidget->setLayout(pBelowLayout);
m_pBelowColorButton->setEnabled(false);
m_pBelowColorButton->setToolTip(tr("Below minimum color"));
m_pAboveRangeCheck = new QCheckBox(tr("Above max"), this);
m_pAboveColorButton = new QPushButton(this);
m_pAboveColorButton->setFixedSize(44, 22);
QHBoxLayout* pAboveLayout = new QHBoxLayout();
pAboveLayout->setContentsMargins(0, 0, 0, 0);
pAboveLayout->addWidget(m_pAboveRangeCheck);
pAboveLayout->addWidget(m_pAboveColorButton);
pAboveLayout->addStretch();
QWidget* pAboveWidget = new QWidget(this);
pAboveWidget->setLayout(pAboveLayout);
QFormLayout* pFormLayout = new QFormLayout();
pFormLayout->addRow(tr("Color map"), m_pColorMapCombo);
pFormLayout->addRow(tr("Minimum"), pMinimumWidget);
pFormLayout->addRow(tr("Maximum"), m_pMaximumEdit);
pFormLayout->addRow(tr("Unit"), m_pUnitLabel);
pFormLayout->addRow(QString(), m_pLogarithmicCheck);
pFormLayout->addRow(QString(), m_pLogReasonLabel);
pFormLayout->addRow(QString(), pBelowWidget);
pFormLayout->addRow(QString(), pAboveWidget);
m_pAboveColorButton->setEnabled(false);
m_pAboveColorButton->setToolTip(tr("Above maximum color"));
QGroupBox* pMappingGroup = new QGroupBox(tr("Color mapping"), this);
QGridLayout* pMappingLayout = new QGridLayout(pMappingGroup);
pMappingLayout->setContentsMargins(10, 16, 10, 10);
pMappingLayout->setHorizontalSpacing(8);
pMappingLayout->setVerticalSpacing(6);
QLabel* pColorMapLabel = new QLabel(tr("Color map"), pMappingGroup);
QLabel* pMinimumLabel = new QLabel(tr("Minimum"), pMappingGroup);
QLabel* pMaximumLabel = new QLabel(tr("Maximum"), pMappingGroup);
pColorMapLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
pMinimumLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
pMaximumLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
const int nFieldLabelWidth = qMax(
pColorMapLabel->sizeHint().width(),
qMax(pMinimumLabel->sizeHint().width(),
pMaximumLabel->sizeHint().width()));
pMappingLayout->setColumnMinimumWidth(0, nFieldLabelWidth);
pMappingLayout->setColumnMinimumWidth(1, 220);
pMappingLayout->addWidget(pColorMapLabel, 0, 0);
pMappingLayout->addWidget(m_pColorMapCombo, 0, 1, 1, 4);
pMappingLayout->addWidget(pMinimumLabel, 1, 0);
pMappingLayout->addWidget(m_pMinimumEdit, 1, 1);
pMappingLayout->addWidget(m_pUnitCombo, 1, 2, 2, 1,
Qt::AlignVCenter);
pMappingLayout->addWidget(m_pRestoreRangeButton, 1, 4, 2, 1,
Qt::AlignCenter);
pMappingLayout->addWidget(pMaximumLabel, 2, 0);
pMappingLayout->addWidget(m_pMaximumEdit, 2, 1);
pMappingLayout->addWidget(m_pLogarithmicCheck, 3, 1, 1, 4);
pMappingLayout->addWidget(m_pLogReasonLabel, 4, 1, 1, 4);
pMappingLayout->setColumnStretch(0, 0);
pMappingLayout->setColumnStretch(1, 0);
pMappingLayout->setColumnStretch(2, 0);
pMappingLayout->setColumnStretch(3, 1);
pMappingLayout->setColumnStretch(4, 0);
QGroupBox* pRangeColorGroup = new QGroupBox(
tr("Out-of-range colors"), this);
QGridLayout* pRangeColorLayout = new QGridLayout(pRangeColorGroup);
pRangeColorLayout->setContentsMargins(10, 16, 10, 10);
pRangeColorLayout->setHorizontalSpacing(12);
pRangeColorLayout->setVerticalSpacing(6);
pRangeColorLayout->addWidget(m_pBelowRangeCheck, 0, 1);
pRangeColorLayout->addWidget(m_pBelowColorButton, 0, 2, Qt::AlignLeft);
pRangeColorLayout->addWidget(m_pAboveRangeCheck, 1, 1);
pRangeColorLayout->addWidget(m_pAboveColorButton, 1, 2, Qt::AlignLeft);
pRangeColorLayout->setColumnStretch(0, 1);
pRangeColorLayout->setColumnStretch(1, 0);
pRangeColorLayout->setColumnStretch(2, 0);
pRangeColorLayout->setColumnStretch(3, 1);
m_pErrorLabel = new QLabel(this);
m_pErrorLabel->setWordWrap(true);
@ -291,18 +402,41 @@ void nmWxPebiResultColorScaleSettingsDlg::createUi()
Qt::Horizontal, this);
m_pApplyButton = pButtonBox->button(QDialogButtonBox::Apply);
m_pOkButton = pButtonBox->button(QDialogButtonBox::Ok);
QPushButton* pCancelButton =
pButtonBox->button(QDialogButtonBox::Cancel);
const QSize oFooterIconSize(16, 16);
m_pOkButton->setIcon(QIcon(resultColorIconPath(
QString::fromLatin1("OK.png"))));
pCancelButton->setIcon(QIcon(resultColorIconPath(
QString::fromLatin1("Cancel.png"))));
m_pOkButton->setMinimumWidth(72);
pCancelButton->setMinimumWidth(72);
m_pApplyButton->setMinimumWidth(72);
m_pOkButton->setIconSize(oFooterIconSize);
pCancelButton->setIconSize(oFooterIconSize);
if(pButtonBox->layout() != nullptr) {
pButtonBox->layout()->setSpacing(6);
}
connect(m_pApplyButton, SIGNAL(clicked()),
this, SLOT(onApplyClicked()));
connect(m_pOkButton, SIGNAL(clicked()),
this, SLOT(onOkClicked()));
connect(pButtonBox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()),
this, SLOT(reject()));
connect(pCancelButton, SIGNAL(clicked()), this, SLOT(reject()));
QVBoxLayout* pMainLayout = new QVBoxLayout(this);
pMainLayout->addLayout(pFormLayout);
pMainLayout->addWidget(m_pErrorLabel);
pMainLayout->addWidget(pButtonBox);
setMinimumWidth(420);
pMainLayout->setContentsMargins(12, 10, 12, 0);
pMainLayout->setSpacing(8);
pMainLayout->addWidget(pMappingGroup);
pMainLayout->addWidget(pRangeColorGroup);
QHBoxLayout* pFooterLayout = new QHBoxLayout();
pFooterLayout->setContentsMargins(4, 2, 4, 5);
pFooterLayout->setSpacing(8);
m_pErrorLabel->setSizePolicy(
QSizePolicy::Expanding, QSizePolicy::Preferred);
pFooterLayout->addWidget(m_pErrorLabel, 1);
pFooterLayout->addWidget(pButtonBox);
pMainLayout->addLayout(pFooterLayout);
setMinimumWidth(470);
connect(m_pRestoreRangeButton, SIGNAL(clicked()),
this, SLOT(onRestorePropertyRangeClicked()));
@ -310,6 +444,10 @@ void nmWxPebiResultColorScaleSettingsDlg::createUi()
this, SLOT(onManualRangeEdited(QString)));
connect(m_pMaximumEdit, SIGNAL(textEdited(QString)),
this, SLOT(onManualRangeEdited(QString)));
connect(m_pColorMapCombo, SIGNAL(currentIndexChanged(int)),
this, SLOT(onColorMapChanged(int)));
connect(m_pUnitCombo, SIGNAL(currentIndexChanged(int)),
this, SLOT(onDisplayUnitChanged(int)));
connect(m_pBelowRangeCheck, SIGNAL(toggled(bool)),
this, SLOT(onBelowRangeToggled(bool)));
connect(m_pAboveRangeCheck, SIGNAL(toggled(bool)),
@ -329,48 +467,102 @@ bool nmWxPebiResultColorScaleSettingsDlg::initializeFromScene()
m_pSceneController->getSnapshotBindingRevision();
m_sExpectedSnapshotId = m_pSceneController->getCurrentSnapshotId();
m_sExpectedPropertyId = m_pSceneController->getCurrentPropertyId();
m_sDisplayUnit = nmPebiResultPropertyDisplayText::getDefaultDisplayUnit(
m_sExpectedPropertyId);
m_pUnitLabel->setText(m_sDisplayUnit.isEmpty()
? tr("Dimensionless") : m_sDisplayUnit);
nmPebiResultPropertyDescriptor oDescriptor;
double dVisibleRange[2] = { 0.0, 0.0 };
if(m_nExpectedBindingRevision == 0 ||
m_sExpectedSnapshotId.isEmpty() || m_sExpectedPropertyId.isEmpty() ||
!nmPebiResultPropertyCatalog::findDescriptor(
m_sExpectedPropertyId, oDescriptor) ||
!m_pSceneController->getCurrentPropertyRange(m_dPropertyRange) ||
!m_pSceneController->getCurrentDisplayRange(dVisibleRange) ||
!m_pSceneController->getCurrentDisplaySettings(
m_oBaselineSettings)) {
return false;
}
populateEditor(m_oBaselineSettings, dVisibleRange);
return true;
m_sBaseUnit = oDescriptor.m_sBaseUnit;
m_sDisplayUnit = oDescriptor.m_sDefaultDisplayUnit.isEmpty()
? m_sBaseUnit : oDescriptor.m_sDefaultDisplayUnit;
initializeUnitEditor();
return populateEditor(m_oBaselineSettings, dVisibleRange);
}
void nmWxPebiResultColorScaleSettingsDlg::populateEditor(
void nmWxPebiResultColorScaleSettingsDlg::initializeUnitEditor()
{
const bool bSignalsBlocked = m_pUnitCombo->blockSignals(true);
m_pUnitCombo->clear();
m_pUnitGroup = nullptr;
if(m_sBaseUnit.isEmpty()) {
m_sDisplayUnit.clear();
m_pUnitCombo->setEnabled(false);
m_pUnitCombo->hide();
m_pUnitCombo->blockSignals(bSignalsBlocked);
return;
}
m_pUnitGroup = iUnitHelper::getUnitGroupByUnit(m_sBaseUnit);
QStringList listUnits;
if(m_pUnitGroup != nullptr &&
m_pUnitGroup->indexOf(m_sBaseUnit) >= 0) {
listUnits = m_pUnitGroup->getAllUnitNames();
}
const bool bHasUnitGroup = !listUnits.isEmpty() &&
listUnits.contains(m_sBaseUnit);
if(!bHasUnitGroup) {
m_pUnitGroup = nullptr;
listUnits.clear();
listUnits.append(m_sBaseUnit);
m_sDisplayUnit = m_sBaseUnit;
} else if(!listUnits.contains(m_sDisplayUnit)) {
m_sDisplayUnit = m_sBaseUnit;
}
m_pUnitCombo->addItems(listUnits);
m_pUnitCombo->setCurrentIndex(
m_pUnitCombo->findText(m_sDisplayUnit));
m_pUnitCombo->setEnabled(bHasUnitGroup);
m_pUnitCombo->show();
m_pUnitCombo->blockSignals(bSignalsBlocked);
}
bool nmWxPebiResultColorScaleSettingsDlg::populateEditor(
const nmPebiResultDisplaySettings& oSettings,
const double dVisibleRange[2])
{
double dDisplayRange[2] = { 0.0, 0.0 };
if(!convertBaseRangeToDisplay(dVisibleRange, dDisplayRange)) {
setErrorText(tr("Unable to convert the range to the selected unit."));
return false;
}
m_oEditedBelowRangeColor = oSettings.m_oBelowRangeColor;
m_oEditedAboveRangeColor = oSettings.m_oAboveRangeColor;
m_oEditedBelowRangeColor.setAlpha(255);
m_oEditedAboveRangeColor.setAlpha(255);
m_bManualRangeEdited = oSettings.m_bHasManualRange;
const bool bColorMapSignalsBlocked =
m_pColorMapCombo->blockSignals(true);
const bool bBelowSignalsBlocked =
m_pBelowRangeCheck->blockSignals(true);
const bool bAboveSignalsBlocked =
m_pAboveRangeCheck->blockSignals(true);
const int nColorIndex = m_pColorMapCombo->findData(
oSettings.m_sColorMapId);
m_pColorMapCombo->setCurrentIndex(nColorIndex);
m_pMinimumEdit->setText(formatValue(dVisibleRange[0]));
m_pMaximumEdit->setText(formatValue(dVisibleRange[1]));
m_bManualRangeEdited = oSettings.m_bHasManualRange;
m_pMinimumEdit->setText(formatValue(dDisplayRange[0]));
m_pMaximumEdit->setText(formatValue(dDisplayRange[1]));
m_pLogarithmicCheck->setChecked(
oSettings.m_eScaleMode == NM_PebiColorScale_Logarithmic);
m_pBelowRangeCheck->setChecked(oSettings.m_bUseBelowRangeColor);
m_pAboveRangeCheck->setChecked(oSettings.m_bUseAboveRangeColor);
updateColorButton(m_pBelowColorButton, oSettings.m_oBelowRangeColor);
updateColorButton(m_pAboveColorButton, oSettings.m_oAboveRangeColor);
onBelowRangeToggled(oSettings.m_bUseBelowRangeColor);
onAboveRangeToggled(oSettings.m_bUseAboveRangeColor);
m_pColorMapCombo->blockSignals(bColorMapSignalsBlocked);
m_pBelowRangeCheck->blockSignals(bBelowSignalsBlocked);
m_pAboveRangeCheck->blockSignals(bAboveSignalsBlocked);
m_bRangeValuesEditedByUser = false;
refreshRangeColorButtons();
refreshLogAvailability();
const QString sUnitSuffix = m_sDisplayUnit.isEmpty()
? QString() : QString::fromLatin1(" (") +
m_sDisplayUnit + QString::fromLatin1(")");
m_pMinimumEdit->setToolTip(tr("Minimum") + sUnitSuffix);
m_pMaximumEdit->setToolTip(tr("Maximum") + sUnitSuffix);
refreshRangeToolTips();
return true;
}
bool nmWxPebiResultColorScaleSettingsDlg::collectEditedSettings(
@ -378,24 +570,40 @@ bool nmWxPebiResultColorScaleSettingsDlg::collectEditedSettings(
QString& sError) const
{
sError.clear();
double dMinimum = 0.0;
double dMaximum = 0.0;
if(!parseFiniteValue(m_pMinimumEdit->text(), dMinimum) ||
!parseFiniteValue(m_pMaximumEdit->text(), dMaximum)) {
double dDisplayMinimum = 0.0;
double dDisplayMaximum = 0.0;
if(!parseFiniteValue(m_pMinimumEdit->text(), dDisplayMinimum) ||
!parseFiniteValue(m_pMaximumEdit->text(), dDisplayMaximum)) {
sError = tr("Minimum and maximum must be finite numbers.");
return false;
}
// 提交值与界面最多 12 位有效数字保持一致,重复 Apply 不产生隐藏精度差异。
double dCanonicalMinimum = 0.0;
double dCanonicalMaximum = 0.0;
if(!parseFiniteValue(formatValue(dMinimum), dCanonicalMinimum) ||
!parseFiniteValue(formatValue(dMaximum), dCanonicalMaximum)) {
if(!parseFiniteValue(
formatValue(dDisplayMinimum), dDisplayMinimum) ||
!parseFiniteValue(
formatValue(dDisplayMaximum), dDisplayMaximum)) {
sError = tr("Minimum and maximum must be finite numbers.");
return false;
}
dMinimum = dCanonicalMinimum;
dMaximum = dCanonicalMaximum;
if(m_bManualRangeEdited && dMinimum >= dMaximum) {
double dBaseMinimum = 0.0;
double dBaseMaximum = 0.0;
const bool bReuseBaselineRange = m_bManualRangeEdited &&
!m_bRangeValuesEditedByUser &&
m_oBaselineSettings.m_bHasManualRange;
if(bReuseBaselineRange) {
dBaseMinimum = m_oBaselineSettings.m_dManualMinimum;
dBaseMaximum = m_oBaselineSettings.m_dManualMaximum;
} else if(!convertUnitValue(
dDisplayMinimum, m_sDisplayUnit,
m_sBaseUnit, dBaseMinimum) ||
!convertUnitValue(
dDisplayMaximum, m_sDisplayUnit,
m_sBaseUnit, dBaseMaximum)) {
sError = tr("Unable to convert the range to the selected unit.");
return false;
}
if(m_bManualRangeEdited && dBaseMinimum >= dBaseMaximum) {
sError = tr("Minimum must be less than maximum.");
return false;
}
@ -407,10 +615,14 @@ bool nmWxPebiResultColorScaleSettingsDlg::collectEditedSettings(
oSettings.m_eScaleMode = m_pLogarithmicCheck->isChecked()
? NM_PebiColorScale_Logarithmic : NM_PebiColorScale_Linear;
oSettings.m_bHasManualRange = m_bManualRangeEdited;
oSettings.m_dManualMinimum = m_bManualRangeEdited ? dMinimum : 0.0;
oSettings.m_dManualMaximum = m_bManualRangeEdited ? dMaximum : 0.0;
oSettings.m_dManualMinimum =
m_bManualRangeEdited ? dBaseMinimum : 0.0;
oSettings.m_dManualMaximum =
m_bManualRangeEdited ? dBaseMaximum : 0.0;
oSettings.m_bUseBelowRangeColor = m_pBelowRangeCheck->isChecked();
oSettings.m_bUseAboveRangeColor = m_pAboveRangeCheck->isChecked();
oSettings.m_oBelowRangeColor = m_oEditedBelowRangeColor;
oSettings.m_oAboveRangeColor = m_oEditedAboveRangeColor;
oSettings.m_oBelowRangeColor.setAlpha(255);
oSettings.m_oAboveRangeColor.setAlpha(255);
return true;
@ -444,7 +656,11 @@ bool nmWxPebiResultColorScaleSettingsDlg::applyEditor()
}
m_oBaselineSettings = oCommittedSettings;
populateEditor(oCommittedSettings, dVisibleRange);
if(!populateEditor(oCommittedSettings, dVisibleRange)) {
sError = tr("Unable to convert the range to the selected unit.");
emit operationFailed(sError);
return false;
}
setErrorText(QString());
emit displaySettingsApplied();
return true;
@ -469,6 +685,98 @@ bool nmWxPebiResultColorScaleSettingsDlg::parseFiniteValue(
return true;
}
bool nmWxPebiResultColorScaleSettingsDlg::convertUnitValue(
double dSourceValue,
const QString& sSourceUnit,
const QString& sDestinationUnit,
double& dDestinationValue) const
{
if(!isFiniteEditorValue(dSourceValue)) {
return false;
}
if(sSourceUnit == sDestinationUnit) {
dDestinationValue = dSourceValue;
return true;
}
if(sSourceUnit.isEmpty() || sDestinationUnit.isEmpty() ||
m_pUnitGroup == nullptr ||
m_pUnitGroup->indexOf(sSourceUnit) < 0 ||
m_pUnitGroup->indexOf(sDestinationUnit) < 0) {
return false;
}
int nDigit = 12;
double dCandidate = 0.0;
if(!m_pUnitGroup->convert(
sSourceUnit, dSourceValue,
sDestinationUnit, dCandidate, nDigit) ||
!isFiniteEditorValue(dCandidate)) {
return false;
}
dDestinationValue = dCandidate;
return true;
}
bool nmWxPebiResultColorScaleSettingsDlg::convertBaseRangeToDisplay(
const double dBaseRange[2],
double dDisplayRange[2]) const
{
double dMinimum = 0.0;
double dMaximum = 0.0;
if(!convertUnitValue(
dBaseRange[0], m_sBaseUnit,
m_sDisplayUnit, dMinimum) ||
!convertUnitValue(
dBaseRange[1], m_sBaseUnit,
m_sDisplayUnit, dMaximum)) {
return false;
}
dDisplayRange[0] = dMinimum;
dDisplayRange[1] = dMaximum;
return true;
}
void nmWxPebiResultColorScaleSettingsDlg::refreshRangeToolTips()
{
const QString sUnitSuffix = m_sDisplayUnit.isEmpty()
? QString() : QString::fromLatin1(" (") +
m_sDisplayUnit + QString::fromLatin1(")");
m_pMinimumEdit->setToolTip(tr("Minimum") + sUnitSuffix);
m_pMaximumEdit->setToolTip(tr("Maximum") + sUnitSuffix);
}
void nmWxPebiResultColorScaleSettingsDlg::refreshRangeColorButtons()
{
const QString sColorMapId = m_pColorMapCombo->itemData(
m_pColorMapCombo->currentIndex()).toString();
QColor oMinimumColor;
QColor oMaximumColor;
const bool bHasMinimumColor = nmVTKColorMapCatalog::getColor(
sColorMapId, 0.0, oMinimumColor);
const bool bAutomaticConstant = !m_bManualRangeEdited &&
m_dPropertyRange[0] == m_dPropertyRange[1];
const bool bHasMaximumColor = bAutomaticConstant
? bHasMinimumColor
: nmVTKColorMapCatalog::getColor(
sColorMapId, 1.0, oMaximumColor);
if(bAutomaticConstant && bHasMinimumColor) {
oMaximumColor = oMinimumColor;
}
const bool bUseBelowColor = m_pBelowRangeCheck->isChecked();
const bool bUseAboveColor = m_pAboveRangeCheck->isChecked();
m_pBelowColorButton->setEnabled(bUseBelowColor);
m_pAboveColorButton->setEnabled(bUseAboveColor);
updateColorButton(
m_pBelowColorButton,
!bUseBelowColor && bHasMinimumColor
? oMinimumColor : m_oEditedBelowRangeColor);
updateColorButton(
m_pAboveColorButton,
!bUseAboveColor && bHasMaximumColor
? oMaximumColor : m_oEditedAboveRangeColor);
}
void nmWxPebiResultColorScaleSettingsDlg::updateColorButton(
QPushButton* pButton,
const QColor& oColor)
@ -477,7 +785,10 @@ void nmWxPebiResultColorScaleSettingsDlg::updateColorButton(
return;
}
pButton->setStyleSheet(QString::fromLatin1(
"QPushButton { background-color: rgb(%1,%2,%3); border: 1px solid #666; }")
"QPushButton { background-color: rgb(%1,%2,%3); "
"border: 1px solid #666; } "
"QPushButton:disabled { background-color: rgb(%1,%2,%3); "
"border: 1px solid #888; }")
.arg(oColor.red()).arg(oColor.green()).arg(oColor.blue()));
}

Loading…
Cancel
Save