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++

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 "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);
}