aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKnud Dollereder <knud.dollereder@qt.io>2022-07-01 13:22:32 +0200
committerKnud Dollereder <knud.dollereder@qt.io>2022-07-08 13:20:26 +0000
commit1df1a065de858fed47e134d79b73657bffe96c6f (patch)
tree376056e851a74dc1a25e32ba97dfe19b77d8bea3
parentb1975da9f78a6a76d0c796b3a77b260ec3c48301 (diff)
QmlDesigner: Improve usability of boolean animation curves
Boolean animation curves are now painted from min to max of the value range instead of from 0 to 1. This allows to see value changes when the curve is loaded together with other animation curves of different value ranges. Boolean curves are now forced to be step interpolated. If the user tries other interpolation types the request is denied and an error message is written in the new status line. Added a status line that displays the current frame number by default and an informative text in case the user did something forbidden. Respect the current state when populating the curve editor. Fixes: QDS-6950 Fixes: QDS-6889 Change-Id: Ia5fa1c1c55ee93eda5a39fd83987b54fb41d54db Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
-rw-r--r--src/plugins/qmldesigner/components/curveeditor/animationcurve.cpp22
-rw-r--r--src/plugins/qmldesigner/components/curveeditor/animationcurve.h14
-rw-r--r--src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp23
-rw-r--r--src/plugins/qmldesigner/components/curveeditor/curveeditor.h4
-rw-r--r--src/plugins/qmldesigner/components/curveeditor/curveeditormodel.cpp36
-rw-r--r--src/plugins/qmldesigner/components/curveeditor/curveeditormodel.h8
-rw-r--r--src/plugins/qmldesigner/components/curveeditor/curveeditorview.cpp56
-rw-r--r--src/plugins/qmldesigner/components/curveeditor/detail/curveitem.cpp65
-rw-r--r--src/plugins/qmldesigner/components/curveeditor/detail/curveitem.h8
-rw-r--r--src/plugins/qmldesigner/components/curveeditor/detail/graphicsscene.cpp2
-rw-r--r--src/plugins/qmldesigner/components/curveeditor/detail/graphicsscene.h2
-rw-r--r--src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp9
-rw-r--r--src/plugins/qmldesigner/components/curveeditor/detail/keyframeitem.cpp30
-rw-r--r--src/plugins/qmldesigner/components/curveeditor/detail/keyframeitem.h7
-rw-r--r--src/plugins/qmldesigner/components/curveeditor/detail/treemodel.cpp1
-rw-r--r--src/plugins/qmldesigner/components/curveeditor/keyframe.h1
-rw-r--r--src/plugins/qmldesigner/components/curveeditor/treeitem.cpp6
-rw-r--r--src/plugins/qmldesigner/components/curveeditor/treeitem.h9
18 files changed, 219 insertions, 84 deletions
diff --git a/src/plugins/qmldesigner/components/curveeditor/animationcurve.cpp b/src/plugins/qmldesigner/components/curveeditor/animationcurve.cpp
index 3e910638da..36e577d38d 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<double>::max())
, m_maxY(std::numeric_limits<double>::lowest())
, m_frames()
{}
-AnimationCurve::AnimationCurve(const std::vector<Keyframe> &frames)
- : m_fromData(false)
+AnimationCurve::AnimationCurve(AnimationCurve::ValueType type, const std::vector<Keyframe> &frames)
+ : m_type(type)
+ , m_fromData(false)
, m_minY(std::numeric_limits<double>::max())
, m_maxY(std::numeric_limits<double>::lowest())
, m_frames(frames)
@@ -51,8 +53,13 @@ AnimationCurve::AnimationCurve(const std::vector<Keyframe> &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<double>::max())
, m_maxY(std::numeric_limits<double>::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 ba39ecd347..1c51d05d80 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<Keyframe> &frames);
+ AnimationCurve(ValueType type, const std::vector<Keyframe> &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 217e0e0eb7..29e88e2581 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 9d1a6f68f9..2265c5538f 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 4377671817..fb60298e61 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<int>(timeline.currentKeyframe());
m_minTime = timeline.startKeyframe();
m_maxTime = timeline.endKeyframe();
std::vector<TreeItem *> 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<Keyframe> resolveSmallCurves(const std::vector<Keyframe> &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<Keyframe> resolveSmallCurves(const std::vector<Keyframe> &frames)
return out;
}
+
+AnimationCurve CurveEditorModel::createBooleanCurve(const QmlDesigner::QmlTimelineKeyframeGroup &group)
+{
+ std::vector<Keyframe> 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<Keyframe> 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 041642aa61..aa804058c6 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 559a97c8fb..5368512d31 100644
--- a/src/plugins/qmldesigner/components/curveeditor/curveeditorview.cpp
+++ b/src/plugins/qmldesigner/components/curveeditor/curveeditorview.cpp
@@ -35,6 +35,7 @@
#include <variantproperty.h>
#include <qmlstate.h>
#include <qmltimeline.h>
+#include <nodelistproperty.h>
#include <cmath>
@@ -214,6 +215,9 @@ void CurveEditorView::propertiesRemoved(const QList<AbstractProperty> &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<int>(QMetaType::QEasingCurve))
- attachEasingCurve(group, pos.x(), data.value<QEasingCurve>());
+ 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());
+
+ 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<int>(QMetaType::QEasingCurve))
+ attachEasingCurve(group, pos.x(), data.value<QEasingCurve>());
+ }
}
+ previous = frame;
}
-
- 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 0b7ab9d391..5b05309976 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<Keyframe> frames;
frames.reserve(m_keyframes.size());
+
+ bool map = (m_type == AnimationCurve::ValueType::Bool) && remap;
for (auto *frameItem : m_keyframes)
- frames.push_back(frameItem->keyframe());
+ frames.push_back(frameItem->keyframe(map));
- return AnimationCurve(frames);
+ return AnimationCurve(m_type, frames);
}
AnimationCurve CurveItem::resolvedCurve() const
@@ -278,11 +269,13 @@ std::vector<AnimationCurve> 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<QEasingCurve>(),
- previous.position(),
- current.position()));
+ out.push_back(AnimationCurve(
+ m_type,
+ current.data().value<QEasingCurve>(),
+ previous.position(),
+ current.position()));
tmp.clear();
tmp.push_back(current);
@@ -293,7 +286,7 @@ std::vector<AnimationCurve> 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 5a2f363df7..c6bdc6d3d4 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 9eda7f8934..3506aab811 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 2e6bc3b080..58738d116b 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 5b4e6e3cfb..8ab71ace97 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 ef0a886d52..49e76a0968 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 3e566c84b7..14c3ae7426 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 c4b6845f51..91e6dbd660 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 fd3c2cb88b..2757d229f5 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 0b90d7d83b..495b3750c8 100644
--- a/src/plugins/qmldesigner/components/curveeditor/treeitem.cpp
+++ b/src/plugins/qmldesigner/components/curveeditor/treeitem.cpp
@@ -321,11 +321,9 @@ std::vector<PropertyTreeItem *> 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 6053877809..bf76d43706 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;