forked from qt-creator/qt-creator
Implement keyframes snapping
When shift is down while dragging keyframe(s), they snap to ruler ticks, keyframes, and the playhead. Task-number: QDS-1068 Change-Id: Iea5fec9e578d3f1db51c429cbd565ad145a90fe8 Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io> Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
@@ -181,10 +181,10 @@ void TimelineGraphicsScene::updateKeyframePositionsCache()
|
||||
}
|
||||
|
||||
// snap a frame to nearest keyframe or ruler tick
|
||||
qreal TimelineGraphicsScene::snap(qreal frame)
|
||||
qreal TimelineGraphicsScene::snap(qreal frame, bool snapToPlayhead)
|
||||
{
|
||||
qreal frameTick = m_layout->ruler()->getFrameTick();
|
||||
qreal rulerTicksSnapframe = qRound(frame / frameTick) * frameTick;
|
||||
qreal rulerFrameTick = m_layout->ruler()->getFrameTick();
|
||||
qreal nearestRulerTickFrame = qRound(frame / rulerFrameTick) * rulerFrameTick;
|
||||
// get nearest keyframe to the input frame
|
||||
bool nearestKeyframeFound = false;
|
||||
qreal nearestKeyframe = 0;
|
||||
@@ -202,23 +202,30 @@ qreal TimelineGraphicsScene::snap(qreal frame)
|
||||
}
|
||||
}
|
||||
|
||||
if (!nearestKeyframeFound && !m_keyframePositionsCache.empty()) {
|
||||
// playhead past last keyframe case
|
||||
if (!nearestKeyframeFound && !m_keyframePositionsCache.empty())
|
||||
nearestKeyframe = m_keyframePositionsCache.last();
|
||||
nearestKeyframeFound = true;
|
||||
}
|
||||
|
||||
// return nearest snappable keyframe or ruler tick
|
||||
return nearestKeyframeFound && qAbs(nearestKeyframe - frame)
|
||||
< qAbs(rulerTicksSnapframe - frame) ? nearestKeyframe
|
||||
: rulerTicksSnapframe;
|
||||
qreal playheadFrame = m_currentFrameIndicator->position();
|
||||
|
||||
qreal dKeyframe = qAbs(nearestKeyframe - frame);
|
||||
qreal dPlayhead = snapToPlayhead ? qAbs(playheadFrame - frame) : 99999.;
|
||||
qreal dRulerTick = qAbs(nearestRulerTickFrame - frame);
|
||||
|
||||
if (dKeyframe <= qMin(dPlayhead, dRulerTick))
|
||||
return nearestKeyframe;
|
||||
|
||||
if (dRulerTick <= dPlayhead)
|
||||
return nearestRulerTickFrame;
|
||||
|
||||
return playheadFrame;
|
||||
}
|
||||
|
||||
void TimelineGraphicsScene::setCurrenFrame(const QmlTimeline &timeline, qreal frame)
|
||||
{
|
||||
if (timeline.isValid()) {
|
||||
if (QApplication::keyboardModifiers() & Qt::ShiftModifier) // playhead snapping
|
||||
frame = snap(frame);
|
||||
frame = snap(frame, false);
|
||||
m_currentFrameIndicator->setPosition(frame);
|
||||
} else {
|
||||
m_currentFrameIndicator->setPosition(0);
|
||||
|
@@ -97,6 +97,8 @@ public:
|
||||
QVector<qreal> keyframePositions() const;
|
||||
QVector<qreal> keyframePositions(const QmlTimelineKeyframeGroup &frames) const;
|
||||
|
||||
qreal snap(qreal frame, bool snapToPlayhead = true);
|
||||
|
||||
void setRulerScaling(int scaling);
|
||||
|
||||
void commitCurrentFrame(qreal frame);
|
||||
@@ -167,7 +169,6 @@ private:
|
||||
QList<QGraphicsItem *> itemsAt(const QPointF &pos);
|
||||
|
||||
private:
|
||||
qreal snap(qreal frame);
|
||||
|
||||
TimelineWidget *m_parent = nullptr;
|
||||
|
||||
|
@@ -90,7 +90,7 @@ void TimelineMoveTool::mouseMoveEvent(TimelineMovableAbstractItem *item,
|
||||
return;
|
||||
|
||||
const qreal sourceFrame = qRound(current->mapFromSceneToFrame(current->rect().center().x()));
|
||||
const qreal targetFrame = qRound(current->mapFromSceneToFrame(event->scenePos().x()));
|
||||
qreal targetFrame = qRound(current->mapFromSceneToFrame(event->scenePos().x()));
|
||||
qreal deltaFrame = targetFrame - sourceFrame - m_pressKeyframeDelta;
|
||||
|
||||
const qreal minFrame = scene()->startFrame();
|
||||
@@ -106,8 +106,16 @@ void TimelineMoveTool::mouseMoveEvent(TimelineMovableAbstractItem *item,
|
||||
else if (firstFrame + deltaFrame < minFrame)
|
||||
deltaFrame = minFrame - firstFrame;
|
||||
|
||||
targetFrame = sourceFrame + deltaFrame;
|
||||
|
||||
if (QApplication::keyboardModifiers() & Qt::ShiftModifier) { // keyframe snapping
|
||||
qreal snappedTargetFrame = scene()->snap(targetFrame);
|
||||
deltaFrame += snappedTargetFrame - targetFrame;
|
||||
targetFrame = snappedTargetFrame;
|
||||
}
|
||||
|
||||
scene()->statusBarMessageChanged(tr(TimelineConstants::statusBarKeyframe)
|
||||
.arg(sourceFrame + deltaFrame));
|
||||
.arg(targetFrame));
|
||||
|
||||
const QList<TimelineKeyframeItem *> selectedKeyframes = scene()->selectedKeyframes();
|
||||
for (auto *keyframe : selectedKeyframes) {
|
||||
|
Reference in New Issue
Block a user