Some timeline visual updates and corrections

- Selection rect selects keyframes based on center point rather than
the whole keyframe.
- Make playhead vertical line extend to the whole height of the
timeline widget.
- Prevent a jump when dragging a selection of keyframes.
- Prevent dragging keyframes if the clicked keyframe is deselected
(i.e. Ctrl+click a selected keyframe).
- Correct timeline bounds checking while dragging multiple keyframes.

Task-number: QDS-1073
Change-Id: Ibf118ecccfe86346f2d4e921c0958294a15c24f1
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Mahmoud Badri
2019-10-01 13:14:16 +03:00
parent 171ad72b7a
commit f9b225ae88
6 changed files with 39 additions and 21 deletions

View File

@@ -112,7 +112,7 @@ TimelineGraphicsScene::TimelineGraphicsScene(TimelineWidget *parent)
if (auto *rview = rulerView()) if (auto *rview = rulerView())
rview->setSceneRect(rect); rview->setSceneRect(rect);
m_currentFrameIndicator->setHeight(m_layout->geometry().height()); m_currentFrameIndicator->setHeight(9999); // big enough number (> timeline widget height)
}); });
auto moveFrameIndicator = [this](const QPointF &pos) { auto moveFrameIndicator = [this](const QPointF &pos) {

View File

@@ -68,7 +68,12 @@ void TimelineMoveTool::mousePressEvent(TimelineMovableAbstractItem *item,
QGraphicsSceneMouseEvent *event) QGraphicsSceneMouseEvent *event)
{ {
Q_UNUSED(item) Q_UNUSED(item)
Q_UNUSED(event)
if (auto *current = currentItem()->asTimelineKeyframeItem()) {
const qreal sourceFrame = qRound(current->mapFromSceneToFrame(current->rect().center().x()));
const qreal targetFrame = qRound(current->mapFromSceneToFrame(event->scenePos().x()));
m_pressKeyframeDelta = targetFrame - sourceFrame;
}
} }
void TimelineMoveTool::mouseMoveEvent(TimelineMovableAbstractItem *item, void TimelineMoveTool::mouseMoveEvent(TimelineMovableAbstractItem *item,
@@ -80,34 +85,34 @@ void TimelineMoveTool::mouseMoveEvent(TimelineMovableAbstractItem *item,
return; return;
if (auto *current = currentItem()->asTimelineKeyframeItem()) { if (auto *current = currentItem()->asTimelineKeyframeItem()) {
// prevent dragging if deselecting a keyframe (Ctrl+click and drag a selected keyframe)
if (!current->highlighted())
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())); const qreal targetFrame = qRound(current->mapFromSceneToFrame(event->scenePos().x()));
qreal deltaFrame = targetFrame - sourceFrame; qreal deltaFrame = targetFrame - sourceFrame - m_pressKeyframeDelta;
const qreal minFrame = scene()->startFrame(); const qreal minFrame = scene()->startFrame();
const qreal maxFrame = scene()->endFrame(); const qreal maxFrame = scene()->endFrame();
auto bbox = scene()->selectionBounds().united(current->rect()); auto bbox = scene()->selectionBounds().adjusted(TimelineConstants::keyFrameSize / 2, 0,
-TimelineConstants::keyFrameSize / 2, 0);
double firstFrame = std::round(current->mapFromSceneToFrame(bbox.left()));
double lastFrame = std::round(current->mapFromSceneToFrame(bbox.right()));
double firstFrame = std::round(current->mapFromSceneToFrame(bbox.center().x())); if (lastFrame + deltaFrame > maxFrame)
double lastFrame = std::round(current->mapFromSceneToFrame(bbox.center().x()));
if ((lastFrame + deltaFrame) > maxFrame)
deltaFrame = maxFrame - lastFrame; deltaFrame = maxFrame - lastFrame;
else if (firstFrame + deltaFrame < minFrame)
if ((firstFrame + deltaFrame) <= minFrame)
deltaFrame = minFrame - firstFrame; deltaFrame = minFrame - firstFrame;
current->setPosition(sourceFrame + deltaFrame);
scene()->statusBarMessageChanged(tr(TimelineConstants::statusBarKeyframe) scene()->statusBarMessageChanged(tr(TimelineConstants::statusBarKeyframe)
.arg(sourceFrame + deltaFrame)); .arg(sourceFrame + deltaFrame));
for (auto *keyframe : scene()->selectedKeyframes()) { const QList<TimelineKeyframeItem *> selectedKeyframes = scene()->selectedKeyframes();
if (keyframe != current) { for (auto *keyframe : selectedKeyframes) {
qreal pos = std::round(current->mapFromSceneToFrame(keyframe->rect().center().x())); qreal pos = std::round(keyframe->mapFromSceneToFrame(keyframe->rect().center().x()));
keyframe->setPosition(pos + deltaFrame); keyframe->setPosition(pos + deltaFrame);
}
} }
} else { } else {

View File

@@ -52,6 +52,9 @@ public:
void keyPressEvent(QKeyEvent *keyEvent) override; void keyPressEvent(QKeyEvent *keyEvent) override;
void keyReleaseEvent(QKeyEvent *keyEvent) override; void keyReleaseEvent(QKeyEvent *keyEvent) override;
private:
qreal m_pressKeyframeDelta = 0.;
}; };
} // namespace QmlDesigner } // namespace QmlDesigner

View File

@@ -517,10 +517,10 @@ void TimelineKeyframeItem::updateFrame()
setPosition(m_frame.variantProperty("frame").value().toReal()); setPosition(m_frame.variantProperty("frame").value().toReal());
} }
void TimelineKeyframeItem::setPosition(qreal position) void TimelineKeyframeItem::setPosition(qreal frame)
{ {
int offset = (TimelineConstants::sectionHeight - TimelineConstants::keyFrameSize) / 2; int offset = (TimelineConstants::sectionHeight - TimelineConstants::keyFrameSize) / 2;
const qreal scenePostion = mapFromFrameToScene(position); const qreal scenePostion = mapFromFrameToScene(frame);
setRect(scenePostion - TimelineConstants::keyFrameSize / 2, setRect(scenePostion - TimelineConstants::keyFrameSize / 2,
offset, offset,
@@ -622,6 +622,11 @@ void TimelineKeyframeItem::setHighlighted(bool b)
update(); update();
} }
bool TimelineKeyframeItem::highlighted() const
{
return m_highlight;
}
TimelinePropertyItem *TimelineKeyframeItem::propertyItem() const TimelinePropertyItem *TimelineKeyframeItem::propertyItem() const
{ {
/* The parentItem is always a TimelinePropertyItem. See constructor */ /* The parentItem is always a TimelinePropertyItem. See constructor */

View File

@@ -58,8 +58,9 @@ public:
void updateFrame(); void updateFrame();
void setHighlighted(bool b); void setHighlighted(bool b);
bool highlighted() const;
void setPosition(qreal position); void setPosition(qreal frame);
void commitPosition(const QPointF &point) override; void commitPosition(const QPointF &point) override;

View File

@@ -98,7 +98,7 @@ void TimelineSelectionTool::mouseMoveEvent(TimelineMovableAbstractItem *item,
m_selectionRect->show(); m_selectionRect->show();
aboutToSelect(selectionMode(event), aboutToSelect(selectionMode(event),
scene()->items(m_selectionRect->rect(), Qt::ContainsItemShape)); scene()->items(m_selectionRect->rect(), Qt::IntersectsItemBoundingRect));
} }
} }
@@ -164,6 +164,10 @@ void TimelineSelectionTool::aboutToSelect(SelectionMode mode, QList<QGraphicsIte
for (auto *item : items) { for (auto *item : items) {
if (auto *keyframe = TimelineMovableAbstractItem::asTimelineKeyframeItem(item)) { if (auto *keyframe = TimelineMovableAbstractItem::asTimelineKeyframeItem(item)) {
// if keyframe's center isn't inside m_selectionRect, discard it
if (!m_selectionRect->rect().contains(keyframe->rect().center() + item->scenePos()))
continue;
if (mode == SelectionMode::Remove) if (mode == SelectionMode::Remove)
keyframe->setHighlighted(false); keyframe->setHighlighted(false);
else if (mode == SelectionMode::Toggle) else if (mode == SelectionMode::Toggle)