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

295 lines
11 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 <QCoreApplication>
#include <QHBoxLayout>
#include <QIcon>
#include <QLabel>
#include <QMenu>
#include <QSize>
#include <QToolBar>
#include <QVBoxLayout>
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_pBoundsGridAction(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);
// 公共容器独占 Renderer、相机和交互对象本类只裁剪可见命令能力。
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_Front |
nmVTKViewCommandController::ViewCommand_SetRotationCenter |
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(32, 32));
m_pToolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
m_pToolBar->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
nmVTKViewCommandController* pCommandController =
m_pRenderContainer->getViewCommandController();
// 比例网格 QAction 长期持有,并同时用于工具栏和右键菜单。
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* pFrontAction = pCommandController->getAction(
nmVTKViewCommandController::ViewCommand_Front);
QAction* pSetRotationCenterAction = pCommandController->getAction(
nmVTKViewCommandController::
ViewCommand_SetRotationCenter);
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;
}
const bool bHasViewGroup = pTopAction != nullptr ||
pFrontAction != nullptr ||
pSetRotationCenterAction != nullptr;
if(bHasViewGroup && bHasPreviousGroup) {
m_pToolBar->addSeparator();
}
if(pTopAction != nullptr) {
m_pToolBar->addAction(pTopAction);
bHasPreviousGroup = true;
}
if(pFrontAction != nullptr) {
m_pToolBar->addAction(pFrontAction);
bHasPreviousGroup = true;
}
if(pSetRotationCenterAction != nullptr) {
m_pToolBar->addAction(pSetRotationCenterAction);
bHasPreviousGroup = true;
}
if(bHasPreviousGroup) {
m_pToolBar->addSeparator();
}
m_pToolBar->addAction(m_pBoundsGridAction);
if(pCopyAction != nullptr) {
m_pToolBar->addSeparator();
m_pToolBar->addAction(pCopyAction);
}
} else {
// 理论上不会进入;仍保留业务动作,避免容器初始化异常时布局跳动。
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);
m_pGridInfoLabel = new QLabel(pControlBar);
m_pGridInfoLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
pControlLayout->addWidget(m_pGridInfoLabel);
pControlLayout->addStretch(1);
pMainLayout->addWidget(pControlBar);
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;
}
// SceneController 负责事务式绑定;失败时这里按其回滚结果同步外层状态。
if(!m_pSceneController->setViewData(oViewData, pError)) {
// 控制器回滚失败时同步清除外层标志,避免把空场景误当作旧成功网格。
m_bHasViewData = m_pSceneController->hasViewData();
return false;
}
// Builder 只接受已提交的 PEBI 网格,因此底栏无需再显示“未知类型”。
m_pGridInfoLabel->setText(
tr("PEBI | %1 valid cells | XY planar grid")
.arg(static_cast<qlonglong>(
oViewData.getValidCellCount())));
m_pStatusLabel->hide();
m_bHasViewData = true;
setControlsEnabled(true);
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_pRenderContainer->setRotationCenterPickingEnabled(false);
m_pStatusLabel->setText(sMessage);
m_pStatusLabel->show();
setControlsEnabled(true);
m_pRenderContainer->showReadyState();
} else {
m_pStatusLabel->hide();
resetControls();
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()
{
const bool bBlocked = m_pBoundsGridAction->blockSignals(true);
m_pBoundsGridAction->setChecked(false);
m_pBoundsGridAction->blockSignals(bBlocked);
m_pGridInfoLabel->setText(
tr("PEBI | %1 valid cells | XY planar grid").arg(0));
}
void nmWxPebiGridViewWidget::setControlsEnabled(bool bEnabled)
{
m_pBoundsGridAction->setEnabled(bEnabled);
}
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_pBoundsGridAction);
}