diff --git a/krita/krita.action b/krita/krita.action
--- a/krita/krita.action
+++ b/krita/krita.action
@@ -2504,6 +2504,50 @@
+
+
+
+
+ Set Start Time
+
+
+
+ 100000
+ 0
+
+ false
+
+
+
+
+
+
+ Set End Time
+
+
+
+ 100000
+ 0
+
+ false
+
+
+
+
+
+
+ Update Playback Range
+
+
+
+ 100000
+ 0
+
+ false
+
+
+
+
diff --git a/libs/image/kis_image_animation_interface.h b/libs/image/kis_image_animation_interface.h
--- a/libs/image/kis_image_animation_interface.h
+++ b/libs/image/kis_image_animation_interface.h
@@ -119,6 +119,10 @@
const KisTimeRange& fullClipRange() const;
void setFullClipRange(const KisTimeRange range);
+ void setFullClipRangeStartTime(int column);
+ void setFullClipRangeEndTime(int column);
+
+
const KisTimeRange &playbackRange() const;
void setPlaybackRange(const KisTimeRange range);
diff --git a/libs/image/kis_image_animation_interface.cpp b/libs/image/kis_image_animation_interface.cpp
--- a/libs/image/kis_image_animation_interface.cpp
+++ b/libs/image/kis_image_animation_interface.cpp
@@ -146,11 +146,24 @@
return m_d->fullClipRange;
}
-void KisImageAnimationInterface::setFullClipRange(const KisTimeRange range) {
+void KisImageAnimationInterface::setFullClipRange(const KisTimeRange range)
+{
m_d->fullClipRange = range;
emit sigFullClipRangeChanged();
}
+void KisImageAnimationInterface::setFullClipRangeStartTime(int column)
+{
+ KisTimeRange newRange(column, m_d->fullClipRange.end(), false);
+ setFullClipRange(newRange);
+}
+
+void KisImageAnimationInterface::setFullClipRangeEndTime(int column)
+{
+ KisTimeRange newRange(m_d->fullClipRange.start(), column, false);
+ setFullClipRange(newRange);
+}
+
const KisTimeRange& KisImageAnimationInterface::playbackRange() const
{
return m_d->playbackRange.isValid() ? m_d->playbackRange : m_d->fullClipRange;
diff --git a/libs/ui/canvas/kis_animation_player.h b/libs/ui/canvas/kis_animation_player.h
--- a/libs/ui/canvas/kis_animation_player.h
+++ b/libs/ui/canvas/kis_animation_player.h
@@ -66,10 +66,12 @@
void slotAudioVolumeChanged();
void slotOnAudioError(const QString &fileName, const QString &message);
+
Q_SIGNALS:
void sigFrameChanged();
void sigPlaybackStopped();
void sigPlaybackStatisticsUpdated();
+ void sigFullClipRangeChanged();
private:
void connectCancelSignals();
diff --git a/libs/ui/canvas/kis_animation_player.cpp b/libs/ui/canvas/kis_animation_player.cpp
--- a/libs/ui/canvas/kis_animation_player.cpp
+++ b/libs/ui/canvas/kis_animation_player.cpp
@@ -162,6 +162,7 @@
connect(m_d->canvas->image()->animationInterface(), SIGNAL(sigAudioChannelChanged()), SLOT(slotAudioChannelChanged()));
connect(m_d->canvas->image()->animationInterface(), SIGNAL(sigAudioVolumeChanged()), SLOT(slotAudioVolumeChanged()));
+
slotAudioChannelChanged();
}
@@ -291,16 +292,17 @@
m_d->timer->stop();
const KisImageAnimationInterface *animation = m_d->canvas->image()->animationInterface();
- const KisTimeRange &range = animation->playbackRange();
- if (!range.isValid()) return;
+ const KisTimeRange &playBackRange = animation->playbackRange();
+ if (!playBackRange.isValid()) return;
const int fps = animation->framerate();
m_d->initialFrame = animation->currentUITime();
- m_d->firstFrame = range.start();
- m_d->lastFrame = range.end();
+ m_d->firstFrame = playBackRange.start();
+ m_d->lastFrame = playBackRange.end();
m_d->expectedFrame = qBound(m_d->firstFrame, m_d->expectedFrame, m_d->lastFrame);
+
m_d->expectedInterval = qreal(1000) / fps / m_d->playbackSpeed;
m_d->lastTimerInterval = m_d->expectedInterval;
diff --git a/plugins/dockers/animation/animation_docker.h b/plugins/dockers/animation/animation_docker.h
--- a/plugins/dockers/animation/animation_docker.h
+++ b/plugins/dockers/animation/animation_docker.h
@@ -78,6 +78,8 @@
void slotCurrentNodeChanged(KisNodeSP node);
+ void updateClipRange();
+
private:
QPointer m_canvas;
diff --git a/plugins/dockers/animation/animation_docker.cpp b/plugins/dockers/animation/animation_docker.cpp
--- a/plugins/dockers/animation/animation_docker.cpp
+++ b/plugins/dockers/animation/animation_docker.cpp
@@ -118,6 +118,10 @@
connect(m_canvas->viewManager()->nodeManager(), SIGNAL(sigNodeActivated(KisNodeSP)),
this, SLOT(slotCurrentNodeChanged(KisNodeSP)));
+ connect (animation, SIGNAL(sigFullClipRangeChanged()), this, SLOT(updateClipRange()));
+
+
+
slotGlobalTimeChanged();
slotCurrentNodeChanged(m_canvas->viewManager()->nodeManager()->activeNode());
}
@@ -495,6 +499,12 @@
m_animationWidget->btnDeleteKeyframe->setEnabled(isNodeAnimatable);
}
+void AnimationDocker::updateClipRange()
+{
+ m_animationWidget->spinFromFrame->setValue(m_canvas->image()->animationInterface()->fullClipRange().start());
+ m_animationWidget->spinToFrame->setValue(m_canvas->image()->animationInterface()->fullClipRange().end());
+}
+
void AnimationDocker::addKeyframe(const QString &channel, bool copy)
{
if (!m_canvas) return;
diff --git a/plugins/dockers/animation/timeline_frames_model.h b/plugins/dockers/animation/timeline_frames_model.h
--- a/plugins/dockers/animation/timeline_frames_model.h
+++ b/plugins/dockers/animation/timeline_frames_model.h
@@ -72,6 +72,9 @@
qreal audioVolume() const;
void setAudioVolume(qreal value);
+ void setFullClipRangeStart(int column);
+ void setFullClipRangeEnd(int column);
+
void setLastClickedIndex(const QModelIndex &index);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
diff --git a/plugins/dockers/animation/timeline_frames_model.cpp b/plugins/dockers/animation/timeline_frames_model.cpp
--- a/plugins/dockers/animation/timeline_frames_model.cpp
+++ b/plugins/dockers/animation/timeline_frames_model.cpp
@@ -939,3 +939,13 @@
KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->image);
m_d->image->animationInterface()->setAudioVolume(value);
}
+
+void TimelineFramesModel::setFullClipRangeStart(int column)
+{
+ m_d->image->animationInterface()->setFullClipRangeStartTime(column);
+}
+
+void TimelineFramesModel::setFullClipRangeEnd(int column)
+{
+ m_d->image->animationInterface()->setFullClipRangeEndTime(column);
+}
diff --git a/plugins/dockers/animation/timeline_frames_view.h b/plugins/dockers/animation/timeline_frames_view.h
--- a/plugins/dockers/animation/timeline_frames_view.h
+++ b/plugins/dockers/animation/timeline_frames_view.h
@@ -51,6 +51,10 @@
void slotUpdateLayersMenu();
void slotUpdateFrameActions();
+ void slotSetStartTimeToCurrentPosition();
+ void slotSetEndTimeToCurrentPosition();
+ void slotUpdatePlackbackRange();
+
void slotAddNewLayer();
void slotAddExistingLayer(QAction *action);
void slotDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
diff --git a/plugins/dockers/animation/timeline_frames_view.cpp b/plugins/dockers/animation/timeline_frames_view.cpp
--- a/plugins/dockers/animation/timeline_frames_view.cpp
+++ b/plugins/dockers/animation/timeline_frames_view.cpp
@@ -363,6 +363,17 @@
action = m_d->actionMan->createAction("paste_frames_from_clipboard");
connect(action, SIGNAL(triggered()), SLOT(slotPasteFrames()));
+ action = m_d->actionMan->createAction("set_start_time");
+ connect(action, SIGNAL(triggered()), SLOT(slotSetStartTimeToCurrentPosition()));
+
+ action = m_d->actionMan->createAction("set_end_time");
+ connect(action, SIGNAL(triggered()), SLOT(slotSetEndTimeToCurrentPosition()));
+
+ action = m_d->actionMan->createAction("update_playback_range");
+ connect(action, SIGNAL(triggered()), SLOT(slotUpdatePlackbackRange()));
+
+
+
}
}
@@ -552,6 +563,9 @@
m_d->model->setAudioVolume(qreal(value) / 100.0);
}
+
+
+
void TimelineFramesView::slotUpdateInfiniteFramesCount()
{
if (horizontalScrollBar()->isSliderDown()) return;
@@ -938,6 +952,7 @@
QMenu *frames = menu->addMenu(i18nc("@item:inmenu", "Keyframes"));
KisActionManager::safePopulateMenu(frames, "insert_keyframes_right", m_d->actionMan);
KisActionManager::safePopulateMenu(frames, "insert_keyframes_left", m_d->actionMan);
+
frames->addSeparator();
KisActionManager::safePopulateMenu(frames, "insert_n_keyframes_right", m_d->actionMan);
KisActionManager::safePopulateMenu(frames, "insert_n_keyframes_left", m_d->actionMan);
@@ -945,6 +960,7 @@
QMenu *hold = menu->addMenu(i18nc("@item:inmenu", "Hold Frames"));
KisActionManager::safePopulateMenu(hold, "insert_hold_frame", m_d->actionMan);
KisActionManager::safePopulateMenu(hold, "remove_hold_frame", m_d->actionMan);
+
hold->addSeparator();
KisActionManager::safePopulateMenu(hold, "insert_n_hold_frames", m_d->actionMan);
KisActionManager::safePopulateMenu(hold, "remove_n_hold_frames", m_d->actionMan);
@@ -952,6 +968,12 @@
menu->addSeparator();
KisActionManager::safePopulateMenu(menu, "remove_frames", m_d->actionMan);
KisActionManager::safePopulateMenu(menu, "remove_frames_and_pull", m_d->actionMan);
+
+ menu->addSeparator();
+ KisActionManager::safePopulateMenu(menu, "set_start_time", m_d->actionMan);
+ KisActionManager::safePopulateMenu(menu, "set_end_time", m_d->actionMan);
+ KisActionManager::safePopulateMenu(menu, "update_playback_range", m_d->actionMan);
+
}
void TimelineFramesView::mousePressEvent(QMouseEvent *event)
@@ -1192,9 +1214,48 @@
enableAction("paste_frames_from_clipboard", data && data->hasFormat("application/x-krita-frame"));
+
+
+ // calculate if selection range is set. This will determine if the update playback range is available
+ QSet rows;
+ int minColumn = 0;
+ int maxColumn = 0;
+ calculateSelectionMetrics(minColumn, maxColumn, rows);
+
+ bool selectionExists = minColumn != maxColumn;
+
+ enableAction("update_playback_range", selectionExists);
+
+ enableAction("set_start_time", !selectionExists);
+ enableAction("set_end_time", !selectionExists);
+
+
+
//TODO: update column actions!
}
+void TimelineFramesView::slotSetStartTimeToCurrentPosition()
+{
+ m_d->model->setFullClipRangeStart(this->currentIndex().column());
+}
+
+void TimelineFramesView::slotSetEndTimeToCurrentPosition()
+{
+ m_d->model->setFullClipRangeEnd(this->currentIndex().column());
+}
+
+void TimelineFramesView::slotUpdatePlackbackRange()
+{
+ QSet rows;
+ int minColumn = 0;
+ int maxColumn = 0;
+
+ calculateSelectionMetrics(minColumn, maxColumn, rows);
+
+ m_d->model->setFullClipRangeStart(minColumn);
+ m_d->model->setFullClipRangeEnd(maxColumn);
+}
+
void TimelineFramesView::slotLayerContextMenuRequested(const QPoint &globalPos)
{
m_d->layerEditingMenu->exec(globalPos);