From 5b000d17cb2f42891db7bd8c9c857866245eddd3 Mon Sep 17 00:00:00 2001 From: Knud Dollereder Date: Fri, 21 Feb 2020 15:28:31 +0100 Subject: QmlDesigner: Add the ability to modify the animation range Add the ability to modify the animation range from the curve editor Fix a synchronization issue between timeline and curve editor when the animation contains pinned curves Change-Id: I89dda234063259f41d662749d696f5fc8a04f988 Reviewed-by: Thomas Hartmann --- .../components/curveeditor/curveeditor.cpp | 47 ++++++++++++--- .../components/curveeditor/curveeditor.h | 2 +- .../components/curveeditor/curveeditormodel.cpp | 23 +++++++- .../components/curveeditor/curveeditormodel.h | 19 +++++- .../components/curveeditor/detail/graphicsview.cpp | 68 ++++++++++++++++++++++ .../components/curveeditor/detail/graphicsview.h | 8 +++ .../timelineeditor/animationcurveeditormodel.cpp | 14 +---- .../timelineeditor/animationcurveeditormodel.h | 8 --- .../components/timelineeditor/timelinetoolbar.cpp | 22 ++++++- .../components/timelineeditor/timelinewidget.cpp | 2 + 10 files changed, 179 insertions(+), 34 deletions(-) diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp b/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp index c6eb2f6327..f5b2ffae1b 100644 --- a/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp @@ -48,15 +48,18 @@ CurveEditor::CurveEditor(CurveEditorModel *model, QWidget *parent) splitter->setStretchFactor(1, 2); auto *box = new QVBoxLayout; - box->addWidget(createToolBar()); + box->addWidget(createToolBar(model)); box->addWidget(splitter); setLayout(box); - connect(m_tree, &TreeView::treeItemLocked, m_view, &GraphicsView::setLocked); - connect(m_tree->selectionModel(), &SelectionModel::curvesSelected, m_view, &GraphicsView::reset); - connect(m_tree, &TreeView::treeItemLocked, model, &CurveEditorModel::curveChanged); connect(m_tree, &TreeView::treeItemPinned, model, &CurveEditorModel::curveChanged); + + connect(m_tree, &TreeView::treeItemLocked, m_view, &GraphicsView::setLocked); + connect(m_tree->selectionModel(), + &SelectionModel::curvesSelected, + m_view, + &GraphicsView::updateSelection); } void CurveEditor::zoomX(double zoom) @@ -74,7 +77,7 @@ void CurveEditor::clearCanvas() m_view->reset({}); } -QToolBar *CurveEditor::createToolBar() +QToolBar *CurveEditor::createToolBar(CurveEditorModel *model) { auto *bar = new QToolBar; bar->setFloatable(false); @@ -111,8 +114,38 @@ QToolBar *CurveEditor::createToolBar() bar->addWidget(valueWidget); auto *durationBox = new QHBoxLayout; - durationBox->addWidget(new QLabel(tr("Duration"))); - durationBox->addWidget(new QSpinBox); + auto *startSpin = new QSpinBox; + auto *endSpin = new QSpinBox; + + startSpin->setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); + startSpin->setValue(model->minimumTime()); + + auto updateStartFrame = [this, model](int frame) { + model->setMinimumTime(frame, false); + m_view->viewport()->update(); + }; + connect(startSpin, QOverload::of(&QSpinBox::valueChanged), updateStartFrame); + + endSpin->setRange(std::numeric_limits::lowest(), std::numeric_limits::max()); + endSpin->setValue(model->maximumTime()); + + auto updateEndFrame = [this, model](int frame) { + model->setMaximumTime(frame, false); + m_view->viewport()->update(); + }; + connect(endSpin, QOverload::of(&QSpinBox::valueChanged), updateEndFrame); + + auto setStartSlot = [startSpin](int frame) { startSpin->setValue(frame); }; + connect(model, &CurveEditorModel::updateStartFrame, setStartSlot); + + auto setEndSlot = [endSpin](int frame) { endSpin->setValue(frame); }; + connect(model, &CurveEditorModel::updateEndFrame, setEndSlot); + + durationBox->addWidget(new QLabel(tr("Start Frame"))); + durationBox->addWidget(startSpin); + durationBox->addWidget(new QLabel(tr("End Frame"))); + durationBox->addWidget(endSpin); + auto *durationWidget = new QWidget; durationWidget->setLayout(durationBox); bar->addWidget(durationWidget); diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditor.h b/src/plugins/qmldesigner/components/curveeditor/curveeditor.h index c82204d83f..b6d9cfc013 100644 --- a/src/plugins/qmldesigner/components/curveeditor/curveeditor.h +++ b/src/plugins/qmldesigner/components/curveeditor/curveeditor.h @@ -48,7 +48,7 @@ public: void clearCanvas(); private: - QToolBar *createToolBar(); + QToolBar *createToolBar(CurveEditorModel *model); TreeView *m_tree; diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditormodel.cpp b/src/plugins/qmldesigner/components/curveeditor/curveeditormodel.cpp index 1769c1d6dd..e6f0f3e326 100644 --- a/src/plugins/qmldesigner/components/curveeditor/curveeditormodel.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/curveeditormodel.cpp @@ -25,13 +25,16 @@ #include "curveeditormodel.h" #include "treeitem.h" + #include "detail/graphicsview.h" #include "detail/selectionmodel.h" namespace DesignTools { -CurveEditorModel::CurveEditorModel(QObject *parent) +CurveEditorModel::CurveEditorModel(double minTime, double maxTime, QObject *parent) : TreeModel(parent) + , m_minTime(minTime) + , m_maxTime(maxTime) {} CurveEditorModel::~CurveEditorModel() {} @@ -42,6 +45,24 @@ void CurveEditorModel::setCurrentFrame(int frame) graphicsView()->setCurrentFrame(frame); } +void CurveEditorModel::setMinimumTime(double time, bool internal) +{ + m_minTime = time; + if (internal) + emit updateStartFrame(m_minTime); + else + emit startFrameChanged(m_minTime); +} + +void CurveEditorModel::setMaximumTime(double time, bool internal) +{ + m_maxTime = time; + if (internal) + emit updateEndFrame(m_maxTime); + else + emit endFrameChanged(m_maxTime); +} + void CurveEditorModel::setCurve(unsigned int id, const AnimationCurve &curve) { if (TreeItem *item = find(id)) { diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditormodel.h b/src/plugins/qmldesigner/components/curveeditor/curveeditormodel.h index 6e212d4c6a..48d05586a2 100644 --- a/src/plugins/qmldesigner/components/curveeditor/curveeditormodel.h +++ b/src/plugins/qmldesigner/components/curveeditor/curveeditormodel.h @@ -48,6 +48,14 @@ class CurveEditorModel : public TreeModel signals: void currentFrameChanged(int frame); + void startFrameChanged(int frame); + + void endFrameChanged(int frame); + + void updateStartFrame(int frame); + + void updateEndFrame(int frame); + void curveChanged(PropertyTreeItem *item); public: @@ -58,15 +66,24 @@ public: virtual CurveEditorStyle style() const = 0; public: - CurveEditorModel(QObject *parent = nullptr); + CurveEditorModel(double minTime, double maxTime, QObject *parent = nullptr); ~CurveEditorModel() override; void setCurrentFrame(int frame); + void setMinimumTime(double time, bool internal); + + void setMaximumTime(double time, bool internal); + void setCurve(unsigned int id, const AnimationCurve &curve); void reset(const std::vector &items); + +protected: + double m_minTime = 0.; + + double m_maxTime = 0.; }; } // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp index 51e4b35c88..b51d916fb0 100644 --- a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp @@ -230,6 +230,16 @@ void GraphicsView::scrollContent(double x, double y) } void GraphicsView::reset(const std::vector &items) +{ + m_scene.clear(); + for (auto *item : items) + m_scene.addCurveItem(item); + + applyZoom(m_zoomX, m_zoomY); + viewport()->update(); +} + +void GraphicsView::updateSelection(const std::vector &items) { const std::vector pinnedItems = m_scene.takePinnedItems(); auto notPinned = [pinnedItems](CurveItem *item) { @@ -541,6 +551,38 @@ void GraphicsView::drawExtremaY(QPainter *painter, const QRectF &rect) } #endif +void GraphicsView::drawRangeBar(QPainter *painter, const QRectF &rect) +{ + QFontMetrics fm(painter->font()); + QRectF labelRect = fm.boundingRect(QString("0")); + labelRect.moveCenter(rect.center()); + + qreal bTick = rect.bottom() - 2; + qreal tTick = labelRect.bottom() + 2; + QRectF activeRect = QRectF(QPointF(mapTimeToX(m_model->minimumTime()), tTick), + QPointF(mapTimeToX(m_model->maximumTime()), bTick)); + + QColor color = Qt::white; + color.setAlpha(30); + + painter->fillRect(activeRect, color); + + QColor handleColor(Qt::green); + painter->setBrush(handleColor); + painter->setPen(handleColor); + + const qreal radius = 5.; + QRectF minHandle = rangeMinHandle(rect); + painter->drawRoundedRect(minHandle, radius, radius); + minHandle.setLeft(minHandle.center().x()); + painter->fillRect(minHandle, Qt::green); + + QRectF maxHandle = rangeMaxHandle(rect); + painter->drawRoundedRect(maxHandle, radius, radius); + maxHandle.setRight(maxHandle.center().x()); + painter->fillRect(maxHandle, Qt::green); +} + void GraphicsView::drawTimeScale(QPainter *painter, const QRectF &rect) { painter->save(); @@ -565,6 +607,8 @@ void GraphicsView::drawTimeScale(QPainter *painter, const QRectF &rect) for (double i = minimumTime(); i <= maximumTime(); i += timeIncrement) paintLabeledTick(i); + drawRangeBar(painter, rect); + painter->restore(); } @@ -619,4 +663,28 @@ double GraphicsView::timeLabelInterval(QPainter *painter, double maxTime) return deltaTime; } +QRectF GraphicsView::rangeMinHandle(const QRectF &rect) +{ + QRectF labelRect = fontMetrics().boundingRect(QString("0")); + labelRect.moveCenter(rect.center()); + + qreal top = rect.bottom() - 2; + qreal bottom = labelRect.bottom() + 2; + QSize size(10, top - bottom); + + int leftHandleLeft = mapTimeToX(m_model->minimumTime()) - size.width(); + return QRectF(QPointF(leftHandleLeft, bottom), size); +} + +QRectF GraphicsView::rangeMaxHandle(const QRectF &rect) +{ + QRectF labelRect = fontMetrics().boundingRect(QString("0")); + labelRect.moveCenter(rect.center()); + + qreal bottom = rect.bottom() - 2; + qreal top = labelRect.bottom() + 2; + + return QRectF(QPointF(mapTimeToX(m_model->maximumTime()), bottom), QSize(10, top - bottom)); +} + } // End namespace DesignTools. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.h b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.h index d56dfa7c57..7308d77608 100644 --- a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.h +++ b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.h @@ -108,6 +108,8 @@ public: void reset(const std::vector &items); + void updateSelection(const std::vector &items); + void setInterpolation(Keyframe::Interpolation interpol); protected: @@ -148,8 +150,14 @@ private: void drawValueScale(QPainter *painter, const QRectF &rect); + void drawRangeBar(QPainter *painter, const QRectF &rect); + double timeLabelInterval(QPainter *painter, double maxTime); + QRectF rangeMinHandle(const QRectF &rect); + + QRectF rangeMaxHandle(const QRectF &rect); + private: double m_zoomX; diff --git a/src/plugins/qmldesigner/components/timelineeditor/animationcurveeditormodel.cpp b/src/plugins/qmldesigner/components/timelineeditor/animationcurveeditormodel.cpp index ce7beba2c9..e09d09532d 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/animationcurveeditormodel.cpp +++ b/src/plugins/qmldesigner/components/timelineeditor/animationcurveeditormodel.cpp @@ -35,9 +35,7 @@ namespace QmlDesigner { AnimationCurveEditorModel::AnimationCurveEditorModel(double minTime, double maxTime) - : CurveEditorModel() - , m_minTime(minTime) - , m_maxTime(maxTime) + : CurveEditorModel(minTime, maxTime) {} AnimationCurveEditorModel::~AnimationCurveEditorModel() {} @@ -102,16 +100,6 @@ void AnimationCurveEditorModel::setTimeline(const QmlTimeline &timeline) reset(items); } -void AnimationCurveEditorModel::setMinimumTime(double time) -{ - m_minTime = time; -} - -void AnimationCurveEditorModel::setMaximumTime(double time) -{ - m_maxTime = time; -} - DesignTools::ValueType typeFrom(const QmlTimelineKeyframeGroup &group) { if (group.valueType() == TypeName("double") || group.valueType() == TypeName("real") diff --git a/src/plugins/qmldesigner/components/timelineeditor/animationcurveeditormodel.h b/src/plugins/qmldesigner/components/timelineeditor/animationcurveeditormodel.h index fe85929cf1..4da0be62b0 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/animationcurveeditormodel.h +++ b/src/plugins/qmldesigner/components/timelineeditor/animationcurveeditormodel.h @@ -49,20 +49,12 @@ public: void setTimeline(const QmlTimeline &timeline); - void setMinimumTime(double time); - - void setMaximumTime(double time); - private: DesignTools::TreeItem *createTopLevelItem(const QmlTimeline &timeline, const ModelNode &node); DesignTools::AnimationCurve createAnimationCurve(const QmlTimelineKeyframeGroup &group); DesignTools::AnimationCurve createDoubleCurve(const QmlTimelineKeyframeGroup &group); - - double m_minTime; - - double m_maxTime; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinetoolbar.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinetoolbar.cpp index ea065e49a1..5d693f5422 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelinetoolbar.cpp +++ b/src/plugins/qmldesigner/components/timelineeditor/timelinetoolbar.cpp @@ -38,7 +38,6 @@ #include #include #include -#include #include #include @@ -112,6 +111,23 @@ TimelineToolBar::TimelineToolBar(QWidget *parent) &AnimationCurveEditorModel::currentFrameChanged, this, &TimelineToolBar::currentFrameChanged); + + auto setStartFrameValue = [this](int val) { + if (m_firstFrame) { + m_firstFrame->setText(QString::number(val, 'f', 0)); + emit startFrameChanged(val); + } + }; + connect(m_curveModel, &AnimationCurveEditorModel::startFrameChanged, setStartFrameValue); + + auto setEndFrameValue = [this](int val) { + if (m_lastFrame) { + m_lastFrame->setText(QString::number(val, 'f', 0)); + emit endFrameChanged(val); + } + }; + connect(m_curveModel, &AnimationCurveEditorModel::endFrameChanged, setEndFrameValue); + connect(m_curveModel, &AnimationCurveEditorModel::curveChanged, this, @@ -181,7 +197,7 @@ void TimelineToolBar::setCurrentTimeline(const QmlTimeline &timeline) void TimelineToolBar::setStartFrame(qreal frame) { - m_curveModel->setMinimumTime(frame); + m_curveModel->setMinimumTime(frame, true); auto text = QString::number(frame, 'f', 0); m_firstFrame->setText(text); @@ -198,7 +214,7 @@ void TimelineToolBar::setCurrentFrame(qreal frame) void TimelineToolBar::setEndFrame(qreal frame) { - m_curveModel->setMaximumTime(frame); + m_curveModel->setMaximumTime(frame, true); auto text = QString::number(frame, 'f', 0); m_lastFrame->setText(text); diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp index e7f12fb5a2..d80749ad08 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp +++ b/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp @@ -459,6 +459,8 @@ void TimelineWidget::invalidateTimelineDuration(const QmlTimeline &timeline) if (timelineView() && timelineView()->model()) { QmlTimeline currentTimeline = graphicsScene()->currentTimeline(); if (currentTimeline.isValid() && currentTimeline == timeline) { + m_toolbar->setStartFrame(timeline.startKeyframe()); + m_toolbar->setEndFrame(timeline.endKeyframe()); graphicsScene()->setTimeline(timeline); qreal playHeadFrame = getcurrentFrame(timeline); -- cgit v1.2.3