#include "nmWxPebiResultControlBar.h" #include "nmPebiResultPlaybackController.h" #include "nmPebiResultPropertyDisplayText.h" #include "nmPebiResultSceneController.h" #include "nmWxPebiResultAnimationSettingsDlg.h" #include "nmWxPebiResultColorScaleSettingsDlg.h" #include #include #include #include #include #include #include #include namespace { QString resultControlIconPath(const QString& sFileName) { const QString sApplicationDir = QCoreApplication::applicationDirPath(); return sApplicationDir.section('/', 0, -2) + "/Res/Icon/" + sFileName; } QToolButton* createControlButton(QWidget* pParent, const QString& sIconFile, const QString& sToolTip) { QToolButton* pButton = new QToolButton(pParent); pButton->setAutoRaise(true); pButton->setFixedSize(24, 24); pButton->setIconSize(QSize(16, 16)); pButton->setIcon(QIcon(resultControlIconPath(sIconFile))); pButton->setToolTip(sToolTip); return pButton; } } nmWxPebiResultControlBar::nmWxPebiResultControlBar( nmPebiResultSceneController* pSceneController, QWidget* pParent) : QWidget(pParent), m_pPlaybackController(nullptr), m_pSceneController(pSceneController), m_pPropertyCombo(nullptr), m_pColorSettingsButton(nullptr), m_pFirstButton(nullptr), m_pPreviousButton(nullptr), m_pTimeCombo(nullptr), m_pNextButton(nullptr), m_pLastButton(nullptr), m_pPlayPauseButton(nullptr), m_pSettingsButton(nullptr), m_nDisplayedBindingRevision(0), m_nDisplayedTimeFrameCount(-1) { Q_ASSERT(pSceneController != nullptr); createUi(); m_pPlaybackController = new nmPebiResultPlaybackController( pSceneController, this); connect(m_pPlaybackController, SIGNAL(stateChanged()), this, SLOT(refreshFromController())); connect(m_pPlaybackController, SIGNAL(operationFailed(QString)), this, SLOT(forwardOperationFailure(QString))); m_pPlaybackController->synchronizeFromScene(); } nmWxPebiResultControlBar::~nmWxPebiResultControlBar() { // QObject 随后删除子控制器;先停表可保证析构期间不再排入超时请求。 if(m_pPlaybackController != nullptr) { m_pPlaybackController->blockSignals(true); m_pPlaybackController->pause(); } } void nmWxPebiResultControlBar::stopPlayback() { if(m_pPlaybackController != nullptr) { m_pPlaybackController->pause(); } } void nmWxPebiResultControlBar::synchronizeFromScene() { if(m_pPlaybackController != nullptr) { m_pPlaybackController->synchronizeFromScene(); } } nmPebiResultPlaybackController* nmWxPebiResultControlBar::getPlaybackController() const { return m_pPlaybackController; } void nmWxPebiResultControlBar::onPropertyIndexChanged(int nIndex) { if(m_pPlaybackController == nullptr || nIndex < 0) { return; } if(m_pPlaybackController->selectProperty( m_pPropertyCombo->itemData(nIndex).toString())) { emit operationSucceeded(); } } void nmWxPebiResultControlBar::onTimeIndexChanged(int nIndex) { if(m_pPlaybackController == nullptr || nIndex < 0) { return; } if(m_pPlaybackController->selectFrame( m_pTimeCombo->itemData(nIndex).toInt())) { emit operationSucceeded(); } } void nmWxPebiResultControlBar::onColorSettingsClicked() { if(m_pPlaybackController == nullptr || m_pSceneController == nullptr || !m_pSceneController->hasSnapshot()) { return; } // 打开任何结果设置都属于手动操作;关闭后不自动恢复播放。 m_pPlaybackController->pause(); nmWxPebiResultColorScaleSettingsDlg oDialog( m_pSceneController, this); connect(&oDialog, SIGNAL(displaySettingsApplied()), this, SIGNAL(operationSucceeded())); connect(&oDialog, SIGNAL(operationFailed(QString)), this, SLOT(forwardOperationFailure(QString))); oDialog.exec(); } void nmWxPebiResultControlBar::onFirstFrameClicked() { if(m_pPlaybackController->selectFirstFrame()) { emit operationSucceeded(); } } void nmWxPebiResultControlBar::onPreviousFrameClicked() { if(m_pPlaybackController->selectPreviousFrame()) { emit operationSucceeded(); } } void nmWxPebiResultControlBar::onNextFrameClicked() { if(m_pPlaybackController->selectNextFrame()) { emit operationSucceeded(); } } void nmWxPebiResultControlBar::onLastFrameClicked() { if(m_pPlaybackController->selectLastFrame()) { emit operationSucceeded(); } } void nmWxPebiResultControlBar::onPlayPauseClicked() { if(m_pPlaybackController->togglePlayback()) { emit operationSucceeded(); } } void nmWxPebiResultControlBar::onAnimationSettingsClicked() { // 打开设置属于明确的手动操作;关闭对话框后不自动恢复播放。 m_pPlaybackController->pause(); nmWxPebiResultAnimationSettingsDlg oDialog( m_pPlaybackController->getPlaybackSpeed(), m_pPlaybackController->isLoopEnabled(), this); if(oDialog.exec() == QDialog::Accepted) { if(m_pPlaybackController->setPlaybackSettings( oDialog.getPlaybackSpeed(), oDialog.isLoopEnabled())) { emit operationSucceeded(); } } } void nmWxPebiResultControlBar::refreshFromController() { // 控件状态严格镜像四类 Scene 状态:无快照、静态、单帧动态、多帧动态。 const bool bAvailable = m_pPlaybackController != nullptr && m_pPlaybackController->isAvailable(); if(!bAvailable) { const bool bPropertyBlocked = m_pPropertyCombo->blockSignals(true); m_pPropertyCombo->clear(); m_pPropertyCombo->blockSignals(bPropertyBlocked); clearTimeItems(); m_sDisplayedSnapshotId.clear(); m_nDisplayedBindingRevision = 0; m_listDisplayedPropertyIds.clear(); m_pPropertyCombo->setEnabled(false); m_pColorSettingsButton->setEnabled(false); m_pFirstButton->setEnabled(false); m_pPreviousButton->setEnabled(false); m_pNextButton->setEnabled(false); m_pLastButton->setEnabled(false); m_pPlayPauseButton->setEnabled(false); m_pSettingsButton->setEnabled(false); m_pPlayPauseButton->setIcon(QIcon(resultControlIconPath( QString::fromLatin1("NmStartAnimation.png")))); m_pPlayPauseButton->setToolTip(tr("Play")); return; } const QString sSnapshotId = m_pPlaybackController->getObservedSnapshotId(); const quint64 nBindingRevision = m_pPlaybackController->getObservedBindingRevision(); const QStringList listPropertyIds = m_pPlaybackController->getAvailablePropertyIds(); const bool bSnapshotChanged = m_nDisplayedBindingRevision != nBindingRevision || m_sDisplayedSnapshotId != sSnapshotId; if(bSnapshotChanged || m_listDisplayedPropertyIds != listPropertyIds) { rebuildPropertyItems(listPropertyIds); m_sDisplayedSnapshotId = sSnapshotId; m_nDisplayedBindingRevision = nBindingRevision; m_listDisplayedPropertyIds = listPropertyIds; // 即使属性和帧数相同,新快照的真实时间值也可能不同,不能复用旧列表。 if(bSnapshotChanged) { m_sDisplayedTimePropertyId.clear(); m_nDisplayedTimeFrameCount = -1; } } const QString sPropertyId = m_pPlaybackController->getCurrentPropertyId(); const int nPropertyIndex = findItemByData( m_pPropertyCombo, QVariant(sPropertyId)); const bool bPropertyBlocked = m_pPropertyCombo->blockSignals(true); m_pPropertyCombo->setCurrentIndex(nPropertyIndex); m_pPropertyCombo->blockSignals(bPropertyBlocked); m_pPropertyCombo->setEnabled(true); m_pColorSettingsButton->setEnabled(true); const bool bTimeDependent = m_pPlaybackController->isPropertyTimeDependent(sPropertyId); const int nFrameCount = bTimeDependent ? m_pPlaybackController->getPropertyFrameCount(sPropertyId) : 0; if(!bTimeDependent) { clearTimeItems(); } else if(m_sDisplayedTimePropertyId != sPropertyId || m_nDisplayedTimeFrameCount != nFrameCount) { rebuildTimeItems(sPropertyId, nFrameCount); } const int nCurrentFrame = m_pPlaybackController->getCurrentFrameIndex(); if(bTimeDependent) { const int nTimeIndex = findItemByData( m_pTimeCombo, QVariant(nCurrentFrame)); const bool bTimeBlocked = m_pTimeCombo->blockSignals(true); m_pTimeCombo->setCurrentIndex(nTimeIndex); m_pTimeCombo->blockSignals(bTimeBlocked); } const bool bHasCompleteTimeList = bTimeDependent && nFrameCount > 0 && m_pTimeCombo->count() == nFrameCount; const bool bHasTime = bHasCompleteTimeList; const bool bHasMultipleFrames = bHasCompleteTimeList && nFrameCount > 1; m_pTimeCombo->setEnabled(bHasTime); m_pFirstButton->setEnabled( bHasMultipleFrames && nCurrentFrame > 0); m_pPreviousButton->setEnabled( bHasMultipleFrames && nCurrentFrame > 0); m_pNextButton->setEnabled( bHasMultipleFrames && nCurrentFrame < nFrameCount - 1); m_pLastButton->setEnabled( bHasMultipleFrames && nCurrentFrame < nFrameCount - 1); m_pPlayPauseButton->setEnabled(bHasMultipleFrames); m_pSettingsButton->setEnabled(bHasMultipleFrames); const bool bPlaying = m_pPlaybackController->isPlaying(); m_pPlayPauseButton->setIcon(QIcon(resultControlIconPath( bPlaying ? QString::fromLatin1("NmStopAnimation.png") : QString::fromLatin1("NmStartAnimation.png")))); m_pPlayPauseButton->setToolTip( bPlaying ? tr("Pause") : tr("Play")); } void nmWxPebiResultControlBar::forwardOperationFailure( const QString& sError) { emit operationFailed(sError); } void nmWxPebiResultControlBar::createUi() { QHBoxLayout* pLayout = new QHBoxLayout(this); pLayout->setContentsMargins(4, 3, 4, 3); pLayout->setSpacing(4); m_pPropertyCombo = new QComboBox(this); m_pPropertyCombo->setMinimumWidth(140); m_pPropertyCombo->setFixedHeight(24); m_pPropertyCombo->setSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed); m_pPropertyCombo->setToolTip(tr("Display property")); m_pColorSettingsButton = createControlButton( this, QString::fromLatin1("NmColorScaleSettings.png"), tr("Color settings")); m_pFirstButton = createControlButton( this, QString::fromLatin1("NmFirstStep.png"), tr("First frame")); m_pPreviousButton = createControlButton( this, QString::fromLatin1("NmPreviousStep.png"), tr("Previous frame")); m_pTimeCombo = new QComboBox(this); m_pTimeCombo->setMinimumWidth(150); m_pTimeCombo->setFixedHeight(24); m_pTimeCombo->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed); m_pTimeCombo->setToolTip(tr("Result time")); m_pNextButton = createControlButton( this, QString::fromLatin1("NmNextStep.png"), tr("Next frame")); m_pLastButton = createControlButton( this, QString::fromLatin1("NmLastStep.png"), tr("Last frame")); m_pPlayPauseButton = createControlButton( this, QString::fromLatin1("NmStartAnimation.png"), tr("Play")); m_pSettingsButton = createControlButton( this, QString::fromLatin1("NmAnimationSettings.png"), tr("Animation settings")); pLayout->addWidget(m_pPropertyCombo); pLayout->addWidget(m_pColorSettingsButton); pLayout->addWidget(m_pFirstButton); pLayout->addWidget(m_pPreviousButton); pLayout->addWidget(m_pTimeCombo, 1); pLayout->addWidget(m_pNextButton); pLayout->addWidget(m_pLastButton); pLayout->addWidget(m_pPlayPauseButton); pLayout->addWidget(m_pSettingsButton); connect(m_pPropertyCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onPropertyIndexChanged(int))); connect(m_pColorSettingsButton, SIGNAL(clicked()), this, SLOT(onColorSettingsClicked())); connect(m_pTimeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(onTimeIndexChanged(int))); connect(m_pFirstButton, SIGNAL(clicked()), this, SLOT(onFirstFrameClicked())); connect(m_pPreviousButton, SIGNAL(clicked()), this, SLOT(onPreviousFrameClicked())); connect(m_pNextButton, SIGNAL(clicked()), this, SLOT(onNextFrameClicked())); connect(m_pLastButton, SIGNAL(clicked()), this, SLOT(onLastFrameClicked())); connect(m_pPlayPauseButton, SIGNAL(clicked()), this, SLOT(onPlayPauseClicked())); connect(m_pSettingsButton, SIGNAL(clicked()), this, SLOT(onAnimationSettingsClicked())); } void nmWxPebiResultControlBar::rebuildPropertyItems( const QStringList& listPropertyIds) { const bool bBlocked = m_pPropertyCombo->blockSignals(true); m_pPropertyCombo->clear(); for(int nIndex = 0; nIndex < listPropertyIds.size(); ++nIndex) { const QString& sPropertyId = listPropertyIds[nIndex]; QString sDisplayName = nmPebiResultPropertyDisplayText::getDisplayName(sPropertyId); if(sDisplayName.isEmpty()) { sDisplayName = sPropertyId; } m_pPropertyCombo->addItem(sDisplayName, sPropertyId); } m_pPropertyCombo->blockSignals(bBlocked); } void nmWxPebiResultControlBar::rebuildTimeItems( const QString& sPropertyId, int nFrameCount) { const bool bBlocked = m_pTimeCombo->blockSignals(true); m_pTimeCombo->clear(); bool bComplete = true; for(int nFrameIndex = 0; nFrameIndex < nFrameCount; ++nFrameIndex) { double dTimeHours = 0.0; if(!m_pPlaybackController->getPropertyTimeAt( sPropertyId, nFrameIndex, dTimeHours)) { // 时间轴来自完整快照;防御性失败时不留下索引错位的半列表。 m_pTimeCombo->clear(); bComplete = false; break; } m_pTimeCombo->addItem( tr("t = %1 h").arg( QString::number(dTimeHours, 'g', 8)), nFrameIndex); } m_pTimeCombo->blockSignals(bBlocked); m_sDisplayedTimePropertyId = bComplete ? sPropertyId : QString(); m_nDisplayedTimeFrameCount = bComplete ? nFrameCount : -1; } void nmWxPebiResultControlBar::clearTimeItems() { const bool bBlocked = m_pTimeCombo->blockSignals(true); m_pTimeCombo->clear(); m_pTimeCombo->blockSignals(bBlocked); m_pTimeCombo->setEnabled(false); m_sDisplayedTimePropertyId.clear(); m_nDisplayedTimeFrameCount = -1; } int nmWxPebiResultControlBar::findItemByData( QComboBox* pComboBox, const QVariant& oData) const { if(pComboBox == nullptr) { return -1; } for(int nIndex = 0; nIndex < pComboBox->count(); ++nIndex) { if(pComboBox->itemData(nIndex) == oData) { return nIndex; } } return -1; }