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