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
|
// 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 rulerFrameTick = m_layout->ruler()->getFrameTick();
|
||||||
qreal rulerTicksSnapframe = qRound(frame / frameTick) * frameTick;
|
qreal nearestRulerTickFrame = qRound(frame / rulerFrameTick) * rulerFrameTick;
|
||||||
// get nearest keyframe to the input frame
|
// get nearest keyframe to the input frame
|
||||||
bool nearestKeyframeFound = false;
|
bool nearestKeyframeFound = false;
|
||||||
qreal nearestKeyframe = 0;
|
qreal nearestKeyframe = 0;
|
||||||
@@ -202,23 +202,30 @@ qreal TimelineGraphicsScene::snap(qreal frame)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!nearestKeyframeFound && !m_keyframePositionsCache.empty()) {
|
// playhead past last keyframe case
|
||||||
// playhead past last keyframe case
|
if (!nearestKeyframeFound && !m_keyframePositionsCache.empty())
|
||||||
nearestKeyframe = m_keyframePositionsCache.last();
|
nearestKeyframe = m_keyframePositionsCache.last();
|
||||||
nearestKeyframeFound = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// return nearest snappable keyframe or ruler tick
|
qreal playheadFrame = m_currentFrameIndicator->position();
|
||||||
return nearestKeyframeFound && qAbs(nearestKeyframe - frame)
|
|
||||||
< qAbs(rulerTicksSnapframe - frame) ? nearestKeyframe
|
qreal dKeyframe = qAbs(nearestKeyframe - frame);
|
||||||
: rulerTicksSnapframe;
|
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)
|
void TimelineGraphicsScene::setCurrenFrame(const QmlTimeline &timeline, qreal frame)
|
||||||
{
|
{
|
||||||
if (timeline.isValid()) {
|
if (timeline.isValid()) {
|
||||||
if (QApplication::keyboardModifiers() & Qt::ShiftModifier) // playhead snapping
|
if (QApplication::keyboardModifiers() & Qt::ShiftModifier) // playhead snapping
|
||||||
frame = snap(frame);
|
frame = snap(frame, false);
|
||||||
m_currentFrameIndicator->setPosition(frame);
|
m_currentFrameIndicator->setPosition(frame);
|
||||||
} else {
|
} else {
|
||||||
m_currentFrameIndicator->setPosition(0);
|
m_currentFrameIndicator->setPosition(0);
|
||||||
|
@@ -97,6 +97,8 @@ public:
|
|||||||
QVector<qreal> keyframePositions() const;
|
QVector<qreal> keyframePositions() const;
|
||||||
QVector<qreal> keyframePositions(const QmlTimelineKeyframeGroup &frames) const;
|
QVector<qreal> keyframePositions(const QmlTimelineKeyframeGroup &frames) const;
|
||||||
|
|
||||||
|
qreal snap(qreal frame, bool snapToPlayhead = true);
|
||||||
|
|
||||||
void setRulerScaling(int scaling);
|
void setRulerScaling(int scaling);
|
||||||
|
|
||||||
void commitCurrentFrame(qreal frame);
|
void commitCurrentFrame(qreal frame);
|
||||||
@@ -167,7 +169,6 @@ private:
|
|||||||
QList<QGraphicsItem *> itemsAt(const QPointF &pos);
|
QList<QGraphicsItem *> itemsAt(const QPointF &pos);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
qreal snap(qreal frame);
|
|
||||||
|
|
||||||
TimelineWidget *m_parent = nullptr;
|
TimelineWidget *m_parent = nullptr;
|
||||||
|
|
||||||
|
@@ -90,7 +90,7 @@ void TimelineMoveTool::mouseMoveEvent(TimelineMovableAbstractItem *item,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
const qreal sourceFrame = qRound(current->mapFromSceneToFrame(current->rect().center().x()));
|
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;
|
qreal deltaFrame = targetFrame - sourceFrame - m_pressKeyframeDelta;
|
||||||
|
|
||||||
const qreal minFrame = scene()->startFrame();
|
const qreal minFrame = scene()->startFrame();
|
||||||
@@ -106,8 +106,16 @@ void TimelineMoveTool::mouseMoveEvent(TimelineMovableAbstractItem *item,
|
|||||||
else if (firstFrame + deltaFrame < minFrame)
|
else if (firstFrame + deltaFrame < minFrame)
|
||||||
deltaFrame = minFrame - firstFrame;
|
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)
|
scene()->statusBarMessageChanged(tr(TimelineConstants::statusBarKeyframe)
|
||||||
.arg(sourceFrame + deltaFrame));
|
.arg(targetFrame));
|
||||||
|
|
||||||
const QList<TimelineKeyframeItem *> selectedKeyframes = scene()->selectedKeyframes();
|
const QList<TimelineKeyframeItem *> selectedKeyframes = scene()->selectedKeyframes();
|
||||||
for (auto *keyframe : selectedKeyframes) {
|
for (auto *keyframe : selectedKeyframes) {
|
||||||
|
Reference in New Issue
Block a user