(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
{
const QString ffmpegPath = GetFFmpegPath();
if (ffmpegPath.isEmpty())
{
QMessageBox::information(NULL, "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
");
return;
}
m_FFmpegWriter->SetFFmpegPath(GetFFmpegPath());
QAction* action = m_RecordMenu->exec(QCursor::pos());
if (action == NULL)
return;
vtkRenderWindow* renderWindow = mitk::BaseRenderer::GetRenderWindowByName(action->data().toString().toStdString());
if (renderWindow == NULL)
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(NULL, "Specify a filename", "", "Movie (*.mp4)");
if (saveFileName.isEmpty())
return;
if(!saveFileName.endsWith(".mp4"))
saveFileName += ".mp4";
m_FFmpegWriter->SetOutputPath(saveFileName);
try
{
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;
}
m_FFmpegWriter->Stop();
m_CurrentFrame = 0;
this->RenderCurrentFrame();
}
catch (const mitk::Exception& exception)
{
m_CurrentFrame = 0;
this->RenderCurrentFrame();
QMessageBox::critical(NULL, "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 != NULL)
{
item->SetStartWithPrevious(index);
this->RedrawTimeline();
this->CalculateTotalDuration();
}
}
void QmitkMovieMakerView::OnDurationSpinBoxValueChanged(double value)
{
QmitkAnimationItem* item = this->GetSelectedAnimationItem();
if (item != NULL)
{
item->SetDuration(value);
this->RedrawTimeline();
this->CalculateTotalDuration();
}
}
void QmitkMovieMakerView::OnDelaySpinBoxValueChanged(double value)
{
QmitkAnimationItem* item = this->GetSelectedAnimationItem();
if (item != NULL)
{
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);
Q_FOREACH(const AnimationInterpolationFactorPair& animation, activeAnimations)
{
const QVector nextActiveAnimations = this->GetActiveAnimations((m_CurrentFrame + 1) * deltaT);
bool lastFrameForAnimation = true;
Q_FOREACH(const AnimationInterpolationFactorPair& 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 != NULL)
{
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 == NULL)
return;
const QString widgetKey = animationItem->GetWidgetKey();
QmitkAnimationWidget* animationWidget = NULL;
if (m_AnimationWidgets.contains(widgetKey))
{
animationWidget = m_AnimationWidgets[widgetKey];
if (animationWidget != NULL)
{
m_Ui->animationWidgetGroupBox->setTitle(widgetKey);
animationWidget->SetAnimationItem(animationItem);
animationWidget->setVisible(true);
}
}
m_Ui->animationWidgetGroupBox->setVisible(animationWidget != NULL);
}
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))
: NULL;
}
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));
if (item == NULL)
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
}
QVector > QmitkMovieMakerView::GetActiveAnimations(double t) const
{
const int rowCount = m_AnimationModel->rowCount();
QVector > 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 == NULL)
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()));
}
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/QmitkTimeSliceAnimationItem.cpp b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkTimeSliceAnimationItem.cpp
new file mode 100644
index 0000000000..8c84cc8fca
--- /dev/null
+++ b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkTimeSliceAnimationItem.cpp
@@ -0,0 +1,74 @@
+/*===================================================================
+
+The Medical Imaging Interaction Toolkit (MITK)
+
+Copyright (c) German Cancer Research Center,
+Division of Medical and Biological Informatics.
+All rights reserved.
+
+This software is distributed WITHOUT ANY WARRANTY; without
+even the implied warranty of MERCHANTABILITY or FITNESS FOR
+A PARTICULAR PURPOSE.
+
+See LICENSE.txt or http://www.mitk.org for details.
+
+===================================================================*/
+
+#include "QmitkTimeSliceAnimationItem.h"
+#include
+
+QmitkTimeSliceAnimationItem::QmitkTimeSliceAnimationItem(int from, int to, bool reverse, double duration, double delay, bool startWithPrevious)
+ : QmitkAnimationItem("Time", duration, delay, startWithPrevious)
+{
+ this->SetFrom(from);
+ this->SetTo(to);
+ this->SetReverse(reverse);
+}
+
+QmitkTimeSliceAnimationItem::~QmitkTimeSliceAnimationItem()
+{
+}
+
+int QmitkTimeSliceAnimationItem::GetFrom() const
+{
+ return this->data(FromRole).toInt();
+}
+
+void QmitkTimeSliceAnimationItem::SetFrom(int from)
+{
+ this->setData(from, FromRole);
+}
+
+int QmitkTimeSliceAnimationItem::GetTo() const
+{
+ return this->data(ToRole).toInt();
+}
+
+void QmitkTimeSliceAnimationItem::SetTo(int to)
+{
+ this->setData(to, ToRole);
+}
+
+bool QmitkTimeSliceAnimationItem::GetReverse() const
+{
+ return this->data(ReverseRole).toBool();
+}
+
+void QmitkTimeSliceAnimationItem::SetReverse(bool reverse)
+{
+ this->setData(reverse, ReverseRole);
+}
+
+void QmitkTimeSliceAnimationItem::Animate(double s)
+{
+ mitk::Stepper* stepper = mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetTime();
+
+ if (stepper == NULL)
+ return;
+
+ int newPos = this->GetReverse()
+ ? this->GetTo() - static_cast((this->GetTo() - this->GetFrom()) * s)
+ : this->GetFrom() + static_cast((this->GetTo() - this->GetFrom()) * s);
+
+ stepper->SetPos(static_cast(newPos));
+}
diff --git a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkTimeSliceAnimationItem.h b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkTimeSliceAnimationItem.h
new file mode 100644
index 0000000000..916f74ae20
--- /dev/null
+++ b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkTimeSliceAnimationItem.h
@@ -0,0 +1,40 @@
+/*===================================================================
+
+The Medical Imaging Interaction Toolkit (MITK)
+
+Copyright (c) German Cancer Research Center,
+Division of Medical and Biological Informatics.
+All rights reserved.
+
+This software is distributed WITHOUT ANY WARRANTY; without
+even the implied warranty of MERCHANTABILITY or FITNESS FOR
+A PARTICULAR PURPOSE.
+
+See LICENSE.txt or http://www.mitk.org for details.
+
+===================================================================*/
+
+#ifndef QmitkTimeSliceAnimationItem_h
+#define QmitkTimeSliceAnimationItem_h
+
+#include "QmitkAnimationItem.h"
+
+class QmitkTimeSliceAnimationItem : public QmitkAnimationItem
+{
+public:
+ explicit QmitkTimeSliceAnimationItem(int from = 0, int to = 0, bool reverse = false, double duration = 2.0, double delay = 0.0, bool startWithPrevious = false);
+ virtual ~QmitkTimeSliceAnimationItem();
+
+ int GetFrom() const;
+ void SetFrom(int from);
+
+ int GetTo() const;
+ void SetTo(int to);
+
+ bool GetReverse() const;
+ void SetReverse(bool reverse);
+
+ void Animate(double s);
+};
+
+#endif
diff --git a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkTimeSliceAnimationWidget.cpp b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkTimeSliceAnimationWidget.cpp
new file mode 100644
index 0000000000..189f4eda95
--- /dev/null
+++ b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkTimeSliceAnimationWidget.cpp
@@ -0,0 +1,102 @@
+/*===================================================================
+
+The Medical Imaging Interaction Toolkit (MITK)
+
+Copyright (c) German Cancer Research Center,
+Division of Medical and Biological Informatics.
+All rights reserved.
+
+This software is distributed WITHOUT ANY WARRANTY; without
+even the implied warranty of MERCHANTABILITY or FITNESS FOR
+A PARTICULAR PURPOSE.
+
+See LICENSE.txt or http://www.mitk.org for details.
+
+===================================================================*/
+
+#include "QmitkTimeSliceAnimationItem.h"
+#include "QmitkTimeSliceAnimationWidget.h"
+#include
+#include
+#include
+#include
+
+static int GetNumberOfSlices()
+{
+ mitk::Stepper* stepper = mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetTime();
+
+ if (stepper != NULL)
+ return std::max(1, static_cast(stepper->GetSteps()));
+
+ 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)));
+}
+
+QmitkTimeSliceAnimationWidget::~QmitkTimeSliceAnimationWidget()
+{
+}
+
+void QmitkTimeSliceAnimationWidget::SetAnimationItem(QmitkAnimationItem* sliceAnimationItem)
+{
+ m_AnimationItem = dynamic_cast(sliceAnimationItem);
+
+ if (m_AnimationItem == NULL)
+ return;
+
+ const int maximum = GetNumberOfSlices() - 1;
+ const int from = std::min(m_AnimationItem->GetFrom(), maximum);
+ const int to = std::min(m_AnimationItem->GetTo(), 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 == NULL)
+ return;
+
+ int intFrom = static_cast(from);
+
+ if (m_AnimationItem->GetFrom() != intFrom)
+ m_AnimationItem->SetFrom(intFrom);
+}
+
+void QmitkTimeSliceAnimationWidget::OnToChanged(double to)
+{
+ if (m_AnimationItem == NULL)
+ return;
+
+ int intTo = static_cast(to);
+
+ if (m_AnimationItem->GetTo() != intTo)
+ m_AnimationItem->SetTo(intTo);
+}
+
+void QmitkTimeSliceAnimationWidget::OnReverseChanged(bool reverse)
+{
+ if (m_AnimationItem == NULL)
+ return;
+
+ if (m_AnimationItem->GetReverse() != reverse)
+ m_AnimationItem->SetReverse(reverse);
+}
diff --git a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkTimeSliceAnimationWidget.h b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkTimeSliceAnimationWidget.h
new file mode 100644
index 0000000000..bed8155dc0
--- /dev/null
+++ b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkTimeSliceAnimationWidget.h
@@ -0,0 +1,49 @@
+/*===================================================================
+
+The Medical Imaging Interaction Toolkit (MITK)
+
+Copyright (c) German Cancer Research Center,
+Division of Medical and Biological Informatics.
+All rights reserved.
+
+This software is distributed WITHOUT ANY WARRANTY; without
+even the implied warranty of MERCHANTABILITY or FITNESS FOR
+A PARTICULAR PURPOSE.
+
+See LICENSE.txt or http://www.mitk.org for details.
+
+===================================================================*/
+
+#ifndef QmitkTimeSliceAnimationWidget_h
+#define QmitkTimeSliceAnimationWidget_h
+
+#include "QmitkAnimationWidget.h"
+
+class QmitkTimeSliceAnimationItem;
+
+namespace Ui
+{
+ class QmitkTimeSliceAnimationWidget;
+}
+
+class QmitkTimeSliceAnimationWidget : public QmitkAnimationWidget
+{
+ Q_OBJECT
+
+public:
+ explicit QmitkTimeSliceAnimationWidget(QWidget* parent = NULL);
+ ~QmitkTimeSliceAnimationWidget();
+
+ void SetAnimationItem(QmitkAnimationItem* sliceAnimationItem);
+
+private slots:
+ void OnFromChanged(double from);
+ void OnToChanged(double to);
+ void OnReverseChanged(bool reverse);
+
+private:
+ Ui::QmitkTimeSliceAnimationWidget* m_Ui;
+ QmitkTimeSliceAnimationItem* m_AnimationItem;
+};
+
+#endif
diff --git a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkTimeSliceAnimationWidget.ui b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkTimeSliceAnimationWidget.ui
new file mode 100644
index 0000000000..a74fa2a150
--- /dev/null
+++ b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkTimeSliceAnimationWidget.ui
@@ -0,0 +1,70 @@
+
+
+ QmitkTimeSliceAnimationWidget
+
+
+
+ 0
+ 0
+ 304
+ 71
+
+
+
+ QmitkTimeSliceAnimationWidget
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Slice range:
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Reverse
+
+
+
+ -
+
+
+ 0
+
+
+ 999.000000000000000
+
+
+ 999.000000000000000
+
+
+
+
+
+
+
+ ctkRangeWidget
+ QWidget
+
+
+
+
+ reverseCheckBox
+
+
+
+