You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nmWTAI-Platform/Src/nmNum/nmSubWxs/nmWxPebiGridViewWidget.cpp

387 lines
14 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "nmWxPebiGridViewWidget.h"
#include "nmPebiGridSceneController.h"
#include "nmPebiGridViewData.h"
#include "nmVTKViewCommandController.h"
#include "nmWxVTKRenderContainerWidget.h"
#include <QAction>
#include <QComboBox>
#include <QCoreApplication>
#include <QHBoxLayout>
#include <QIcon>
#include <QLabel>
#include <QMenu>
#include <QSize>
#include <QToolBar>
#include <QVBoxLayout>
#include <QVariant>
namespace {
QString gridViewIconPath(const QString& sFileName)
{
const QString sApplicationDir = QCoreApplication::applicationDirPath();
return sApplicationDir.section('/', 0, -2) +
"/Res/Icon/" + sFileName;
}
}
nmWxPebiGridViewWidget::nmWxPebiGridViewWidget(QWidget* pParent)
: QWidget(pParent),
m_pRenderContainer(nullptr),
m_pSceneController(nullptr),
m_pToolBar(nullptr),
m_pGridLinesAction(nullptr),
m_pScalarBarAction(nullptr),
m_pBoundsGridAction(nullptr),
m_pPropertyComboBox(nullptr),
m_pGridInfoLabel(nullptr),
m_pStatusLabel(nullptr),
m_bHasViewData(false)
{
createUi();
// 控制器必须在容器之后创建,以便使用当前实例独占的 Scene 和相机。
m_pSceneController =
new nmPebiGridSceneController(m_pRenderContainer);
resetControls();
setControlsEnabled(false);
m_pRenderContainer->showEmptyState(tr("No grid data."));
}
nmWxPebiGridViewWidget::~nmWxPebiGridViewWidget()
{
// 控制器先解除 Mapper 输入Scene 和 Layer 随后由容器析构统一清理。
delete m_pSceneController;
m_pSceneController = nullptr;
}
void nmWxPebiGridViewWidget::createUi()
{
QVBoxLayout* pMainLayout = new QVBoxLayout(this);
pMainLayout->setContentsMargins(0, 0, 0, 0);
pMainLayout->setSpacing(0);
// 绘图区单独使用水平布局,渲染容器伸展,竖向工具栏固定在右侧。
QWidget* pRenderArea = new QWidget(this);
QHBoxLayout* pRenderLayout = new QHBoxLayout(pRenderArea);
pRenderLayout->setContentsMargins(0, 0, 0, 0);
pRenderLayout->setSpacing(0);
m_pRenderContainer = new nmWxVTKRenderContainerWidget(pRenderArea);
m_pRenderContainer->setSizePolicy(
QSizePolicy::Expanding, QSizePolicy::Expanding);
m_pRenderContainer->setViewCommandCapabilities(
nmVTKViewCommandController::ViewCommand_ZoomIn |
nmVTKViewCommandController::ViewCommand_ZoomOut |
nmVTKViewCommandController::ViewCommand_Fit |
nmVTKViewCommandController::ViewCommand_Top |
nmVTKViewCommandController::ViewCommand_SaveImage |
nmVTKViewCommandController::ViewCommand_CopyImage |
nmVTKViewCommandController::ViewCommand_Print |
nmVTKViewCommandController::ViewCommand_PrintPreview);
m_pToolBar = new QToolBar(pRenderArea);
m_pToolBar->setOrientation(Qt::Vertical);
m_pToolBar->setMovable(false);
m_pToolBar->setFloatable(false);
m_pToolBar->setIconSize(QSize(24, 24));
m_pToolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
m_pToolBar->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
nmVTKViewCommandController* pCommandController =
m_pRenderContainer->getViewCommandController();
// 三个业务 QAction 与公共命令一样长期持有,并同时用于工具栏和右键菜单。
m_pGridLinesAction = new QAction(
QIcon(gridViewIconPath("Grids.png")),
tr("Show Grid Lines"), this);
m_pGridLinesAction->setToolTip(tr("Show Grid Lines"));
m_pGridLinesAction->setCheckable(true);
m_pScalarBarAction = new QAction(
QIcon(gridViewIconPath("NmColorScale.png")),
tr("Show Scalar Bar"), this);
m_pScalarBarAction->setToolTip(tr("Show Scalar Bar"));
m_pScalarBarAction->setCheckable(true);
m_pBoundsGridAction = new QAction(
QIcon(gridViewIconPath("NmScaleGrid.png")),
tr("Scale Grid"), this);
m_pBoundsGridAction->setToolTip(tr("Scale Grid"));
m_pBoundsGridAction->setCheckable(true);
if(pCommandController != nullptr) {
// 网格视图按自身工作流排序,但仍引用命令控制器持有的公共 QAction。
QAction* pZoomOutAction = pCommandController->getAction(
nmVTKViewCommandController::ViewCommand_ZoomOut);
QAction* pFitAction = pCommandController->getAction(
nmVTKViewCommandController::ViewCommand_Fit);
QAction* pZoomInAction = pCommandController->getAction(
nmVTKViewCommandController::ViewCommand_ZoomIn);
QAction* pTopAction = pCommandController->getAction(
nmVTKViewCommandController::ViewCommand_Top);
QAction* pCopyAction = pCommandController->getAction(
nmVTKViewCommandController::ViewCommand_CopyImage);
bool bHasPreviousGroup = false;
if(pZoomOutAction != nullptr) {
m_pToolBar->addAction(pZoomOutAction);
bHasPreviousGroup = true;
}
if(pFitAction != nullptr) {
m_pToolBar->addAction(pFitAction);
bHasPreviousGroup = true;
}
if(pZoomInAction != nullptr) {
m_pToolBar->addAction(pZoomInAction);
bHasPreviousGroup = true;
}
if(pTopAction != nullptr) {
if(bHasPreviousGroup) {
m_pToolBar->addSeparator();
}
m_pToolBar->addAction(pTopAction);
bHasPreviousGroup = true;
}
if(bHasPreviousGroup) {
m_pToolBar->addSeparator();
}
m_pToolBar->addAction(m_pGridLinesAction);
m_pToolBar->addAction(m_pScalarBarAction);
m_pToolBar->addAction(m_pBoundsGridAction);
if(pCopyAction != nullptr) {
m_pToolBar->addSeparator();
m_pToolBar->addAction(pCopyAction);
}
} else {
// 理论上不会进入;仍保留业务动作,避免容器初始化异常时布局跳动。
m_pToolBar->addAction(m_pGridLinesAction);
m_pToolBar->addAction(m_pScalarBarAction);
m_pToolBar->addAction(m_pBoundsGridAction);
}
pRenderLayout->addWidget(m_pRenderContainer, 1);
pRenderLayout->addWidget(m_pToolBar);
pMainLayout->addWidget(pRenderArea, 1);
m_pStatusLabel = new QLabel(this);
m_pStatusLabel->setWordWrap(true);
m_pStatusLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
m_pStatusLabel->setStyleSheet(
"QLabel { color: rgb(126, 76, 0); "
"background-color: rgb(255, 244, 204); "
"border-top: 1px solid rgb(220, 190, 105); "
"padding: 4px 8px; }");
m_pStatusLabel->hide();
pMainLayout->addWidget(m_pStatusLabel);
QWidget* pControlBar = new QWidget(this);
QHBoxLayout* pControlLayout = new QHBoxLayout(pControlBar);
pControlLayout->setContentsMargins(8, 5, 8, 5);
pControlLayout->setSpacing(6);
QLabel* pPropertyLabel = new QLabel(tr("Property:"), pControlBar);
m_pPropertyComboBox = new QComboBox(pControlBar);
m_pPropertyComboBox->setMinimumContentsLength(9);
pControlLayout->addWidget(pPropertyLabel);
pControlLayout->addWidget(m_pPropertyComboBox);
pControlLayout->addStretch(1);
m_pGridInfoLabel = new QLabel(pControlBar);
m_pGridInfoLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
pControlLayout->addWidget(m_pGridInfoLabel);
pMainLayout->addWidget(pControlBar);
connect(m_pPropertyComboBox, SIGNAL(currentIndexChanged(int)),
this, SLOT(onPropertyChanged(int)));
connect(m_pGridLinesAction, SIGNAL(toggled(bool)),
this, SLOT(onGridLinesToggled(bool)));
connect(m_pScalarBarAction, SIGNAL(toggled(bool)),
this, SLOT(onScalarBarToggled(bool)));
connect(m_pBoundsGridAction, SIGNAL(toggled(bool)),
this, SLOT(onBoundsGridToggled(bool)));
connect(m_pRenderContainer, SIGNAL(contextMenuAboutToShow(QMenu*)),
this, SLOT(appendContextMenuActions(QMenu*)));
}
bool nmWxPebiGridViewWidget::setViewData(
const nmPebiGridViewData& oViewData,
QString* pError)
{
if(m_pSceneController == nullptr || !oViewData.isValid()) {
if(pError != nullptr) {
*pError = tr("The grid preview data is invalid.");
}
return false;
}
if(!m_pSceneController->setViewData(oViewData, pError)) {
// 控制器回滚失败时同步清除外层标志,避免把空场景误当作旧成功网格。
m_bHasViewData = m_pSceneController->hasViewData();
return false;
}
// 属性列表只登记 Builder 已确认与 CellData 单元数一致的 Material。
const bool bOldBlockState = m_pPropertyComboBox->blockSignals(true);
m_pPropertyComboBox->clear();
m_pPropertyComboBox->addItem(tr("No property"), QString());
if(oViewData.hasMaterial()) {
m_pPropertyComboBox->addItem(tr("Material"), QString("Material"));
}
const QString sActiveProperty = m_pSceneController->getProperty();
for(int nIndex = 0; nIndex < m_pPropertyComboBox->count(); ++nIndex) {
if(m_pPropertyComboBox->itemData(nIndex).toString() ==
sActiveProperty) {
m_pPropertyComboBox->setCurrentIndex(nIndex);
break;
}
}
m_pPropertyComboBox->blockSignals(bOldBlockState);
m_pGridInfoLabel->setText(
tr("%1 cells | %2")
.arg(static_cast<qlonglong>(
oViewData.getValidCellCount()))
.arg(gridTypeText(static_cast<int>(oViewData.getGridType()))));
m_pStatusLabel->hide();
m_bHasViewData = true;
setControlsEnabled(true);
updateScalarBarActionState();
return true;
}
void nmWxPebiGridViewWidget::showLoading()
{
m_pStatusLabel->hide();
setControlsEnabled(false);
m_pRenderContainer->showRenderingState(tr("Generating grid..."));
}
void nmWxPebiGridViewWidget::showFailure(const QString& sMessage)
{
if(m_bHasViewData) {
// 失败时旧网格引用保持不变,状态条明确说明当前画面并非本次成果。
m_pStatusLabel->setText(sMessage);
m_pStatusLabel->show();
setControlsEnabled(true);
updateScalarBarActionState();
m_pRenderContainer->showReadyState();
} else {
m_pStatusLabel->hide();
setControlsEnabled(false);
m_pRenderContainer->showErrorState(sMessage);
}
}
void nmWxPebiGridViewWidget::clearView()
{
if(m_pSceneController != nullptr) {
m_pSceneController->clear();
}
m_bHasViewData = false;
m_pStatusLabel->hide();
resetControls();
setControlsEnabled(false);
m_pRenderContainer->showEmptyState(tr("No grid data."));
}
bool nmWxPebiGridViewWidget::hasViewData() const
{
return m_bHasViewData;
}
void nmWxPebiGridViewWidget::resetControls()
{
bool bBlocked = m_pPropertyComboBox->blockSignals(true);
m_pPropertyComboBox->clear();
m_pPropertyComboBox->addItem(tr("No property"), QString());
m_pPropertyComboBox->blockSignals(bBlocked);
bBlocked = m_pGridLinesAction->blockSignals(true);
m_pGridLinesAction->setChecked(true);
m_pGridLinesAction->blockSignals(bBlocked);
bBlocked = m_pScalarBarAction->blockSignals(true);
m_pScalarBarAction->setChecked(true);
m_pScalarBarAction->blockSignals(bBlocked);
bBlocked = m_pBoundsGridAction->blockSignals(true);
m_pBoundsGridAction->setChecked(false);
m_pBoundsGridAction->blockSignals(bBlocked);
m_pGridInfoLabel->setText(tr("0 cells | Unknown"));
}
void nmWxPebiGridViewWidget::setControlsEnabled(bool bEnabled)
{
m_pPropertyComboBox->setEnabled(bEnabled);
m_pGridLinesAction->setEnabled(bEnabled);
m_pBoundsGridAction->setEnabled(bEnabled);
m_pScalarBarAction->setEnabled(
bEnabled && m_pSceneController != nullptr &&
!m_pSceneController->getProperty().isEmpty());
}
void nmWxPebiGridViewWidget::updateScalarBarActionState()
{
if(m_pSceneController == nullptr) {
return;
}
const bool bBlocked = m_pScalarBarAction->blockSignals(true);
m_pScalarBarAction->setChecked(
m_pSceneController->isScalarBarVisible());
m_pScalarBarAction->blockSignals(bBlocked);
m_pScalarBarAction->setEnabled(
m_bHasViewData &&
!m_pSceneController->getProperty().isEmpty());
}
QString nmWxPebiGridViewWidget::gridTypeText(int nGridType) const
{
return nGridType == static_cast<int>(NM_Grid_PEBI)
? QString("PEBI") : tr("Unknown");
}
void nmWxPebiGridViewWidget::onPropertyChanged(int nIndex)
{
if(!m_bHasViewData || nIndex < 0 || m_pSceneController == nullptr) {
return;
}
const QString sPropertyName =
m_pPropertyComboBox->itemData(nIndex).toString();
if(!m_pSceneController->setProperty(sPropertyName)) {
const bool bBlocked = m_pPropertyComboBox->blockSignals(true);
m_pPropertyComboBox->setCurrentIndex(0);
m_pPropertyComboBox->blockSignals(bBlocked);
}
updateScalarBarActionState();
}
void nmWxPebiGridViewWidget::onGridLinesToggled(bool bVisible)
{
if(m_bHasViewData && m_pSceneController != nullptr) {
m_pSceneController->setGridLinesVisible(bVisible);
}
}
void nmWxPebiGridViewWidget::onScalarBarToggled(bool bVisible)
{
if(m_bHasViewData && m_pSceneController != nullptr) {
m_pSceneController->setScalarBarVisible(bVisible);
}
}
void nmWxPebiGridViewWidget::onBoundsGridToggled(bool bVisible)
{
if(m_bHasViewData && m_pSceneController != nullptr) {
m_pSceneController->setBoundsGridVisible(bVisible);
}
}
void nmWxPebiGridViewWidget::appendContextMenuActions(QMenu* pMenu)
{
if(pMenu == nullptr) {
return;
}
// 右键菜单与工具栏引用同三个业务 QAction勾选状态不会发生分叉。
pMenu->addAction(m_pGridLinesAction);
pMenu->addAction(m_pScalarBarAction);
pMenu->addAction(m_pBoundsGridAction);
}