summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKnud Dollereder <knud.dollereder@qt.io>2019-02-07 11:46:17 +0100
committerThomas Hartmann <thomas.hartmann@qt.io>2019-02-07 15:09:35 +0000
commiteb031b8ef94da5601dc3e1e133d9abe2c8dfbd5b (patch)
tree400e4445e8570cd1418af2dbedc4f2bf266ad8dc
parent566a9ce6a4fc840d5d4b1d5793166c023643e2c6 (diff)
Introduce curves
and extend the style-options. Change-Id: Ie5652517dca5766cb6d7eab5d29dde9c030e762b Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io> Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
-rw-r--r--examples/curveeditorapp/examplecurvemodel.cpp53
-rw-r--r--examples/curveeditorapp/examplecurvemodel.h2
-rw-r--r--examples/curveeditorapp/mainwindow.cpp2
-rw-r--r--src/curveeditor/animationcurve.cpp143
-rw-r--r--src/curveeditor/animationcurve.h99
-rw-r--r--src/curveeditor/curveeditor.cpp2
-rw-r--r--src/curveeditor/curveeditor.pri15
-rw-r--r--src/curveeditor/curveeditormodel.h4
-rw-r--r--src/curveeditor/curveeditorstyle.cpp169
-rw-r--r--src/curveeditor/curveeditorstyle.h91
-rw-r--r--src/curveeditor/curveeditorstyledialog.cpp244
-rw-r--r--src/curveeditor/curveeditorstyledialog.h117
-rw-r--r--src/curveeditor/curveeditorview.cpp70
-rw-r--r--src/curveeditor/curveeditorview.h3
-rw-r--r--src/curveeditor/curveitem.cpp100
-rw-r--r--src/curveeditor/curveitem.h31
-rw-r--r--src/curveeditor/handleitem.cpp134
-rw-r--r--src/curveeditor/handleitem.h60
-rw-r--r--src/curveeditor/keyframeitem.cpp181
-rw-r--r--src/curveeditor/keyframeitem.h85
-rw-r--r--src/curveeditor/utils.cpp78
-rw-r--r--src/curveeditor/utils.h48
22 files changed, 1418 insertions, 313 deletions
diff --git a/examples/curveeditorapp/examplecurvemodel.cpp b/examples/curveeditorapp/examplecurvemodel.cpp
index 79b1899..a20740b 100644
--- a/examples/curveeditorapp/examplecurvemodel.cpp
+++ b/examples/curveeditorapp/examplecurvemodel.cpp
@@ -23,6 +23,7 @@
**
****************************************************************************/
#include "examplecurvemodel.h"
+#include "animationcurve.h"
namespace DesignTools {
@@ -38,39 +39,61 @@ double ExampleCurveModel::maximumTime() const
double ExampleCurveModel::minimumValue() const
{
- return -50.0;
+ return -1.0;
}
double ExampleCurveModel::maximumValue() const
{
- return 100.0;
+ return 1.0;
}
-std::vector<QPointF> ExampleCurveModel::curve(int i) const
+AnimationCurve ExampleCurveModel::curve(int i) const
{
- if (i == 0)
- return {QPointF(0.0, -5.0), QPointF(100.1, 0.9), QPointF(200., 0.7), QPointF(500., 0.3)};
- else
- return {QPointF(0.0, 10.0), QPointF(100.1, 30.), QPointF(200., -50.), QPointF(500., 100)};
+ if (i == 0) {
+ return AnimationCurve({
+ Keyframe(QPointF(0.0, -1.0), QPointF(), QPointF(100.0, -1.0)),
+ Keyframe(QPointF(250.0, 0.0), QPointF(150.0, 0.0), QPointF(350.0, 0.0)),
+ Keyframe(QPointF(500.0, 1.0), QPointF(400.0, 1.0), QPointF()),
+ });
+ } else {
+ return AnimationCurve({
+ Keyframe(QPointF(0.0, -1.0), QPointF(), QPointF(1.0, -1.0)),
+ Keyframe(QPointF(5.0, 0.0), QPointF(4.0, 0.0), QPointF(6.0, 0.0)),
+ Keyframe(QPointF(200.0, 1.0), QPointF(199.0, 1.0), QPointF()),
+ });
+ }
}
CurveEditorStyle ExampleCurveModel::style() const
{
// Pseudo auto generated. See: CurveEditorStyleDialog
CurveEditorStyle out;
- out.backgroundBrush = QBrush(QColor(138, 226, 52));
- out.backgroundAlternateBrush = QBrush(QColor(78, 154, 6));
+ out.backgroundBrush = QBrush(QColor(5, 0, 100));
+ out.backgroundAlternateBrush = QBrush(QColor(0, 0, 50));
out.fontColor = QColor(200, 200, 200);
- out.curveColor = QColor(128, 128, 128);
out.gridColor = QColor(128, 128, 128);
+ out.canvasMargin = 5;
+ out.zoomInWidth = 99;
+ out.zoomInHeight = 99;
+ out.timeAxisHeight = 40;
+ out.timeOffsetLeft = 10;
+ out.timeOffsetRight = 10;
out.rangeBarColor = QColor(50, 50, 255);
out.rangeBarCapsColor = QColor(50, 50, 255);
+ out.valueAxisWidth = 60;
+ out.valueOffsetTop = 10;
+ out.valueOffsetBottom = 10;
out.playheadColor = QColor(200, 200, 0);
- out.abscissaHeight = 40;
- out.ordinateWidth = 60;
- out.canvasMargin = 5;
- out.cellCountX = 10;
- out.cellCountY = 10;
+ out.handleStyle.size = 12;
+ out.handleStyle.lineWidth = 1;
+ out.handleStyle.color = QColor(200, 0, 0);
+ out.handleStyle.selectionColor = QColor(200, 200, 200);
+ out.keyframeStyle.size = 13;
+ out.keyframeStyle.color = QColor(240, 255, 0);
+ out.keyframeStyle.selectionColor = QColor(200, 200, 200);
+ out.curveStyle.width = 1;
+ out.curveStyle.color = QColor(0, 200, 0);
+ out.curveStyle.selectionColor = QColor(200, 200, 200);
return out;
}
diff --git a/examples/curveeditorapp/examplecurvemodel.h b/examples/curveeditorapp/examplecurvemodel.h
index 62bfc0b..7f0433e 100644
--- a/examples/curveeditorapp/examplecurvemodel.h
+++ b/examples/curveeditorapp/examplecurvemodel.h
@@ -40,7 +40,7 @@ public:
double maximumValue() const override;
- std::vector<QPointF> curve(int i) const override;
+ AnimationCurve curve(int i) const override;
CurveEditorStyle style() const override;
};
diff --git a/examples/curveeditorapp/mainwindow.cpp b/examples/curveeditorapp/mainwindow.cpp
index 1154538..7138b4e 100644
--- a/examples/curveeditorapp/mainwindow.cpp
+++ b/examples/curveeditorapp/mainwindow.cpp
@@ -69,6 +69,8 @@ MainWindow::MainWindow()
auto *centralWidget = new QWidget;
centralWidget->setLayout(box);
setCentralWidget(centralWidget);
+
+ resize(QSize(1070, 739));
}
} // End namespace DesignTools.
diff --git a/src/curveeditor/animationcurve.cpp b/src/curveeditor/animationcurve.cpp
new file mode 100644
index 0000000..4818a81
--- /dev/null
+++ b/src/curveeditor/animationcurve.cpp
@@ -0,0 +1,143 @@
+/****************************************************************************
+**
+** 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 "animationcurve.h"
+
+#include <assert.h>
+#include <cmath>
+
+namespace DesignTools {
+
+Keyframe::Keyframe()
+ : m_position()
+ , m_leftHandle()
+ , m_rightHandle()
+{}
+
+Keyframe::Keyframe(const QPointF &position)
+ : m_position(position)
+ , m_leftHandle()
+ , m_rightHandle()
+{}
+
+Keyframe::Keyframe(const QPointF &position, const QPointF &leftHandle, const QPointF &rightHandle)
+ : m_position(position)
+ , m_leftHandle(leftHandle)
+ , m_rightHandle(rightHandle)
+{}
+
+bool Keyframe::hasLeftHandle() const
+{
+ return !m_leftHandle.isNull();
+}
+
+bool Keyframe::hasRightHandle() const
+{
+ return !m_rightHandle.isNull();
+}
+
+QPointF Keyframe::position() const
+{
+ return m_position;
+}
+
+QPointF Keyframe::leftHandle() const
+{
+ return m_leftHandle;
+}
+
+QPointF Keyframe::rightHandle() const
+{
+ return m_rightHandle;
+}
+
+void Keyframe::setPosition(const QPointF &pos)
+{
+ m_position = pos;
+}
+
+void Keyframe::setLeftHandle(const QPointF &pos)
+{
+ m_leftHandle = pos;
+}
+
+void Keyframe::setRightHandle(const QPointF &pos)
+{
+ m_rightHandle = pos;
+}
+
+
+CurveSegment::CurveSegment()
+ : m_left()
+ , m_right()
+{}
+
+CurveSegment::CurveSegment(const Keyframe &left, const Keyframe &right)
+ : m_left(left)
+ , m_right(right)
+{}
+
+QPointF CurveSegment::evaluate(double t) const
+{
+ assert(t >= 0. && t <= 1.);
+
+ const double it = 1.0 - t;
+
+ auto binomialPolynomial = [t, it](double p0, double p1, double p2, double p3) {
+ return p0 * std::pow(it, 3.0) + p1 * 3.0 * std::pow(it, 2.0) * t
+ + p2 * 3.0 * it * std::pow(t, 2.0) + p3 * std::pow(t, 3.0);
+ };
+
+ const double x = binomialPolynomial(
+ m_left.position().x(), m_left.rightHandle().x(),
+ m_right.leftHandle().x(), m_right.position().x());
+
+ const double y = binomialPolynomial(
+ m_left.position().y(), m_left.rightHandle().y(),
+ m_right.leftHandle().y(), m_right.position().y());
+
+ return QPointF(x, y);
+}
+
+
+AnimationCurve::AnimationCurve()
+ : m_frames()
+{}
+
+AnimationCurve::AnimationCurve(const std::vector<Keyframe> &frames)
+ : m_frames(frames)
+{}
+
+bool AnimationCurve::isValid() const
+{
+ return !m_frames.empty();
+}
+
+std::vector<Keyframe> AnimationCurve::keyframes() const
+{
+ return m_frames;
+}
+
+} // End namespace DesignTools.
diff --git a/src/curveeditor/animationcurve.h b/src/curveeditor/animationcurve.h
new file mode 100644
index 0000000..7b42e07
--- /dev/null
+++ b/src/curveeditor/animationcurve.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** 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 <QPointF>
+
+#include <vector>
+
+namespace DesignTools {
+
+class Keyframe
+{
+public:
+ Keyframe();
+
+ Keyframe(const QPointF &position);
+
+ Keyframe(const QPointF &position, const QPointF &leftHandle, const QPointF &rightHandle);
+
+ bool hasLeftHandle() const;
+
+ bool hasRightHandle() const;
+
+ QPointF position() const;
+
+ QPointF leftHandle() const;
+
+ QPointF rightHandle() const;
+
+ void setPosition(const QPointF &pos);
+
+ void setLeftHandle(const QPointF &pos);
+
+ void setRightHandle(const QPointF &pos);
+
+private:
+ QPointF m_position = QPointF();
+
+ QPointF m_leftHandle = QPointF();
+
+ QPointF m_rightHandle = QPointF();
+};
+
+
+class CurveSegment
+{
+public:
+ CurveSegment();
+
+ CurveSegment(const Keyframe &first, const Keyframe &last);
+
+ QPointF evaluate(double t) const;
+
+private:
+ Keyframe m_left;
+
+ Keyframe m_right;
+};
+
+
+class AnimationCurve
+{
+public:
+ AnimationCurve();
+
+ AnimationCurve(const std::vector<Keyframe> &frames);
+
+ bool isValid() const;
+
+ std::vector<Keyframe> keyframes() const;
+
+private:
+ std::vector<Keyframe> m_frames;
+};
+
+} // End namespace DesignTools.
diff --git a/src/curveeditor/curveeditor.cpp b/src/curveeditor/curveeditor.cpp
index 95adefd..b72f905 100644
--- a/src/curveeditor/curveeditor.cpp
+++ b/src/curveeditor/curveeditor.cpp
@@ -37,6 +37,8 @@ CurveEditor::CurveEditor(CurveEditorModel *model, QWidget *parent)
, m_tree(new QTreeView)
, m_view(new CurveEditorView(model))
{
+ m_tree->setFixedWidth(100);
+
QSplitter *splitter = new QSplitter;
splitter->addWidget(m_tree);
splitter->addWidget(m_view);
diff --git a/src/curveeditor/curveeditor.pri b/src/curveeditor/curveeditor.pri
index ba5aaf9..861abd8 100644
--- a/src/curveeditor/curveeditor.pri
+++ b/src/curveeditor/curveeditor.pri
@@ -2,15 +2,22 @@ INCLUDEPATH += $$PWD
### include required files
HEADERS += \
+ $$PWD/animationcurve.h \
$$PWD/curveeditor.h \
- $$PWD/curveeditorstyle.h \
+ $$PWD/curveeditorstyledialog.h \
$$PWD/curveeditorview.h \
$$PWD/curveitem.h \
- $$PWD/colorcontrol.h
+ $$PWD/colorcontrol.h \
+ $$PWD/handleitem.h \
+ $$PWD/keyframeitem.h
SOURCES += \
+ $$PWD/animationcurve.cpp \
$$PWD/curveeditor.cpp \
- $$PWD/curveeditorstyle.cpp \
+ $$PWD/curveeditorstyledialog.cpp \
$$PWD/curveeditorview.cpp \
$$PWD/curveitem.cpp \
- $$PWD/colorcontrol.cpp
+ $$PWD/colorcontrol.cpp \
+ $$PWD/handleitem.cpp \
+ $$PWD/keyframeitem.cpp \
+ $$PWD/utils.cpp
diff --git a/src/curveeditor/curveeditormodel.h b/src/curveeditor/curveeditormodel.h
index 883d928..351aa73 100644
--- a/src/curveeditor/curveeditormodel.h
+++ b/src/curveeditor/curveeditormodel.h
@@ -33,6 +33,8 @@ class QPointF;
namespace DesignTools {
+class AnimationCurve;
+
class CurveEditorModel
{
public:
@@ -44,7 +46,7 @@ public:
virtual double maximumValue() const = 0;
- virtual std::vector<QPointF> curve(int i) const = 0;
+ virtual AnimationCurve curve(int i) const = 0;
virtual CurveEditorStyle style() const { return CurveEditorStyle(); }
};
diff --git a/src/curveeditor/curveeditorstyle.cpp b/src/curveeditor/curveeditorstyle.cpp
deleted file mode 100644
index a055596..0000000
--- a/src/curveeditor/curveeditorstyle.cpp
+++ /dev/null
@@ -1,169 +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.
-**
-****************************************************************************/
-#include "curveeditorstyle.h"
-#include "colorcontrol.h"
-
-#include <QDebug>
-#include <QDoubleSpinBox>
-#include <QLabel>
-#include <QPushButton>
-#include <QSpinBox>
-#include <QVBoxLayout>
-
-namespace DesignTools {
-
-QHBoxLayout *createRow(const QString &title, QWidget *widget)
-{
- auto *label = new QLabel(title);
- label->setFixedWidth(200);
- label->setAlignment(Qt::AlignRight);
-
- auto *box = new QHBoxLayout;
- box->addWidget(label);
- box->addWidget(widget);
- return box;
-}
-
-CurveEditorStyleDialog::CurveEditorStyleDialog(CurveEditorStyle &style, QWidget *parent)
- : QDialog(parent)
- , m_printButton(new QPushButton("Print"))
- , m_abscissa(new QDoubleSpinBox())
- , m_ordinate(new QDoubleSpinBox())
- , m_canvasMargin(new QDoubleSpinBox())
- , m_cellCountX(new QSpinBox())
- , m_cellCountY(new QSpinBox())
- , m_background(new ColorControl(style.backgroundBrush.color()))
- , m_backgroundAlternate(new ColorControl(style.backgroundAlternateBrush.color()))
- , m_fontColor(new ColorControl(style.fontColor))
- , m_curveColor(new ColorControl(style.curveColor))
- , m_gridColor(new ColorControl(style.gridColor))
- , m_rangeBarColor(new ColorControl(style.rangeBarCapsColor))
- , m_rangeBarCapsColor(new ColorControl(style.rangeBarCapsColor))
- , m_playhead(new ColorControl(style.playheadColor))
-{
- m_abscissa->setValue(style.abscissaHeight);
- m_ordinate->setValue(style.ordinateWidth);
- m_canvasMargin->setValue(style.canvasMargin);
- m_cellCountX->setValue(style.cellCountX);
- m_cellCountY->setValue(style.cellCountY);
-
- connect(m_printButton, &QPushButton::released, this, &CurveEditorStyleDialog::printStyle);
-
- auto intChanged = [this](int) { emitStyleChanged(); };
- auto doubleChanged = [this](double) { emitStyleChanged(); };
- auto colorChanged = [this]() { emitStyleChanged(); };
-
- auto intSignal = static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged);
- auto doubleSignal = static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged);
-
- connect(m_abscissa, doubleSignal, doubleChanged);
- connect(m_ordinate, doubleSignal, doubleChanged);
- connect(m_canvasMargin, doubleSignal, doubleChanged);
-
- connect(m_cellCountX, intSignal, intChanged);
- connect(m_cellCountY, intSignal, intChanged);
-
- connect(m_background, &ColorControl::valueChanged, colorChanged);
- connect(m_backgroundAlternate, &ColorControl::valueChanged, colorChanged);
-
- connect(m_fontColor, &ColorControl::valueChanged, colorChanged);
- connect(m_curveColor, &ColorControl::valueChanged, colorChanged);
- connect(m_gridColor, &ColorControl::valueChanged, colorChanged);
- connect(m_rangeBarColor, &ColorControl::valueChanged, colorChanged);
- connect(m_rangeBarCapsColor, &ColorControl::valueChanged, colorChanged);
- connect(m_playhead, &ColorControl::valueChanged, colorChanged);
-
- auto *box = new QVBoxLayout;
- box->addLayout(createRow("Abscissa Width", m_abscissa));
- box->addLayout(createRow("Ordinate Width", m_ordinate));
- box->addLayout(createRow("Canvas Margin", m_canvasMargin));
- box->addLayout(createRow("Cellcount X", m_cellCountX));
- box->addLayout(createRow("Cellcount Y", m_cellCountY));
- box->addLayout(createRow("Background Color", m_background));
- box->addLayout(createRow("Alternate Background Color", m_backgroundAlternate));
- box->addLayout(createRow("Font Color", m_fontColor));
- box->addLayout(createRow("Curve Color", m_curveColor));
- box->addLayout(createRow("Grid Color", m_gridColor));
- box->addLayout(createRow("Range Bar Color", m_rangeBarColor));
- box->addLayout(createRow("Range Bar Caps Color", m_rangeBarCapsColor));
- box->addLayout(createRow("Playhead Color", m_playhead));
-
- box->addWidget(m_printButton);
- setLayout(box);
-}
-
-CurveEditorStyle CurveEditorStyleDialog::style() const
-{
- CurveEditorStyle style;
- style.backgroundBrush = QBrush(m_background->value());
- style.backgroundAlternateBrush = QBrush(m_backgroundAlternate->value());
- style.fontColor = m_fontColor->value();
- style.curveColor = m_curveColor->value();
- style.gridColor = m_gridColor->value();
- style.rangeBarColor = m_rangeBarColor->value();
- style.rangeBarCapsColor = m_rangeBarCapsColor->value();
- style.playheadColor = m_playhead->value();
- style.abscissaHeight = m_abscissa->value();
- style.ordinateWidth = m_ordinate->value();
- style.canvasMargin = m_canvasMargin->value();
- style.cellCountX = m_cellCountX->value();
- style.cellCountY = m_cellCountY->value();
- return style;
-}
-
-void CurveEditorStyleDialog::emitStyleChanged()
-{
- emit styleChanged(style());
-}
-
-void CurveEditorStyleDialog::printStyle()
-{
- auto toString = [](const QColor &color) {
- QString tmp = QString("QColor(%1, %2, %3)").arg(color.red()).arg(color.green()).arg(color.blue());
- return qPrintable(tmp);
- };
-
- CurveEditorStyle s = style();
- qDebug() << "";
- qDebug().nospace() << "CurveEditorStyle out;";
- qDebug().nospace() << "out.backgroundBrush = QBrush(" << toString(s.backgroundBrush.color()) << ");";
- qDebug().nospace() << "out.backgroundAlternateBrush = QBrush(" << toString(s.backgroundAlternateBrush.color())
- << ");";
- qDebug().nospace() << "out.fontColor = " << toString(s.fontColor) << ";";
- qDebug().nospace() << "out.curveColor = " << toString(s.curveColor) << ";";
- qDebug().nospace() << "out.gridColor = " << toString(s.gridColor) << ";";
- qDebug().nospace() << "out.rangeBarColor = " << toString(s.rangeBarColor) << ";";
- qDebug().nospace() << "out.rangeBarCapsColor = " << toString(s.rangeBarCapsColor) << ";";
- qDebug().nospace() << "out.playheadColor = " << toString(s.playheadColor) << ";";
- qDebug().nospace() << "out.abscissaHeight = " << s.abscissaHeight << ";";
- qDebug().nospace() << "out.ordinateWidth = " << s.ordinateWidth << ";";
- qDebug().nospace() << "out.canvasMargin = " << s.canvasMargin << ";";
- qDebug().nospace() << "out.cellCountX = " << s.cellCountX << ";";
- qDebug().nospace() << "out.cellCountY = " << s.cellCountY << ";";
- qDebug().nospace() << "return out;";
- qDebug() << "";
-}
-
-} // End namespace DesignTools.
diff --git a/src/curveeditor/curveeditorstyle.h b/src/curveeditor/curveeditorstyle.h
index 81cb83c..23fdaf8 100644
--- a/src/curveeditor/curveeditorstyle.h
+++ b/src/curveeditor/curveeditorstyle.h
@@ -29,13 +29,29 @@
#include <QColor>
#include <QDialog>
-class QPushButton;
-class QSpinBox;
-class QDoubleSpinBox;
-
namespace DesignTools {
-class ColorControl;
+struct HandleItemStyleOption
+{
+ double size = 10.0;
+ double lineWidth = 1.0;
+ QColor color = QColor(200, 0, 0);
+ QColor selectionColor = QColor(200, 200, 200);
+};
+
+struct KeyframeItemStyleOption
+{
+ double size = 10.0;
+ QColor color = QColor(200, 200, 0);
+ QColor selectionColor = QColor(200, 200, 200);
+};
+
+struct CurveItemStyleOption
+{
+ double width = 1.0;
+ QColor color = QColor(0, 200, 0);
+ QColor selectionColor = QColor(200, 200, 200);
+};
struct CurveEditorStyle
{
@@ -45,78 +61,37 @@ struct CurveEditorStyle
QColor fontColor = QColor(200, 200, 200);
- QColor curveColor = QColor(128, 128, 128);
-
QColor gridColor = QColor(128, 128, 128);
- QColor rangeBarColor = QColor(128, 128, 128);
-
- QColor rangeBarCapsColor = QColor(50, 50, 255);
-
- QColor playheadColor = QColor(200, 200, 0);
-
- double abscissaHeight = 40.0;
-
- double ordinateWidth = 60.0;
-
double canvasMargin = 5.0;
int zoomInWidth = 100;
int zoomInHeight = 100;
- int cellCountX = 10;
-
- int cellCountY = 10;
-};
-
-class CurveEditorView;
-
-class CurveEditorStyleDialog : public QDialog
-{
- Q_OBJECT
-
-signals:
- void styleChanged(const CurveEditorStyle &style);
-
-public:
- CurveEditorStyleDialog(CurveEditorStyle &style, QWidget *parent = nullptr);
-
- CurveEditorStyle style() const;
+ double timeAxisHeight = 40.0;
-private:
- void emitStyleChanged();
+ double timeOffsetLeft = 10.0;
- void printStyle();
+ double timeOffsetRight = 10.0;
-private:
- QPushButton *m_printButton;
-
- QDoubleSpinBox *m_abscissa;
-
- QDoubleSpinBox *m_ordinate;
-
- QDoubleSpinBox *m_canvasMargin;
-
- QSpinBox *m_cellCountX;
-
- QSpinBox *m_cellCountY;
+ QColor rangeBarColor = QColor(128, 128, 128);
- ColorControl *m_background;
+ QColor rangeBarCapsColor = QColor(50, 50, 255);
- ColorControl *m_backgroundAlternate;
+ double valueAxisWidth = 60.0;
- ColorControl *m_fontColor;
+ double valueOffsetTop = 10.0;
- ColorControl *m_curveColor;
+ double valueOffsetBottom = 10.0;
- ColorControl *m_gridColor;
+ QColor playheadColor = QColor(200, 200, 0);
- ColorControl *m_rangeBarColor;
+ HandleItemStyleOption handleStyle;
- ColorControl *m_rangeBarCapsColor;
+ KeyframeItemStyleOption keyframeStyle;
- ColorControl *m_playhead;
+ CurveItemStyleOption curveStyle;
};
} // End namespace DesignTools.
diff --git a/src/curveeditor/curveeditorstyledialog.cpp b/src/curveeditor/curveeditorstyledialog.cpp
new file mode 100644
index 0000000..2629f24
--- /dev/null
+++ b/src/curveeditor/curveeditorstyledialog.cpp
@@ -0,0 +1,244 @@
+/****************************************************************************
+**
+** 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 "curveeditorstyledialog.h"
+#include "colorcontrol.h"
+#include "curveeditorstyle.h"
+
+#include <QDebug>
+#include <QDoubleSpinBox>
+#include <QLabel>
+#include <QPushButton>
+#include <QSpinBox>
+#include <QVBoxLayout>
+
+namespace DesignTools {
+
+QHBoxLayout *createRow(const QString &title, QWidget *widget)
+{
+ auto *label = new QLabel(title);
+ label->setFixedWidth(200);
+ label->setAlignment(Qt::AlignRight);
+
+ auto *box = new QHBoxLayout;
+ box->addWidget(label);
+ box->addWidget(widget);
+ return box;
+}
+
+CurveEditorStyleDialog::CurveEditorStyleDialog(CurveEditorStyle &style, QWidget *parent)
+ : QDialog(parent)
+ , m_printButton(new QPushButton("Print"))
+ , m_background(new ColorControl(style.backgroundBrush.color()))
+ , m_backgroundAlternate(new ColorControl(style.backgroundAlternateBrush.color()))
+ , m_fontColor(new ColorControl(style.fontColor))
+ , m_gridColor(new ColorControl(style.gridColor))
+ , m_canvasMargin(new QDoubleSpinBox())
+ , m_zoomInWidth(new QSpinBox())
+ , m_zoomInHeight(new QSpinBox())
+ , m_timeAxisHeight(new QDoubleSpinBox())
+ , m_timeOffsetLeft(new QDoubleSpinBox())
+ , m_timeOffsetRight(new QDoubleSpinBox())
+ , m_rangeBarColor(new ColorControl(style.rangeBarCapsColor))
+ , m_rangeBarCapsColor(new ColorControl(style.rangeBarCapsColor))
+ , m_valueAxisWidth(new QDoubleSpinBox())
+ , m_valueOffsetTop(new QDoubleSpinBox())
+ , m_valueOffsetBottom(new QDoubleSpinBox())
+ , m_playhead(new ColorControl(style.playheadColor))
+ , m_handleSize(new QDoubleSpinBox())
+ , m_handleLineWidth(new QDoubleSpinBox())
+ , m_handleColor(new ColorControl(style.handleStyle.color))
+ , m_handleSelectionColor(new ColorControl(style.handleStyle.selectionColor))
+ , m_keyframeSize(new QDoubleSpinBox())
+ , m_keyframeColor(new ColorControl(style.keyframeStyle.color))
+ , m_keyframeSelectionColor(new ColorControl(style.keyframeStyle.selectionColor))
+ , m_curveWidth(new QDoubleSpinBox())
+ , m_curveColor(new ColorControl(style.curveStyle.color))
+ , m_curveSelectionColor(new ColorControl(style.curveStyle.selectionColor))
+{
+ m_canvasMargin->setValue(style.canvasMargin);
+ m_zoomInWidth->setValue(style.zoomInWidth);
+ m_zoomInHeight->setValue(style.zoomInHeight);
+ m_timeAxisHeight->setValue(style.timeAxisHeight);
+ m_timeOffsetLeft->setValue(style.timeOffsetLeft);
+ m_timeOffsetRight->setValue(style.timeOffsetRight);
+ m_valueAxisWidth->setValue(style.valueAxisWidth);
+ m_valueOffsetTop->setValue(style.valueOffsetTop);
+ m_valueOffsetBottom->setValue(style.valueOffsetBottom);
+ m_handleSize->setValue(style.handleStyle.size);
+ m_handleLineWidth->setValue(style.handleStyle.lineWidth);
+ m_keyframeSize->setValue(style.keyframeStyle.size);
+ m_curveWidth->setValue(style.curveStyle.width);
+
+ connect(m_printButton, &QPushButton::released, this, &CurveEditorStyleDialog::printStyle);
+
+ auto intChanged = [this](int) { emitStyleChanged(); };
+ auto doubleChanged = [this](double) { emitStyleChanged(); };
+ auto colorChanged = [this]() { emitStyleChanged(); };
+
+ auto intSignal = static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged);
+ auto doubleSignal = static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged);
+
+ connect(m_background, &ColorControl::valueChanged, colorChanged);
+ connect(m_backgroundAlternate, &ColorControl::valueChanged, colorChanged);
+ connect(m_fontColor, &ColorControl::valueChanged, colorChanged);
+ connect(m_gridColor, &ColorControl::valueChanged, colorChanged);
+ connect(m_canvasMargin, doubleSignal, doubleChanged);
+ connect(m_zoomInWidth, intSignal, intChanged);
+ connect(m_zoomInHeight, intSignal, intChanged);
+ connect(m_timeAxisHeight, doubleSignal, doubleChanged);
+ connect(m_timeOffsetLeft, doubleSignal, doubleChanged);
+ connect(m_timeOffsetRight, doubleSignal, doubleChanged);
+ connect(m_rangeBarColor, &ColorControl::valueChanged, colorChanged);
+ connect(m_rangeBarCapsColor, &ColorControl::valueChanged, colorChanged);
+ connect(m_valueAxisWidth, doubleSignal, doubleChanged);
+ connect(m_valueOffsetTop, doubleSignal, doubleChanged);
+ connect(m_valueOffsetBottom, doubleSignal, doubleChanged);
+ connect(m_playhead, &ColorControl::valueChanged, colorChanged);
+ connect(m_handleSize, doubleSignal, doubleChanged);
+ connect(m_handleLineWidth, doubleSignal, doubleChanged);
+ connect(m_handleColor, &ColorControl::valueChanged, colorChanged);
+ connect(m_handleSelectionColor, &ColorControl::valueChanged, colorChanged);
+ connect(m_keyframeSize, doubleSignal, doubleChanged);
+ connect(m_keyframeColor, &ColorControl::valueChanged, colorChanged);
+ connect(m_keyframeSelectionColor, &ColorControl::valueChanged, colorChanged);
+ connect(m_curveWidth, doubleSignal, doubleChanged);
+ connect(m_curveColor, &ColorControl::valueChanged, colorChanged);
+ connect(m_curveSelectionColor, &ColorControl::valueChanged, colorChanged);
+
+ auto *box = new QVBoxLayout;
+ box->addLayout(createRow("Background Color", m_background));
+ box->addLayout(createRow("Alternate Background Color", m_backgroundAlternate));
+ box->addLayout(createRow("Font Color", m_fontColor));
+ box->addLayout(createRow("Grid Color", m_gridColor));
+ box->addLayout(createRow("Canvas Margin", m_canvasMargin));
+ box->addLayout(createRow("Zoom In Width", m_zoomInWidth));
+ box->addLayout(createRow("Zoom In Height", m_zoomInHeight));
+ box->addLayout(createRow("Time Axis Height", m_timeAxisHeight));
+ box->addLayout(createRow("Time Axis Left Offset", m_timeOffsetLeft));
+ box->addLayout(createRow("Time Axis Right Offset", m_timeOffsetRight));
+ box->addLayout(createRow("Range Bar Color", m_rangeBarColor));
+ box->addLayout(createRow("Range Bar Caps Color", m_rangeBarCapsColor));
+ box->addLayout(createRow("Value Axis Width", m_valueAxisWidth));
+ box->addLayout(createRow("Value Axis Top Offset", m_valueOffsetTop));
+ box->addLayout(createRow("Value Axis Bottom Offset", m_valueOffsetBottom));
+ box->addLayout(createRow("Playhead Color", m_playhead));
+ box->addLayout(createRow("Handle Size", m_handleSize));
+ box->addLayout(createRow("Handle Line Width", m_handleLineWidth));
+ box->addLayout(createRow("Handle Color", m_handleColor));
+ box->addLayout(createRow("Handle Selection Color", m_handleSelectionColor));
+ box->addLayout(createRow("Keyframe Size", m_keyframeSize));
+ box->addLayout(createRow("Keyframe Color", m_keyframeColor));
+ box->addLayout(createRow("Keyframe Selection Color", m_keyframeSelectionColor));
+ box->addLayout(createRow("Curve Width", m_curveWidth));
+ box->addLayout(createRow("Curve Color", m_curveColor));
+ box->addLayout(createRow("Curve Selection Color", m_curveSelectionColor));
+
+ box->addWidget(m_printButton);
+ setLayout(box);
+}
+
+CurveEditorStyle CurveEditorStyleDialog::style() const
+{
+ CurveEditorStyle style;
+ style.backgroundBrush = QBrush(m_background->value());
+ style.backgroundAlternateBrush = QBrush(m_backgroundAlternate->value());
+ style.fontColor = m_fontColor->value();
+ style.gridColor = m_gridColor->value();
+ style.canvasMargin = m_canvasMargin->value();
+ style.zoomInWidth = m_zoomInWidth->value();
+ style.zoomInHeight = m_zoomInHeight->value();
+ style.timeAxisHeight = m_timeAxisHeight->value();
+ style.timeOffsetLeft = m_timeOffsetLeft->value();
+ style.timeOffsetRight = m_timeOffsetRight->value();
+ style.rangeBarColor = m_rangeBarColor->value();
+ style.rangeBarCapsColor = m_rangeBarCapsColor->value();
+ style.valueAxisWidth = m_valueAxisWidth->value();
+ style.valueOffsetTop = m_valueOffsetTop->value();
+ style.valueOffsetBottom = m_valueOffsetBottom->value();
+ style.playheadColor = m_playhead->value();
+ style.handleStyle.size = m_handleSize->value();
+ style.handleStyle.lineWidth = m_handleLineWidth->value();
+ style.handleStyle.color = m_handleColor->value();
+ style.handleStyle.selectionColor = m_handleSelectionColor->value();
+ style.keyframeStyle.size = m_keyframeSize->value();
+ style.keyframeStyle.color = m_keyframeColor->value();
+ style.keyframeStyle.selectionColor = m_keyframeSelectionColor->value();
+ style.curveStyle.width = m_curveWidth->value();
+ style.curveStyle.color = m_curveColor->value();
+ style.curveStyle.selectionColor = m_curveSelectionColor->value();
+ return style;
+}
+
+void CurveEditorStyleDialog::emitStyleChanged()
+{
+ emit styleChanged(style());
+}
+
+void CurveEditorStyleDialog::printStyle()
+{
+ auto toString = [](const QColor &color) {
+ QString tmp = QString("QColor(%1, %2, %3)").arg(color.red()).arg(color.green()).arg(color.blue());
+ return qPrintable(tmp);
+ };
+
+ CurveEditorStyle s = style();
+ qDebug() << "";
+ qDebug().nospace() << "CurveEditorStyle out;";
+ qDebug().nospace() << "out.backgroundBrush = QBrush(" << toString(s.backgroundBrush.color())
+ << ");";
+ qDebug().nospace() << "out.backgroundAlternateBrush = QBrush("
+ << toString(s.backgroundAlternateBrush.color()) << ");";
+ qDebug().nospace() << "out.fontColor = " << toString(s.fontColor) << ";";
+ qDebug().nospace() << "out.gridColor = " << toString(s.gridColor) << ";";
+ qDebug().nospace() << "out.canvasMargin = " << s.canvasMargin << ";";
+ qDebug().nospace() << "out.zoomInWidth = " << s.zoomInWidth << ";";
+ qDebug().nospace() << "out.zoomInHeight = " << s.zoomInHeight << ";";
+ qDebug().nospace() << "out.timeAxisHeight = " << s.timeAxisHeight << ";";
+ qDebug().nospace() << "out.timeOffsetLeft = " << s.timeOffsetLeft << ";";
+ qDebug().nospace() << "out.timeOffsetRight = " << s.timeOffsetRight << ";";
+ qDebug().nospace() << "out.rangeBarColor = " << toString(s.rangeBarColor) << ";";
+ qDebug().nospace() << "out.rangeBarCapsColor = " << toString(s.rangeBarCapsColor) << ";";
+ qDebug().nospace() << "out.valueAxisWidth = " << s.valueAxisWidth << ";";
+ qDebug().nospace() << "out.valueOffsetTop = " << s.valueOffsetTop << ";";
+ qDebug().nospace() << "out.valueOffsetBottom = " << s.valueOffsetBottom << ";";
+ qDebug().nospace() << "out.playheadColor = " << toString(s.playheadColor) << ";";
+ qDebug().nospace() << "out.handleStyle.size = " << s.handleStyle.size << ";";
+ qDebug().nospace() << "out.handleStyle.lineWidth = " << s.handleStyle.lineWidth << ";";
+ qDebug().nospace() << "out.handleStyle.color = " << toString(s.handleStyle.color) << ";";
+ qDebug().nospace() << "out.handleStyle.selectionColor = "
+ << toString(s.handleStyle.selectionColor) << ";";
+ qDebug().nospace() << "out.keyframeStyle.size = " << s.keyframeStyle.size << ";";
+ qDebug().nospace() << "out.keyframeStyle.color = " << toString(s.keyframeStyle.color) << ";";
+ qDebug().nospace() << "out.keyframeStyle.selectionColor = "
+ << toString(s.keyframeStyle.selectionColor) << ";";
+ qDebug().nospace() << "out.curveStyle.width = " << s.curveStyle.width << ";";
+ qDebug().nospace() << "out.curveStyle.color = " << toString(s.curveStyle.color) << ";";
+ qDebug().nospace() << "out.curveStyle.selectionColor = "
+ << toString(s.curveStyle.selectionColor) << ";";
+ qDebug().nospace() << "return out;";
+ qDebug() << "";
+}
+
+} // End namespace DesignTools.
diff --git a/src/curveeditor/curveeditorstyledialog.h b/src/curveeditor/curveeditorstyledialog.h
new file mode 100644
index 0000000..645f545
--- /dev/null
+++ b/src/curveeditor/curveeditorstyledialog.h
@@ -0,0 +1,117 @@
+
+/****************************************************************************
+**
+** 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 <QDialog>
+
+class QPushButton;
+class QSpinBox;
+class QDoubleSpinBox;
+
+namespace DesignTools {
+
+class ColorControl;
+
+struct CurveEditorStyle;
+
+class CurveEditorStyleDialog : public QDialog
+{
+ Q_OBJECT
+
+signals:
+ void styleChanged(const CurveEditorStyle &style);
+
+public:
+ CurveEditorStyleDialog(CurveEditorStyle &style, QWidget *parent = nullptr);
+
+ CurveEditorStyle style() const;
+
+private:
+ void emitStyleChanged();
+
+ void printStyle();
+
+private:
+ QPushButton *m_printButton;
+
+ ColorControl *m_background;
+
+ ColorControl *m_backgroundAlternate;
+
+ ColorControl *m_fontColor;
+
+ ColorControl *m_gridColor;
+
+ QDoubleSpinBox *m_canvasMargin;
+
+ QSpinBox *m_zoomInWidth;
+
+ QSpinBox *m_zoomInHeight;
+
+ QDoubleSpinBox *m_timeAxisHeight;
+
+ QDoubleSpinBox *m_timeOffsetLeft;
+
+ QDoubleSpinBox *m_timeOffsetRight;
+
+ ColorControl *m_rangeBarColor;
+
+ ColorControl *m_rangeBarCapsColor;
+
+ QDoubleSpinBox *m_valueAxisWidth;
+
+ QDoubleSpinBox *m_valueOffsetTop;
+
+ QDoubleSpinBox *m_valueOffsetBottom;
+
+ ColorControl *m_playhead;
+
+ // HandleItem
+ QDoubleSpinBox *m_handleSize;
+
+ QDoubleSpinBox *m_handleLineWidth;
+
+ ColorControl *m_handleColor;
+
+ ColorControl *m_handleSelectionColor;
+
+ // KeyframeItem
+ QDoubleSpinBox *m_keyframeSize;
+
+ ColorControl *m_keyframeColor;
+
+ ColorControl *m_keyframeSelectionColor;
+
+ // CurveItem
+ QDoubleSpinBox *m_curveWidth;
+
+ ColorControl *m_curveColor;
+
+ ColorControl *m_curveSelectionColor;
+};
+
+} // End namespace DesignTools.
diff --git a/src/curveeditor/curveeditorview.cpp b/src/curveeditor/curveeditorview.cpp
index 5aba268..0a54c82 100644
--- a/src/curveeditor/curveeditorview.cpp
+++ b/src/curveeditor/curveeditorview.cpp
@@ -25,37 +25,16 @@
#include "curveeditorview.h"
#include "curveeditormodel.h"
#include "curveitem.h"
+#include "utils.h"
#include <QAction>
-#include <QDebug>
#include <QMenu>
#include <QResizeEvent>
-#include <QScrollBar>
#include <cmath>
namespace DesignTools {
-double clamp(double val, double lo, double hi)
-{
- return val < lo ? lo : (val > hi ? hi : val);
-}
-
-double lerp(double blend, double a, double b)
-{
- return (1.0 - blend) * a + blend * b;
-}
-
-double scaleX(const QTransform &transform)
-{
- return transform.m11();
-}
-
-double scaleY(const QTransform &transform)
-{
- return transform.m22();
-}
-
CurveEditorView::CurveEditorView(CurveEditorModel *model, QWidget *parent)
: QGraphicsView(parent)
, m_scene()
@@ -74,7 +53,6 @@ CurveEditorView::CurveEditorView(CurveEditorModel *model, QWidget *parent)
connect(&m_dialog, &CurveEditorStyleDialog::styleChanged, this, &CurveEditorView::setStyle);
m_scene.addItem(new CurveItem(model->curve(0)));
- m_scene.addItem(new CurveItem(model->curve(1)));
applyZoom(m_zoomX, m_zoomY);
update();
@@ -83,7 +61,15 @@ CurveEditorView::CurveEditorView(CurveEditorModel *model, QWidget *parent)
void CurveEditorView::setStyle(const CurveEditorStyle &style)
{
m_style = style;
+
+ const auto itemList = items();
+ for (auto *item : itemList) {
+ if (auto *curveItem = qgraphicsitem_cast<CurveItem *>(item))
+ curveItem->setStyle(style);
+ }
+
updateSceneRect();
+ applyZoom(m_zoomX, m_zoomY);
viewport()->update();
}
@@ -101,11 +87,9 @@ void CurveEditorView::zoomY(double zoom)
void CurveEditorView::resizeEvent(QResizeEvent *event)
{
- Q_UNUSED(event);
-
updateSceneRect();
applyZoom(m_zoomX, m_zoomY);
- viewport()->update();
+ QGraphicsView::resizeEvent(event);
}
void CurveEditorView::contextMenuEvent(QContextMenuEvent *event)
@@ -123,7 +107,7 @@ void CurveEditorView::contextMenuEvent(QContextMenuEvent *event)
void CurveEditorView::drawForeground(QPainter *painter, const QRectF &rect)
{
- auto gap = QRectF(rect.topLeft(), QSizeF(m_style.ordinateWidth, m_style.abscissaHeight));
+ auto gap = QRectF(rect.topLeft(), QSizeF(m_style.valueAxisWidth, m_style.timeAxisHeight));
auto abscissa = QRectF(gap.topRight(), rect.topRight() + QPointF(0.0, gap.height()));
drawTimeScale(painter, abscissa);
@@ -144,7 +128,7 @@ void CurveEditorView::drawBackground(QPainter *painter, const QRectF &rect)
drawExtremaY(painter, rect);
}
-int CurveEditorView::mapTimetoX(double time)
+int CurveEditorView::mapTimeToX(double time)
{
return std::round(time * scaleX(m_transform));
}
@@ -169,12 +153,12 @@ void CurveEditorView::applyZoom(double x, double y)
m_zoomX = x;
m_zoomY = y;
- double canvasWidth = rect().width() - m_style.ordinateWidth - 2 * m_style.canvasMargin - rect().width() / 20.0;
+ double canvasWidth = rect().width() - m_style.valueAxisWidth - 2 * m_style.canvasMargin - rect().width() / 20.0;
double xZoomedOut = canvasWidth / (m_model->maximumTime() - m_model->minimumTime());
double xZoomedIn = m_style.zoomInWidth;
double scaleX = lerp(clamp(m_zoomX, 0.0, 1.0), xZoomedOut, xZoomedIn);
- double canvasHeight = rect().height() - m_style.abscissaHeight - 2 * m_style.canvasMargin - rect().height() / 10;
+ double canvasHeight = rect().height() - m_style.timeAxisHeight - 2 * m_style.canvasMargin - rect().height() / 10;
double yZoomedOut = canvasHeight / (m_model->maximumValue() - m_model->minimumValue());
double yZoomedIn = m_style.zoomInHeight;
double scaleY = lerp(clamp(m_zoomY, 0.0, 1.0), -yZoomedOut, -yZoomedIn);
@@ -184,7 +168,7 @@ void CurveEditorView::applyZoom(double x, double y)
QRectF sceneBounds;
for (auto *item : items())
if (auto *curveItem = qgraphicsitem_cast<CurveItem *>(item))
- sceneBounds = sceneBounds.united(curveItem->zoom(m_transform));
+ sceneBounds = sceneBounds.united(curveItem->setComponentTransform(m_transform));
updateSceneRect(sceneBounds);
}
@@ -195,8 +179,8 @@ void CurveEditorView::updateSceneRect(const QRectF &rect)
scene()->setSceneRect(rect);
QRectF sr = scene()->sceneRect().adjusted(
- -m_style.ordinateWidth - m_style.canvasMargin,
- -m_style.abscissaHeight - m_style.canvasMargin,
+ -m_style.valueAxisWidth - m_style.canvasMargin,
+ -m_style.timeAxisHeight - m_style.canvasMargin,
m_style.canvasMargin,
m_style.canvasMargin);
@@ -209,8 +193,8 @@ void CurveEditorView::drawGrid(QPainter *painter, const QRectF &rect)
painter->setPen(m_style.gridColor);
QRectF gridRect = rect.adjusted(
- m_style.ordinateWidth + m_style.canvasMargin,
- m_style.abscissaHeight + m_style.canvasMargin,
+ m_style.valueAxisWidth + m_style.canvasMargin,
+ m_style.timeAxisHeight + m_style.canvasMargin,
-m_style.canvasMargin,
-m_style.canvasMargin);
@@ -220,7 +204,7 @@ void CurveEditorView::drawGrid(QPainter *painter, const QRectF &rect)
double timeIncrement = timeLabelInterval(painter, m_model->maximumTime());
for (double i = m_model->minimumTime(); i <= m_model->maximumTime(); i += timeIncrement)
- drawVerticalLine(mapTimetoX(i));
+ drawVerticalLine(mapTimeToX(i));
painter->restore();
}
@@ -233,8 +217,8 @@ void CurveEditorView::drawExtremaX(QPainter *painter, const QRectF &rect)
painter->save();
painter->setPen(Qt::red);
- drawVerticalLine(mapTimetoX(m_model->minimumTime()));
- drawVerticalLine(mapTimetoX(m_model->maximumTime()));
+ drawVerticalLine(mapTimeToX(m_model->minimumTime()));
+ drawVerticalLine(mapTimeToX(m_model->maximumTime()));
painter->restore();
}
@@ -248,6 +232,9 @@ void CurveEditorView::drawExtremaY(QPainter *painter, const QRectF &rect)
painter->setPen(Qt::blue);
drawHorizontalLine(mapValueToY(m_model->minimumValue()));
drawHorizontalLine(mapValueToY(m_model->maximumValue()));
+
+ drawHorizontalLine(mapValueToY(0.0));
+
painter->restore();
}
@@ -262,7 +249,7 @@ void CurveEditorView::drawTimeScale(QPainter *painter, const QRectF &rect)
auto paintLabeledTick = [this, painter, rect, fm](double time) {
QString timeText = QString("%1").arg(time);
- int position = mapTimetoX(time);
+ int position = mapTimeToX(time);
QRect textRect = fm.boundingRect(timeText);
textRect.moveCenter(QPoint(position, rect.center().y()));
@@ -307,20 +294,19 @@ double CurveEditorView::timeLabelInterval(QPainter *painter, double maxTime)
int deltaTime = 1;
int nextFactor = 5;
- double tickDistance = mapTimetoX(deltaTime);
+ double tickDistance = mapTimeToX(deltaTime);
while (true) {
if (tickDistance > minTextSpacing)
break;
deltaTime *= nextFactor;
- tickDistance = mapTimetoX(deltaTime);
+ tickDistance = mapTimeToX(deltaTime);
if (nextFactor == 5)
nextFactor = 2;
else
nextFactor = 5;
}
-
return deltaTime;
}
diff --git a/src/curveeditor/curveeditorview.h b/src/curveeditor/curveeditorview.h
index 91a7023..fe35933 100644
--- a/src/curveeditor/curveeditorview.h
+++ b/src/curveeditor/curveeditorview.h
@@ -26,6 +26,7 @@
#pragma once
#include "curveeditorstyle.h"
+#include "curveeditorstyledialog.h"
#include <QGraphicsScene>
#include <QGraphicsView>
@@ -57,7 +58,7 @@ protected:
void drawBackground(QPainter *painter, const QRectF &rect) override;
private:
- int mapTimetoX(double time);
+ int mapTimeToX(double time);
int mapValueToY(double value);
diff --git a/src/curveeditor/curveitem.cpp b/src/curveeditor/curveitem.cpp
index 1514081..128b60e 100644
--- a/src/curveeditor/curveitem.cpp
+++ b/src/curveeditor/curveitem.cpp
@@ -23,6 +23,8 @@
**
****************************************************************************/
#include "curveitem.h"
+#include "keyframeitem.h"
+#include "utils.h"
#include <QPainter>
#include <QPainterPath>
@@ -31,41 +33,109 @@ namespace DesignTools {
CurveItem::CurveItem(QGraphicsItem *parent)
: QGraphicsObject(parent)
- , m_points({QPointF(0.0, 0.0), QPointF(1.1, 1.1)})
+ , m_transform()
+ , m_keyframes()
{}
-CurveItem::CurveItem(const std::vector<QPointF> &points, QGraphicsItem *parent)
+CurveItem::CurveItem(const AnimationCurve &curve, QGraphicsItem *parent)
: QGraphicsObject(parent)
- , m_points(points)
-{}
+ , m_transform()
+ , m_keyframes()
+{
+ auto emitCurveChanged = [this]() {
+ update();
+ emit curveChanged(this->curve());
+ };
+
+ for (auto frame : curve.keyframes()) {
+ auto *item = new KeyframeItem(frame, this);
+ connect(item, &KeyframeItem::keyframeChanged, emitCurveChanged);
+ m_keyframes.push_back(item);
+ }
+}
+
+CurveItem::~CurveItem() {}
+
+int CurveItem::type() const
+{
+ return Type;
+}
QRectF CurveItem::boundingRect() const
{
- return path().boundingRect();
+ QRectF bounds;
+
+ auto bbox = [&bounds](const Keyframe &frame) {
+ grow(bounds, frame.position());
+ grow(bounds, frame.leftHandle());
+ grow(bounds, frame.rightHandle());
+ };
+
+ for (auto *item : m_keyframes)
+ bbox(item->keyframe());
+
+ return m_transform.mapRect(bounds);
}
void CurveItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
{
- painter->drawPath(path());
+ if (m_keyframes.size() > 1) {
+ painter->save();
+
+ QPen pen = painter->pen();
+ pen.setWidthF(m_style.width);
+ pen.setColor(isSelected() ? m_style.selectionColor : m_style.color);
+ painter->setPen(pen);
+
+ Keyframe previous = m_keyframes.front()->keyframe();
+ Keyframe current;
+ for (size_t i = 1; i < m_keyframes.size(); ++i) {
+ current = m_keyframes[i]->keyframe();
+
+ QPainterPath path(m_transform.map(previous.position()));
+
+ if (previous.rightHandle().isNull() || current.leftHandle().isNull())
+ path.lineTo(m_transform.map(current.position()));
+ else
+ path.cubicTo(
+ m_transform.map(previous.rightHandle()),
+ m_transform.map(current.leftHandle()),
+ m_transform.map(current.position()));
+
+ painter->drawPath(path);
+
+ previous = current;
+ }
+
+ painter->restore();
+ }
+}
+
+AnimationCurve CurveItem::curve() const
+{
+ std::vector<Keyframe> out;
+ for (auto item : m_keyframes) {
+ out.push_back(item->keyframe());
+ }
+ return out;
}
-QRectF CurveItem::zoom(const QTransform &transform)
+QRectF CurveItem::setComponentTransform(const QTransform &transform)
{
prepareGeometryChange();
m_transform = transform;
+ for (auto frame : m_keyframes)
+ frame->setComponentTransform(transform);
+
return boundingRect();
}
-QPainterPath CurveItem::path() const
+void CurveItem::setStyle(const CurveEditorStyle &style)
{
- if (m_points.empty())
- return QPainterPath();
-
- auto out = QPainterPath(m_points.front());
- for (size_t i = 1; i < m_points.size(); ++i)
- out.lineTo(m_transform.map(m_points[i]));
+ m_style = style.curveStyle;
- return out;
+ for (auto *frame : m_keyframes)
+ frame->setStyle(style);
}
} // End namespace DesignTools.
diff --git a/src/curveeditor/curveitem.h b/src/curveeditor/curveitem.h
index 6bfc177..bae12e8 100644
--- a/src/curveeditor/curveitem.h
+++ b/src/curveeditor/curveitem.h
@@ -25,34 +25,51 @@
#pragma once
-#include <QGraphicsObject>
+#include "animationcurve.h"
+#include "curveeditorstyle.h"
-class QPainterPath;
+#include <QGraphicsObject>
namespace DesignTools {
+class KeyframeItem;
+
class CurveItem : public QGraphicsObject
{
Q_OBJECT
+signals:
+ void curveChanged(const AnimationCurve &curve);
+
public:
CurveItem(QGraphicsItem *parent = nullptr);
- CurveItem(const std::vector<QPointF> &points, QGraphicsItem *parent = nullptr);
+ CurveItem(const AnimationCurve &curve, QGraphicsItem *parent = nullptr);
+
+ ~CurveItem() override;
+
+ enum { Type = UserType + 1 };
+
+ int type() const override;
QRectF boundingRect() const override;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
- QRectF zoom(const QTransform &transform);
+ AnimationCurve curve() const;
-private:
- QPainterPath path() const;
+ QRectF setComponentTransform(const QTransform &transform);
+
+ void setStyle(const CurveEditorStyle &style);
private:
QTransform m_transform;
- std::vector<QPointF> m_points;
+ CurveItemStyleOption m_style;
+
+ AnimationCurve m_curve;
+
+ std::vector<KeyframeItem *> m_keyframes;
};
} // End namespace DesignTools.
diff --git a/src/curveeditor/handleitem.cpp b/src/curveeditor/handleitem.cpp
new file mode 100644
index 0000000..4653af6
--- /dev/null
+++ b/src/curveeditor/handleitem.cpp
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** 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 "handleitem.h"
+#include "utils.h"
+
+#include <QEvent>
+#include <QGraphicsSceneMouseEvent>
+#include <QPainter>
+
+namespace DesignTools {
+
+struct HandleGeometry
+{
+ HandleGeometry(const QPointF &pos, const HandleItemStyleOption &style)
+ {
+ QPointF topLeft(-style.size / 2.0, -style.size / 2.0);
+
+ handle = QRectF(topLeft, -topLeft);
+ toKeyframe = QLineF(QPointF(0.0, 0.0), -pos);
+ angle = -toKeyframe.angle() + 45.0;
+ }
+
+ QRectF handle;
+
+ QLineF toKeyframe;
+
+ double angle;
+};
+
+HandleItem::HandleItem(QGraphicsItem *parent)
+ : QGraphicsObject(parent)
+ , m_style()
+{
+ setFlag(QGraphicsItem::ItemIsMovable, true);
+ setFlag(QGraphicsItem::ItemIgnoresTransformations, true);
+ setFlag(QGraphicsItem::ItemStacksBehindParent, true);
+}
+
+HandleItem::~HandleItem()
+{ }
+
+int HandleItem::type() const
+{
+ return Type;
+}
+
+QRectF HandleItem::boundingRect() const
+{
+ HandleGeometry geom(pos(), m_style);
+
+ QTransform transform;
+ transform.rotate(geom.angle);
+
+ QRectF bounds = bbox(geom.handle, transform);
+ grow(bounds, -pos());
+ return bounds;
+}
+
+void HandleItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+ Q_UNUSED(option);
+ Q_UNUSED(widget);
+
+ QColor handleColor(isSelected() ? m_style.selectionColor : m_style.color);
+
+ HandleGeometry geom(pos(), m_style);
+
+ QPen pen = painter->pen();
+ pen.setWidthF(m_style.lineWidth);
+ pen.setColor(handleColor);
+
+ painter->save();
+ painter->setPen(pen);
+
+ painter->drawLine(geom.toKeyframe);
+ painter->rotate(geom.angle);
+ painter->fillRect(geom.handle, handleColor);
+
+ painter->restore();
+}
+
+void HandleItem::setStyle(const CurveEditorStyle &style)
+{
+ m_style = style.handleStyle;
+}
+
+bool HandleItem::sceneEvent(QEvent *event)
+{
+ auto intersectsHandle = [this, event]() {
+ HandleGeometry geom(pos(), m_style);
+
+ QTransform transform;
+ transform.rotate(geom.angle);
+
+ auto *mousePressEvent = static_cast<QGraphicsSceneMouseEvent *>(event);
+ return bbox(geom.handle, transform).contains(mousePressEvent->pos());
+ };
+
+ switch (event->type()) {
+
+ case QEvent::GraphicsSceneMousePress:
+ if (!intersectsHandle())
+ event->ignore();
+ return true;
+
+ default:
+ return QGraphicsObject::sceneEvent(event);
+ }
+}
+
+} // End namespace DesignTools.
diff --git a/src/curveeditor/handleitem.h b/src/curveeditor/handleitem.h
new file mode 100644
index 0000000..8e2ffd7
--- /dev/null
+++ b/src/curveeditor/handleitem.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** 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 "curveeditorstyle.h"
+
+#include <QGraphicsObject>
+
+namespace DesignTools {
+
+class HandleItem : public QGraphicsObject
+{
+ Q_OBJECT
+
+public:
+ HandleItem(QGraphicsItem *parent);
+
+ ~HandleItem() override;
+
+ enum { Type = UserType + 3 };
+
+ int type() const override;
+
+ QRectF boundingRect() const override;
+
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
+
+ void setStyle(const CurveEditorStyle &style);
+
+protected:
+ bool sceneEvent(QEvent *event) override;
+
+private:
+ HandleItemStyleOption m_style;
+};
+
+} // End namespace DesignTools.
diff --git a/src/curveeditor/keyframeitem.cpp b/src/curveeditor/keyframeitem.cpp
new file mode 100644
index 0000000..867585c
--- /dev/null
+++ b/src/curveeditor/keyframeitem.cpp
@@ -0,0 +1,181 @@
+/****************************************************************************
+**
+** 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 "keyframeitem.h"
+#include "handleitem.h"
+
+#include <QPainter>
+
+#include <cmath>
+
+namespace DesignTools {
+
+KeyframeItem::KeyframeItem(QGraphicsItem *parent)
+ : QGraphicsObject(parent)
+ , m_frame()
+{}
+
+KeyframeItem::KeyframeItem(const Keyframe &keyframe, QGraphicsItem *parent)
+ : QGraphicsObject(parent)
+ , m_transform()
+ , m_frame(keyframe)
+ , m_left(keyframe.hasLeftHandle() ? new HandleItem(this) : nullptr)
+ , m_right(keyframe.hasRightHandle() ? new HandleItem(this) : nullptr)
+{
+ setFlag(QGraphicsItem::ItemIsMovable, true);
+ setFlag(QGraphicsItem::ItemIgnoresTransformations, true);
+ setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);
+
+ connect(this, &QGraphicsObject::xChanged, this, &KeyframeItem::updatePosition);
+ connect(this, &QGraphicsObject::yChanged, this, &KeyframeItem::updatePosition);
+
+ if (m_left) {
+ m_left->setPos(m_frame.leftHandle() - m_frame.position());
+ auto updateLeftHandle = [this]() { updateHandle(m_left); };
+ connect(m_left, &QGraphicsObject::xChanged, updateLeftHandle);
+ connect(m_left, &QGraphicsObject::yChanged, updateLeftHandle);
+ }
+
+ if (m_right) {
+ m_right->setPos(m_frame.rightHandle() - m_frame.position());
+ auto updateRightHandle = [this]() { updateHandle(m_right); };
+ connect(m_right, &QGraphicsObject::xChanged, updateRightHandle);
+ connect(m_right, &QGraphicsObject::yChanged, updateRightHandle);
+ }
+
+ setPos(m_frame.position());
+}
+
+int KeyframeItem::type() const
+{
+ return Type;
+}
+
+QRectF KeyframeItem::boundingRect() const
+{
+ QPointF topLeft(-m_style.size / 2.0, -m_style.size / 2.0);
+ return QRectF(topLeft, -topLeft);
+}
+
+void KeyframeItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+ Q_UNUSED(option);
+ Q_UNUSED(widget);
+
+ QPen pen = painter->pen();
+ pen.setColor(Qt::black);
+
+ painter->save();
+ painter->setPen(pen);
+ painter->setBrush(isSelected() ? m_style.selectionColor : m_style.color);
+ painter->drawEllipse(boundingRect());
+
+ painter->restore();
+}
+
+KeyframeItem::~KeyframeItem() {}
+
+Keyframe KeyframeItem::keyframe() const
+{
+ return m_frame;
+}
+
+void KeyframeItem::setComponentTransform(const QTransform &transform)
+{
+ m_transform = transform;
+
+ if (m_left)
+ m_left->setPos(m_transform.map(m_frame.leftHandle() - m_frame.position()));
+
+ if (m_right)
+ m_right->setPos(m_transform.map(m_frame.rightHandle() - m_frame.position()));
+
+ setPos(m_transform.map(m_frame.position()));
+}
+
+void KeyframeItem::setStyle(const CurveEditorStyle &style)
+{
+ m_style = style.keyframeStyle;
+
+ if (m_left)
+ m_left->setStyle(style);
+
+ if (m_right)
+ m_right->setStyle(style);
+}
+
+void KeyframeItem::updatePosition()
+{
+ bool ok = false;
+ QPointF position = m_transform.inverted(&ok).map(pos());
+
+ if (!ok)
+ return;
+
+ m_frame.setPosition(position);
+
+ if (m_left)
+ updateHandle(m_left, false);
+
+ if (m_right)
+ updateHandle(m_right, false);
+
+ emit keyframeChanged();
+}
+
+void KeyframeItem::updateHandle(HandleItem *handle, bool emitChanged)
+{
+ bool ok = false;
+
+ QPointF handlePosition = m_transform.inverted(&ok).map(handle->pos());
+
+ if (!ok)
+ return;
+
+ if (handle == m_left)
+ m_frame.setLeftHandle(m_frame.position() + handlePosition);
+ else
+ m_frame.setRightHandle(m_frame.position() + handlePosition);
+
+ if (emitChanged)
+ emit keyframeChanged();
+}
+
+QVariant KeyframeItem::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
+{
+ if (change == ItemPositionChange) {
+ // Snap to keyframe.
+ bool ok;
+ QPointF position = m_transform.inverted(&ok).map(value.toPointF());
+ if (ok) {
+ position.setX(std::round(position.x()));
+ return QVariant(m_transform.map(position));
+ }
+ }
+
+ return QGraphicsItem::itemChange(change, value);
+}
+
+} // End namespace DesignTools.
diff --git a/src/curveeditor/keyframeitem.h b/src/curveeditor/keyframeitem.h
new file mode 100644
index 0000000..39221d2
--- /dev/null
+++ b/src/curveeditor/keyframeitem.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** 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 "animationcurve.h"
+#include "curveeditorstyle.h"
+
+#include <QGraphicsObject>
+
+namespace DesignTools {
+
+class HandleItem;
+
+class KeyframeItem : public QGraphicsObject
+{
+ Q_OBJECT
+
+signals:
+ void keyframeChanged();
+
+public:
+ KeyframeItem(QGraphicsItem *parent = nullptr);
+
+ KeyframeItem(const Keyframe &keyframe, QGraphicsItem *parent = nullptr);
+
+ ~KeyframeItem() override;
+
+ enum { Type = UserType + 2 };
+
+ int type() const override;
+
+ QRectF boundingRect() const override;
+
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
+
+ Keyframe keyframe() const;
+
+ void setComponentTransform(const QTransform &transform);
+
+ void setStyle(const CurveEditorStyle &style);
+
+protected:
+ QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override;
+
+private:
+ void updatePosition();
+
+ void updateHandle(HandleItem *handle, bool emit = true);
+
+private:
+ QTransform m_transform;
+
+ KeyframeItemStyleOption m_style;
+
+ Keyframe m_frame;
+
+ HandleItem *m_left;
+
+ HandleItem *m_right;
+};
+
+} // End namespace DesignTools.
diff --git a/src/curveeditor/utils.cpp b/src/curveeditor/utils.cpp
new file mode 100644
index 0000000..da74946
--- /dev/null
+++ b/src/curveeditor/utils.cpp
@@ -0,0 +1,78 @@
+
+/****************************************************************************
+**
+** 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 <QPointF>
+#include <QRectF>
+#include <QTransform>
+
+namespace DesignTools {
+
+double clamp(double val, double lo, double hi)
+{
+ return val < lo ? lo : (val > hi ? hi : val);
+}
+
+double lerp(double blend, double a, double b)
+{
+ return (1.0 - blend) * a + blend * b;
+}
+
+double scaleX(const QTransform &transform)
+{
+ return transform.m11();
+}
+
+double scaleY(const QTransform &transform)
+{
+ return transform.m22();
+}
+
+void grow(QRectF &rect, const QPointF &point)
+{
+ if (rect.left() > point.x())
+ rect.setLeft(point.x());
+
+ if (rect.right() < point.x())
+ rect.setRight(point.x());
+
+ if (rect.top() > point.y())
+ rect.setTop(point.y());
+
+ if (rect.bottom() < point.y())
+ rect.setBottom(point.y());
+}
+
+QRectF bbox(const QRectF &rect, const QTransform &transform)
+{
+ QRectF out = rect;
+ grow(out, transform.map(rect.topLeft()));
+ grow(out, transform.map(rect.topRight()));
+ grow(out, transform.map(rect.bottomLeft()));
+ grow(out, transform.map(rect.bottomRight()));
+ return out;
+}
+
+} // End namespace DesignTools.
diff --git a/src/curveeditor/utils.h b/src/curveeditor/utils.h
new file mode 100644
index 0000000..c8a44fb
--- /dev/null
+++ b/src/curveeditor/utils.h
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** 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
+
+class QPointF;
+class QRectF;
+class QTransform;
+
+namespace DesignTools {
+
+class Keyframe;
+
+double clamp(double val, double lo, double hi);
+
+double lerp(double blend, double a, double b);
+
+double scaleX(const QTransform &transform);
+
+double scaleY(const QTransform &transform);
+
+void grow(QRectF &rect, const QPointF &point);
+
+QRectF bbox(const QRectF &rect, const QTransform &transform);
+
+} // End namespace DesignTools.