Convert the CurveEditorDialog to a view-plugin

Continuously send frame-changed signals when dragging the playhead
Fix timescale painting
Paint playhead behind the valuescale

Task-number: QDS-2551
Change-Id: Ia8d3952b4401500a4c6d31ff9f5742ff44b2c092
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Knud Dollereder
2020-09-02 13:42:32 +02:00
parent 1c53cff4fa
commit 3bce5f2e76
26 changed files with 779 additions and 656 deletions

View File

@@ -649,8 +649,6 @@ extend_qtc_plugin(QmlDesigner
extend_qtc_plugin(QmlDesigner
SOURCES_PREFIX components/timelineeditor
SOURCES
animationcurvedialog.cpp animationcurvedialog.h
animationcurveeditormodel.cpp animationcurveeditormodel.h
canvas.cpp canvas.h
canvasstyledialog.cpp canvasstyledialog.h
easingcurve.cpp easingcurve.h
@@ -707,6 +705,7 @@ extend_qtc_plugin(QmlDesigner
SOURCES_PREFIX components/curveeditor
SOURCES
curveeditor.qrc
curveeditorview.cpp curveeditorview.h
animationcurve.cpp animationcurve.h
curveeditor.cpp curveeditor.h
curveeditormodel.cpp curveeditormodel.h

View File

@@ -62,6 +62,11 @@ CurveEditor::CurveEditor(CurveEditorModel *model, QWidget *parent)
&GraphicsView::updateSelection);
}
bool CurveEditor::dragging() const
{
return m_view->dragging();
}
void CurveEditor::zoomX(double zoom)
{
m_view->setZoomX(zoom);
@@ -82,18 +87,21 @@ QToolBar *CurveEditor::createToolBar(CurveEditorModel *model)
auto *bar = new QToolBar;
bar->setFloatable(false);
QAction *tangentLinearAction = bar->addAction(QIcon(":/curveeditor/images/tangetToolsLinearIcon.png"), "Linear");
QAction *tangentStepAction = bar->addAction(QIcon(":/curveeditor/images/tangetToolsStepIcon.png"), "Step");
QAction *tangentSplineAction = bar->addAction(QIcon(":/curveeditor/images/tangetToolsSplineIcon.png"), "Spline");
QAction *tangentDefaultAction = bar->addAction("Set Default");
QAction *tangentUnifyAction = bar->addAction("Unify");
QAction *tangentLinearAction = bar->addAction(
QIcon(":/curveeditor/images/tangetToolsLinearIcon.png"), "Linear");
QAction *tangentStepAction = bar->addAction(QIcon(
":/curveeditor/images/tangetToolsStepIcon.png"),
"Step");
QAction *tangentSplineAction = bar->addAction(
QIcon(":/curveeditor/images/tangetToolsSplineIcon.png"), "Spline");
QAction *tangentDefaultAction = bar->addAction(tr("Set Default"));
QAction *tangentUnifyAction = bar->addAction(tr("Unify"));
auto setLinearInterpolation = [this]() {
m_view->setInterpolation(Keyframe::Interpolation::Linear);
};
auto setStepInterpolation = [this]() {
m_view->setInterpolation(Keyframe::Interpolation::Step);
};
auto setStepInterpolation = [this]() { m_view->setInterpolation(Keyframe::Interpolation::Step); };
auto setSplineInterpolation = [this]() {
m_view->setInterpolation(Keyframe::Interpolation::Bezier);
};
@@ -118,7 +126,7 @@ QToolBar *CurveEditor::createToolBar(CurveEditorModel *model)
startSpin->setValue(model->minimumTime());
auto updateStartFrame = [this, model](int frame) {
model->setMinimumTime(frame, false);
model->setMinimumTime(frame);
m_view->viewport()->update();
};
connect(startSpin, QOverload<int>::of(&QSpinBox::valueChanged), updateStartFrame);
@@ -127,16 +135,16 @@ QToolBar *CurveEditor::createToolBar(CurveEditorModel *model)
endSpin->setValue(model->maximumTime());
auto updateEndFrame = [this, model](int frame) {
model->setMaximumTime(frame, false);
model->setMaximumTime(frame);
m_view->viewport()->update();
};
connect(endSpin, QOverload<int>::of(&QSpinBox::valueChanged), updateEndFrame);
auto setStartSlot = [startSpin](int frame) { startSpin->setValue(frame); };
connect(model, &CurveEditorModel::updateStartFrame, setStartSlot);
connect(model, &CurveEditorModel::commitStartFrame, setStartSlot);
auto setEndSlot = [endSpin](int frame) { endSpin->setValue(frame); };
connect(model, &CurveEditorModel::updateEndFrame, setEndSlot);
connect(model, &CurveEditorModel::commitEndFrame, setEndSlot);
durationBox->addWidget(new QLabel(tr("Start Frame")));
durationBox->addWidget(startSpin);
@@ -152,10 +160,14 @@ QToolBar *CurveEditor::createToolBar(CurveEditorModel *model)
cfspin->setMaximum(std::numeric_limits<int>::max());
auto intSignal = static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged);
connect(cfspin, intSignal, [this](int val) { m_view->setCurrentFrame(val, false); });
connect(m_view, &GraphicsView::notifyFrameChanged, [cfspin](int val) {
QSignalBlocker blocker(cfspin);
connect(cfspin, intSignal, [this, model](int val) { model->commitCurrentFrame(val); });
connect(m_view, &GraphicsView::currentFrameChanged, [cfspin](int val, bool notify) {
if (notify) {
cfspin->setValue(val);
} else {
const QSignalBlocker blocker(cfspin);
cfspin->setValue(val);
}
});
auto *positionBox = new QHBoxLayout;

View File

@@ -41,6 +41,8 @@ class CurveEditor : public QWidget
public:
CurveEditor(CurveEditorModel *model, QWidget *parent = nullptr);
bool dragging() const;
void zoomX(double zoom);
void zoomY(double zoom);

View File

@@ -4,6 +4,7 @@ HEADERS += \
$$PWD/animationcurve.h \
$$PWD/curveeditor.h \
$$PWD/curveeditormodel.h \
$$PWD/curveeditorview.h \
$$PWD/curvesegment.h \
$$PWD/detail/colorcontrol.h \
$$PWD/detail/curveeditorstyledialog.h \
@@ -28,6 +29,7 @@ SOURCES += \
$$PWD/curvesegment.cpp \
$$PWD/curveeditor.cpp \
$$PWD/curveeditormodel.cpp \
$$PWD/curveeditorview.cpp \
$$PWD/detail/colorcontrol.cpp \
$$PWD/detail/curveeditorstyledialog.cpp \
$$PWD/detail/curveitem.cpp \

View File

@@ -24,11 +24,19 @@
****************************************************************************/
#include "curveeditormodel.h"
#include "curveeditorstyle.h"
#include "treeitem.h"
#include "detail/graphicsview.h"
#include "detail/selectionmodel.h"
#include "easingcurve.h"
#include "qmltimeline.h"
#include <bindingproperty.h>
#include <theme.h>
#include <variantproperty.h>
namespace DesignTools {
CurveEditorModel::CurveEditorModel(double minTime, double maxTime, QObject *parent)
@@ -39,28 +47,82 @@ CurveEditorModel::CurveEditorModel(double minTime, double maxTime, QObject *pare
CurveEditorModel::~CurveEditorModel() {}
double CurveEditorModel::minimumTime() const
{
return m_minTime;
}
double CurveEditorModel::maximumTime() const
{
return m_maxTime;
}
DesignTools::CurveEditorStyle CurveEditorModel::style() const
{
// Pseudo auto generated. See: CurveEditorStyleDialog
DesignTools::CurveEditorStyle out;
out.backgroundBrush = QBrush(QColor(21, 21, 21));
out.backgroundAlternateBrush = QBrush(QColor(32, 32, 32));
out.fontColor = QColor(255, 255, 255);
out.gridColor = QColor(114, 116, 118);
out.canvasMargin = 15;
out.zoomInWidth = 99;
out.zoomInHeight = 99;
out.timeAxisHeight = 60;
out.timeOffsetLeft = 10;
out.timeOffsetRight = 10;
out.rangeBarColor = QmlDesigner::Theme::instance()->qmlDesignerBackgroundColorDarkAlternate();
out.rangeBarCapsColor = QmlDesigner::Theme::getColor(
QmlDesigner::Theme::QmlDesigner_HighlightColor);
out.valueAxisWidth = 60;
out.valueOffsetTop = 10;
out.valueOffsetBottom = 10;
out.handleStyle.size = 10;
out.handleStyle.lineWidth = 1;
out.handleStyle.color = QColor(255, 255, 255);
out.handleStyle.selectionColor = QColor(255, 255, 255);
out.keyframeStyle.size = 14;
out.keyframeStyle.color = QColor(172, 210, 255);
out.keyframeStyle.selectionColor = QColor(255, 255, 255);
out.curveStyle.width = 2;
out.curveStyle.color = QColor(0, 200, 0);
out.curveStyle.selectionColor = QColor(255, 255, 255);
out.treeItemStyle.margins = 0;
out.playhead.width = 20;
out.playhead.radius = 4;
out.playhead.color = QColor(200, 200, 0);
return out;
}
void CurveEditorModel::setTimeline(const QmlDesigner::QmlTimeline &timeline)
{
m_minTime = timeline.startKeyframe();
m_maxTime = timeline.endKeyframe();
std::vector<DesignTools::TreeItem *> items;
for (auto &&target : timeline.allTargets()) {
if (DesignTools::TreeItem *item = createTopLevelItem(timeline, target))
items.push_back(item);
}
reset(items);
}
void CurveEditorModel::setCurrentFrame(int frame)
{
if (graphicsView())
graphicsView()->setCurrentFrame(frame);
graphicsView()->setCurrentFrame(frame, false);
}
void CurveEditorModel::setMinimumTime(double time, bool internal)
void CurveEditorModel::setMinimumTime(double time)
{
m_minTime = time;
if (internal)
emit updateStartFrame(m_minTime);
else
emit startFrameChanged(m_minTime);
emit commitStartFrame(static_cast<int>(m_minTime));
}
void CurveEditorModel::setMaximumTime(double time, bool internal)
void CurveEditorModel::setMaximumTime(double time)
{
m_maxTime = time;
if (internal)
emit updateEndFrame(m_maxTime);
else
emit endFrameChanged(m_maxTime);
emit commitEndFrame(static_cast<int>(m_maxTime));
}
void CurveEditorModel::setCurve(unsigned int id, const AnimationCurve &curve)
@@ -114,4 +176,152 @@ void CurveEditorModel::reset(const std::vector<TreeItem *> &items)
sm->selectPaths(sel);
}
DesignTools::ValueType typeFrom(const QmlDesigner::QmlTimelineKeyframeGroup &group)
{
if (group.valueType() == QmlDesigner::TypeName("double")
|| group.valueType() == QmlDesigner::TypeName("real")
|| group.valueType() == QmlDesigner::TypeName("float"))
return DesignTools::ValueType::Double;
if (group.valueType() == QmlDesigner::TypeName("boolean")
|| group.valueType() == QmlDesigner::TypeName("bool"))
return DesignTools::ValueType::Bool;
if (group.valueType() == QmlDesigner::TypeName("integer")
|| group.valueType() == QmlDesigner::TypeName("int"))
return DesignTools::ValueType::Integer;
// Ignoring: QColor / HAlignment / VAlignment
return DesignTools::ValueType::Undefined;
}
DesignTools::TreeItem *CurveEditorModel::createTopLevelItem(const QmlDesigner::QmlTimeline &timeline,
const QmlDesigner::ModelNode &node)
{
if (!node.isValid())
return nullptr;
auto *nodeItem = new DesignTools::NodeTreeItem(node.id(), QIcon(":/ICON_INSTANCE"));
for (auto &&grp : timeline.keyframeGroupsForTarget(node)) {
if (grp.isValid()) {
DesignTools::AnimationCurve curve = createAnimationCurve(grp);
if (curve.isValid()) {
QString name = QString::fromUtf8(grp.propertyName());
auto propertyItem = new DesignTools::PropertyTreeItem(name, curve, typeFrom(grp));
QmlDesigner::ModelNode target = grp.modelNode();
if (target.hasAuxiliaryData("locked"))
propertyItem->setLocked(true);
if (target.hasAuxiliaryData("pinned"))
propertyItem->setPinned(true);
nodeItem->addChild(propertyItem);
}
}
}
if (!nodeItem->hasChildren()) {
delete nodeItem;
nodeItem = nullptr;
}
return nodeItem;
}
DesignTools::AnimationCurve CurveEditorModel::createAnimationCurve(
const QmlDesigner::QmlTimelineKeyframeGroup &group)
{
switch (typeFrom(group)) {
case DesignTools::ValueType::Bool:
return createDoubleCurve(group);
case DesignTools::ValueType::Integer:
return createDoubleCurve(group);
case DesignTools::ValueType::Double:
return createDoubleCurve(group);
default:
return DesignTools::AnimationCurve();
}
}
std::vector<DesignTools::Keyframe> createKeyframes(QList<QmlDesigner::ModelNode> nodes)
{
auto byTime = [](const auto &a, const auto &b) {
return a.variantProperty("frame").value().toDouble()
< b.variantProperty("frame").value().toDouble();
};
std::sort(nodes.begin(), nodes.end(), byTime);
std::vector<DesignTools::Keyframe> frames;
for (auto &&node : nodes) {
QVariant timeVariant = node.variantProperty("frame").value();
QVariant valueVariant = node.variantProperty("value").value();
if (!timeVariant.isValid() || !valueVariant.isValid())
continue;
QPointF position(timeVariant.toDouble(), valueVariant.toDouble());
auto keyframe = DesignTools::Keyframe(position);
if (node.hasBindingProperty("easing.bezierCurve")) {
QmlDesigner::EasingCurve ecurve;
ecurve.fromString(node.bindingProperty("easing.bezierCurve").expression());
keyframe.setData(static_cast<QEasingCurve>(ecurve));
}
frames.push_back(keyframe);
}
return frames;
}
std::vector<DesignTools::Keyframe> resolveSmallCurves(const std::vector<DesignTools::Keyframe> &frames)
{
std::vector<DesignTools::Keyframe> out;
for (auto &&frame : frames) {
if (frame.hasData() && !out.empty()) {
QEasingCurve curve = frame.data().toEasingCurve();
// One-segment-curve: Since (0,0) is implicit => 3
if (curve.toCubicSpline().count() == 3) {
DesignTools::Keyframe &previous = out.back();
#if 0
// Do not resolve when two adjacent keyframes have the same value.
if (qFuzzyCompare(previous.position().y(), frame.position().y())) {
out.push_back(frame);
continue;
}
#endif
DesignTools::AnimationCurve acurve(curve, previous.position(), frame.position());
previous.setRightHandle(acurve.keyframeAt(0).rightHandle());
out.push_back(acurve.keyframeAt(1));
continue;
}
}
out.push_back(frame);
}
return out;
}
DesignTools::AnimationCurve CurveEditorModel::createDoubleCurve(
const QmlDesigner::QmlTimelineKeyframeGroup &group)
{
std::vector<DesignTools::Keyframe> keyframes = createKeyframes(group.keyframePositions());
keyframes = resolveSmallCurves(keyframes);
QString str;
QmlDesigner::ModelNode target = group.modelNode();
if (target.hasAuxiliaryData("unified"))
str = target.auxiliaryData("unified").toString();
if (str.size() == static_cast<int>(keyframes.size())) {
for (int i = 0; i < str.size(); ++i) {
if (str.at(i) == '1')
keyframes[static_cast<size_t>(i)].setUnified(true);
}
}
return DesignTools::AnimationCurve(keyframes);
}
} // End namespace DesignTools.

View File

@@ -27,6 +27,8 @@
#include "detail/treemodel.h"
#include <qmltimelinekeyframegroup.h>
#include <vector>
QT_BEGIN_NAMESPACE
@@ -46,41 +48,46 @@ class CurveEditorModel : public TreeModel
Q_OBJECT
signals:
void currentFrameChanged(int frame);
void commitCurrentFrame(int frame);
void startFrameChanged(int frame);
void commitStartFrame(int frame);
void endFrameChanged(int frame);
void updateStartFrame(int frame);
void updateEndFrame(int frame);
void commitEndFrame(int frame);
void curveChanged(PropertyTreeItem *item);
public:
virtual double minimumTime() const = 0;
virtual double maximumTime() const = 0;
virtual CurveEditorStyle style() const = 0;
public:
CurveEditorModel(double minTime, double maxTime, QObject *parent = nullptr);
~CurveEditorModel() override;
double minimumTime() const;
double maximumTime() const;
DesignTools::CurveEditorStyle style() const;
public:
void setTimeline(const QmlDesigner::QmlTimeline &timeline);
void setCurrentFrame(int frame);
void setMinimumTime(double time, bool internal);
void setMinimumTime(double time);
void setMaximumTime(double time, bool internal);
void setMaximumTime(double time);
void setCurve(unsigned int id, const AnimationCurve &curve);
void reset(const std::vector<TreeItem *> &items);
protected:
private:
DesignTools::TreeItem *createTopLevelItem(const QmlDesigner::QmlTimeline &timeline,
const QmlDesigner::ModelNode &node);
DesignTools::AnimationCurve createAnimationCurve(const QmlDesigner::QmlTimelineKeyframeGroup &group);
DesignTools::AnimationCurve createDoubleCurve(const QmlDesigner::QmlTimelineKeyframeGroup &group);
double m_minTime = 0.;
double m_maxTime = 0.;

View File

@@ -0,0 +1,375 @@
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Design Tooling
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "curveeditorview.h"
#include "curveeditor.h"
#include "curveeditormodel.h"
#include "curvesegment.h"
#include <bindingproperty.h>
#include <easingcurve.h>
#include <nodeabstractproperty.h>
#include <variantproperty.h>
#include <qmlstate.h>
#include <qmltimeline.h>
#include <cmath>
namespace QmlDesigner {
CurveEditorView::CurveEditorView(QObject *parent)
: AbstractView(parent)
, m_block(false)
, m_model(new DesignTools::CurveEditorModel(0., 500.))
, m_editor(new DesignTools::CurveEditor(m_model))
{
Q_UNUSED(parent);
connect(m_model,
&DesignTools::CurveEditorModel::commitCurrentFrame,
this,
&CurveEditorView::commitCurrentFrame);
connect(m_model,
&DesignTools::CurveEditorModel::commitStartFrame,
this,
&CurveEditorView::commitStartFrame);
connect(m_model,
&DesignTools::CurveEditorModel::commitEndFrame,
this,
&CurveEditorView::commitEndFrame);
connect(m_model,
&DesignTools::CurveEditorModel::curveChanged,
this,
&CurveEditorView::commitKeyframes);
}
CurveEditorView::~CurveEditorView() {}
bool CurveEditorView::hasWidget() const
{
return true;
}
WidgetInfo CurveEditorView::widgetInfo()
{
return createWidgetInfo(
m_editor, nullptr, "CurveEditorId", WidgetInfo::BottomPane, 0, tr("CurveEditor"));
}
void CurveEditorView::modelAttached(Model *model)
{
AbstractView::modelAttached(model);
QmlTimeline timeline = activeTimeline();
if (timeline.isValid()) {
m_model->setTimeline(timeline);
}
}
void CurveEditorView::modelAboutToBeDetached(Model *model)
{
AbstractView::modelAboutToBeDetached(model);
m_model->reset({});
}
bool dirtyfiesView(const ModelNode &node)
{
return QmlTimeline::isValidQmlTimeline(node)
|| QmlTimelineKeyframeGroup::isValidQmlTimelineKeyframeGroup(node);
}
void CurveEditorView::nodeRemoved(const ModelNode &removedNode,
const NodeAbstractProperty &parentProperty,
PropertyChangeFlags propertyChange)
{
Q_UNUSED(removedNode);
Q_UNUSED(propertyChange);
if (!parentProperty.isValid())
return;
ModelNode parent = parentProperty.parentModelNode();
if (dirtyfiesView(parent))
updateKeyframes();
}
void CurveEditorView::nodeReparented(const ModelNode &node,
const NodeAbstractProperty &newPropertyParent,
const NodeAbstractProperty &oldPropertyParent,
PropertyChangeFlags propertyChange)
{
Q_UNUSED(node);
Q_UNUSED(newPropertyParent);
Q_UNUSED(oldPropertyParent);
Q_UNUSED(propertyChange);
ModelNode parent = newPropertyParent.parentModelNode();
if (newPropertyParent.isValid() && dirtyfiesView(parent))
updateKeyframes();
else if (QmlTimelineKeyframeGroup::checkKeyframesType(node))
updateKeyframes();
}
void CurveEditorView::instancePropertyChanged(const QList<QPair<ModelNode, PropertyName>> &propertyList)
{
Q_UNUSED(propertyList);
for (const auto &pair : propertyList) {
if (!QmlTimeline::isValidQmlTimeline(pair.first))
continue;
if (pair.second == "startFrame")
updateStartFrame(pair.first);
else if (pair.second == "endFrame")
updateEndFrame(pair.first);
else if (pair.second == "currentFrame")
updateCurrentFrame(pair.first);
}
}
void CurveEditorView::variantPropertiesChanged(const QList<VariantProperty> &propertyList,
PropertyChangeFlags propertyChange)
{
Q_UNUSED(propertyList);
Q_UNUSED(propertyChange);
for (const auto &property : propertyList) {
if ((property.name() == "frame" || property.name() == "value")
&& property.parentModelNode().type() == "QtQuick.Timeline.Keyframe"
&& property.parentModelNode().isValid()
&& property.parentModelNode().hasParentProperty()) {
const ModelNode framesNode = property.parentModelNode().parentProperty().parentModelNode();
if (QmlTimelineKeyframeGroup::isValidQmlTimelineKeyframeGroup(framesNode))
updateKeyframes();
}
}
}
void CurveEditorView::bindingPropertiesChanged(const QList<BindingProperty> &propertyList,
PropertyChangeFlags propertyChange)
{
Q_UNUSED(propertyList);
Q_UNUSED(propertyChange);
for (const auto &property : propertyList) {
if (property.name() == "easing.bezierCurve") {
updateKeyframes();
}
}
}
void CurveEditorView::propertiesRemoved(const QList<AbstractProperty> &propertyList)
{
Q_UNUSED(propertyList);
for (const auto &property : propertyList) {
if (property.name() == "keyframes" && property.parentModelNode().isValid()) {
ModelNode parent = property.parentModelNode();
if (dirtyfiesView(parent))
updateKeyframes();
}
}
}
QmlTimeline CurveEditorView::activeTimeline() const
{
QmlModelState state = currentState();
if (state.isBaseState()) {
for (const ModelNode &node : allModelNodesOfType("QtQuick.Timeline.Timeline")) {
if (QmlTimeline::isValidQmlTimeline(node)) {
if (node.hasVariantProperty("enabled")
&& node.variantProperty("enabled").value().toBool())
return QmlTimeline(node);
return {};
}
}
}
for (const ModelNode &node : allModelNodesOfType("QtQuick.Timeline.Timeline")) {
if (QmlTimeline::isValidQmlTimeline(node) && state.affectsModelNode(node)) {
QmlPropertyChanges propertyChanges(state.propertyChanges(node));
if (!propertyChanges.isValid())
continue;
if (node.hasVariantProperty("enabled") && node.variantProperty("enabled").value().toBool())
return QmlTimeline(node);
}
}
return {};
}
void CurveEditorView::updateKeyframes()
{
if (m_block)
return;
QmlTimeline timeline = activeTimeline();
if (timeline.isValid())
m_model->setTimeline(timeline);
else
m_model->reset({});
}
void CurveEditorView::updateCurrentFrame(const ModelNode &node)
{
if (m_editor->dragging())
return;
QmlTimeline timeline(node);
if (timeline.isValid())
m_model->setCurrentFrame(static_cast<int>(std::round(timeline.currentKeyframe())));
else
m_model->setCurrentFrame(0);
}
void CurveEditorView::updateStartFrame(const ModelNode &node)
{
QmlTimeline timeline(node);
if (timeline.isValid())
m_model->setMinimumTime(static_cast<int>(std::round(timeline.startKeyframe())));
}
void CurveEditorView::updateEndFrame(const ModelNode &node)
{
QmlTimeline timeline(node);
if (timeline.isValid())
m_model->setMaximumTime(static_cast<int>(std::round(timeline.endKeyframe())));
}
ModelNode getTargetNode1(DesignTools::PropertyTreeItem *item, const QmlTimeline &timeline)
{
if (const DesignTools::NodeTreeItem *nodeItem = item->parentNodeTreeItem()) {
QString targetId = nodeItem->name();
if (timeline.isValid()) {
for (auto &&target : timeline.allTargets()) {
if (target.displayName() == targetId)
return target;
}
}
}
return ModelNode();
}
QmlTimelineKeyframeGroup timelineKeyframeGroup1(QmlTimeline &timeline,
DesignTools::PropertyTreeItem *item)
{
ModelNode node = getTargetNode1(item, timeline);
if (node.isValid())
return timeline.keyframeGroup(node, item->name().toLatin1());
return QmlTimelineKeyframeGroup();
}
void attachEasingCurve1(double frame, const QEasingCurve &curve, const QmlTimelineKeyframeGroup &group)
{
ModelNode frameNode = group.keyframe(frame);
if (frameNode.isValid()) {
auto expression = EasingCurve(curve).toString();
frameNode.bindingProperty("easing.bezierCurve").setExpression(expression);
}
}
void CurveEditorView::commitKeyframes(DesignTools::PropertyTreeItem *item)
{
QmlTimeline currentTimeline = activeTimeline();
QmlTimelineKeyframeGroup group = timelineKeyframeGroup1(currentTimeline, item);
if (group.isValid()) {
ModelNode groupNode = group.modelNode();
if (groupNode.isValid()) {
if (item->locked())
groupNode.setAuxiliaryData("locked", true);
else
groupNode.removeAuxiliaryData("locked");
if (item->pinned())
groupNode.setAuxiliaryData("pinned", true);
else
groupNode.removeAuxiliaryData("pinned");
if (item->hasUnified())
groupNode.setAuxiliaryData("unified", item->unifyString());
else
groupNode.removeAuxiliaryData("unified");
}
auto replaceKeyframes = [&group, item, this]() {
m_block = true;
for (auto frame : group.keyframes())
frame.destroy();
DesignTools::Keyframe previous;
for (auto &&frame : item->curve().keyframes()) {
QPointF pos = frame.position();
group.setValue(QVariant(pos.y()), pos.x());
if (previous.isValid()) {
if (frame.interpolation() == DesignTools::Keyframe::Interpolation::Bezier) {
DesignTools::CurveSegment segment(previous, frame);
if (segment.isValid())
attachEasingCurve1(pos.x(), segment.easingCurve(), group);
} else if (frame.interpolation() == DesignTools::Keyframe::Interpolation::Easing) {
QVariant data = frame.data();
if (data.type() == static_cast<int>(QMetaType::QEasingCurve))
attachEasingCurve1(pos.x(), data.value<QEasingCurve>(), group);
} else if (frame.interpolation() == DesignTools::Keyframe::Interpolation::Step) {
// Warning: Keyframe::Interpolation::Step not yet implemented
}
}
previous = frame;
}
m_block = false;
};
executeInTransaction("CurveEditor::commitKeyframes", replaceKeyframes);
}
}
void CurveEditorView::commitCurrentFrame(int frame)
{
QmlTimeline timeline = activeTimeline();
timeline.modelNode().setAuxiliaryData("currentFrame@NodeInstance", frame);
}
void CurveEditorView::commitStartFrame(int frame)
{
QmlTimeline timeline = activeTimeline();
if (timeline.isValid())
timeline.modelNode().variantProperty("startFrame").setValue(frame);
}
void CurveEditorView::commitEndFrame(int frame)
{
QmlTimeline timeline = activeTimeline();
if (timeline.isValid())
timeline.modelNode().variantProperty("endFrame").setValue(frame);
}
} // namespace QmlDesigner

View File

@@ -0,0 +1,91 @@
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Design Tooling
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "curveeditor.h"
#include "curveeditormodel.h"
#include <abstractview.h>
namespace QmlDesigner {
class TimelineWidget;
class CurveEditorView : public AbstractView
{
Q_OBJECT
public:
explicit CurveEditorView(QObject *parent = nullptr);
~CurveEditorView() override;
public:
bool hasWidget() const override;
WidgetInfo widgetInfo() override;
void modelAttached(Model *model) override;
void modelAboutToBeDetached(Model *model) override;
void nodeRemoved(const ModelNode &removedNode,
const NodeAbstractProperty &parentProperty,
PropertyChangeFlags propertyChange) override;
void nodeReparented(const ModelNode &node,
const NodeAbstractProperty &newPropertyParent,
const NodeAbstractProperty &oldPropertyParent,
PropertyChangeFlags propertyChange) override;
void instancePropertyChanged(const QList<QPair<ModelNode, PropertyName>> &propertyList) override;
void variantPropertiesChanged(const QList<VariantProperty> &propertyList,
PropertyChangeFlags propertyChange) override;
void bindingPropertiesChanged(const QList<BindingProperty> &propertyList,
PropertyChangeFlags propertyChange) override;
void propertiesRemoved(const QList<AbstractProperty> &propertyList) override;
private:
QmlTimeline activeTimeline() const;
void updateKeyframes();
void updateCurrentFrame(const ModelNode &node);
void updateStartFrame(const ModelNode &node);
void updateEndFrame(const ModelNode &node);
void commitKeyframes(DesignTools::PropertyTreeItem *item);
void commitCurrentFrame(int frame);
void commitStartFrame(int frame);
void commitEndFrame(int frame);
private:
bool m_block;
DesignTools::CurveEditorModel *m_model;
DesignTools::CurveEditor *m_editor;
};
} // namespace QmlDesigner

View File

@@ -43,6 +43,7 @@ namespace DesignTools {
GraphicsView::GraphicsView(CurveEditorModel *model, QWidget *parent)
: QGraphicsView(parent)
, m_dragging(false)
, m_zoomX(0.0)
, m_zoomY(0.0)
, m_transform()
@@ -98,6 +99,11 @@ CurveEditorStyle GraphicsView::editorStyle() const
return m_style;
}
bool GraphicsView::dragging() const
{
return m_dragging;
}
double GraphicsView::minimumTime() const
{
bool check = m_model->minimumTime() < m_scene->minimumTime();
@@ -152,9 +158,8 @@ QRectF GraphicsView::timeScaleRect() const
QRectF GraphicsView::valueScaleRect() const
{
QRect vp(viewport()->rect());
QPoint tl = vp.topLeft() + QPoint(0, m_style.timeAxisHeight);
QPoint br = vp.bottomLeft() + QPoint(m_style.valueAxisWidth, 0);
return mapToScene(QRect(tl, br)).boundingRect();
return mapToScene(QRect(vp.topLeft(), br)).boundingRect();
}
QRectF GraphicsView::defaultRasterRect() const
@@ -204,11 +209,11 @@ void GraphicsView::setZoomY(double zoom, const QPoint &pivot)
void GraphicsView::setCurrentFrame(int frame, bool notify)
{
int clampedFrame = clamp(frame, m_model->minimumTime(), m_model->maximumTime());
m_playhead.moveToFrame(clampedFrame, this);
viewport()->update();
if (notify)
notifyFrameChanged(frame);
currentFrameChanged(clampedFrame, notify);
}
void GraphicsView::scrollContent(double x, double y)
@@ -276,8 +281,10 @@ void GraphicsView::keyPressEvent(QKeyEvent *event)
void GraphicsView::mousePressEvent(QMouseEvent *event)
{
if (m_playhead.mousePress(globalToScene(event->globalPos())))
if (m_playhead.mousePress(globalToScene(event->globalPos()))) {
m_dragging = true;
return;
}
Shortcut shortcut(event);
if (shortcut == m_style.shortcuts.insertKeyframe) {
@@ -288,6 +295,7 @@ void GraphicsView::mousePressEvent(QMouseEvent *event)
if (shortcut == Shortcut(Qt::LeftButton)) {
QPointF pos = mapToScene(event->pos());
if (timeScaleRect().contains(pos)) {
m_dragging = true;
setCurrentFrame(std::round(mapXtoTime(pos.x())));
m_playhead.setMoving(true);
event->accept();
@@ -317,6 +325,7 @@ void GraphicsView::mouseReleaseEvent(QMouseEvent *event)
m_playhead.mouseRelease(this);
m_selector.mouseRelease(event, m_scene);
this->viewport()->update();
m_dragging = false;
}
void GraphicsView::wheelEvent(QWheelEvent *event)
@@ -364,15 +373,14 @@ void GraphicsView::drawForeground(QPainter *painter, const QRectF &rect)
if (abscissa.isValid())
drawTimeScale(painter, abscissa);
painter->fillRect(QRectF(rect.topLeft(), abscissa.bottomLeft()),
m_style.backgroundAlternateBrush);
painter->fillRect(QRectF(rect.topLeft(), abscissa.bottomLeft()), m_style.backgroundAlternateBrush);
m_playhead.paint(painter, this);
auto ordinate = valueScaleRect();
if (ordinate.isValid())
drawValueScale(painter, ordinate);
m_playhead.paint(painter, this);
m_selector.paint(painter);
}
@@ -463,11 +471,7 @@ void GraphicsView::applyZoom(double x, double y, const QPoint &pivot)
void GraphicsView::drawGrid(QPainter *painter, const QRectF &rect)
{
QRectF gridRect = rect.adjusted(
m_style.valueAxisWidth + m_style.canvasMargin,
m_style.timeAxisHeight + m_style.canvasMargin,
-m_style.canvasMargin,
-m_style.canvasMargin);
QRectF gridRect = scene()->sceneRect();
if (!gridRect.isValid())
return;
@@ -577,8 +581,6 @@ void GraphicsView::drawTimeScale(QPainter *painter, const QRectF &rect)
for (double i = minimumTime(); i <= maximumTime(); i += timeIncrement)
paintLabeledTick(i);
drawRangeBar(painter, rect);
painter->restore();
}

View File

@@ -47,7 +47,7 @@ class GraphicsView : public QGraphicsView
friend class Playhead;
signals:
void notifyFrameChanged(int frame);
void currentFrameChanged(int frame, bool notify);
public:
GraphicsView(CurveEditorModel *model, QWidget *parent = nullptr);
@@ -58,6 +58,8 @@ public:
CurveEditorStyle editorStyle() const;
bool dragging() const;
int mapTimeToX(double time) const;
int mapValueToY(double value) const;
@@ -153,6 +155,8 @@ private:
QRectF rangeMaxHandle(const QRectF &rect);
private:
bool m_dragging;
double m_zoomX;
double m_zoomY;

View File

@@ -102,9 +102,10 @@ bool Playhead::mouseMove(const QPointF &pos, GraphicsView *view)
QRectF canvas = view->canvasRect().adjusted(0.0, -style.timeAxisHeight, 0.0, 0.0);
if (canvas.contains(pos))
view->setCurrentFrame(std::round(view->mapXtoTime(pos.x())));
else if (!m_timer.isActive())
if (canvas.contains(pos)) {
int frame = std::round(view->mapXtoTime(pos.x()));
view->setCurrentFrame(frame);
} else if (!m_timer.isActive())
m_timer.start();
}
@@ -148,9 +149,6 @@ void Playhead::mouseMoveOutOfBounds(GraphicsView *view)
void Playhead::mouseRelease(GraphicsView *view)
{
if (m_moving)
emit view->model()->currentFrameChanged(m_frame);
m_moving = false;
}

View File

@@ -1,63 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "animationcurvedialog.h"
#include <QVBoxLayout>
namespace QmlDesigner {
AnimationCurveDialog::AnimationCurveDialog(QWidget *parent)
: QDialog(parent)
, m_editor(nullptr)
{
}
AnimationCurveDialog::AnimationCurveDialog(DesignTools::CurveEditorModel *model, QWidget *parent)
: QDialog(parent)
, m_editor(nullptr)
{
setModel(model);
}
void AnimationCurveDialog::setModel(DesignTools::CurveEditorModel *model)
{
if (m_editor)
return;
m_editor = new DesignTools::CurveEditor(model);
auto *layout = new QVBoxLayout;
layout->addWidget(m_editor);
setLayout(layout);
}
void AnimationCurveDialog::refresh()
{
if (m_editor)
m_editor->clearCanvas();
}
} // namespace QmlDesigner

View File

@@ -1,51 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "curveeditor/curveeditor.h"
#include <QDialog>
namespace QmlDesigner {
class AnimationCurveDialog : public QDialog
{
Q_OBJECT
public:
AnimationCurveDialog(QWidget *parent = nullptr);
AnimationCurveDialog(DesignTools::CurveEditorModel *model, QWidget *parent = nullptr);
void setModel(DesignTools::CurveEditorModel *model);
void refresh();
private:
DesignTools::CurveEditor *m_editor;
};
} // namespace QmlDesigner

View File

@@ -1,249 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "animationcurveeditormodel.h"
#include "curveeditor/curveeditorstyle.h"
#include "curveeditor/treeitem.h"
#include "easingcurve.h"
#include "qmltimeline.h"
#include <bindingproperty.h>
#include <theme.h>
#include <variantproperty.h>
namespace QmlDesigner {
AnimationCurveEditorModel::AnimationCurveEditorModel(double minTime, double maxTime)
: CurveEditorModel(minTime, maxTime)
{}
AnimationCurveEditorModel::~AnimationCurveEditorModel() {}
double AnimationCurveEditorModel::minimumTime() const
{
return m_minTime;
}
double AnimationCurveEditorModel::maximumTime() const
{
return m_maxTime;
}
DesignTools::CurveEditorStyle AnimationCurveEditorModel::style() const
{
// Pseudo auto generated. See: CurveEditorStyleDialog
DesignTools::CurveEditorStyle out;
out.backgroundBrush = QBrush(QColor(21, 21, 21));
out.backgroundAlternateBrush = QBrush(QColor(32, 32, 32));
out.fontColor = QColor(255, 255, 255);
out.gridColor = QColor(114, 116, 118);
out.canvasMargin = 15;
out.zoomInWidth = 99;
out.zoomInHeight = 99;
out.timeAxisHeight = 60;
out.timeOffsetLeft = 10;
out.timeOffsetRight = 10;
out.rangeBarColor = Theme::instance()->qmlDesignerBackgroundColorDarkAlternate();
out.rangeBarCapsColor = Theme::getColor(Theme::QmlDesigner_HighlightColor);
out.valueAxisWidth = 60;
out.valueOffsetTop = 10;
out.valueOffsetBottom = 10;
out.handleStyle.size = 10;
out.handleStyle.lineWidth = 1;
out.handleStyle.color = QColor(255, 255, 255);
out.handleStyle.selectionColor = QColor(255, 255, 255);
out.keyframeStyle.size = 14;
out.keyframeStyle.color = QColor(172, 210, 255);
out.keyframeStyle.selectionColor = QColor(255, 255, 255);
out.curveStyle.width = 2;
out.curveStyle.color = QColor(0, 200, 0);
out.curveStyle.selectionColor = QColor(255, 255, 255);
out.treeItemStyle.margins = 0;
out.playhead.width = 20;
out.playhead.radius = 4;
out.playhead.color = QColor(200, 200, 0);
return out;
}
void AnimationCurveEditorModel::setTimeline(const QmlTimeline &timeline)
{
m_minTime = timeline.startKeyframe();
m_maxTime = timeline.endKeyframe();
std::vector<DesignTools::TreeItem *> items;
for (auto &&target : timeline.allTargets()) {
if (DesignTools::TreeItem *item = createTopLevelItem(timeline, target))
items.push_back(item);
}
reset(items);
}
DesignTools::ValueType typeFrom(const QmlTimelineKeyframeGroup &group)
{
if (group.valueType() == TypeName("double") || group.valueType() == TypeName("real")
|| group.valueType() == TypeName("float"))
return DesignTools::ValueType::Double;
if (group.valueType() == TypeName("boolean") || group.valueType() == TypeName("bool"))
return DesignTools::ValueType::Bool;
if (group.valueType() == TypeName("integer") || group.valueType() == TypeName("int"))
return DesignTools::ValueType::Integer;
// Ignoring: QColor / HAlignment / VAlignment
return DesignTools::ValueType::Undefined;
}
DesignTools::TreeItem *AnimationCurveEditorModel::createTopLevelItem(const QmlTimeline &timeline,
const ModelNode &node)
{
if (!node.isValid())
return nullptr;
auto *nodeItem = new DesignTools::NodeTreeItem(node.id(), QIcon(":/ICON_INSTANCE"));
for (auto &&grp : timeline.keyframeGroupsForTarget(node)) {
if (grp.isValid()) {
DesignTools::AnimationCurve curve = createAnimationCurve(grp);
if (curve.isValid()) {
QString name = QString::fromUtf8(grp.propertyName());
auto propertyItem = new DesignTools::PropertyTreeItem(name, curve, typeFrom(grp));
ModelNode target = grp.modelNode();
if (target.hasAuxiliaryData("locked"))
propertyItem->setLocked(true);
if (target.hasAuxiliaryData("pinned"))
propertyItem->setPinned(true);
nodeItem->addChild(propertyItem);
}
}
}
if (!nodeItem->hasChildren()) {
delete nodeItem;
nodeItem = nullptr;
}
return nodeItem;
}
DesignTools::AnimationCurve AnimationCurveEditorModel::createAnimationCurve(
const QmlTimelineKeyframeGroup &group)
{
switch (typeFrom(group)) {
case DesignTools::ValueType::Bool:
return createDoubleCurve(group);
case DesignTools::ValueType::Integer:
return createDoubleCurve(group);
case DesignTools::ValueType::Double:
return createDoubleCurve(group);
default:
return DesignTools::AnimationCurve();
}
}
std::vector<DesignTools::Keyframe> createKeyframes(QList<ModelNode> nodes)
{
auto byTime = [](const auto &a, const auto &b) {
return a.variantProperty("frame").value().toDouble()
< b.variantProperty("frame").value().toDouble();
};
std::sort(nodes.begin(), nodes.end(), byTime);
std::vector<DesignTools::Keyframe> frames;
for (auto &&node : nodes) {
QVariant timeVariant = node.variantProperty("frame").value();
QVariant valueVariant = node.variantProperty("value").value();
if (!timeVariant.isValid() || !valueVariant.isValid())
continue;
QPointF position(timeVariant.toDouble(), valueVariant.toDouble());
auto keyframe = DesignTools::Keyframe(position);
if (node.hasBindingProperty("easing.bezierCurve")) {
EasingCurve ecurve;
ecurve.fromString(node.bindingProperty("easing.bezierCurve").expression());
keyframe.setData(static_cast<QEasingCurve>(ecurve));
}
frames.push_back(keyframe);
}
return frames;
}
std::vector<DesignTools::Keyframe> resolveSmallCurves(
const std::vector<DesignTools::Keyframe> &frames)
{
std::vector<DesignTools::Keyframe> out;
for (auto &&frame : frames) {
if (frame.hasData() && !out.empty()) {
QEasingCurve curve = frame.data().toEasingCurve();
// One-segment-curve: Since (0,0) is implicit => 3
if (curve.toCubicSpline().count() == 3) {
DesignTools::Keyframe &previous = out.back();
#if 0
// Do not resolve when two adjacent keyframes have the same value.
if (qFuzzyCompare(previous.position().y(), frame.position().y())) {
out.push_back(frame);
continue;
}
#endif
DesignTools::AnimationCurve acurve(curve, previous.position(), frame.position());
previous.setRightHandle(acurve.keyframeAt(0).rightHandle());
out.push_back(acurve.keyframeAt(1));
continue;
}
}
out.push_back(frame);
}
return out;
}
DesignTools::AnimationCurve AnimationCurveEditorModel::createDoubleCurve(
const QmlTimelineKeyframeGroup &group)
{
std::vector<DesignTools::Keyframe> keyframes = createKeyframes(group.keyframePositions());
keyframes = resolveSmallCurves(keyframes);
QString str;
ModelNode target = group.modelNode();
if (target.hasAuxiliaryData("unified"))
str = target.auxiliaryData("unified").toString();
if (str.size() == static_cast<int>(keyframes.size())) {
for (int i = 0; i < str.size(); ++i) {
if (str.at(i) == '1')
keyframes[i].setUnified(true);
}
}
return DesignTools::AnimationCurve(keyframes);
}
} // namespace QmlDesigner

View File

@@ -1,60 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Design Tooling
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "curveeditor/curveeditormodel.h"
#include "curveeditor/treeitem.h"
#include <qmltimelinekeyframegroup.h>
namespace QmlDesigner {
class AnimationCurveEditorModel : public DesignTools::CurveEditorModel
{
Q_OBJECT
public:
AnimationCurveEditorModel(double minTime, double maxTime);
~AnimationCurveEditorModel() override;
double minimumTime() const override;
double maximumTime() const override;
DesignTools::CurveEditorStyle style() const override;
void setTimeline(const QmlTimeline &timeline);
private:
DesignTools::TreeItem *createTopLevelItem(const QmlTimeline &timeline, const ModelNode &node);
DesignTools::AnimationCurve createAnimationCurve(const QmlTimelineKeyframeGroup &group);
DesignTools::AnimationCurve createDoubleCurve(const QmlTimelineKeyframeGroup &group);
};
} // namespace QmlDesigner

View File

@@ -36,9 +36,7 @@ SOURCES += \
easingcurve.cpp \
timelinesettingsmodel.cpp \
timelinetooldelegate.cpp \
timelinecontrols.cpp \
animationcurveeditormodel.cpp \
animationcurvedialog.cpp
timelinecontrols.cpp
HEADERS += \
timelineview.h \

View File

@@ -103,36 +103,7 @@ static QAction *createAction(const Utils::Id &id,
TimelineToolBar::TimelineToolBar(QWidget *parent)
: QToolBar(parent)
, m_grp()
, m_dialog(new AnimationCurveDialog(this))
, m_curveModel(new AnimationCurveEditorModel(0., 500.))
{
m_dialog->setModel(m_curveModel);
connect(m_curveModel,
&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,
&TimelineToolBar::curveChanged);
setContentsMargins(0, 0, 0, 0);
createLeftControls();
createCenterControls();
@@ -143,8 +114,6 @@ void TimelineToolBar::reset()
{
if (recording())
m_recording->setChecked(false);
m_curveModel->reset({});
}
bool TimelineToolBar::recording() const
@@ -189,7 +158,6 @@ void TimelineToolBar::setCurrentTimeline(const QmlTimeline &timeline)
setStartFrame(timeline.startKeyframe());
setEndFrame(timeline.endKeyframe());
m_timelineLabel->setText(timeline.modelNode().id());
m_curveModel->setTimeline(timeline);
} else {
m_timelineLabel->setText("");
}
@@ -197,8 +165,6 @@ void TimelineToolBar::setCurrentTimeline(const QmlTimeline &timeline)
void TimelineToolBar::setStartFrame(qreal frame)
{
m_curveModel->setMinimumTime(frame, true);
auto text = QString::number(frame, 'f', 0);
m_firstFrame->setText(text);
setupCurrentFrameValidator();
@@ -206,16 +172,12 @@ void TimelineToolBar::setStartFrame(qreal frame)
void TimelineToolBar::setCurrentFrame(qreal frame)
{
m_curveModel->setCurrentFrame(std::round(frame));
auto text = QString::number(frame, 'f', 0);
m_currentFrame->setText(text);
}
void TimelineToolBar::setEndFrame(qreal frame)
{
m_curveModel->setMaximumTime(frame, true);
auto text = QString::number(frame, 'f', 0);
m_lastFrame->setText(text);
setupCurrentFrameValidator();
@@ -240,19 +202,6 @@ void TimelineToolBar::removeTimeline(const QmlTimeline &timeline)
setCurrentTimeline(QmlTimeline());
}
void TimelineToolBar::openAnimationCurveEditor()
{
QmlTimeline timeline;
if (auto *tlw = qobject_cast<TimelineWidget *>(parent())) {
if (auto *tlv = tlw->timelineView())
timeline = tlv->timelineForState(tlv->currentState());
}
m_dialog->refresh();
m_curveModel->setTimeline(timeline);
m_dialog->show();
}
void TimelineToolBar::createLeftControls()
{
auto addActionToGroup = [&](QAction *action) {
@@ -282,17 +231,6 @@ void TimelineToolBar::createLeftControls()
connect(settingsAction, &QAction::triggered, this, &TimelineToolBar::settingDialogClicked);
addActionToGroup(settingsAction);
auto *curveEditorAction = createAction(TimelineConstants::C_CURVE_EDITOR,
TimelineIcons::CURVE_EDITORDIALOG.icon(),
tr("Animation Curve Editor"),
QKeySequence(Qt::Key_C));
connect(curveEditorAction,
&QAction::triggered,
this,
&TimelineToolBar::openAnimationCurveEditor);
addActionToGroup(curveEditorAction);
addWidgetToGroup(createSpacer());
m_timelineLabel = new QLabel(this);

View File

@@ -25,9 +25,6 @@
#pragma once
#include "animationcurvedialog.h"
#include "animationcurveeditormodel.h"
#include <QToolBar>
QT_FORWARD_DECLARE_CLASS(QLabel)
@@ -67,8 +64,6 @@ signals:
void currentFrameChanged(int value);
void endFrameChanged(int value);
void curveChanged(DesignTools::PropertyTreeItem *item);
public:
explicit TimelineToolBar(QWidget *parent = nullptr);
@@ -89,8 +84,6 @@ public:
void setActionEnabled(const QString &name, bool enabled);
void removeTimeline(const QmlTimeline &timeline);
void openAnimationCurveEditor();
protected:
void resizeEvent(QResizeEvent *event) override;
@@ -103,10 +96,6 @@ private:
QList<QObject *> m_grp;
AnimationCurveDialog *m_dialog = nullptr;
AnimationCurveEditorModel *m_curveModel = nullptr;
QLabel *m_timelineLabel = nullptr;
QLabel *m_stateLabel = nullptr;
QSlider *m_scale = nullptr;

View File

@@ -25,8 +25,6 @@
#pragma once
#include "animationcurvedialog.h"
#include "animationcurveeditormodel.h"
#include "treeitem.h"
#include <abstractview.h>

View File

@@ -258,8 +258,6 @@ void TimelineWidget::connectToolbar()
connect(graphicsScene(), &TimelineGraphicsScene::scroll, this, &TimelineWidget::scroll);
connect(m_toolbar, &TimelineToolBar::curveChanged, this, &TimelineWidget::updateAnimationCurve);
auto setRulerScaling = [this](int val) { m_graphicsScene->setRulerScaling(val); };
connect(m_toolbar, &TimelineToolBar::scaleFactorChanged, setRulerScaling);
@@ -372,66 +370,6 @@ void attachEasingCurve(double frame,
}
}
void TimelineWidget::updateAnimationCurve(DesignTools::PropertyTreeItem *item)
{
QmlTimeline currentTimeline = graphicsScene()->currentTimeline();
QmlTimelineKeyframeGroup group = timelineKeyframeGroup(currentTimeline, item);
if (group.isValid()) {
ModelNode groupNode = group.modelNode();
if (groupNode.isValid()) {
if (item->locked())
groupNode.setAuxiliaryData("locked", true);
else
groupNode.removeAuxiliaryData("locked");
if (item->pinned())
groupNode.setAuxiliaryData("pinned", true);
else
groupNode.removeAuxiliaryData("pinned");
if (item->hasUnified())
groupNode.setAuxiliaryData("unified", item->unifyString());
else
groupNode.removeAuxiliaryData("unified");
}
auto replaceKeyframes = [&group, item, this]() {
m_toolbar->setBlockReflection(true);
for (auto frame : group.keyframes())
frame.destroy();
DesignTools::Keyframe previous;
for (auto &&frame : item->curve().keyframes()) {
QPointF pos = frame.position();
group.setValue(QVariant(pos.y()), pos.x());
if (previous.isValid()) {
if (frame.interpolation() == DesignTools::Keyframe::Interpolation::Bezier) {
DesignTools::CurveSegment segment(previous, frame);
if (segment.isValid())
attachEasingCurve(pos.x(), segment.easingCurve(), group);
} else if (frame.interpolation()
== DesignTools::Keyframe::Interpolation::Easing) {
QVariant data = frame.data();
if (data.type() == static_cast<int>(QMetaType::QEasingCurve))
attachEasingCurve(pos.x(), data.value<QEasingCurve>(), group);
} else if (frame.interpolation() == DesignTools::Keyframe::Interpolation::Step) {
// Warning: Keyframe::Interpolation::Step not yet implemented
}
}
previous = frame;
}
m_toolbar->setBlockReflection(false);
};
timelineView()->executeInTransaction("TimelineWidget::handleKeyframeReplacement",
replaceKeyframes);
}
}
void TimelineWidget::selectionChanged()
{
if (graphicsScene()->hasSelection())

View File

@@ -25,7 +25,6 @@
#pragma once
#include "animationcurveeditormodel.h"
#include "timelineutils.h"
#include <coreplugin/icontext.h>
@@ -79,8 +78,6 @@ public slots:
void changeScaleFactor(int factor);
void scroll(const TimelineUtils::Side &side);
void updateAnimationCurve(DesignTools::PropertyTreeItem *item);
protected:
void showEvent(QShowEvent *event) override;
void resizeEvent(QResizeEvent *event) override;

View File

@@ -125,11 +125,6 @@ QString TransitionEditorToolBar::currentTransitionId() const
return m_transitionComboBox->currentText();
}
void TransitionEditorToolBar::setBlockReflection(bool block)
{
m_blockReflection = block;
}
void TransitionEditorToolBar::updateComboBox(const ModelNode &root)
{
if (root.isValid() && root.hasProperty("transitions")) {
@@ -142,9 +137,6 @@ void TransitionEditorToolBar::updateComboBox(const ModelNode &root)
void TransitionEditorToolBar::setCurrentTransition(const ModelNode &transition)
{
if (m_blockReflection)
return;
if (transition.isValid()) {
m_transitionComboBox->clear();
const ModelNode root = transition.view()->rootModelNode();

View File

@@ -25,9 +25,7 @@
#pragma once
#include "animationcurvedialog.h"
#include "animationcurveeditormodel.h"
#include <modelnode.h>
#include <QToolBar>
QT_FORWARD_DECLARE_CLASS(QComboBox)
@@ -85,8 +83,6 @@ private:
QComboBox *m_transitionComboBox = nullptr;
QSlider *m_scale = nullptr;
QLineEdit *m_duration = nullptr;
bool m_blockReflection = false;
};
} // namespace QmlDesigner

View File

@@ -25,10 +25,6 @@
#pragma once
#include "animationcurvedialog.h"
#include "animationcurveeditormodel.h"
#include "treeitem.h"
#include <abstractview.h>
#include <QPointer>

View File

@@ -38,6 +38,7 @@
#include <sourcetool/sourcetool.h>
#include <colortool/colortool.h>
#include <annotationeditor/annotationtool.h>
#include <curveeditor/curveeditorview.h>
#include <formeditor/transitiontool.h>
#include <texttool/texttool.h>
#include <timelineeditor/timelineview.h>
@@ -238,6 +239,9 @@ bool QmlDesignerPlugin::delayedInitialize()
auto timelineView = new QmlDesigner::TimelineView;
d->viewManager.registerViewTakingOwnership(timelineView);
timelineView->registerActions();
auto curveEditorView = new QmlDesigner::CurveEditorView;
d->viewManager.registerViewTakingOwnership(curveEditorView);
}
auto transitionEditorView = new QmlDesigner::TransitionEditorView;

View File

@@ -721,6 +721,8 @@ Project {
"connectioneditor/dynamicpropertiesmodel.cpp",
"connectioneditor/dynamicpropertiesmodel.h",
"connectioneditor/stylesheet.css",
"curveeditor/curveeditorview.cpp",
"curveeditor/curveeditorview.h",
"curveeditor/animationcurve.cpp",
"curveeditor/animationcurve.h",
"curveeditor/curveeditor.cpp",
@@ -796,10 +798,6 @@ Project {
"texttool/textedititemwidget.h",
"texttool/texttool.cpp",
"texttool/texttool.h",
"timelineeditor/animationcurvedialog.cpp",
"timelineeditor/animationcurvedialog.h",
"timelineeditor/animationcurveeditormodel.cpp",
"timelineeditor/animationcurveeditormodel.h",
"timelineeditor/canvas.cpp",
"timelineeditor/canvas.h",
"timelineeditor/canvasstyledialog.cpp",