diff --git a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkMovieMakerView.cpp b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkMovieMakerView.cpp index d9be01a646..2226e032cc 100644 --- a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkMovieMakerView.cpp +++ b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkMovieMakerView.cpp @@ -1,686 +1,657 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ -#include "QmitkAnimationItemDelegate.h" -#include "QmitkFFmpegWriter.h" #include "QmitkMovieMakerView.h" +#include + +#include "QmitkAnimationItemDelegate.h" #include "QmitkOrbitAnimationItem.h" #include "QmitkOrbitAnimationWidget.h" #include "QmitkSliceAnimationItem.h" #include "QmitkSliceAnimationWidget.h" -#include "QmitkTimeSliceAnimationWidget.h" #include "QmitkTimeSliceAnimationItem.h" -#include -#include -#include -#include -#include -#include +#include "QmitkTimeSliceAnimationWidget.h" + #include -#include -#include -static QmitkAnimationItem* CreateDefaultAnimation(const QString& widgetKey) -{ - if (widgetKey == "Orbit") - return new QmitkOrbitAnimationItem; +#include - if (widgetKey == "Slice") - return new QmitkSliceAnimationItem; +#include - if (widgetKey == "Time") - return new QmitkTimeSliceAnimationItem; +#include +#include +#include +#include - return nullptr; -} +#include -QString QmitkMovieMakerView::GetFFmpegPath() const +namespace { - berry::IPreferences::Pointer preferences = berry::Platform::GetPreferencesService()->GetSystemPreferences()->Node("/org.mitk.gui.qt.ext.externalprograms"); + QmitkAnimationItem* CreateDefaultAnimation(const QString& widgetKey) + { + if (widgetKey == "Orbit") + return new QmitkOrbitAnimationItem; - return preferences.IsNotNull() - ? preferences->Get("ffmpeg", "") - : ""; -} + if (widgetKey == "Slice") + return new QmitkSliceAnimationItem; + + if (widgetKey == "Time") + return new QmitkTimeSliceAnimationItem; -static unsigned char* ReadPixels(vtkRenderWindow* renderWindow, int x, int y, int width, int height) -{ - if (renderWindow == nullptr) return nullptr; + } - unsigned char* frame = new unsigned char[width * height * 3]; + QString GetFFmpegPath() + { + auto preferences = berry::Platform::GetPreferencesService()->GetSystemPreferences()->Node("/org.mitk.gui.qt.ext.externalprograms"); + + return preferences.IsNotNull() + ? preferences->Get("ffmpeg", "") + : ""; + } - renderWindow->MakeCurrent(); - glReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, frame); + void ReadPixels(std::unique_ptr& frame, vtkRenderWindow* renderWindow, int x, int y, int width, int height) + { + if (nullptr == renderWindow) + return; - return frame; + renderWindow->MakeCurrent(); + glReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, frame.get()); + } } const std::string QmitkMovieMakerView::VIEW_ID = "org.mitk.views.moviemaker"; QmitkMovieMakerView::QmitkMovieMakerView() : m_FFmpegWriter(nullptr), m_Ui(new Ui::QmitkMovieMakerView), m_AnimationModel(nullptr), m_AddAnimationMenu(nullptr), m_RecordMenu(nullptr), m_Timer(nullptr), m_TotalDuration(0.0), m_NumFrames(0), m_CurrentFrame(0) { } QmitkMovieMakerView::~QmitkMovieMakerView() { } void QmitkMovieMakerView::CreateQtPartControl(QWidget* parent) { m_FFmpegWriter = new QmitkFFmpegWriter(parent); m_Ui->setupUi(parent); this->InitializeAnimationWidgets(); this->InitializeAnimationTreeViewWidgets(); this->InitializePlaybackAndRecordWidgets(); this->InitializeTimer(parent); m_Ui->animationWidgetGroupBox->setVisible(false); } void QmitkMovieMakerView::InitializeAnimationWidgets() { m_AnimationWidgets["Orbit"] = new QmitkOrbitAnimationWidget; m_AnimationWidgets["Slice"] = new QmitkSliceAnimationWidget; m_AnimationWidgets["Time"] = new QmitkTimeSliceAnimationWidget; - Q_FOREACH(QWidget* widget, m_AnimationWidgets.values()) + for (const auto& widget : m_AnimationWidgets) { - if (widget != nullptr) + if (nullptr != widget.second) { - widget->setVisible(false); - m_Ui->animationWidgetGroupBoxLayout->addWidget(widget); + widget.second->setVisible(false); + m_Ui->animationWidgetGroupBoxLayout->addWidget(widget.second); } } this->ConnectAnimationWidgets(); } void QmitkMovieMakerView::InitializeAnimationTreeViewWidgets() { this->InitializeAnimationModel(); this->InitializeAddAnimationMenu(); this->ConnectAnimationTreeViewWidgets(); } void QmitkMovieMakerView::InitializePlaybackAndRecordWidgets() { this->InitializeRecordMenu(); this->ConnectPlaybackAndRecordWidgets(); } void QmitkMovieMakerView::InitializeAnimationModel() { m_AnimationModel = new QStandardItemModel(m_Ui->animationTreeView); m_AnimationModel->setHorizontalHeaderLabels(QStringList() << "Animation" << "Timeline"); - m_Ui->animationTreeView->setModel(m_AnimationModel); + m_Ui->animationTreeView->setModel(m_AnimationModel); m_Ui->animationTreeView->setItemDelegate(new QmitkAnimationItemDelegate(m_Ui->animationTreeView)); } void QmitkMovieMakerView::InitializeAddAnimationMenu() { m_AddAnimationMenu = new QMenu(m_Ui->addAnimationButton); - Q_FOREACH(const QString& key, m_AnimationWidgets.keys()) - { - m_AddAnimationMenu->addAction(key); - } + for(const auto& widget : m_AnimationWidgets) + m_AddAnimationMenu->addAction(widget.first); } void QmitkMovieMakerView::InitializeRecordMenu() { - typedef QPair PairOfStrings; + std::array, 4> renderWindows = { + std::make_pair(QStringLiteral("Axial"), QStringLiteral("stdmulti.widget0")), + std::make_pair(QStringLiteral("Sagittal"), QStringLiteral("stdmulti.widget1")), + std::make_pair(QStringLiteral("Coronal"), QStringLiteral("stdmulti.widget2")), + std::make_pair(QStringLiteral("3D"), QStringLiteral("stdmulti.widget3")) + }; m_RecordMenu = new QMenu(m_Ui->recordButton); - QVector renderWindows; - renderWindows.push_back(qMakePair(QString("Axial"), QString("stdmulti.widget0"))); - renderWindows.push_back(qMakePair(QString("Sagittal"), QString("stdmulti.widget1"))); - renderWindows.push_back(qMakePair(QString("Coronal"), QString("stdmulti.widget2"))); - renderWindows.push_back(qMakePair(QString("3D"), QString("stdmulti.widget3"))); - - Q_FOREACH(const PairOfStrings& renderWindow, renderWindows) + for(const auto& renderWindow : renderWindows) { - QAction* action = new QAction(m_RecordMenu); + auto* action = new QAction(m_RecordMenu); action->setText(renderWindow.first); action->setData(renderWindow.second); m_RecordMenu->addAction(action); } } void QmitkMovieMakerView::InitializeTimer(QWidget* parent) { m_Timer = new QTimer(parent); this->OnFPSSpinBoxValueChanged(m_Ui->fpsSpinBox->value()); this->ConnectTimer(); } void QmitkMovieMakerView::ConnectAnimationTreeViewWidgets() { - this->connect(m_AnimationModel, SIGNAL(rowsInserted(const QModelIndex&, int, int)), - this, SLOT(OnAnimationTreeViewRowsInserted(const QModelIndex&, int, int))); - - this->connect(m_AnimationModel, SIGNAL(rowsRemoved(const QModelIndex&, int, int)), - this, SLOT(OnAnimationTreeViewRowsRemoved(const QModelIndex&, int, int))); - - this->connect(m_Ui->animationTreeView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), - this, SLOT(OnAnimationTreeViewSelectionChanged(const QItemSelection&, const QItemSelection&))); - - this->connect(m_Ui->moveAnimationUpButton, SIGNAL(clicked()), - this, SLOT(OnMoveAnimationUpButtonClicked())); - - this->connect(m_Ui->moveAnimationDownButton, SIGNAL(clicked()), - this, SLOT(OnMoveAnimationDownButtonClicked())); - - this->connect(m_Ui->addAnimationButton, SIGNAL(clicked()), - this, SLOT(OnAddAnimationButtonClicked())); - - this->connect(m_Ui->removeAnimationButton, SIGNAL(clicked()), - this, SLOT(OnRemoveAnimationButtonClicked())); + connect(m_AnimationModel, &QStandardItemModel::rowsInserted, this, &QmitkMovieMakerView::OnAnimationTreeViewRowsInserted); + connect(m_AnimationModel, &QStandardItemModel::rowsRemoved, this, &QmitkMovieMakerView::OnAnimationTreeViewRowsRemoved); + connect(m_Ui->animationTreeView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QmitkMovieMakerView::OnAnimationTreeViewSelectionChanged); + connect(m_Ui->moveAnimationUpButton, &QToolButton::clicked, this, &QmitkMovieMakerView::OnMoveAnimationUpButtonClicked); + connect(m_Ui->moveAnimationDownButton, &QToolButton::clicked, this, &QmitkMovieMakerView::OnMoveAnimationDownButtonClicked); + connect(m_Ui->addAnimationButton, &QToolButton::clicked, this, &QmitkMovieMakerView::OnAddAnimationButtonClicked); + connect(m_Ui->removeAnimationButton, &QToolButton::clicked, this, &QmitkMovieMakerView::OnRemoveAnimationButtonClicked); } void QmitkMovieMakerView::ConnectAnimationWidgets() { - this->connect(m_Ui->startComboBox, SIGNAL(currentIndexChanged(int)), - this, SLOT(OnStartComboBoxCurrentIndexChanged(int))); - - this->connect(m_Ui->durationSpinBox, SIGNAL(valueChanged(double)), - this, SLOT(OnDurationSpinBoxValueChanged(double))); - - this->connect(m_Ui->delaySpinBox, SIGNAL(valueChanged(double)), - this, SLOT(OnDelaySpinBoxValueChanged(double))); + connect(m_Ui->startComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnStartComboBoxCurrentIndexChanged(int))); + connect(m_Ui->durationSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnDurationSpinBoxValueChanged(double))); + connect(m_Ui->delaySpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnDelaySpinBoxValueChanged(double))); } void QmitkMovieMakerView::ConnectPlaybackAndRecordWidgets() { - this->connect(m_Ui->playButton, SIGNAL(toggled(bool)), - this, SLOT(OnPlayButtonToggled(bool))); - - this->connect(m_Ui->stopButton, SIGNAL(clicked()), - this, SLOT(OnStopButtonClicked())); - - this->connect(m_Ui->recordButton, SIGNAL(clicked()), - this, SLOT(OnRecordButtonClicked())); - - this->connect(m_Ui->fpsSpinBox, SIGNAL(valueChanged(int)), - this, SLOT(OnFPSSpinBoxValueChanged(int))); + connect(m_Ui->playButton, &QToolButton::toggled, this, &QmitkMovieMakerView::OnPlayButtonToggled); + connect(m_Ui->stopButton, &QToolButton::clicked, this, &QmitkMovieMakerView::OnStopButtonClicked); + connect(m_Ui->recordButton, &QToolButton::clicked, this, &QmitkMovieMakerView::OnRecordButtonClicked); + connect(m_Ui->fpsSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnFPSSpinBoxValueChanged(int))); } void QmitkMovieMakerView::ConnectTimer() { - this->connect(m_Timer, SIGNAL(timeout()), - this, SLOT(OnTimerTimeout())); + connect(m_Timer, &QTimer::timeout, this, &QmitkMovieMakerView::OnTimerTimeout); } void QmitkMovieMakerView::SetFocus() { m_Ui->addAnimationButton->setFocus(); } void QmitkMovieMakerView::OnMoveAnimationUpButtonClicked() { const QItemSelection selection = m_Ui->animationTreeView->selectionModel()->selection(); if (!selection.isEmpty()) { const int selectedRow = selection[0].top(); if (selectedRow > 0) m_AnimationModel->insertRow(selectedRow - 1, m_AnimationModel->takeRow(selectedRow)); } this->CalculateTotalDuration(); } void QmitkMovieMakerView::OnMoveAnimationDownButtonClicked() { const QItemSelection selection = m_Ui->animationTreeView->selectionModel()->selection(); if (!selection.isEmpty()) { const int rowCount = m_AnimationModel->rowCount(); const int selectedRow = selection[0].top(); if (selectedRow < rowCount - 1) m_AnimationModel->insertRow(selectedRow + 1, m_AnimationModel->takeRow(selectedRow)); } this->CalculateTotalDuration(); } void QmitkMovieMakerView::OnAddAnimationButtonClicked() { - QAction* action = m_AddAnimationMenu->exec(QCursor::pos()); + auto action = m_AddAnimationMenu->exec(QCursor::pos()); - if (action != nullptr) + if (nullptr != action) { - const QString widgetKey = action->text(); + const auto key = action->text(); m_AnimationModel->appendRow(QList() - << new QStandardItem(widgetKey) - << CreateDefaultAnimation(widgetKey)); + << new QStandardItem(key) + << CreateDefaultAnimation(key)); m_Ui->playbackAndRecordingGroupBox->setEnabled(true); } } void QmitkMovieMakerView::OnPlayButtonToggled(bool checked) { if (checked) { m_Ui->playButton->setIcon(QIcon(":/org_mitk_icons/icons/tango/scalable/actions/media-playback-pause.svg")); m_Ui->playButton->repaint(); m_Timer->start(static_cast(1000.0 / m_Ui->fpsSpinBox->value())); } else { m_Timer->stop(); m_Ui->playButton->setIcon(QIcon(":/org_mitk_icons/icons/tango/scalable/actions/media-playback-start.svg")); m_Ui->playButton->repaint(); } } void QmitkMovieMakerView::OnStopButtonClicked() { m_Ui->playButton->setChecked(false); m_Ui->stopButton->setEnabled(false); m_CurrentFrame = 0; this->RenderCurrentFrame(); } -void QmitkMovieMakerView::OnRecordButtonClicked() // TODO: Refactor +void QmitkMovieMakerView::OnRecordButtonClicked() { + if (0 == m_NumFrames || 0.0 == m_TotalDuration) + return; + const QString ffmpegPath = GetFFmpegPath(); if (ffmpegPath.isEmpty()) { QMessageBox::information(nullptr, "Movie Maker", - "

Set path to FFmpeg1 or Libav2 (avconv) in preferences (Window -> Preferences... (Ctrl+P) -> External Programs) to be able to record your movies to video files.

" - "

If you are using Linux, chances are good that either FFmpeg or Libav is included in the official package repositories.

" - "

[1] Download FFmpeg from ffmpeg.org
" - "[2] Download Libav from libav.org

"); + "

Set path to FFmpeg (ffmpeg.org) in preferences " + "(Window -> Preferences... (Ctrl+P) -> External Programs) " + "to be able to record your movies to video files.

"); return; } m_FFmpegWriter->SetFFmpegPath(GetFFmpegPath()); - QAction* action = m_RecordMenu->exec(QCursor::pos()); + auto action = m_RecordMenu->exec(QCursor::pos()); - if (action == nullptr) + if (nullptr == action) return; - vtkRenderWindow* renderWindow = mitk::BaseRenderer::GetRenderWindowByName(action->data().toString().toStdString()); + auto renderWindow = mitk::BaseRenderer::GetRenderWindowByName(action->data().toString().toStdString()); - if (renderWindow == nullptr) + if (nullptr == renderWindow) return; const int border = 3; const int x = border; const int y = border; int width = renderWindow->GetSize()[0] - border * 2; int height = renderWindow->GetSize()[1] - border * 2; if (width & 1) --width; if (height & 1) --height; if (width < 16 || height < 16) return; m_FFmpegWriter->SetSize(width, height); m_FFmpegWriter->SetFramerate(m_Ui->fpsSpinBox->value()); QString saveFileName = QFileDialog::getSaveFileName(nullptr, "Specify a filename", "", "Movie (*.mp4)"); if (saveFileName.isEmpty()) return; if(!saveFileName.endsWith(".mp4")) saveFileName += ".mp4"; m_FFmpegWriter->SetOutputPath(saveFileName); try { + auto frame = std::make_unique(width * height * 3); m_FFmpegWriter->Start(); for (m_CurrentFrame = 0; m_CurrentFrame < m_NumFrames; ++m_CurrentFrame) { this->RenderCurrentFrame(); - - renderWindow->MakeCurrent(); - unsigned char* frame = ReadPixels(renderWindow, x, y, width, height); - m_FFmpegWriter->WriteFrame(frame); - delete[] frame; + ReadPixels(frame, renderWindow, x, y, width, height); + m_FFmpegWriter->WriteFrame(frame.get()); } m_FFmpegWriter->Stop(); m_CurrentFrame = 0; this->RenderCurrentFrame(); } catch (const mitk::Exception& exception) { m_CurrentFrame = 0; this->RenderCurrentFrame(); QMessageBox::critical(nullptr, "Movie Maker", exception.GetDescription()); } } void QmitkMovieMakerView::OnRemoveAnimationButtonClicked() { const QItemSelection selection = m_Ui->animationTreeView->selectionModel()->selection(); if (!selection.isEmpty()) m_AnimationModel->removeRow(selection[0].top()); } void QmitkMovieMakerView::OnAnimationTreeViewRowsInserted(const QModelIndex& parent, int start, int) { this->CalculateTotalDuration(); m_Ui->animationTreeView->selectionModel()->select( m_AnimationModel->index(start, 0, parent), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); } void QmitkMovieMakerView::OnAnimationTreeViewRowsRemoved(const QModelIndex&, int, int) { this->CalculateTotalDuration(); this->UpdateWidgets(); } void QmitkMovieMakerView::OnAnimationTreeViewSelectionChanged(const QItemSelection&, const QItemSelection&) { this->UpdateWidgets(); } void QmitkMovieMakerView::OnStartComboBoxCurrentIndexChanged(int index) { QmitkAnimationItem* item = this->GetSelectedAnimationItem(); if (item != nullptr) { item->SetStartWithPrevious(index); this->RedrawTimeline(); this->CalculateTotalDuration(); } } void QmitkMovieMakerView::OnDurationSpinBoxValueChanged(double value) { QmitkAnimationItem* item = this->GetSelectedAnimationItem(); if (item != nullptr) { item->SetDuration(value); this->RedrawTimeline(); this->CalculateTotalDuration(); } } void QmitkMovieMakerView::OnDelaySpinBoxValueChanged(double value) { QmitkAnimationItem* item = this->GetSelectedAnimationItem(); if (item != nullptr) { item->SetDelay(value); this->RedrawTimeline(); this->CalculateTotalDuration(); } } void QmitkMovieMakerView::OnFPSSpinBoxValueChanged(int value) { this->CalculateTotalDuration(); m_Timer->setInterval(static_cast(1000.0 / value)); } void QmitkMovieMakerView::OnTimerTimeout() { this->RenderCurrentFrame(); m_CurrentFrame = std::min(m_NumFrames, m_CurrentFrame + 1); if (m_CurrentFrame >= m_NumFrames) { m_Ui->playButton->setChecked(false); m_CurrentFrame = 0; this->RenderCurrentFrame(); } m_Ui->stopButton->setEnabled(m_CurrentFrame != 0); } void QmitkMovieMakerView::RenderCurrentFrame() { - typedef QPair AnimationInterpolationFactorPair; - const double deltaT = m_TotalDuration / (m_NumFrames - 1); - const QVector activeAnimations = this->GetActiveAnimations(m_CurrentFrame * deltaT); + const auto activeAnimations = this->GetActiveAnimations(m_CurrentFrame * deltaT); - Q_FOREACH(const AnimationInterpolationFactorPair& animation, activeAnimations) + for (const auto& animation : activeAnimations) { - const QVector nextActiveAnimations = this->GetActiveAnimations((m_CurrentFrame + 1) * deltaT); + const auto nextActiveAnimations = this->GetActiveAnimations((m_CurrentFrame + 1) * deltaT); bool lastFrameForAnimation = true; - Q_FOREACH(const AnimationInterpolationFactorPair& nextAnimation, nextActiveAnimations) + for (const auto& nextAnimation : nextActiveAnimations) { if (nextAnimation.first == animation.first) { lastFrameForAnimation = false; break; } } animation.first->Animate(!lastFrameForAnimation ? animation.second : 1.0); } mitk::RenderingManager::GetInstance()->ForceImmediateUpdateAll(); } void QmitkMovieMakerView::UpdateWidgets() { const QItemSelection selection = m_Ui->animationTreeView->selectionModel()->selection(); if (selection.isEmpty()) { m_Ui->moveAnimationUpButton->setEnabled(false); m_Ui->moveAnimationDownButton->setEnabled(false); m_Ui->removeAnimationButton->setEnabled(false); m_Ui->playbackAndRecordingGroupBox->setEnabled(false); this->HideCurrentAnimationWidget(); } else { const int rowCount = m_AnimationModel->rowCount(); const int selectedRow = selection[0].top(); m_Ui->moveAnimationUpButton->setEnabled(rowCount > 1 && selectedRow != 0); m_Ui->moveAnimationDownButton->setEnabled(rowCount > 1 && selectedRow < rowCount - 1); m_Ui->removeAnimationButton->setEnabled(true); m_Ui->playbackAndRecordingGroupBox->setEnabled(true); this->ShowAnimationWidget(dynamic_cast(m_AnimationModel->item(selectedRow, 1))); } this->UpdateAnimationWidgets(); } void QmitkMovieMakerView::UpdateAnimationWidgets() { QmitkAnimationItem* item = this->GetSelectedAnimationItem(); if (item != nullptr) { m_Ui->startComboBox->setCurrentIndex(item->GetStartWithPrevious()); m_Ui->durationSpinBox->setValue(item->GetDuration()); m_Ui->delaySpinBox->setValue(item->GetDelay()); m_Ui->animationGroupBox->setEnabled(true); } else { m_Ui->animationGroupBox->setEnabled(false); } } void QmitkMovieMakerView::HideCurrentAnimationWidget() { if (m_Ui->animationWidgetGroupBox->isVisible()) { m_Ui->animationWidgetGroupBox->setVisible(false); int numWidgets = m_Ui->animationWidgetGroupBoxLayout->count(); for (int i = 0; i < numWidgets; ++i) m_Ui->animationWidgetGroupBoxLayout->itemAt(i)->widget()->setVisible(false); } } void QmitkMovieMakerView::ShowAnimationWidget(QmitkAnimationItem* animationItem) { this->HideCurrentAnimationWidget(); if (animationItem == nullptr) return; const QString widgetKey = animationItem->GetWidgetKey(); - QmitkAnimationWidget* animationWidget = nullptr; + auto animationWidgetIter = m_AnimationWidgets.find(widgetKey); + auto animationWidget = m_AnimationWidgets.end() != animationWidgetIter + ? animationWidgetIter->second + : nullptr; - if (m_AnimationWidgets.contains(widgetKey)) + if (nullptr != animationWidget) { - animationWidget = m_AnimationWidgets[widgetKey]; - - if (animationWidget != nullptr) - { - m_Ui->animationWidgetGroupBox->setTitle(widgetKey); - animationWidget->SetAnimationItem(animationItem); - animationWidget->setVisible(true); - } + m_Ui->animationWidgetGroupBox->setTitle(widgetKey); + animationWidget->SetAnimationItem(animationItem); + animationWidget->setVisible(true); } m_Ui->animationWidgetGroupBox->setVisible(animationWidget != nullptr); } void QmitkMovieMakerView::RedrawTimeline() { if (m_AnimationModel->rowCount() > 1) { m_Ui->animationTreeView->dataChanged( m_AnimationModel->index(0, 1), m_AnimationModel->index(m_AnimationModel->rowCount() - 1, 1)); } } QmitkAnimationItem* QmitkMovieMakerView::GetSelectedAnimationItem() const { const QItemSelection selection = m_Ui->animationTreeView->selectionModel()->selection(); return !selection.isEmpty() ? dynamic_cast(m_AnimationModel->item(selection[0].top(), 1)) : nullptr; } void QmitkMovieMakerView::CalculateTotalDuration() { const int rowCount = m_AnimationModel->rowCount(); double totalDuration = 0.0; double previousStart = 0.0; for (int i = 0; i < rowCount; ++i) { - QmitkAnimationItem* item = dynamic_cast(m_AnimationModel->item(i, 1)); + auto item = dynamic_cast(m_AnimationModel->item(i, 1)); - if (item == nullptr) + if (nullptr == item) continue; if (item->GetStartWithPrevious()) { totalDuration = std::max(totalDuration, previousStart + item->GetDelay() + item->GetDuration()); } else { previousStart = totalDuration; totalDuration += item->GetDelay() + item->GetDuration(); } } - m_TotalDuration = totalDuration; // TODO totalDuration == 0 - m_NumFrames = static_cast(totalDuration * m_Ui->fpsSpinBox->value()); // TODO numFrames < 2 + m_TotalDuration = totalDuration; + m_NumFrames = static_cast(totalDuration * m_Ui->fpsSpinBox->value()); } -QVector > QmitkMovieMakerView::GetActiveAnimations(double t) const +std::vector> QmitkMovieMakerView::GetActiveAnimations(double t) const { const int rowCount = m_AnimationModel->rowCount(); - QVector > activeAnimations; + std::vector> activeAnimations; double totalDuration = 0.0; double previousStart = 0.0; for (int i = 0; i < rowCount; ++i) { QmitkAnimationItem* item = dynamic_cast(m_AnimationModel->item(i, 1)); if (item == nullptr) continue; if (item->GetDuration() > 0.0) { double start = item->GetStartWithPrevious() ? previousStart + item->GetDelay() : totalDuration + item->GetDelay(); if (start <= t && t <= start + item->GetDuration()) - activeAnimations.push_back(qMakePair(item, (t - start) / item->GetDuration())); + activeAnimations.emplace_back(item, (t - start) / item->GetDuration()); } if (item->GetStartWithPrevious()) { totalDuration = std::max(totalDuration, previousStart + item->GetDelay() + item->GetDuration()); } else { previousStart = totalDuration; totalDuration += item->GetDelay() + item->GetDuration(); } } return activeAnimations; } diff --git a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkMovieMakerView.h b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkMovieMakerView.h index 92f30f13b5..85403bc857 100644 --- a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkMovieMakerView.h +++ b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkMovieMakerView.h @@ -1,96 +1,97 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef QmitkMovieMakerView_h #define QmitkMovieMakerView_h #include +#include +#include + class QmitkAnimationItem; class QmitkAnimationWidget; class QmitkFFmpegWriter; class QMenu; class QStandardItemModel; class QTimer; namespace Ui { class QmitkMovieMakerView; } class QmitkMovieMakerView : public QmitkAbstractView { Q_OBJECT public: static const std::string VIEW_ID; QmitkMovieMakerView(); ~QmitkMovieMakerView() override; void CreateQtPartControl(QWidget* parent) override; void SetFocus() override; private slots: void OnMoveAnimationUpButtonClicked(); void OnMoveAnimationDownButtonClicked(); void OnAddAnimationButtonClicked(); void OnRemoveAnimationButtonClicked(); void OnAnimationTreeViewRowsInserted(const QModelIndex& parent, int start, int end); void OnAnimationTreeViewRowsRemoved(const QModelIndex& parent, int start, int end); void OnAnimationTreeViewSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected); void OnStartComboBoxCurrentIndexChanged(int index); void OnDurationSpinBoxValueChanged(double value); void OnDelaySpinBoxValueChanged(double value); void OnPlayButtonToggled(bool checked); void OnStopButtonClicked(); void OnRecordButtonClicked(); void OnFPSSpinBoxValueChanged(int value); void OnTimerTimeout(); private: void InitializeAnimationWidgets(); void InitializeAnimationTreeViewWidgets(); void InitializeAnimationModel(); void InitializeAddAnimationMenu(); void InitializePlaybackAndRecordWidgets(); void InitializeRecordMenu(); void InitializeTimer(QWidget* parent); void ConnectAnimationTreeViewWidgets(); void ConnectAnimationWidgets(); void ConnectPlaybackAndRecordWidgets(); void ConnectTimer(); void RenderCurrentFrame(); void UpdateWidgets(); void UpdateAnimationWidgets(); void HideCurrentAnimationWidget(); void ShowAnimationWidget(QmitkAnimationItem* animationItem); void RedrawTimeline(); void CalculateTotalDuration(); QmitkAnimationItem* GetSelectedAnimationItem() const; - QVector > GetActiveAnimations(double t) const; - - QString GetFFmpegPath() const; + std::vector> GetActiveAnimations(double t) const; QmitkFFmpegWriter* m_FFmpegWriter; Ui::QmitkMovieMakerView* m_Ui; QStandardItemModel* m_AnimationModel; - QMap m_AnimationWidgets; + std::map m_AnimationWidgets; QMenu* m_AddAnimationMenu; QMenu* m_RecordMenu; QTimer* m_Timer; double m_TotalDuration; int m_NumFrames; int m_CurrentFrame; }; #endif diff --git a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkSliceAnimationWidget.cpp b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkSliceAnimationWidget.cpp index c8fba8bd0c..bca0c6de77 100644 --- a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkSliceAnimationWidget.cpp +++ b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkSliceAnimationWidget.cpp @@ -1,127 +1,127 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkSliceAnimationItem.h" #include "QmitkSliceAnimationWidget.h" #include #include -static int GetNumberOfSlices(int renderWindow) +namespace { - const QString renderWindowName = QString("stdmulti.widget%1").arg(renderWindow); - vtkRenderWindow* theRenderWindow = mitk::BaseRenderer::GetRenderWindowByName(renderWindowName.toStdString()); - - if (theRenderWindow != nullptr) + int GetNumberOfSlices(int renderWindow) { - mitk::Stepper* stepper = mitk::BaseRenderer::GetInstance(theRenderWindow)->GetSliceNavigationController()->GetSlice(); + const QString renderWindowName = QString("stdmulti.widget%1").arg(renderWindow); + vtkRenderWindow* theRenderWindow = mitk::BaseRenderer::GetRenderWindowByName(renderWindowName.toStdString()); - if (stepper != nullptr) - return std::max(1, static_cast(stepper->GetSteps())); - } + if (theRenderWindow != nullptr) + { + mitk::Stepper* stepper = mitk::BaseRenderer::GetInstance(theRenderWindow)->GetSliceNavigationController()->GetSlice(); - return 1; + if (stepper != nullptr) + return std::max(1, static_cast(stepper->GetSteps())); + } + + return 1; + } } QmitkSliceAnimationWidget::QmitkSliceAnimationWidget(QWidget* parent) : QmitkAnimationWidget(parent), - m_Ui(new Ui::QmitkSliceAnimationWidget) + m_Ui(new Ui::QmitkSliceAnimationWidget), + m_AnimationItem(nullptr) { m_Ui->setupUi(this); - this->connect(m_Ui->windowComboBox, SIGNAL(currentIndexChanged(int)), - this, SLOT(OnRenderWindowChanged(int))); - - this->connect(m_Ui->sliceRangeWidget, SIGNAL(minimumValueChanged(double)), - this, SLOT(OnFromChanged(double))); - - this->connect(m_Ui->sliceRangeWidget, SIGNAL(maximumValueChanged(double)), - this, SLOT(OnToChanged(double))); - - this->connect(m_Ui->reverseCheckBox, SIGNAL(clicked(bool)), - this, SLOT(OnReverseChanged(bool))); + connect(m_Ui->windowComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnRenderWindowChanged(int))); + connect(m_Ui->sliceRangeWidget, SIGNAL(minimumValueChanged(double)), this, SLOT(OnFromChanged(double))); + connect(m_Ui->sliceRangeWidget, SIGNAL(maximumValueChanged(double)), this, SLOT(OnToChanged(double))); + connect(m_Ui->reverseCheckBox, SIGNAL(clicked(bool)), this, SLOT(OnReverseChanged(bool))); } QmitkSliceAnimationWidget::~QmitkSliceAnimationWidget() { } void QmitkSliceAnimationWidget::SetAnimationItem(QmitkAnimationItem* sliceAnimationItem) { m_AnimationItem = dynamic_cast(sliceAnimationItem); - if (m_AnimationItem == nullptr) + if (nullptr == m_AnimationItem) return; m_Ui->windowComboBox->setCurrentIndex(m_AnimationItem->GetRenderWindow()); const int maximum = GetNumberOfSlices(m_AnimationItem->GetRenderWindow()) - 1; const int from = std::min(m_AnimationItem->GetFrom(), maximum); - const int to = std::min(m_AnimationItem->GetTo(), maximum); + int to = std::max(from, std::min(m_AnimationItem->GetTo(), maximum)); + + if (0 == to) + to = maximum; m_AnimationItem->SetFrom(from); m_AnimationItem->SetTo(to); m_Ui->sliceRangeWidget->setMaximum(maximum); m_Ui->sliceRangeWidget->setValues(from, to); m_Ui->reverseCheckBox->setChecked(m_AnimationItem->GetReverse()); } void QmitkSliceAnimationWidget::OnRenderWindowChanged(int renderWindow) { - if (m_AnimationItem == nullptr) + if (nullptr == m_AnimationItem) return; const int lastSlice = static_cast(GetNumberOfSlices(renderWindow) - 1); if (lastSlice < m_AnimationItem->GetFrom()) m_AnimationItem->SetFrom(lastSlice); if (lastSlice < m_AnimationItem->GetTo()) m_AnimationItem->SetTo(lastSlice); m_Ui->sliceRangeWidget->setMaximum(lastSlice); m_Ui->sliceRangeWidget->setValues(m_AnimationItem->GetFrom(), m_AnimationItem->GetTo()); if (m_AnimationItem->GetRenderWindow() != renderWindow) m_AnimationItem->SetRenderWindow(renderWindow); } void QmitkSliceAnimationWidget::OnFromChanged(double from) { - if (m_AnimationItem == nullptr) + if (nullptr == m_AnimationItem) return; int intFrom = static_cast(from); if (m_AnimationItem->GetFrom() != intFrom) m_AnimationItem->SetFrom(intFrom); } void QmitkSliceAnimationWidget::OnToChanged(double to) { - if (m_AnimationItem == nullptr) + if (nullptr == m_AnimationItem) return; int intTo = static_cast(to); if (m_AnimationItem->GetTo() != intTo) m_AnimationItem->SetTo(intTo); } void QmitkSliceAnimationWidget::OnReverseChanged(bool reverse) { - if (m_AnimationItem == nullptr) + if (nullptr == m_AnimationItem) return; if (m_AnimationItem->GetReverse() != reverse) m_AnimationItem->SetReverse(reverse); } diff --git a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkTimeSliceAnimationWidget.cpp b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkTimeSliceAnimationWidget.cpp index 2e45ee9b37..a5f2e52f7f 100644 --- a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkTimeSliceAnimationWidget.cpp +++ b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkTimeSliceAnimationWidget.cpp @@ -1,98 +1,99 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkTimeSliceAnimationItem.h" #include "QmitkTimeSliceAnimationWidget.h" #include #include #include #include -static int GetNumberOfSlices() +namespace { - mitk::Stepper* stepper = mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetTime(); + int GetNumberOfSlices() + { + mitk::Stepper* stepper = mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetTime(); - if (stepper != nullptr) - return std::max(1, static_cast(stepper->GetSteps())); + if (stepper != nullptr) + return std::max(1, static_cast(stepper->GetSteps())); - return 1; + return 1; + } } QmitkTimeSliceAnimationWidget::QmitkTimeSliceAnimationWidget(QWidget* parent) : QmitkAnimationWidget(parent), m_Ui(new Ui::QmitkTimeSliceAnimationWidget) { m_Ui->setupUi(this); - this->connect(m_Ui->sliceRangeWidget, SIGNAL(minimumValueChanged(double)), - this, SLOT(OnFromChanged(double))); - - this->connect(m_Ui->sliceRangeWidget, SIGNAL(maximumValueChanged(double)), - this, SLOT(OnToChanged(double))); - - this->connect(m_Ui->reverseCheckBox, SIGNAL(clicked(bool)), - this, SLOT(OnReverseChanged(bool))); + connect(m_Ui->sliceRangeWidget, SIGNAL(minimumValueChanged(double)), this, SLOT(OnFromChanged(double))); + connect(m_Ui->sliceRangeWidget, SIGNAL(maximumValueChanged(double)), this, SLOT(OnToChanged(double))); + connect(m_Ui->reverseCheckBox, SIGNAL(clicked(bool)), this, SLOT(OnReverseChanged(bool))); } QmitkTimeSliceAnimationWidget::~QmitkTimeSliceAnimationWidget() { } void QmitkTimeSliceAnimationWidget::SetAnimationItem(QmitkAnimationItem* sliceAnimationItem) { m_AnimationItem = dynamic_cast(sliceAnimationItem); - if (m_AnimationItem == nullptr) + if (nullptr == m_AnimationItem) return; const int maximum = GetNumberOfSlices() - 1; const int from = std::min(m_AnimationItem->GetFrom(), maximum); - const int to = std::min(m_AnimationItem->GetTo(), maximum); + int to = std::max(from, std::min(m_AnimationItem->GetTo(), maximum)); + + if (0 == to) + to = maximum; m_AnimationItem->SetFrom(from); m_AnimationItem->SetTo(to); m_Ui->sliceRangeWidget->setMaximum(maximum); m_Ui->sliceRangeWidget->setValues(from, to); m_Ui->reverseCheckBox->setChecked(m_AnimationItem->GetReverse()); } void QmitkTimeSliceAnimationWidget::OnFromChanged(double from) { - if (m_AnimationItem == nullptr) + if (nullptr == m_AnimationItem) return; int intFrom = static_cast(from); if (m_AnimationItem->GetFrom() != intFrom) m_AnimationItem->SetFrom(intFrom); } void QmitkTimeSliceAnimationWidget::OnToChanged(double to) { - if (m_AnimationItem == nullptr) + if (nullptr == m_AnimationItem) return; int intTo = static_cast(to); if (m_AnimationItem->GetTo() != intTo) m_AnimationItem->SetTo(intTo); } void QmitkTimeSliceAnimationWidget::OnReverseChanged(bool reverse) { - if (m_AnimationItem == nullptr) + if (nullptr == m_AnimationItem) return; if (m_AnimationItem->GetReverse() != reverse) m_AnimationItem->SetReverse(reverse); }