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