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/nmWxPebiResultAnimationExpo...

301 lines
11 KiB
C++

#include "nmWxPebiResultAnimationExportDlg.h"
#include <QComboBox>
#include <QCoreApplication>
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QIcon>
#include <QLabel>
#include <QPushButton>
#include <QSpinBox>
#include <QVBoxLayout>
#include <QVariant>
namespace {
QString exportDialogIconPath(const QString& sFileName)
{
const QString sApplicationDir = QCoreApplication::applicationDirPath();
return sApplicationDir.section('/', 0, -2) +
"/Res/Icon/" + sFileName;
}
}
nmWxPebiResultAnimationExportDlg::nmWxPebiResultAnimationExportDlg(
const QVector<double>& vecFrameTimesHours,
const QSize& oCurrentViewportSize,
QWidget* pParent)
: QDialog(pParent),
m_vecFrameTimesHours(vecFrameTimesHours),
m_oCurrentViewportSize(oCurrentViewportSize),
m_pFpsSpinBox(nullptr),
m_pStartFrameCombo(nullptr),
m_pEndFrameCombo(nullptr),
m_pSamplingIntervalSpinBox(nullptr),
m_pResolutionCombo(nullptr),
m_pWidthSpinBox(nullptr),
m_pHeightSpinBox(nullptr),
m_pOutputFrameCountLabel(nullptr),
m_pEstimatedDurationLabel(nullptr),
m_pErrorLabel(nullptr)
{
createUi();
populateFrameItems();
onResolutionPresetChanged(m_pResolutionCombo->currentIndex());
onFrameRangeChanged();
}
nmPebiResultAnimationExportSettings
nmWxPebiResultAnimationExportDlg::getSettings() const
{
return m_oAcceptedSettings;
}
void nmWxPebiResultAnimationExportDlg::onFrameRangeChanged()
{
const int nStartIndex = m_pStartFrameCombo->currentIndex();
if(nStartIndex >= 0 &&
m_pEndFrameCombo->currentIndex() < nStartIndex) {
const bool bBlocked = m_pEndFrameCombo->blockSignals(true);
m_pEndFrameCombo->setCurrentIndex(nStartIndex);
m_pEndFrameCombo->blockSignals(bBlocked);
}
const int nRangeLength = qMax(1,
m_pEndFrameCombo->currentIndex() -
m_pStartFrameCombo->currentIndex());
m_pSamplingIntervalSpinBox->setMaximum(nRangeLength);
updateSummary();
}
void nmWxPebiResultAnimationExportDlg::onResolutionPresetChanged(
int nIndex)
{
Q_UNUSED(nIndex);
const ResolutionPreset ePreset = static_cast<ResolutionPreset>(
m_pResolutionCombo->itemData(
m_pResolutionCombo->currentIndex()).toInt());
int nWidth = m_oCurrentViewportSize.width();
int nHeight = m_oCurrentViewportSize.height();
if(ePreset == Resolution_720p) {
nWidth = 1280;
nHeight = 720;
} else if(ePreset == Resolution_1080p) {
nWidth = 1920;
nHeight = 1080;
}
if(nWidth <= 0 || nHeight <= 0) {
nWidth = 1280;
nHeight = 720;
}
const bool bCustom = ePreset == Resolution_Custom;
if(!bCustom) {
m_pWidthSpinBox->setValue(normalizeEvenDimension(nWidth));
m_pHeightSpinBox->setValue(normalizeEvenDimension(nHeight));
}
m_pWidthSpinBox->setEnabled(bCustom);
m_pHeightSpinBox->setEnabled(bCustom);
updateSummary();
}
void nmWxPebiResultAnimationExportDlg::normalizeCustomDimensions()
{
// editingFinished后再回写,避免valueChanged期间干扰用户键盘输入。
m_pWidthSpinBox->setValue(
normalizeEvenDimension(m_pWidthSpinBox->value()));
m_pHeightSpinBox->setValue(
normalizeEvenDimension(m_pHeightSpinBox->value()));
updateSummary();
}
void nmWxPebiResultAnimationExportDlg::updateSummary()
{
const nmPebiResultAnimationExportSettings oSettings =
collectSettings();
const int nOutputFrameCount = oSettings.getOutputFrameCount();
m_pOutputFrameCountLabel->setText(
QString::number(nOutputFrameCount));
const double dDuration = oSettings.m_nFramesPerSecond > 0
? static_cast<double>(nOutputFrameCount) /
static_cast<double>(oSettings.m_nFramesPerSecond)
: 0.0;
m_pEstimatedDurationLabel->setText(
tr("%1 s").arg(QString::number(dDuration, 'g', 6)));
m_pErrorLabel->clear();
}
void nmWxPebiResultAnimationExportDlg::acceptSettings()
{
// 接受前再规范化一次,覆盖按钮点击与焦点事件顺序差异。
normalizeCustomDimensions();
const nmPebiResultAnimationExportSettings oSettings =
collectSettings();
if(!oSettings.isValid(m_vecFrameTimesHours.size())) {
m_pErrorLabel->setText(
tr("The animation export settings are invalid."));
return;
}
m_oAcceptedSettings = oSettings;
accept();
}
void nmWxPebiResultAnimationExportDlg::createUi()
{
setWindowTitle(tr("Export Animation"));
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
setMinimumWidth(430);
QVBoxLayout* pMainLayout = new QVBoxLayout(this);
pMainLayout->setContentsMargins(12, 10, 12, 10);
pMainLayout->setSpacing(8);
QGridLayout* pGrid = new QGridLayout();
pGrid->setHorizontalSpacing(8);
pGrid->setVerticalSpacing(6);
int nRow = 0;
m_pFpsSpinBox = new QSpinBox(this);
m_pFpsSpinBox->setRange(1, 5000);
m_pFpsSpinBox->setValue(15);
m_pFpsSpinBox->setSuffix(tr(" FPS"));
pGrid->addWidget(new QLabel(tr("Frame rate"), this), nRow, 0);
pGrid->addWidget(m_pFpsSpinBox, nRow++, 1, 1, 2);
m_pStartFrameCombo = new QComboBox(this);
pGrid->addWidget(new QLabel(tr("Start frame"), this), nRow, 0);
pGrid->addWidget(m_pStartFrameCombo, nRow++, 1, 1, 2);
m_pEndFrameCombo = new QComboBox(this);
pGrid->addWidget(new QLabel(tr("End frame"), this), nRow, 0);
pGrid->addWidget(m_pEndFrameCombo, nRow++, 1, 1, 2);
m_pSamplingIntervalSpinBox = new QSpinBox(this);
m_pSamplingIntervalSpinBox->setRange(1, 1);
pGrid->addWidget(new QLabel(tr("Sampling interval"), this), nRow, 0);
pGrid->addWidget(m_pSamplingIntervalSpinBox, nRow++, 1, 1, 2);
m_pResolutionCombo = new QComboBox(this);
m_pResolutionCombo->addItem(tr("Current view"), Resolution_CurrentView);
m_pResolutionCombo->addItem(QString::fromLatin1("1280 x 720"),
Resolution_720p);
m_pResolutionCombo->addItem(QString::fromLatin1("1920 x 1080"),
Resolution_1080p);
m_pResolutionCombo->addItem(tr("Custom"), Resolution_Custom);
pGrid->addWidget(new QLabel(tr("Resolution"), this), nRow, 0);
pGrid->addWidget(m_pResolutionCombo, nRow++, 1, 1, 2);
m_pWidthSpinBox = new QSpinBox(this);
m_pHeightSpinBox = new QSpinBox(this);
m_pWidthSpinBox->setRange(2, 8192);
m_pHeightSpinBox->setRange(2, 8192);
m_pWidthSpinBox->setSingleStep(2);
m_pHeightSpinBox->setSingleStep(2);
QHBoxLayout* pCustomSizeLayout = new QHBoxLayout();
pCustomSizeLayout->setContentsMargins(0, 0, 0, 0);
pCustomSizeLayout->setSpacing(6);
pCustomSizeLayout->addWidget(m_pWidthSpinBox);
pCustomSizeLayout->addWidget(new QLabel(QString::fromLatin1("x"), this));
pCustomSizeLayout->addWidget(m_pHeightSpinBox);
pGrid->addWidget(new QLabel(tr("Output size"), this), nRow, 0);
pGrid->addLayout(pCustomSizeLayout, nRow++, 1, 1, 2);
m_pOutputFrameCountLabel = new QLabel(this);
pGrid->addWidget(new QLabel(tr("Output frames"), this), nRow, 0);
pGrid->addWidget(m_pOutputFrameCountLabel, nRow++, 1, 1, 2);
m_pEstimatedDurationLabel = new QLabel(this);
pGrid->addWidget(new QLabel(tr("Estimated duration"), this), nRow, 0);
pGrid->addWidget(m_pEstimatedDurationLabel, nRow++, 1, 1, 2);
pGrid->setColumnStretch(1, 1);
pMainLayout->addLayout(pGrid);
m_pErrorLabel = new QLabel(this);
m_pErrorLabel->setStyleSheet("QLabel { color: #a32626; }");
m_pErrorLabel->setWordWrap(true);
pMainLayout->addWidget(m_pErrorLabel);
QDialogButtonBox* pButtonBox = new QDialogButtonBox(
QDialogButtonBox::Ok | QDialogButtonBox::Cancel,
Qt::Horizontal, this);
QPushButton* pOkButton = pButtonBox->button(QDialogButtonBox::Ok);
QPushButton* pCancelButton = pButtonBox->button(QDialogButtonBox::Cancel);
pOkButton->setIcon(QIcon(exportDialogIconPath("OK.png")));
pCancelButton->setIcon(QIcon(exportDialogIconPath("Cancel.png")));
pOkButton->setIconSize(QSize(16, 16));
pCancelButton->setIconSize(QSize(16, 16));
pOkButton->setMinimumWidth(72);
pCancelButton->setMinimumWidth(72);
pMainLayout->addWidget(pButtonBox);
connect(m_pStartFrameCombo, SIGNAL(currentIndexChanged(int)),
this, SLOT(onFrameRangeChanged()));
connect(m_pEndFrameCombo, SIGNAL(currentIndexChanged(int)),
this, SLOT(onFrameRangeChanged()));
connect(m_pSamplingIntervalSpinBox, SIGNAL(valueChanged(int)),
this, SLOT(updateSummary()));
connect(m_pFpsSpinBox, SIGNAL(valueChanged(int)),
this, SLOT(updateSummary()));
connect(m_pResolutionCombo, SIGNAL(currentIndexChanged(int)),
this, SLOT(onResolutionPresetChanged(int)));
connect(m_pWidthSpinBox, SIGNAL(valueChanged(int)),
this, SLOT(updateSummary()));
connect(m_pHeightSpinBox, SIGNAL(valueChanged(int)),
this, SLOT(updateSummary()));
connect(m_pWidthSpinBox, SIGNAL(editingFinished()),
this, SLOT(normalizeCustomDimensions()));
connect(m_pHeightSpinBox, SIGNAL(editingFinished()),
this, SLOT(normalizeCustomDimensions()));
connect(pButtonBox, SIGNAL(accepted()),
this, SLOT(acceptSettings()));
connect(pButtonBox, SIGNAL(rejected()),
this, SLOT(reject()));
}
void nmWxPebiResultAnimationExportDlg::populateFrameItems()
{
for(int nFrameIndex = 0;
nFrameIndex < m_vecFrameTimesHours.size(); ++nFrameIndex) {
const QString sText = tr("%1 h").arg(QString::number(
m_vecFrameTimesHours[nFrameIndex], 'g', 8));
m_pStartFrameCombo->addItem(sText, nFrameIndex);
m_pEndFrameCombo->addItem(sText, nFrameIndex);
}
if(!m_vecFrameTimesHours.isEmpty()) {
m_pStartFrameCombo->setCurrentIndex(0);
m_pEndFrameCombo->setCurrentIndex(
m_vecFrameTimesHours.size() - 1);
}
}
nmPebiResultAnimationExportSettings
nmWxPebiResultAnimationExportDlg::collectSettings() const
{
nmPebiResultAnimationExportSettings oSettings;
oSettings.m_nFramesPerSecond = m_pFpsSpinBox->value();
oSettings.m_nStartFrameIndex =
m_pStartFrameCombo->itemData(
m_pStartFrameCombo->currentIndex()).toInt();
oSettings.m_nEndFrameIndex =
m_pEndFrameCombo->itemData(
m_pEndFrameCombo->currentIndex()).toInt();
oSettings.m_nSamplingInterval =
m_pSamplingIntervalSpinBox->value();
oSettings.m_nOutputWidth =
normalizeEvenDimension(m_pWidthSpinBox->value());
oSettings.m_nOutputHeight =
normalizeEvenDimension(m_pHeightSpinBox->value());
return oSettings;
}
int nmWxPebiResultAnimationExportDlg::normalizeEvenDimension(int nValue)
{
nValue = qBound(2, nValue, 8192);
if((nValue % 2) != 0) {
++nValue;
}
return qMin(nValue, 8192);
}