diff --git a/src/plugins/qmldesigner/components/curveeditor/animationcurve.cpp b/src/plugins/qmldesigner/components/curveeditor/animationcurve.cpp index 9a88b332407..ecaf9036555 100644 --- a/src/plugins/qmldesigner/components/curveeditor/animationcurve.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/animationcurve.cpp @@ -93,6 +93,11 @@ AnimationCurve::AnimationCurve(const QEasingCurve &easing, const QPointF &start, analyze(); } +bool AnimationCurve::isEmpty() const +{ + return m_frames.empty(); +} + bool AnimationCurve::isValid() const { return m_frames.size() >= 2; @@ -352,45 +357,43 @@ void AnimationCurve::insert(double time) void AnimationCurve::analyze() { - if (isValid()) { - m_minY = std::numeric_limits::max(); - m_maxY = std::numeric_limits::lowest(); + m_minY = std::numeric_limits::max(); + m_maxY = std::numeric_limits::lowest(); - auto byTime = [](const auto &a, const auto &b) { - return a.position().x() < b.position().x(); - }; - std::sort(m_frames.begin(), m_frames.end(), byTime); + auto byTime = [](const auto &a, const auto &b) { + return a.position().x() < b.position().x(); + }; + std::sort(m_frames.begin(), m_frames.end(), byTime); - for (auto e : extrema()) { - if (m_minY > e.y()) - m_minY = e.y(); + for (auto e : extrema()) { + if (m_minY > e.y()) + m_minY = e.y(); - if (m_maxY < e.y()) - m_maxY = e.y(); + if (m_maxY < e.y()) + m_maxY = e.y(); + } + + for (auto &frame : qAsConst(m_frames)) { + if (frame.position().y() < m_minY) + m_minY = frame.position().y(); + + if (frame.position().y() > m_maxY) + m_maxY = frame.position().y(); + + if (frame.hasLeftHandle()) { + if (frame.leftHandle().y() < m_minY) + m_minY = frame.leftHandle().y(); + + if (frame.leftHandle().y() > m_maxY) + m_maxY = frame.leftHandle().y(); } - for (auto &frame : qAsConst(m_frames)) { - if (frame.position().y() < m_minY) - m_minY = frame.position().y(); + if (frame.hasRightHandle()) { + if (frame.rightHandle().y() < m_minY) + m_minY = frame.rightHandle().y(); - if (frame.position().y() > m_maxY) - m_maxY = frame.position().y(); - - if (frame.hasLeftHandle()) { - if (frame.leftHandle().y() < m_minY) - m_minY = frame.leftHandle().y(); - - if (frame.leftHandle().y() > m_maxY) - m_maxY = frame.leftHandle().y(); - } - - if (frame.hasRightHandle()) { - if (frame.rightHandle().y() < m_minY) - m_minY = frame.rightHandle().y(); - - if (frame.rightHandle().y() > m_maxY) - m_maxY = frame.rightHandle().y(); - } + if (frame.rightHandle().y() > m_maxY) + m_maxY = frame.rightHandle().y(); } } } diff --git a/src/plugins/qmldesigner/components/curveeditor/animationcurve.h b/src/plugins/qmldesigner/components/curveeditor/animationcurve.h index d364fd247c9..ba39ecd3471 100644 --- a/src/plugins/qmldesigner/components/curveeditor/animationcurve.h +++ b/src/plugins/qmldesigner/components/curveeditor/animationcurve.h @@ -46,6 +46,8 @@ public: AnimationCurve(const QEasingCurve &easing, const QPointF &start, const QPointF &end); + bool isEmpty() const; + bool isValid() const; bool isFromData() const; diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditormodel.cpp b/src/plugins/qmldesigner/components/curveeditor/curveeditormodel.cpp index 6b52b3d1db1..d357d555f7a 100644 --- a/src/plugins/qmldesigner/components/curveeditor/curveeditormodel.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/curveeditormodel.cpp @@ -255,7 +255,7 @@ TreeItem *CurveEditorModel::createTopLevelItem(const QmlDesigner::QmlTimeline &t for (auto &&grp : timeline.keyframeGroupsForTarget(node)) { if (grp.isValid()) { AnimationCurve curve = createAnimationCurve(grp); - if (curve.isValid()) { + if (!curve.isEmpty()) { QString name = QString::fromUtf8(grp.propertyName()); auto propertyItem = new PropertyTreeItem(name, curve, typeFrom(grp)); diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditorview.cpp b/src/plugins/qmldesigner/components/curveeditor/curveeditorview.cpp index 3f3f60d50a4..5172d10d8db 100644 --- a/src/plugins/qmldesigner/components/curveeditor/curveeditorview.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/curveeditorview.cpp @@ -101,6 +101,9 @@ void CurveEditorView::nodeRemoved(const ModelNode &removedNode, ModelNode parent = parentProperty.parentModelNode(); if (dirtyfiesView(parent)) updateKeyframes(); + + if (!activeTimeline().isValid()) + m_model->reset({}); } void CurveEditorView::nodeReparented(const ModelNode &node, diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/curveitem.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/curveitem.cpp index b81fe960b60..5a0d7c40434 100644 --- a/src/plugins/qmldesigner/components/curveeditor/detail/curveitem.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/detail/curveitem.cpp @@ -292,7 +292,7 @@ std::vector CurveItem::curves() const } } - if (tmp.size() >= 2) + if (!tmp.empty()) out.push_back(AnimationCurve(tmp)); return out; @@ -372,6 +372,9 @@ void CurveItem::restore() currItem->setInterpolation(segment.interpolation()); prevItem = currItem; } + + // It is now the last item. + prevItem->setRightHandle(QPointF()); } void CurveItem::setDirty(bool dirty) @@ -404,12 +407,12 @@ void CurveItem::setCurve(const AnimationCurve &curve) item->setLocked(locked()); item->setComponentTransform(m_transform); m_keyframes.push_back(item); - QObject::connect(item, &KeyframeItem::redrawCurve, this, &CurveItem::emitCurveChanged); + QObject::connect(item, &KeyframeItem::redrawCurve, this, &CurveItem::markDirty); QObject::connect(item, &KeyframeItem::keyframeMoved, this, &CurveItem::keyframeMoved); QObject::connect(item, &KeyframeItem::handleMoved, this, &CurveItem::handleMoved); } - emitCurveChanged(); + markDirty(); } QRectF CurveItem::setComponentTransform(const QTransform &transform) @@ -499,10 +502,12 @@ void CurveItem::deleteSelectedKeyframes() m_keyframes.erase(iter, m_keyframes.end()); restore(); - emitCurveChanged(); + markDirty(); + + emit curveChanged(id(), curve()); } -void CurveItem::emitCurveChanged() +void CurveItem::markDirty() { setDirty(true); update(); diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/curveitem.h b/src/plugins/qmldesigner/components/curveeditor/detail/curveitem.h index 00a3a9c3604..f6857f7c065 100644 --- a/src/plugins/qmldesigner/components/curveeditor/detail/curveitem.h +++ b/src/plugins/qmldesigner/components/curveeditor/detail/curveitem.h @@ -134,7 +134,7 @@ public: void deleteSelectedKeyframes(); private: - void emitCurveChanged(); + void markDirty(); unsigned int m_id; diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsscene.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsscene.cpp index 688c1e4fb1f..9198a4d9e57 100644 --- a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsscene.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsscene.cpp @@ -216,6 +216,7 @@ void GraphicsScene::reset() void GraphicsScene::deleteSelectedKeyframes() { + m_dirty = true; for (auto *curve : qAsConst(m_curves)) curve->deleteSelectedKeyframes(); } diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp index 9324059cf79..8ed0653a11a 100644 --- a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp @@ -72,8 +72,8 @@ GraphicsView::GraphicsView(CurveEditorModel *model, QWidget *parent) connect(&m_dialog, &CurveEditorStyleDialog::styleChanged, this, &GraphicsView::setStyle); auto itemSlot = [this](unsigned int id, const AnimationCurve &curve) { - applyZoom(m_zoomX, m_zoomY); m_model->setCurve(id, curve); + applyZoom(m_zoomX, m_zoomY); }; connect(m_scene, &GraphicsScene::curveChanged, itemSlot); @@ -671,11 +671,15 @@ void GraphicsView::drawValueScale(QPainter *painter, const QRectF &rect) painter->drawText(textRect, Qt::AlignCenter, valueText); }; - double density = 1. / (static_cast(fm.height()) * m_style.labelDensityY); - Axis axis = Axis::compute(minimumValue(), maximumValue(), rect.height(), density); - const double eps = 1.0e-10; - for (double i = axis.lmin; i <= axis.lmax + eps; i += axis.lstep) - paintLabeledTick(i); + double min = minimumValue(); + double max = maximumValue(); + if (std::isfinite(min) && std::isfinite(max) && rect.isValid()) { + double density = 1. / (static_cast(fm.height()) * m_style.labelDensityY); + Axis axis = Axis::compute(min, max, rect.height(), density); + const double eps = 1.0e-10; + for (double i = axis.lmin; i <= axis.lmax + eps; i += axis.lstep) + paintLabeledTick(i); + } painter->restore(); } diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelineitem.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelineitem.cpp index 6d7fb552621..665b7b88dc3 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelineitem.cpp +++ b/src/plugins/qmldesigner/components/timelineeditor/timelineitem.cpp @@ -242,13 +242,8 @@ void TimelineFrameHandle::scrollOutOfBoundsMax() { const double width = abstractScrollGraphicsScene()->width(); if (QApplication::mouseButtons() == Qt::LeftButton) { - const double frameWidth = abstractScrollGraphicsScene()->rulerScaling(); - const double upperThreshold = width - frameWidth; - - if (rect().center().x() > upperThreshold) { - abstractScrollGraphicsScene()->setScrollOffset(computeScrollSpeed()); - abstractScrollGraphicsScene()->invalidateScrollbar(); - } + abstractScrollGraphicsScene()->setScrollOffset(computeScrollSpeed()); + abstractScrollGraphicsScene()->invalidateScrollbar(); callSetClampedXPosition(width - (rect().width() / 2) - 1); m_timer.start();