diff --git a/krita/krita.action b/krita/krita.action --- a/krita/krita.action +++ b/krita/krita.action @@ -2504,6 +2504,36 @@ + + + + + Set Start Time + + + + 100000 + 0 + + false + + + + + + + Set End Time + + + + 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,26 @@ 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) +{ + qWarning() << "end: " << QString::number(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 @@ -57,6 +57,7 @@ void slotUpdatePlaybackSpeed(double value); void slotUpdatePlaybackTimer(); void slotUpdateDropFramesMode(); + void slotFullClipRangeChanged(); private Q_SLOTS: void slotSyncScrubbingAudio(int msecTime); @@ -66,10 +67,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 @@ -79,6 +79,11 @@ int lastFrame; qreal playbackSpeed; + // start and end times for what will be exported. Called "full clip" elsewhere + int startFrame; + int endFrame; + + KisCanvas2 *canvas; KisSignalAutoConnectionsStore cancelStrokeConnections; @@ -162,6 +167,10 @@ connect(m_d->canvas->image()->animationInterface(), SIGNAL(sigAudioChannelChanged()), SLOT(slotAudioChannelChanged())); connect(m_d->canvas->image()->animationInterface(), SIGNAL(sigAudioVolumeChanged()), SLOT(slotAudioVolumeChanged())); + connect(m_d->canvas->image()->animationInterface(), SIGNAL(sigFullClipRangeChanged()), SLOT(slotFullClipRangeChanged())); + + + slotAudioChannelChanged(); } @@ -228,6 +237,19 @@ m_d->canvas->viewManager()->showFloatingMessage(errorMessage, KisIconUtils::loadIcon("warning")); } +void KisAnimationPlayer::slotFullClipRangeChanged() +{ + const KisImageAnimationInterface *animation = m_d->canvas->image()->animationInterface(); + const KisTimeRange &fullClipRange = animation->fullClipRange(); + + if (!fullClipRange.isValid()) return; + + m_d->startFrame = fullClipRange.start(); + m_d->endFrame = fullClipRange.end(); + + emit sigFullClipRangeChanged(); // tell the animation UI to update +} + void KisAnimationPlayer::connectCancelSignals() { m_d->cancelStrokeConnections.addConnection( @@ -291,16 +313,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,11 @@ connect(m_canvas->viewManager()->nodeManager(), SIGNAL(sigNodeActivated(KisNodeSP)), this, SLOT(slotCurrentNodeChanged(KisNodeSP))); + + connect(m_canvas->animationPlayer(), SIGNAL(sigFullClipRangeChanged()), this, SLOT(updateClipRange())); + + + slotGlobalTimeChanged(); slotCurrentNodeChanged(m_canvas->viewManager()->nodeManager()->activeNode()); } @@ -495,6 +500,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 @@ -892,3 +892,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,9 @@ void slotUpdateLayersMenu(); void slotUpdateFrameActions(); + void slotSetStartTimeToCurrentPosition(); + void slotSetEndTimeToCurrentPosition(); + 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,12 @@ 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())); + } } @@ -552,6 +558,9 @@ m_d->model->setAudioVolume(qreal(value) / 100.0); } + + + void TimelineFramesView::slotUpdateInfiniteFramesCount() { if (horizontalScrollBar()->isSliderDown()) return; @@ -938,6 +947,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 +955,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 +963,10 @@ 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); } void TimelineFramesView::mousePressEvent(QMouseEvent *event) @@ -1189,9 +1204,22 @@ enableAction("paste_frames_from_clipboard", data && data->hasFormat("application/x-krita-frame")); + enableAction("set_start_time", true); + enableAction("set_end_time", true); + //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::slotLayerContextMenuRequested(const QPoint &globalPos) { m_d->layerEditingMenu->exec(globalPos);