diff --git a/src/plugins/qmldesigner/components/curveeditor/animationcurve.cpp b/src/plugins/qmldesigner/components/curveeditor/animationcurve.cpp index 3e910638daf..36e577d38d7 100644 --- a/src/plugins/qmldesigner/components/curveeditor/animationcurve.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/animationcurve.cpp @@ -36,14 +36,16 @@ namespace QmlDesigner { AnimationCurve::AnimationCurve() - : m_fromData(false) + : m_type(AnimationCurve::ValueType::Undefined) + , m_fromData(false) , m_minY(std::numeric_limits::max()) , m_maxY(std::numeric_limits::lowest()) , m_frames() {} -AnimationCurve::AnimationCurve(const std::vector &frames) - : m_fromData(false) +AnimationCurve::AnimationCurve(AnimationCurve::ValueType type, const std::vector &frames) + : m_type(type) + , m_fromData(false) , m_minY(std::numeric_limits::max()) , m_maxY(std::numeric_limits::lowest()) , m_frames(frames) @@ -51,8 +53,13 @@ AnimationCurve::AnimationCurve(const std::vector &frames) analyze(); } -AnimationCurve::AnimationCurve(const QEasingCurve &easing, const QPointF &start, const QPointF &end) - : m_fromData(true) +AnimationCurve::AnimationCurve( + AnimationCurve::ValueType type, + const QEasingCurve &easing, + const QPointF &start, + const QPointF &end) + : m_type(type) + , m_fromData(true) , m_minY(std::numeric_limits::max()) , m_maxY(std::numeric_limits::lowest()) , m_frames() @@ -117,6 +124,11 @@ bool AnimationCurve::hasUnified() const return false; } +AnimationCurve::ValueType AnimationCurve::valueType() const +{ + return m_type; +} + double AnimationCurve::minimumTime() const { if (!m_frames.empty()) diff --git a/src/plugins/qmldesigner/components/curveeditor/animationcurve.h b/src/plugins/qmldesigner/components/curveeditor/animationcurve.h index ba39ecd3471..1c51d05d806 100644 --- a/src/plugins/qmldesigner/components/curveeditor/animationcurve.h +++ b/src/plugins/qmldesigner/components/curveeditor/animationcurve.h @@ -40,11 +40,17 @@ class CurveSegment; class AnimationCurve { public: + using ValueType = Keyframe::ValueType; + AnimationCurve(); - AnimationCurve(const std::vector &frames); + AnimationCurve(ValueType type, const std::vector &frames); - AnimationCurve(const QEasingCurve &easing, const QPointF &start, const QPointF &end); + AnimationCurve( + ValueType type, + const QEasingCurve &easing, + const QPointF &start, + const QPointF &end); bool isEmpty() const; @@ -54,6 +60,8 @@ public: bool hasUnified() const; + ValueType valueType() const; + double minimumTime() const; double maximumTime() const; @@ -93,6 +101,8 @@ public: private: void analyze(); + ValueType m_type; + bool m_fromData; double m_minY; diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp b/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp index 217e0e0eb76..29e88e2581d 100644 --- a/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp @@ -42,6 +42,7 @@ namespace QmlDesigner { CurveEditor::CurveEditor(CurveEditorModel *model, QWidget *parent) : QWidget(parent) , m_infoText(nullptr) + , m_statusLine(nullptr) , m_toolbar(new CurveEditorToolBar(model, this)) , m_tree(new TreeView(model, this)) , m_view(new GraphicsView(model, this)) @@ -61,10 +62,13 @@ CurveEditor::CurveEditor(CurveEditorModel *model, QWidget *parent) area->setWidget(splitter); area->setWidgetResizable(true); + m_statusLine = new QLabel(); + auto *box = new QVBoxLayout; box->addWidget(m_infoText); box->addWidget(m_toolbar); box->addWidget(area); + box->addWidget(m_statusLine); setLayout(box); connect(m_toolbar, &CurveEditorToolBar::defaultClicked, [this]() { @@ -89,9 +93,11 @@ CurveEditor::CurveEditor(CurveEditorModel *model, QWidget *parent) m_view->viewport()->update(); }); - connect( - m_toolbar, &CurveEditorToolBar::currentFrameChanged, - model, &CurveEditorModel::commitCurrentFrame); + connect(m_toolbar, &CurveEditorToolBar::currentFrameChanged, [this, model](int frame) { + model->setCurrentFrame(frame); + updateStatusLine(); + m_view->viewport()->update(); + }); connect( m_view, &GraphicsView::currentFrameChanged, @@ -106,6 +112,8 @@ CurveEditor::CurveEditor(CurveEditorModel *model, QWidget *parent) auto updateTimeline = [this, model](bool validTimeline) { if (validTimeline) { + updateStatusLine(); + m_view->setCurrentFrame(m_view->model()->currentFrame(), false); m_toolbar->updateBoundsSilent(model->minimumTime(), model->maximumTime()); m_toolbar->show(); m_tree->show(); @@ -119,6 +127,8 @@ CurveEditor::CurveEditor(CurveEditorModel *model, QWidget *parent) } }; connect(model, &CurveEditorModel::timelineChanged, this, updateTimeline); + + connect(model, &CurveEditorModel::setStatusLineMsg, m_statusLine, &QLabel::setText); } bool CurveEditor::dragging() const @@ -153,4 +163,11 @@ void CurveEditor::hideEvent(QHideEvent *event) QWidget::hideEvent(event); } +void CurveEditor::updateStatusLine() +{ + int currentFrame = m_view->model()->currentFrame(); + QString currentText = QString("Playhead frame %1").arg(currentFrame); + m_statusLine->setText(currentText); +} + } // End namespace QmlDesigner. diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditor.h b/src/plugins/qmldesigner/components/curveeditor/curveeditor.h index 9d1a6f68f94..2265c5538f8 100644 --- a/src/plugins/qmldesigner/components/curveeditor/curveeditor.h +++ b/src/plugins/qmldesigner/components/curveeditor/curveeditor.h @@ -59,8 +59,12 @@ protected: void hideEvent(QHideEvent *event) override; private: + void updateStatusLine(); + QLabel *m_infoText; + QLabel *m_statusLine; + CurveEditorToolBar *m_toolbar; TreeView *m_tree; diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditormodel.cpp b/src/plugins/qmldesigner/components/curveeditor/curveeditormodel.cpp index 43776718174..fb60298e612 100644 --- a/src/plugins/qmldesigner/components/curveeditor/curveeditormodel.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/curveeditormodel.cpp @@ -44,12 +44,18 @@ namespace QmlDesigner { CurveEditorModel::CurveEditorModel(QObject *parent) : TreeModel(parent) , m_hasTimeline(false) + , m_currentFrame(0) , m_minTime(CurveEditorStyle::defaultTimeMin) , m_maxTime(CurveEditorStyle::defaultTimeMax) {} CurveEditorModel::~CurveEditorModel() {} +int CurveEditorModel::currentFrame() const +{ + return m_currentFrame; +} + double CurveEditorModel::minimumTime() const { return m_minTime; @@ -102,6 +108,7 @@ void CurveEditorModel::setTimeline(const QmlDesigner::QmlTimeline &timeline) m_hasTimeline = timeline.isValid(); if (m_hasTimeline) { + m_currentFrame = static_cast(timeline.currentKeyframe()); m_minTime = timeline.startKeyframe(); m_maxTime = timeline.endKeyframe(); std::vector items; @@ -116,8 +123,8 @@ void CurveEditorModel::setTimeline(const QmlDesigner::QmlTimeline &timeline) void CurveEditorModel::setCurrentFrame(int frame) { - if (graphicsView()) - graphicsView()->setCurrentFrame(frame, false); + m_currentFrame = frame; + emit commitCurrentFrame(m_currentFrame); } void CurveEditorModel::setMinimumTime(double time) @@ -262,7 +269,7 @@ TreeItem *CurveEditorModel::createTopLevelItem(const QmlDesigner::QmlTimeline &t AnimationCurve curve = createAnimationCurve(grp); if (!curve.isEmpty()) { QString name = QString::fromUtf8(grp.propertyName()); - auto propertyItem = new PropertyTreeItem(name, curve, typeFrom(grp)); + auto propertyItem = new PropertyTreeItem(name, curve); QmlDesigner::ModelNode target = grp.modelNode(); if (target.hasAuxiliaryData("locked")) @@ -288,7 +295,7 @@ AnimationCurve CurveEditorModel::createAnimationCurve(const QmlDesigner::QmlTime { switch (typeFrom(group)) { case PropertyTreeItem::ValueType::Bool: - return createDoubleCurve(group); + return createBooleanCurve(group); case PropertyTreeItem::ValueType::Integer: return createDoubleCurve(group); @@ -346,7 +353,13 @@ std::vector resolveSmallCurves(const std::vector &frames) continue; } #endif - AnimationCurve acurve(curve, previous.position(), frame.position()); + // This is just a temporary curve. ValueType does not matter + AnimationCurve acurve( + AnimationCurve::ValueType::Undefined, + curve, + previous.position(), + frame.position()); + previous.setRightHandle(acurve.keyframeAt(0).rightHandle()); out.push_back(acurve.keyframeAt(1)); continue; @@ -357,6 +370,17 @@ std::vector resolveSmallCurves(const std::vector &frames) return out; } + +AnimationCurve CurveEditorModel::createBooleanCurve(const QmlDesigner::QmlTimelineKeyframeGroup &group) +{ + std::vector keyframes = createKeyframes(group.keyframePositions()); + + for (auto& keyframe : keyframes) + keyframe.setInterpolation(Keyframe::Interpolation::Step); + + return AnimationCurve(typeFrom(group), keyframes); +} + AnimationCurve CurveEditorModel::createDoubleCurve(const QmlDesigner::QmlTimelineKeyframeGroup &group) { std::vector keyframes = createKeyframes(group.keyframePositions()); @@ -374,7 +398,7 @@ AnimationCurve CurveEditorModel::createDoubleCurve(const QmlDesigner::QmlTimelin } } - return AnimationCurve(keyframes); + return AnimationCurve(typeFrom(group), keyframes); } } // End namespace QmlDesigner. diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditormodel.h b/src/plugins/qmldesigner/components/curveeditor/curveeditormodel.h index 041642aa610..aa804058c64 100644 --- a/src/plugins/qmldesigner/components/curveeditor/curveeditormodel.h +++ b/src/plugins/qmldesigner/components/curveeditor/curveeditormodel.h @@ -48,6 +48,8 @@ class CurveEditorModel : public TreeModel Q_OBJECT signals: + void setStatusLineMsg(const QString& msg); + void commitCurrentFrame(int frame); void commitStartFrame(int frame); @@ -63,6 +65,8 @@ public: ~CurveEditorModel() override; + int currentFrame() const; + double minimumTime() const; double maximumTime() const; @@ -92,10 +96,14 @@ private: AnimationCurve createAnimationCurve(const QmlDesigner::QmlTimelineKeyframeGroup &group); + AnimationCurve createBooleanCurve(const QmlDesigner::QmlTimelineKeyframeGroup &group); + AnimationCurve createDoubleCurve(const QmlDesigner::QmlTimelineKeyframeGroup &group); bool m_hasTimeline = false; + int m_currentFrame = 0; + double m_minTime = 0.; double m_maxTime = 0.; diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditorview.cpp b/src/plugins/qmldesigner/components/curveeditor/curveeditorview.cpp index 559a97c8fbc..5368512d315 100644 --- a/src/plugins/qmldesigner/components/curveeditor/curveeditorview.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/curveeditorview.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include @@ -214,6 +215,9 @@ void CurveEditorView::propertiesRemoved(const QList &propertyL QmlTimeline CurveEditorView::activeTimeline() const { + if (!isAttached()) + return {}; + QmlModelState state = currentState(); if (state.isBaseState()) { for (const ModelNode &node : allModelNodesOfType("QtQuick.Timeline.Timeline")) { @@ -334,42 +338,56 @@ void commitAuxiliaryData(ModelNode &node, TreeItem *item) void CurveEditorView::commitKeyframes(TreeItem *item) { + if (!isAttached()) + return; + if (auto *nitem = item->asNodeItem()) { ModelNode node = modelNodeForId(nitem->name()); commitAuxiliaryData(node, item); } else if (auto *pitem = item->asPropertyItem()) { QmlTimeline currentTimeline = activeTimeline(); + if (!currentTimeline.isValid()) + return; + QmlTimelineKeyframeGroup group = timelineKeyframeGroup(currentTimeline, pitem); if (group.isValid()) { ModelNode groupNode = group.modelNode(); commitAuxiliaryData(groupNode, item); - auto replaceKeyframes = [&group, pitem, this]() { + auto replaceKeyframes = [&group, pitem, this]() mutable { m_block = true; - for (auto frame : group.keyframes()) + + for (auto& frame : group.keyframes()) frame.destroy(); - Keyframe previous; - for (auto &&frame : pitem->curve().keyframes()) { - QPointF pos = frame.position(); - group.setValue(QVariant(pos.y()), pos.x()); - - if (previous.isValid()) { - if (frame.interpolation() == Keyframe::Interpolation::Bezier || - frame.interpolation() == Keyframe::Interpolation::Step ) { - CurveSegment segment(previous, frame); - if (segment.isValid()) - attachEasingCurve(group, pos.x(), segment.easingCurve()); - } else if (frame.interpolation() == Keyframe::Interpolation::Easing) { - QVariant data = frame.data(); - if (data.type() == static_cast(QMetaType::QEasingCurve)) - attachEasingCurve(group, pos.x(), data.value()); - } + AnimationCurve curve = pitem->curve(); + if (curve.valueType() == AnimationCurve::ValueType::Bool) { + for (const auto& frame : curve.keyframes()) { + QPointF pos = frame.position(); + group.setValue(QVariant(pos.y()), pos.x()); } + } else { + Keyframe previous; + for (const auto& frame : curve.keyframes()) { + QPointF pos = frame.position(); + group.setValue(QVariant(pos.y()), pos.x()); - previous = frame; + if (previous.isValid()) { + if (frame.interpolation() == Keyframe::Interpolation::Bezier || + frame.interpolation() == Keyframe::Interpolation::Step ) { + CurveSegment segment(previous, frame); + if (segment.isValid()) + attachEasingCurve(group, pos.x(), segment.easingCurve()); + } else if (frame.interpolation() == Keyframe::Interpolation::Easing) { + QVariant data = frame.data(); + if (data.type() == static_cast(QMetaType::QEasingCurve)) + attachEasingCurve(group, pos.x(), data.value()); + } + } + previous = frame; + } } m_block = false; }; diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/curveitem.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/curveitem.cpp index 0b7ab9d391d..5b053099763 100644 --- a/src/plugins/qmldesigner/components/curveeditor/detail/curveitem.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/detail/curveitem.cpp @@ -37,22 +37,11 @@ namespace QmlDesigner { -CurveItem::CurveItem(QGraphicsItem *parent) - : CurveEditorItem(parent) - , m_id(0) - , m_style() - , m_type(PropertyTreeItem::ValueType::Undefined) - , m_component(PropertyTreeItem::Component::Generic) - , m_transform() - , m_keyframes() - , m_itemDirty(false) -{} - CurveItem::CurveItem(unsigned int id, const AnimationCurve &curve, QGraphicsItem *parent) : CurveEditorItem(parent) , m_id(id) , m_style() - , m_type(PropertyTreeItem::ValueType::Undefined) + , m_type(curve.valueType()) , m_component(PropertyTreeItem::Component::Generic) , m_transform() , m_keyframes() @@ -235,14 +224,16 @@ PropertyTreeItem::Component CurveItem::component() const return m_component; } -AnimationCurve CurveItem::curve() const +AnimationCurve CurveItem::curve(bool remap) const { std::vector frames; frames.reserve(m_keyframes.size()); - for (auto *frameItem : m_keyframes) - frames.push_back(frameItem->keyframe()); - return AnimationCurve(frames); + bool map = (m_type == AnimationCurve::ValueType::Bool) && remap; + for (auto *frameItem : m_keyframes) + frames.push_back(frameItem->keyframe(map)); + + return AnimationCurve(m_type, frames); } AnimationCurve CurveItem::resolvedCurve() const @@ -278,11 +269,13 @@ std::vector CurveItem::curves() const Keyframe previous = tmp.back(); if (tmp.size() >= 2) - out.push_back(AnimationCurve(tmp)); + out.push_back(AnimationCurve(m_type, tmp)); - out.push_back(AnimationCurve(current.data().value(), - previous.position(), - current.position())); + out.push_back(AnimationCurve( + m_type, + current.data().value(), + previous.position(), + current.position())); tmp.clear(); tmp.push_back(current); @@ -293,7 +286,7 @@ std::vector CurveItem::curves() const } if (!tmp.empty()) - out.push_back(AnimationCurve(tmp)); + out.push_back(AnimationCurve(m_type, tmp)); return out; } @@ -384,7 +377,7 @@ void CurveItem::setDirty(bool dirty) void CurveItem::setHandleVisibility(bool visible) { - for (auto frame : qAsConst(m_keyframes)) + for (auto *frame : qAsConst(m_keyframes)) frame->setHandleVisibility(visible); } @@ -402,7 +395,7 @@ void CurveItem::setCurve(const AnimationCurve &curve) { freeClear(m_keyframes); - for (const auto &frame : curve.keyframes()) { + for (const auto& frame : curve.keyframes()) { auto *item = new KeyframeItem(frame, this); item->setLocked(locked()); item->setComponentTransform(m_transform); @@ -419,7 +412,7 @@ QRectF CurveItem::setComponentTransform(const QTransform &transform) { prepareGeometryChange(); m_transform = transform; - for (auto frame : qAsConst(m_keyframes)) + for (auto *frame : qAsConst(m_keyframes)) frame->setComponentTransform(transform); return boundingRect(); @@ -438,6 +431,14 @@ void CurveItem::setInterpolation(Keyframe::Interpolation interpolation) if (m_keyframes.empty()) return; + if (m_type == AnimationCurve::ValueType::Bool) { + if (interpolation != Keyframe::Interpolation::Step) { + interpolation = Keyframe::Interpolation::Step; + QString msg("Warning: Curves of type bool can only be step-interpolated!"); + emit curveMessage(msg); + } + } + KeyframeItem *prevItem = m_keyframes[0]; for (int i = 1; i < m_keyframes.size(); ++i) { KeyframeItem *currItem = m_keyframes[i]; @@ -454,7 +455,7 @@ void CurveItem::setInterpolation(Keyframe::Interpolation interpolation) prevItem = currItem; } setDirty(false); - emit curveChanged(id(), curve()); + emit curveChanged(id(), curve(true)); } void CurveItem::setDefaultInterpolation() @@ -466,7 +467,7 @@ void CurveItem::setDefaultInterpolation() if (frame->selected()) frame->setDefaultInterpolation(); } - emit curveChanged(id(), curve()); + emit curveChanged(id(), curve(true)); } void CurveItem::toggleUnified() @@ -478,12 +479,13 @@ void CurveItem::toggleUnified() if (frame->selected()) frame->toggleUnified(); } - emit curveChanged(id(), curve()); + emit curveChanged(id(), curve(true)); } void CurveItem::connect(GraphicsScene *scene) { QObject::connect(this, &CurveItem::curveChanged, scene, &GraphicsScene::curveChanged); + QObject::connect(this, &CurveItem::curveMessage, scene, &GraphicsScene::curveMessage); QObject::connect(this, &CurveItem::keyframeMoved, scene, &GraphicsScene::keyframeMoved); QObject::connect(this, &CurveItem::handleMoved, scene, &GraphicsScene::handleMoved); @@ -498,7 +500,7 @@ void CurveItem::insertKeyframeByTime(double time) acurve.insert(time); setCurve(acurve); - emit curveChanged(id(), curve()); + emit curveChanged(id(), curve(true)); } void CurveItem::deleteSelectedKeyframes() @@ -516,7 +518,14 @@ void CurveItem::deleteSelectedKeyframes() markDirty(); - emit curveChanged(id(), curve()); + emit curveChanged(id(), curve(true)); +} + +void CurveItem::remapValue(double min, double max) +{ + for (auto *frameItem : qAsConst(m_keyframes)) { + frameItem->remapValue(min, max); + } } void CurveItem::markDirty() diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/curveitem.h b/src/plugins/qmldesigner/components/curveeditor/detail/curveitem.h index 5a2f363df7f..c6bdc6d3d4c 100644 --- a/src/plugins/qmldesigner/components/curveeditor/detail/curveitem.h +++ b/src/plugins/qmldesigner/components/curveeditor/detail/curveitem.h @@ -46,6 +46,8 @@ class CurveItem : public CurveEditorItem Q_OBJECT signals: + void curveMessage(const QString& msg); + void curveChanged(unsigned int id, const AnimationCurve &curve); void keyframeMoved(KeyframeItem *item, const QPointF &direction); @@ -53,8 +55,6 @@ signals: void handleMoved(KeyframeItem *frame, HandleItem::Slot slot, double angle, double deltaLength); public: - CurveItem(QGraphicsItem *parent = nullptr); - CurveItem(unsigned int id, const AnimationCurve &curve, QGraphicsItem *parent = nullptr); ~CurveItem() override; @@ -93,7 +93,7 @@ public: PropertyTreeItem::Component component() const; - AnimationCurve curve() const; + AnimationCurve curve(bool remap = false) const; AnimationCurve resolvedCurve() const; @@ -135,6 +135,8 @@ public: void deleteSelectedKeyframes(); + void remapValue(double min, double max); + private: void markDirty(); diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsscene.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsscene.cpp index 9eda7f8934b..3506aab811c 100644 --- a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsscene.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsscene.cpp @@ -426,7 +426,7 @@ void GraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent) if (curve->isDirty()) { m_dirty = true; curve->setDirty(false); - emit curveChanged(curve->id(), curve->curve()); + emit curveChanged(curve->id(), curve->curve(true)); } } diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsscene.h b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsscene.h index 2e6bc3b080d..58738d116b1 100644 --- a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsscene.h +++ b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsscene.h @@ -41,6 +41,8 @@ class GraphicsScene : public QGraphicsScene Q_OBJECT signals: + void curveMessage(const QString& msg); + void curveChanged(unsigned int id, const AnimationCurve &curve); public: diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp index 5b4e6e3cfbc..8ab71ace978 100644 --- a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp @@ -83,6 +83,8 @@ GraphicsView::GraphicsView(CurveEditorModel *model, QWidget *parent) connect(&m_dialog, &CurveEditorStyleDialog::styleChanged, this, &GraphicsView::setStyle); + connect(m_scene, &GraphicsScene::curveMessage, m_model, &CurveEditorModel::setStatusLineMsg); + auto itemSlot = [this](unsigned int id, const AnimationCurve &curve) { m_model->setCurve(id, curve); applyZoom(m_zoomX, m_zoomY); @@ -560,7 +562,14 @@ void GraphicsView::applyZoom(double x, double y, const QPoint &pivot) scrollContent(mapTimeToX(deltaTransformed.x()), mapValueToY(deltaTransformed.y())); } + for (auto *curve : m_scene->curves()) { + if (curve->valueType() == AnimationCurve::ValueType::Bool) { + curve->remapValue(minValue, maxValue); + } + } + m_scene->doNotMoveItems(false); + this->update(); } void GraphicsView::drawGrid(QPainter *painter) diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/keyframeitem.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/keyframeitem.cpp index ef0a886d523..49e76a09687 100644 --- a/src/plugins/qmldesigner/components/curveeditor/detail/keyframeitem.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/detail/keyframeitem.cpp @@ -103,8 +103,16 @@ void KeyframeItem::lockedCallback() KeyframeItem::~KeyframeItem() {} -Keyframe KeyframeItem::keyframe() const +Keyframe KeyframeItem::keyframe(bool remap) const { + if (remap) { + auto frame = m_frame; + auto pos = frame.position(); + auto center = m_min + ((m_max - m_min) / 2.0); + pos.ry() = pos.y() > center ? 1.0 : 0.0; + frame.setPosition(pos); + return frame; + } return m_frame; } @@ -350,6 +358,18 @@ void KeyframeItem::moveHandle(HandleItem::Slot slot, double deltaAngle, double d emit redrawCurve(); } +void KeyframeItem::remapValue(double min, double max) +{ + auto center = m_min + ((m_max - m_min) / 2.0); + auto pos = m_frame.position(); + pos.ry() = pos.y() > center ? max : min; + m_frame.setPosition(pos); + + m_max = max; + m_min = min; + setKeyframe(m_frame); +} + void KeyframeItem::updateHandle(HandleItem *handle, bool emitChanged) { bool ok = false; @@ -422,8 +442,10 @@ QVariant KeyframeItem::itemChange(QGraphicsItem::GraphicsItemChange change, cons if (curveItem->valueType() == PropertyTreeItem::ValueType::Integer) position.setY(std::round(position.y())); - else if (curveItem->valueType() == PropertyTreeItem::ValueType::Bool) - position.setY(position.y() > 0.5 ? 1.0 : 0.0); + else if (curveItem->valueType() == PropertyTreeItem::ValueType::Bool) { + double center = m_min + ((m_max - m_min) / 2.0); + position.setY(position.y() > center ? m_max : m_min); + } if (!legalLeft() || !legalRight()) { return QVariant(m_transform.map(position)); diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/keyframeitem.h b/src/plugins/qmldesigner/components/curveeditor/detail/keyframeitem.h index 3e566c84b74..14c3ae74266 100644 --- a/src/plugins/qmldesigner/components/curveeditor/detail/keyframeitem.h +++ b/src/plugins/qmldesigner/components/curveeditor/detail/keyframeitem.h @@ -64,7 +64,7 @@ public: void lockedCallback() override; - Keyframe keyframe() const; + Keyframe keyframe(bool remap = false) const; bool isUnified() const; @@ -106,6 +106,8 @@ public: void moveHandle(HandleItem::Slot slot, double deltaAngle, double deltaLength); + void remapValue(double min, double max); + protected: QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override; @@ -134,6 +136,9 @@ private: QPointF m_validPos; bool m_visibleOverride = true; + + double m_min = 0.0; + double m_max = 1.0; }; } // End namespace QmlDesigner. diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/treemodel.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/treemodel.cpp index c4b6845f51f..91e6dbd6604 100644 --- a/src/plugins/qmldesigner/components/curveeditor/detail/treemodel.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/detail/treemodel.cpp @@ -84,7 +84,6 @@ CurveItem *TreeModel::curveItem(TreeItem *item) { if (auto *pti = item->asPropertyItem()) { auto *citem = new CurveItem(pti->id(), pti->curve()); - citem->setValueType(pti->valueType()); citem->setComponent(pti->component()); citem->setLocked(pti->locked() || item->implicitlyLocked()); citem->setPinned(pti->pinned() || item->implicitlyPinned()); diff --git a/src/plugins/qmldesigner/components/curveeditor/keyframe.h b/src/plugins/qmldesigner/components/curveeditor/keyframe.h index fd3c2cb88bc..2757d229f58 100644 --- a/src/plugins/qmldesigner/components/curveeditor/keyframe.h +++ b/src/plugins/qmldesigner/components/curveeditor/keyframe.h @@ -35,6 +35,7 @@ namespace QmlDesigner { class Keyframe { public: + enum class ValueType { Undefined, Bool, Integer, Double }; enum class Interpolation { Undefined, Step, Linear, Bezier, Easing }; Keyframe(); diff --git a/src/plugins/qmldesigner/components/curveeditor/treeitem.cpp b/src/plugins/qmldesigner/components/curveeditor/treeitem.cpp index 0b90d7d83b0..495b3750c8c 100644 --- a/src/plugins/qmldesigner/components/curveeditor/treeitem.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/treeitem.cpp @@ -321,11 +321,9 @@ std::vector NodeTreeItem::properties() const return out; } -PropertyTreeItem::PropertyTreeItem(const QString &name, - const AnimationCurve &curve, - const ValueType &type) +PropertyTreeItem::PropertyTreeItem(const QString &name, const AnimationCurve &curve) : TreeItem(name) - , m_type(type) + , m_type(curve.valueType()) , m_component(Component::Generic) , m_curve(curve) {} diff --git a/src/plugins/qmldesigner/components/curveeditor/treeitem.h b/src/plugins/qmldesigner/components/curveeditor/treeitem.h index 60538778092..bf76d43706b 100644 --- a/src/plugins/qmldesigner/components/curveeditor/treeitem.h +++ b/src/plugins/qmldesigner/components/curveeditor/treeitem.h @@ -151,15 +151,10 @@ class PropertyTreeItem : public TreeItem public: enum class Component { Generic, R, G, B, A, X, Y, Z, W }; - enum class ValueType { - Undefined, - Bool, - Integer, - Double, - }; + using ValueType = AnimationCurve::ValueType; public: - PropertyTreeItem(const QString &name, const AnimationCurve &curve, const ValueType &type); + PropertyTreeItem(const QString &name, const AnimationCurve &curve); PropertyTreeItem *asPropertyItem() override;