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

624 lines
23 KiB
C++

#include "nmWxPebiResultAnimationExportDlg.h"
#include "nmFFmpegVideoWriter.h"
#include "ZxBaseUtil.h"
#include <QButtonGroup>
#include <QComboBox>
#include <QCoreApplication>
#include <QDialogButtonBox>
#include <QDir>
#include <QFileDialog>
#include <QFileInfo>
#include <QGridLayout>
#include <QGroupBox>
#include <QIcon>
#include <QLabel>
#include <QLineEdit>
#include <QMessageBox>
#include <QPushButton>
#include <QRadioButton>
#include <QSizePolicy>
#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;
}
QLabel* createRightAlignedLabel(const QString& sText, QWidget* pParent)
{
QLabel* pLabel = new QLabel(sText, pParent);
pLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
return pLabel;
}
QString formatPixelSize(int nWidth, int nHeight)
{
QString sText = QString::number(nWidth);
sText.append(' ');
sText.append(QChar(0x00D7));
sText.append(QString::fromLatin1(" %1 px").arg(nHeight));
return sText;
}
}
nmWxPebiResultAnimationExportDlg::nmWxPebiResultAnimationExportDlg(
const QVector<double>& vecFrameTimesHours,
const QSize& oCurrentViewportSize,
QWidget* pParent)
: iDlgBase(pParent),
m_vecFrameTimesHours(vecFrameTimesHours),
m_pFpsSpinBox(nullptr),
m_pStartFrameCombo(nullptr),
m_pEndFrameCombo(nullptr),
m_pSamplingIntervalSpinBox(nullptr),
m_pResolutionButtonGroup(nullptr),
m_pCurrentSizeRadioButton(nullptr),
m_p720pRadioButton(nullptr),
m_p1080pRadioButton(nullptr),
m_pCustomSizeRadioButton(nullptr),
m_pWidthSpinBox(nullptr),
m_pHeightSpinBox(nullptr),
m_pVideoFormatCombo(nullptr),
m_pTargetPathEdit(nullptr),
m_pOutputFrameCountLabel(nullptr),
m_pEstimatedDurationLabel(nullptr),
m_pErrorLabel(nullptr)
{
int nCurrentWidth = oCurrentViewportSize.width();
int nCurrentHeight = oCurrentViewportSize.height();
if(nCurrentWidth <= 0 || nCurrentHeight <= 0) {
nCurrentWidth = 1280;
nCurrentHeight = 720;
}
m_oEffectiveCurrentViewportSize = QSize(
normalizeEvenDimension(nCurrentWidth),
normalizeEvenDimension(nCurrentHeight));
createUi();
populateFrameItems();
populateVideoFormats();
setTargetFilePath(getSuggestedTargetFilePath());
onResolutionPresetChanged(Resolution_CurrentView);
onFrameRangeChanged();
}
nmPebiResultAnimationExportSettings
nmWxPebiResultAnimationExportDlg::getSettings() const
{
return m_oAcceptedSettings;
}
QString nmWxPebiResultAnimationExportDlg::getTargetFilePath() const
{
return m_sAcceptedTargetFilePath;
}
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 nPresetId)
{
const bool bCustom = nPresetId == Resolution_Custom;
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(
tr("%1 frames").arg(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', 4)));
clearError();
}
void nmWxPebiResultAnimationExportDlg::onVideoFormatChanged(int nIndex)
{
Q_UNUSED(nIndex);
if(m_pTargetPathEdit != nullptr &&
!m_pTargetPathEdit->text().isEmpty()) {
setTargetFilePath(normalizeTargetFilePath(
m_pTargetPathEdit->text()));
}
clearError();
}
void nmWxPebiResultAnimationExportDlg::browseTargetFile()
{
const QString sExtension = getSelectedVideoExtension();
if(sExtension.isEmpty()) {
showError(tr("The selected video format is unsupported."));
return;
}
const QString sInitialPath = m_pTargetPathEdit->text().isEmpty()
? getSuggestedTargetFilePath() : m_pTargetPathEdit->text();
const QFileInfo oInitialFileInfo(sInitialPath);
QFileDialog oFileDialog(this, tr("Save Result Animation"));
oFileDialog.setAcceptMode(QFileDialog::AcceptSave);
oFileDialog.setFileMode(QFileDialog::AnyFile);
oFileDialog.setNameFilter(getSelectedVideoFilter());
oFileDialog.setDefaultSuffix(sExtension);
oFileDialog.setOption(QFileDialog::DontConfirmOverwrite, true);
oFileDialog.setDirectory(oInitialFileInfo.absolutePath());
oFileDialog.selectFile(oInitialFileInfo.fileName());
if(oFileDialog.exec() != QDialog::Accepted ||
oFileDialog.selectedFiles().isEmpty()) {
return;
}
const QString sTargetPath = normalizeTargetFilePath(
oFileDialog.selectedFiles().first());
const QFileInfo oTargetFileInfo(sTargetPath);
setTargetFilePath(oTargetFileInfo.absoluteFilePath());
ZxBaseUtil::setLastDir(oTargetFileInfo.absolutePath());
clearError();
}
void nmWxPebiResultAnimationExportDlg::acceptSettings()
{
// 只有自定义模式需要把编辑值回写为编码器最终使用的偶数尺寸。
if(m_pCustomSizeRadioButton->isChecked()) {
normalizeCustomDimensions();
}
const nmPebiResultAnimationExportSettings oSettings =
collectSettings();
if(!oSettings.isValid(m_vecFrameTimesHours.size())) {
showError(tr("The animation export settings are invalid."));
return;
}
if(m_pTargetPathEdit->text().isEmpty()) {
showError(tr("Please select an output file."));
return;
}
const QString sExtension = getSelectedVideoExtension();
if(sExtension.isEmpty()) {
showError(tr("The selected video format is unsupported."));
return;
}
const QString sTargetPath = QFileInfo(normalizeTargetFilePath(
m_pTargetPathEdit->text())).absoluteFilePath();
const QFileInfo oTargetFileInfo(sTargetPath);
if(oTargetFileInfo.suffix().compare(
sExtension, Qt::CaseInsensitive) != 0) {
showError(tr("The selected video file extension does not match "
"the selected format."));
return;
}
if(oTargetFileInfo.isDir()) {
showError(tr("The selected output path is a directory."));
return;
}
if(!QDir(oTargetFileInfo.absolutePath()).exists()) {
showError(tr("The selected output directory does not exist."));
return;
}
setTargetFilePath(sTargetPath);
if(oTargetFileInfo.exists() &&
QMessageBox::question(
this, tr("Export Animation"),
tr("The selected file already exists. Replace it?"),
QMessageBox::Yes | QMessageBox::No,
QMessageBox::No) != QMessageBox::Yes) {
return;
}
m_oAcceptedSettings = oSettings;
m_sAcceptedTargetFilePath = sTargetPath;
accept();
}
void nmWxPebiResultAnimationExportDlg::createUi()
{
setWindowTitle(tr("Export Animation"));
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
setMinimumWidth(460);
QVBoxLayout* pMainLayout = new QVBoxLayout(this);
pMainLayout->setContentsMargins(12, 10, 12, 10);
pMainLayout->setSpacing(8);
QGroupBox* pFrameGroup = new QGroupBox(tr("Frame Settings"), this);
QGridLayout* pFrameGrid = new QGridLayout(pFrameGroup);
pFrameGrid->setHorizontalSpacing(8);
pFrameGrid->setVerticalSpacing(6);
pFrameGrid->setColumnStretch(1, 1);
const QSizePolicy oFieldSizePolicy(
QSizePolicy::Expanding, QSizePolicy::Fixed);
m_pFpsSpinBox = new QSpinBox(pFrameGroup);
m_pFpsSpinBox->setRange(1, 5000);
m_pFpsSpinBox->setValue(15);
m_pFpsSpinBox->setSuffix(tr(" FPS"));
m_pFpsSpinBox->setSizePolicy(oFieldSizePolicy);
pFrameGrid->addWidget(
createRightAlignedLabel(tr("Frame rate"), pFrameGroup), 0, 0);
pFrameGrid->addWidget(m_pFpsSpinBox, 0, 1);
m_pStartFrameCombo = new QComboBox(pFrameGroup);
m_pStartFrameCombo->setSizePolicy(oFieldSizePolicy);
pFrameGrid->addWidget(
createRightAlignedLabel(tr("Start time"), pFrameGroup), 1, 0);
pFrameGrid->addWidget(m_pStartFrameCombo, 1, 1);
m_pEndFrameCombo = new QComboBox(pFrameGroup);
m_pEndFrameCombo->setSizePolicy(oFieldSizePolicy);
pFrameGrid->addWidget(
createRightAlignedLabel(tr("End time"), pFrameGroup), 2, 0);
pFrameGrid->addWidget(m_pEndFrameCombo, 2, 1);
m_pSamplingIntervalSpinBox = new QSpinBox(pFrameGroup);
m_pSamplingIntervalSpinBox->setRange(1, 1);
m_pSamplingIntervalSpinBox->setSizePolicy(oFieldSizePolicy);
pFrameGrid->addWidget(
createRightAlignedLabel(tr("Frame step"), pFrameGroup), 3, 0);
pFrameGrid->addWidget(m_pSamplingIntervalSpinBox, 3, 1);
pMainLayout->addWidget(pFrameGroup);
QGroupBox* pOutputSizeGroup = new QGroupBox(tr("Output Size"), this);
QGridLayout* pOutputSizeGrid = new QGridLayout(pOutputSizeGroup);
pOutputSizeGrid->setHorizontalSpacing(6);
pOutputSizeGrid->setVerticalSpacing(6);
m_pResolutionButtonGroup = new QButtonGroup(this);
m_pCurrentSizeRadioButton = new QRadioButton(
tr("Current image size") + QString::fromLatin1(" ") +
formatPixelSize(m_oEffectiveCurrentViewportSize.width(),
m_oEffectiveCurrentViewportSize.height()),
pOutputSizeGroup);
m_p720pRadioButton = new QRadioButton(
formatPixelSize(1280, 720), pOutputSizeGroup);
m_p1080pRadioButton = new QRadioButton(
formatPixelSize(1920, 1080), pOutputSizeGroup);
m_pCustomSizeRadioButton = new QRadioButton(
tr("Custom size"), pOutputSizeGroup);
m_pResolutionButtonGroup->addButton(
m_pCurrentSizeRadioButton, Resolution_CurrentView);
m_pResolutionButtonGroup->addButton(
m_p720pRadioButton, Resolution_720p);
m_pResolutionButtonGroup->addButton(
m_p1080pRadioButton, Resolution_1080p);
m_pResolutionButtonGroup->addButton(
m_pCustomSizeRadioButton, Resolution_Custom);
m_pCurrentSizeRadioButton->setChecked(true);
pOutputSizeGrid->addWidget(
m_pCurrentSizeRadioButton, 0, 1, 1, 5, Qt::AlignLeft);
pOutputSizeGrid->addWidget(
m_p720pRadioButton, 1, 1, 1, 5, Qt::AlignLeft);
pOutputSizeGrid->addWidget(
m_p1080pRadioButton, 2, 1, 1, 5, Qt::AlignLeft);
pOutputSizeGrid->addWidget(m_pCustomSizeRadioButton, 3, 1, Qt::AlignLeft);
m_pWidthSpinBox = new QSpinBox(pOutputSizeGroup);
m_pHeightSpinBox = new QSpinBox(pOutputSizeGroup);
m_pWidthSpinBox->setRange(2, 8192);
m_pHeightSpinBox->setRange(2, 8192);
m_pWidthSpinBox->setSingleStep(2);
m_pHeightSpinBox->setSingleStep(2);
m_pWidthSpinBox->setMinimumWidth(90);
m_pWidthSpinBox->setMaximumWidth(110);
m_pHeightSpinBox->setMinimumWidth(90);
m_pHeightSpinBox->setMaximumWidth(110);
m_pWidthSpinBox->setValue(m_oEffectiveCurrentViewportSize.width());
m_pHeightSpinBox->setValue(m_oEffectiveCurrentViewportSize.height());
QLabel* pMultiplyLabel = new QLabel(
QString(QChar(0x00D7)), pOutputSizeGroup);
pMultiplyLabel->setAlignment(Qt::AlignCenter);
QLabel* pPixelLabel = new QLabel(
QString::fromLatin1("px"), pOutputSizeGroup);
pOutputSizeGrid->addWidget(m_pWidthSpinBox, 3, 2);
pOutputSizeGrid->addWidget(pMultiplyLabel, 3, 3, Qt::AlignCenter);
pOutputSizeGrid->addWidget(m_pHeightSpinBox, 3, 4);
pOutputSizeGrid->addWidget(pPixelLabel, 3, 5, Qt::AlignLeft);
// 两侧等权留白使完整尺寸选项块居中,块内控件仍保持左对齐。
pOutputSizeGrid->setColumnStretch(0, 1);
pOutputSizeGrid->setColumnStretch(6, 1);
pMainLayout->addWidget(pOutputSizeGroup);
QGroupBox* pOutputFileGroup = new QGroupBox(
tr("Output File"), this);
QGridLayout* pOutputFileGrid = new QGridLayout(pOutputFileGroup);
pOutputFileGrid->setHorizontalSpacing(8);
pOutputFileGrid->setVerticalSpacing(6);
pOutputFileGrid->setColumnStretch(1, 1);
m_pVideoFormatCombo = new QComboBox(pOutputFileGroup);
m_pVideoFormatCombo->setSizePolicy(oFieldSizePolicy);
pOutputFileGrid->addWidget(
createRightAlignedLabel(
tr("File format"), pOutputFileGroup), 0, 0);
pOutputFileGrid->addWidget(m_pVideoFormatCombo, 0, 1, 1, 2);
m_pTargetPathEdit = new QLineEdit(pOutputFileGroup);
m_pTargetPathEdit->setReadOnly(true);
m_pTargetPathEdit->setSizePolicy(oFieldSizePolicy);
QPushButton* pBrowseButton = new QPushButton(
tr("Browse..."), pOutputFileGroup);
pBrowseButton->setMinimumWidth(72);
pOutputFileGrid->addWidget(
createRightAlignedLabel(
tr("Save location"), pOutputFileGroup), 1, 0);
pOutputFileGrid->addWidget(m_pTargetPathEdit, 1, 1);
pOutputFileGrid->addWidget(pBrowseButton, 1, 2);
pMainLayout->addWidget(pOutputFileGroup);
QGroupBox* pInformationGroup = new QGroupBox(
tr("Export Information"), this);
QGridLayout* pInformationGrid = new QGridLayout(pInformationGroup);
pInformationGrid->setHorizontalSpacing(8);
pInformationGrid->setVerticalSpacing(6);
m_pOutputFrameCountLabel = new QLabel(pInformationGroup);
m_pEstimatedDurationLabel = new QLabel(pInformationGroup);
m_pOutputFrameCountLabel->setTextInteractionFlags(
Qt::TextSelectableByMouse);
m_pEstimatedDurationLabel->setTextInteractionFlags(
Qt::TextSelectableByMouse);
pInformationGrid->addWidget(
createRightAlignedLabel(
tr("Output frames"), pInformationGroup), 0, 1);
pInformationGrid->addWidget(
m_pOutputFrameCountLabel, 0, 2, Qt::AlignLeft);
pInformationGrid->addWidget(
createRightAlignedLabel(
tr("Estimated duration"), pInformationGroup), 1, 1);
pInformationGrid->addWidget(
m_pEstimatedDurationLabel, 1, 2, Qt::AlignLeft);
// 标签列和数值列作为一个整体居中,保留内部左右对齐关系。
pInformationGrid->setColumnStretch(0, 1);
pInformationGrid->setColumnStretch(3, 1);
pMainLayout->addWidget(pInformationGroup);
m_pErrorLabel = new QLabel(this);
m_pErrorLabel->setStyleSheet("QLabel { color: #a32626; }");
m_pErrorLabel->setWordWrap(true);
m_pErrorLabel->hide();
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, 0, Qt::AlignRight);
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_pResolutionButtonGroup, SIGNAL(buttonClicked(int)),
this, SLOT(onResolutionPresetChanged(int)));
connect(m_pVideoFormatCombo, SIGNAL(currentIndexChanged(int)),
this, SLOT(onVideoFormatChanged(int)));
connect(pBrowseButton, SIGNAL(clicked()),
this, SLOT(browseTargetFile()));
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);
}
}
void nmWxPebiResultAnimationExportDlg::populateVideoFormats()
{
// itemData只保存稳定扩展名,界面翻译不会参与格式识别。
m_pVideoFormatCombo->addItem(
tr("MP4 Video (*.mp4)"), QString::fromLatin1("mp4"));
m_pVideoFormatCombo->addItem(
tr("AVI Video (*.avi)"), QString::fromLatin1("avi"));
m_pVideoFormatCombo->addItem(
tr("QuickTime Video (*.mov)"), QString::fromLatin1("mov"));
m_pVideoFormatCombo->addItem(
tr("MPEG Video (*.mpg)"), QString::fromLatin1("mpg"));
m_pVideoFormatCombo->addItem(
tr("WebM Video (*.webm)"), QString::fromLatin1("webm"));
m_pVideoFormatCombo->addItem(
tr("Matroska Video (*.mkv)"), QString::fromLatin1("mkv"));
m_pVideoFormatCombo->addItem(
tr("Windows Media Video (*.wmv)"), QString::fromLatin1("wmv"));
m_pVideoFormatCombo->addItem(
tr("Flash Video (*.flv)"), QString::fromLatin1("flv"));
m_pVideoFormatCombo->setCurrentIndex(0);
}
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();
const QSize oOutputSize = getSelectedOutputSize();
oSettings.m_nOutputWidth = oOutputSize.width();
oSettings.m_nOutputHeight = oOutputSize.height();
return oSettings;
}
QSize nmWxPebiResultAnimationExportDlg::getSelectedOutputSize() const
{
const int nPresetId = m_pResolutionButtonGroup == nullptr
? Resolution_CurrentView :
m_pResolutionButtonGroup->checkedId();
if(nPresetId == Resolution_720p) {
return QSize(1280, 720);
}
if(nPresetId == Resolution_1080p) {
return QSize(1920, 1080);
}
if(nPresetId == Resolution_Custom) {
return QSize(
normalizeEvenDimension(m_pWidthSpinBox->value()),
normalizeEvenDimension(m_pHeightSpinBox->value()));
}
return m_oEffectiveCurrentViewportSize;
}
QString nmWxPebiResultAnimationExportDlg::getSelectedVideoExtension() const
{
if(m_pVideoFormatCombo == nullptr ||
m_pVideoFormatCombo->currentIndex() < 0) {
return QString();
}
const QString sExtension = m_pVideoFormatCombo->itemData(
m_pVideoFormatCombo->currentIndex()).toString().toLower();
return nmFFmpegVideoWriter::isSupportedExtension(sExtension)
? sExtension : QString();
}
QString nmWxPebiResultAnimationExportDlg::getSelectedVideoFilter() const
{
return m_pVideoFormatCombo == nullptr
? QString() : m_pVideoFormatCombo->currentText();
}
QString nmWxPebiResultAnimationExportDlg::normalizeTargetFilePath(
const QString& sPath) const
{
const QString sExtension = getSelectedVideoExtension();
if(sPath.isEmpty() || sExtension.isEmpty()) {
return QString();
}
QString sNormalizedPath = QDir::fromNativeSeparators(sPath);
const QString sExistingExtension =
QFileInfo(sNormalizedPath).suffix().toLower();
if(sExistingExtension.isEmpty()) {
if(!sNormalizedPath.endsWith('.')) {
sNormalizedPath.append('.');
}
sNormalizedPath.append(sExtension);
} else if(nmFFmpegVideoWriter::isSupportedExtension(
sExistingExtension)) {
sNormalizedPath.chop(sExistingExtension.length());
sNormalizedPath.append(sExtension);
} else {
sNormalizedPath.append(
QString::fromLatin1(".%1").arg(sExtension));
}
return QDir::cleanPath(sNormalizedPath);
}
QString nmWxPebiResultAnimationExportDlg::getSuggestedTargetFilePath() const
{
QString sDirectory = ZxBaseUtil::getLastDir();
if(sDirectory.isEmpty() || !QDir(sDirectory).exists()) {
sDirectory = QDir::homePath();
}
return QDir(sDirectory).absoluteFilePath(
QString::fromLatin1("PEBI-result.%1").arg(
getSelectedVideoExtension()));
}
void nmWxPebiResultAnimationExportDlg::setTargetFilePath(
const QString& sPath)
{
const QString sDisplayPath = QDir::toNativeSeparators(sPath);
m_pTargetPathEdit->setText(sDisplayPath);
m_pTargetPathEdit->setToolTip(sDisplayPath);
}
void nmWxPebiResultAnimationExportDlg::showError(const QString& sError)
{
m_pErrorLabel->setText(sError);
m_pErrorLabel->show();
}
void nmWxPebiResultAnimationExportDlg::clearError()
{
m_pErrorLabel->clear();
m_pErrorLabel->hide();
}
int nmWxPebiResultAnimationExportDlg::normalizeEvenDimension(int nValue)
{
nValue = qBound(2, nValue, 8192);
if((nValue % 2) != 0) {
++nValue;
}
return qMin(nValue, 8192);
}