summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/curveeditorapp/curveeditorapp.pro5
-rw-r--r--examples/curveeditorapp/examplecurvemodel.cpp94
-rw-r--r--examples/curveeditorapp/examplecurvemodel.h12
-rw-r--r--examples/curveeditorapp/mainwindow.cpp7
-rw-r--r--resources/curveeditor.qrc14
-rw-r--r--resources/instance.pngbin0 -> 1182 bytes
-rw-r--r--resources/locked.pngbin0 -> 1049 bytes
-rw-r--r--resources/material.pngbin0 -> 1404 bytes
-rw-r--r--resources/pinned.pngbin0 -> 916 bytes
-rw-r--r--resources/unlocked.pngbin0 -> 1049 bytes
-rw-r--r--resources/unpinned.pngbin0 -> 916 bytes
-rw-r--r--src/curveeditor/animationcurve.cpp175
-rw-r--r--src/curveeditor/animationcurve.h64
-rw-r--r--src/curveeditor/curveeditor.cpp25
-rw-r--r--src/curveeditor/curveeditor.h13
-rw-r--r--src/curveeditor/curveeditor.pri47
-rw-r--r--src/curveeditor/curveeditormodel.cpp106
-rw-r--r--src/curveeditor/curveeditormodel.h59
-rw-r--r--src/curveeditor/curveeditorstyle.h22
-rw-r--r--src/curveeditor/detail/colorcontrol.cpp (renamed from src/curveeditor/colorcontrol.cpp)0
-rw-r--r--src/curveeditor/detail/colorcontrol.h (renamed from src/curveeditor/colorcontrol.h)0
-rw-r--r--src/curveeditor/detail/curveeditorstyledialog.cpp (renamed from src/curveeditor/curveeditorstyledialog.cpp)3
-rw-r--r--src/curveeditor/detail/curveeditorstyledialog.h (renamed from src/curveeditor/curveeditorstyledialog.h)0
-rw-r--r--src/curveeditor/detail/curveitem.cpp (renamed from src/curveeditor/curveitem.cpp)135
-rw-r--r--src/curveeditor/detail/curveitem.h (renamed from src/curveeditor/curveitem.h)36
-rw-r--r--src/curveeditor/detail/curvesegment.cpp280
-rw-r--r--src/curveeditor/detail/curvesegment.h63
-rw-r--r--src/curveeditor/detail/graphicsscene.cpp141
-rw-r--r--src/curveeditor/detail/graphicsscene.h72
-rw-r--r--src/curveeditor/detail/graphicsview.cpp (renamed from src/curveeditor/curveeditorview.cpp)93
-rw-r--r--src/curveeditor/detail/graphicsview.h (renamed from src/curveeditor/curveeditorview.h)11
-rw-r--r--src/curveeditor/detail/handleitem.cpp (renamed from src/curveeditor/handleitem.cpp)4
-rw-r--r--src/curveeditor/detail/handleitem.h (renamed from src/curveeditor/handleitem.h)0
-rw-r--r--src/curveeditor/detail/keyframeitem.cpp (renamed from src/curveeditor/keyframeitem.cpp)0
-rw-r--r--src/curveeditor/detail/keyframeitem.h (renamed from src/curveeditor/keyframeitem.h)2
-rw-r--r--src/curveeditor/detail/treeitem.cpp188
-rw-r--r--src/curveeditor/detail/treeitem.h102
-rw-r--r--src/curveeditor/detail/treeitemdelegate.cpp146
-rw-r--r--src/curveeditor/detail/treeitemdelegate.h63
-rw-r--r--src/curveeditor/detail/treemodel.cpp142
-rw-r--r--src/curveeditor/detail/treemodel.h68
-rw-r--r--src/curveeditor/detail/treeview.cpp127
-rw-r--r--src/curveeditor/detail/treeview.h61
-rw-r--r--src/curveeditor/detail/utils.cpp (renamed from src/curveeditor/utils.cpp)29
-rw-r--r--src/curveeditor/detail/utils.h (renamed from src/curveeditor/utils.h)4
-rw-r--r--src/curveeditor/keyframe.cpp88
-rw-r--r--src/curveeditor/keyframe.h65
47 files changed, 2283 insertions, 283 deletions
diff --git a/examples/curveeditorapp/curveeditorapp.pro b/examples/curveeditorapp/curveeditorapp.pro
index 2602ffd..3f44741 100644
--- a/examples/curveeditorapp/curveeditorapp.pro
+++ b/examples/curveeditorapp/curveeditorapp.pro
@@ -10,11 +10,14 @@ DEFINES += QT_DEPRECATED_WARNINGS
INCLUDEPATH += .
+RESOURCES = $$PWD/../../resources/curveeditor.qrc
+
include($$PWD/../../sharedcomponents.pri)
# Input
HEADERS += \
- mainwindow.h
+ mainwindow.h \
+ examplecurvemodel.h
SOURCES += \
main.cpp \
diff --git a/examples/curveeditorapp/examplecurvemodel.cpp b/examples/curveeditorapp/examplecurvemodel.cpp
index a20740b..751ae1c 100644
--- a/examples/curveeditorapp/examplecurvemodel.cpp
+++ b/examples/curveeditorapp/examplecurvemodel.cpp
@@ -24,9 +24,18 @@
****************************************************************************/
#include "examplecurvemodel.h"
#include "animationcurve.h"
+#include "curveeditorstyle.h"
+
+#include <QDebug>
namespace DesignTools {
+ExampleCurveModel::ExampleCurveModel()
+ : CurveEditorModel()
+{
+ connect(this, &CurveEditorModel::curveChanged, this, &ExampleCurveModel::curveChangeEmitted);
+}
+
double ExampleCurveModel::minimumTime() const
{
return 0.0;
@@ -37,64 +46,75 @@ double ExampleCurveModel::maximumTime() const
return 500.0;
}
-double ExampleCurveModel::minimumValue() const
-{
- return -1.0;
-}
-
-double ExampleCurveModel::maximumValue() const
-{
- return 1.0;
-}
-
-AnimationCurve ExampleCurveModel::curve(int i) const
-{
- 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(5, 0, 100));
+ out.backgroundBrush = QBrush(QColor(55, 55, 55));
out.backgroundAlternateBrush = QBrush(QColor(0, 0, 50));
- out.fontColor = QColor(200, 200, 200);
- out.gridColor = QColor(128, 128, 128);
+ out.fontColor = QColor(255, 255, 255);
+ out.gridColor = QColor(114, 116, 118);
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.rangeBarColor = QColor(46, 47, 48);
out.rangeBarCapsColor = QColor(50, 50, 255);
out.valueAxisWidth = 60;
out.valueOffsetTop = 10;
out.valueOffsetBottom = 10;
- out.playheadColor = QColor(200, 200, 0);
+ out.playheadColor = QColor(255, 255, 0);
out.handleStyle.size = 12;
out.handleStyle.lineWidth = 1;
- out.handleStyle.color = QColor(200, 0, 0);
- out.handleStyle.selectionColor = QColor(200, 200, 200);
+ out.handleStyle.color = QColor(255, 255, 255);
+ out.handleStyle.selectionColor = QColor(255, 255, 255);
out.keyframeStyle.size = 13;
- out.keyframeStyle.color = QColor(240, 255, 0);
- out.keyframeStyle.selectionColor = QColor(200, 200, 200);
+ out.keyframeStyle.color = QColor(172, 210, 255);
+ out.keyframeStyle.selectionColor = QColor(255, 255, 255);
out.curveStyle.width = 1;
out.curveStyle.color = QColor(0, 200, 0);
- out.curveStyle.selectionColor = QColor(200, 200, 200);
+ out.curveStyle.selectionColor = QColor(255, 255, 255);
return out;
}
+void ExampleCurveModel::createItems()
+{
+ AnimationCurve curve1({
+ Keyframe(QPointF(0.0, -1.0), QPointF(), QPointF(100.0, -1.0)),
+ Keyframe(QPointF(150.0, 0.7), QPointF(50.0, 0.7), QPointF(250.0, 0.7)),
+ Keyframe(QPointF(500.0, 1.0), QPointF(400.0, 1.0), QPointF())});
+
+ AnimationCurve curve2({
+ Keyframe(QPointF(0.0, -1.0), QPointF(), QPointF(100.0, -1.0)),
+ Keyframe(QPointF(200.0, 0.4), QPointF(100.0, 0.4), QPointF(300.0, 0.4)),
+ Keyframe(QPointF(500.0, 1.0), QPointF(400.0, 1.0), QPointF())});
+
+ AnimationCurve curve3({
+ 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())});
+
+ AnimationCurve curve4({
+ Keyframe(QPointF(0.0, -1.0), QPointF(), QPointF(100.0, -1.0)),
+ Keyframe(QPointF(300.0, -0.4), QPointF(200.0, -0.4), QPointF(400.0, -0.4)),
+ Keyframe(QPointF(500.0, 1.0), QPointF(400.0, 1.0), QPointF())});
+
+ auto *instance = new NodeTreeItem("Instance", QIcon(":/ICON_INSTANCE"));
+ instance->addChild(new PropertyTreeItem("Position X", curve1));
+ instance->addChild(new PropertyTreeItem("Position Y", curve2));
+
+ auto *material = new NodeTreeItem("Material", QIcon(":/ICON_MATERIAL"));
+ material->addChild(new PropertyTreeItem("Opacity", curve3));
+ material->addChild(new PropertyTreeItem("Color R", curve4));
+
+ reset({instance, material});
+}
+
+void ExampleCurveModel::curveChangeEmitted(PropertyTreeItem *item)
+{
+ qDebug() << "The Curve with the id " << item->id() << " has changed";
+}
+
} // End namespace DesignTools.
diff --git a/examples/curveeditorapp/examplecurvemodel.h b/examples/curveeditorapp/examplecurvemodel.h
index 7f0433e..815af5e 100644
--- a/examples/curveeditorapp/examplecurvemodel.h
+++ b/examples/curveeditorapp/examplecurvemodel.h
@@ -31,18 +31,20 @@ namespace DesignTools {
class ExampleCurveModel : public CurveEditorModel
{
+ Q_OBJECT
+
public:
+ ExampleCurveModel();
+
double minimumTime() const override;
double maximumTime() const override;
- double minimumValue() const override;
-
- double maximumValue() const override;
+ CurveEditorStyle style() const override;
- AnimationCurve curve(int i) const override;
+ void createItems();
- CurveEditorStyle style() const override;
+ void curveChangeEmitted(PropertyTreeItem *item);
};
} // End namespace DesignTools.
diff --git a/examples/curveeditorapp/mainwindow.cpp b/examples/curveeditorapp/mainwindow.cpp
index 7138b4e..6fbcd67 100644
--- a/examples/curveeditorapp/mainwindow.cpp
+++ b/examples/curveeditorapp/mainwindow.cpp
@@ -24,7 +24,6 @@
****************************************************************************/
#include "mainwindow.h"
#include "curveeditor.h"
-#include "curveeditorview.h"
#include "examplecurvemodel.h"
#include <QHBoxLayout>
@@ -58,8 +57,8 @@ MainWindow::MainWindow()
auto *model = new ExampleCurveModel;
auto *editor = new CurveEditor(model);
- auto zoomX = [editor](int val) { editor->view()->zoomX(static_cast<double>(val) / 1000.); };
- auto zoomY = [editor](int val) { editor->view()->zoomY(static_cast<double>(val) / 1000.); };
+ auto zoomX = [editor](int val) { editor->zoomX(static_cast<double>(val) / 1000.); };
+ auto zoomY = [editor](int val) { editor->zoomY(static_cast<double>(val) / 1000.); };
auto *box = new QVBoxLayout;
box->addWidget(editor);
@@ -71,6 +70,8 @@ MainWindow::MainWindow()
setCentralWidget(centralWidget);
resize(QSize(1070, 739));
+
+ model->createItems();
}
} // End namespace DesignTools.
diff --git a/resources/curveeditor.qrc b/resources/curveeditor.qrc
new file mode 100644
index 0000000..9dfc5d7
--- /dev/null
+++ b/resources/curveeditor.qrc
@@ -0,0 +1,14 @@
+ <!DOCTYPE RCC><RCC version="1.0">
+ <qresource>
+
+ <file alias = "ICON_MATERIAL" >material.png</file>
+ <file alias = "ICON_INSTANCE" >instance.png</file>
+
+ <file alias = "ICON_LOCKED" >locked.png</file>
+ <file alias = "ICON_UNLOCKED" >unlocked.png</file>
+
+ <file alias = "ICON_PINNED" >pinned.png</file>
+ <file alias = "ICON_UNPINNED" >unpinned.png</file>
+
+ </qresource>
+ </RCC>
diff --git a/resources/instance.png b/resources/instance.png
new file mode 100644
index 0000000..4f3d80a
--- /dev/null
+++ b/resources/instance.png
Binary files differ
diff --git a/resources/locked.png b/resources/locked.png
new file mode 100644
index 0000000..1e8d129
--- /dev/null
+++ b/resources/locked.png
Binary files differ
diff --git a/resources/material.png b/resources/material.png
new file mode 100644
index 0000000..22524e8
--- /dev/null
+++ b/resources/material.png
Binary files differ
diff --git a/resources/pinned.png b/resources/pinned.png
new file mode 100644
index 0000000..8f70e76
--- /dev/null
+++ b/resources/pinned.png
Binary files differ
diff --git a/resources/unlocked.png b/resources/unlocked.png
new file mode 100644
index 0000000..1e8d129
--- /dev/null
+++ b/resources/unlocked.png
Binary files differ
diff --git a/resources/unpinned.png b/resources/unpinned.png
new file mode 100644
index 0000000..8f70e76
--- /dev/null
+++ b/resources/unpinned.png
Binary files differ
diff --git a/src/curveeditor/animationcurve.cpp b/src/curveeditor/animationcurve.cpp
index 4818a81..acb64ce 100644
--- a/src/curveeditor/animationcurve.cpp
+++ b/src/curveeditor/animationcurve.cpp
@@ -24,120 +24,155 @@
****************************************************************************/
#include "animationcurve.h"
+#include "detail/curvesegment.h"
-#include <assert.h>
-#include <cmath>
+#include <QLineF>
namespace DesignTools {
-Keyframe::Keyframe()
- : m_position()
- , m_leftHandle()
- , m_rightHandle()
+AnimationCurve::AnimationCurve()
+ : m_frames()
{}
-Keyframe::Keyframe(const QPointF &position)
- : m_position(position)
- , m_leftHandle()
- , m_rightHandle()
-{}
+AnimationCurve::AnimationCurve(const std::vector<Keyframe> &frames)
+ : m_frames(frames)
+ , m_minY(std::numeric_limits<double>::max())
+ , m_maxY(std::numeric_limits<double>::lowest())
+{
+ if (m_frames.size() >= 2) {
+ for (auto e : extrema()) {
-Keyframe::Keyframe(const QPointF &position, const QPointF &leftHandle, const QPointF &rightHandle)
- : m_position(position)
- , m_leftHandle(leftHandle)
- , m_rightHandle(rightHandle)
-{}
+ if (m_minY > e.y())
+ m_minY = e.y();
-bool Keyframe::hasLeftHandle() const
-{
- return !m_leftHandle.isNull();
+ if (m_maxY < e.y())
+ m_maxY = e.y();
+ }
+ }
}
-bool Keyframe::hasRightHandle() const
+bool AnimationCurve::isValid() const
{
- return !m_rightHandle.isNull();
+ return !m_frames.empty();
}
-QPointF Keyframe::position() const
+double AnimationCurve::minimumTime() const
{
- return m_position;
+ if (!m_frames.empty())
+ return m_frames.front().position().x();
+
+ return std::numeric_limits<double>::max();
}
-QPointF Keyframe::leftHandle() const
+double AnimationCurve::maximumTime() const
{
- return m_leftHandle;
+ if (!m_frames.empty())
+ return m_frames.back().position().x();
+
+ return std::numeric_limits<double>::lowest();
}
-QPointF Keyframe::rightHandle() const
+double AnimationCurve::minimumValue() const
{
- return m_rightHandle;
+ return m_minY;
}
-void Keyframe::setPosition(const QPointF &pos)
+double AnimationCurve::maximumValue() const
{
- m_position = pos;
+ return m_maxY;
}
-void Keyframe::setLeftHandle(const QPointF &pos)
+std::vector<Keyframe> AnimationCurve::keyframes() const
{
- m_leftHandle = pos;
+ return m_frames;
}
-void Keyframe::setRightHandle(const QPointF &pos)
+std::vector<QPointF> AnimationCurve::extrema() const
{
- m_rightHandle = pos;
-}
+ std::vector<QPointF> out;
+ CurveSegment segment;
+ segment.setLeft(m_frames.at(0));
-CurveSegment::CurveSegment()
- : m_left()
- , m_right()
-{}
+ for (size_t i = 1; i < m_frames.size(); ++i) {
-CurveSegment::CurveSegment(const Keyframe &left, const Keyframe &right)
- : m_left(left)
- , m_right(right)
-{}
+ segment.setRight(m_frames[i]);
+
+ const auto es = segment.extrema();
+ out.insert(std::end(out), std::begin(es), std::end(es));
+
+ segment.setLeft(m_frames[i]);
+ }
+
+ return out;
+}
-QPointF CurveSegment::evaluate(double t) const
+std::vector<double> AnimationCurve::yForX(double x) const
{
- assert(t >= 0. && t <= 1.);
+ if (m_frames.front().position().x() > x)
+ return std::vector<double>();
+
+ CurveSegment segment;
+ for (auto &frame : m_frames) {
+ if (frame.position().x() > x) {
+ segment.setRight(frame);
+ return segment.yForX(x);
+ }
+ segment.setLeft(frame);
+ }
+ return std::vector<double>();
+}
- const double it = 1.0 - t;
+std::vector<double> AnimationCurve::xForY(double y, uint segment) const
+{
+ if (m_frames.size() > segment + 1) {
+ CurveSegment seg(m_frames[segment], m_frames[segment + 1]);
+ return seg.xForY(y);
+ }
+ return std::vector<double>();
+}
- 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);
- };
+bool AnimationCurve::intersects(const QPointF &coord, double radius)
+{
+ if (m_frames.size() < 2)
+ return false;
- const double x = binomialPolynomial(
- m_left.position().x(), m_left.rightHandle().x(),
- m_right.leftHandle().x(), m_right.position().x());
+ std::vector<CurveSegment> influencer;
- const double y = binomialPolynomial(
- m_left.position().y(), m_left.rightHandle().y(),
- m_right.leftHandle().y(), m_right.position().y());
+ CurveSegment current;
+ current.setLeft(m_frames.at(0));
- return QPointF(x, y);
-}
+ for (size_t i = 1; i < m_frames.size(); ++i) {
+ Keyframe &frame = m_frames.at(i);
+ current.setRight(frame);
-AnimationCurve::AnimationCurve()
- : m_frames()
-{}
+ if (current.containsX(coord.x() - radius) ||
+ current.containsX(coord.x()) ||
+ current.containsX(coord.x() + radius)) {
+ influencer.push_back(current);
+ }
-AnimationCurve::AnimationCurve(const std::vector<Keyframe> &frames)
- : m_frames(frames)
-{}
+ if (frame.position().x() > coord.x() + radius)
+ break;
-bool AnimationCurve::isValid() const
-{
- return !m_frames.empty();
-}
+ current.setLeft(frame);
+ }
-std::vector<Keyframe> AnimationCurve::keyframes() const
-{
- return m_frames;
+ for (auto &segment : influencer) {
+ for (auto &y : segment.yForX(coord.x())) {
+ QLineF line(coord.x(), y, coord.x(), coord.y());
+ if (line.length() < radius)
+ return true;
+ }
+
+ for (auto &x : segment.xForY(coord.y())) {
+ QLineF line(x, coord.y(), coord.x(), coord.y());
+ if (line.length() < radius)
+ return true;
+ }
+ }
+ return false;
}
} // End namespace DesignTools.
diff --git a/src/curveeditor/animationcurve.h b/src/curveeditor/animationcurve.h
index 7b42e07..0533e47 100644
--- a/src/curveeditor/animationcurve.h
+++ b/src/curveeditor/animationcurve.h
@@ -25,75 +25,45 @@
#pragma once
-#include <QPointF>
+#include "keyframe.h"
#include <vector>
namespace DesignTools {
-class Keyframe
+class AnimationCurve
{
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;
+ AnimationCurve();
- QPointF rightHandle() const;
+ AnimationCurve(const std::vector<Keyframe> &frames);
- void setPosition(const QPointF &pos);
+ bool isValid() const;
- void setLeftHandle(const QPointF &pos);
+ double minimumTime() const;
- void setRightHandle(const QPointF &pos);
+ double maximumTime() const;
-private:
- QPointF m_position = QPointF();
+ double minimumValue() const;
- QPointF m_leftHandle = QPointF();
+ double maximumValue() const;
- QPointF m_rightHandle = QPointF();
-};
+ std::vector<Keyframe> keyframes() const;
+ std::vector<QPointF> extrema() const;
-class CurveSegment
-{
-public:
- CurveSegment();
+ std::vector<double> yForX(double x) const;
- CurveSegment(const Keyframe &first, const Keyframe &last);
+ std::vector<double> xForY(double y, uint segment) const;
- QPointF evaluate(double t) const;
+ bool intersects(const QPointF &coord, double radius);
private:
- Keyframe m_left;
-
- Keyframe m_right;
-};
-
-
-class AnimationCurve
-{
-public:
- AnimationCurve();
-
- AnimationCurve(const std::vector<Keyframe> &frames);
+ std::vector<Keyframe> m_frames;
- bool isValid() const;
+ double m_minY;
- std::vector<Keyframe> keyframes() const;
-
-private:
- std::vector<Keyframe> m_frames;
+ double m_maxY;
};
} // End namespace DesignTools.
diff --git a/src/curveeditor/curveeditor.cpp b/src/curveeditor/curveeditor.cpp
index b72f905..8501041 100644
--- a/src/curveeditor/curveeditor.cpp
+++ b/src/curveeditor/curveeditor.cpp
@@ -22,36 +22,43 @@
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
+
#include "curveeditor.h"
#include "curveeditormodel.h"
-#include "curveeditorview.h"
+#include "detail/curveitem.h"
+#include "detail/graphicsview.h"
+#include "detail/treeview.h"
#include <QHBoxLayout>
#include <QSplitter>
-#include <QTreeView>
namespace DesignTools {
CurveEditor::CurveEditor(CurveEditorModel *model, QWidget *parent)
: QWidget(parent)
- , m_tree(new QTreeView)
- , m_view(new CurveEditorView(model))
+ , m_tree(new TreeView(model, this))
+ , m_view(new GraphicsView(model))
{
- m_tree->setFixedWidth(100);
-
QSplitter *splitter = new QSplitter;
splitter->addWidget(m_tree);
splitter->addWidget(m_view);
- splitter->setSizes({5, 80});
+ splitter->setStretchFactor(1, 2);
QHBoxLayout *box = new QHBoxLayout;
box->addWidget(splitter);
setLayout(box);
+
+ connect(m_tree, &TreeView::curvesSelected, m_view, &GraphicsView::reset);
+}
+
+void CurveEditor::zoomX(double zoom)
+{
+ m_view->zoomX(zoom);
}
-CurveEditorView *CurveEditor::view() const
+void CurveEditor::zoomY(double zoom)
{
- return m_view;
+ m_view->zoomY(zoom);
}
} // End namespace DesignTools.
diff --git a/src/curveeditor/curveeditor.h b/src/curveeditor/curveeditor.h
index f5e1af8..a2c5873 100644
--- a/src/curveeditor/curveeditor.h
+++ b/src/curveeditor/curveeditor.h
@@ -27,12 +27,11 @@
#include <QWidget>
-class QTreeView;
-
namespace DesignTools {
class CurveEditorModel;
-class CurveEditorView;
+class GraphicsView;
+class TreeView;
class CurveEditor : public QWidget
{
@@ -41,12 +40,14 @@ class CurveEditor : public QWidget
public:
CurveEditor(CurveEditorModel *model, QWidget *parent = nullptr);
- CurveEditorView *view() const;
+ void zoomX(double zoom);
+
+ void zoomY(double zoom);
private:
- QTreeView *m_tree;
+ TreeView *m_tree;
- CurveEditorView *m_view;
+ GraphicsView *m_view;
};
} // End namespace DesignTools.
diff --git a/src/curveeditor/curveeditor.pri b/src/curveeditor/curveeditor.pri
index 861abd8..6b325e3 100644
--- a/src/curveeditor/curveeditor.pri
+++ b/src/curveeditor/curveeditor.pri
@@ -1,23 +1,38 @@
INCLUDEPATH += $$PWD
-### include required files
-HEADERS += \
+HEADERS += \
$$PWD/animationcurve.h \
$$PWD/curveeditor.h \
- $$PWD/curveeditorstyledialog.h \
- $$PWD/curveeditorview.h \
- $$PWD/curveitem.h \
- $$PWD/colorcontrol.h \
- $$PWD/handleitem.h \
- $$PWD/keyframeitem.h
+ $$PWD/curveeditormodel.h \
+ $$PWD/keyframe.h \
+ $$PWD/detail/colorcontrol.h \
+ $$PWD/detail/curveeditorstyledialog.h \
+ $$PWD/detail/curveitem.h \
+ $$PWD/detail/curvesegment.h \
+ $$PWD/detail/graphicsscene.h \
+ $$PWD/detail/graphicsview.h \
+ $$PWD/detail/handleitem.h \
+ $$PWD/detail/keyframeitem.h \
+ $$PWD/detail/treeitem.h \
+ $$PWD/detail/treeitemdelegate.h \
+ $$PWD/detail/treemodel.h \
+ $$PWD/detail/treeview.h
-SOURCES += \
+SOURCES += \
$$PWD/animationcurve.cpp \
$$PWD/curveeditor.cpp \
- $$PWD/curveeditorstyledialog.cpp \
- $$PWD/curveeditorview.cpp \
- $$PWD/curveitem.cpp \
- $$PWD/colorcontrol.cpp \
- $$PWD/handleitem.cpp \
- $$PWD/keyframeitem.cpp \
- $$PWD/utils.cpp
+ $$PWD/curveeditormodel.cpp \
+ $$PWD/keyframe.cpp \
+ $$PWD/detail/colorcontrol.cpp \
+ $$PWD/detail/curveeditorstyledialog.cpp \
+ $$PWD/detail/curveitem.cpp \
+ $$PWD/detail/curvesegment.cpp \
+ $$PWD/detail/graphicsscene.cpp \
+ $$PWD/detail/graphicsview.cpp \
+ $$PWD/detail/handleitem.cpp \
+ $$PWD/detail/keyframeitem.cpp \
+ $$PWD/detail/treeitem.cpp \
+ $$PWD/detail/treeitemdelegate.cpp \
+ $$PWD/detail/treemodel.cpp \
+ $$PWD/detail/treeview.cpp \
+ $$PWD/detail/utils.cpp
diff --git a/src/curveeditor/curveeditormodel.cpp b/src/curveeditor/curveeditormodel.cpp
new file mode 100644
index 0000000..31d4d6b
--- /dev/null
+++ b/src/curveeditor/curveeditormodel.cpp
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** 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 "curveeditormodel.h"
+
+namespace DesignTools {
+
+CurveEditorModel::CurveEditorModel(QObject *parent)
+ : TreeModel(parent)
+{}
+
+CurveEditorModel::~CurveEditorModel() {}
+
+void CurveEditorModel::setCurrentTime(uint frame)
+{
+ Q_UNUSED(frame);
+ printf("CurveEditorModel::setCurrentTime unimplememted!\n");
+}
+
+void CurveEditorModel::setCurve(unsigned int id, const AnimationCurve &curve)
+{
+ if (TreeItem *item = find(id)) {
+ if (PropertyTreeItem *propertyItem = item->asPropertyItem()) {
+ propertyItem->setCurve(curve);
+ emit curveChanged(propertyItem);
+ }
+ }
+}
+
+void CurveEditorModel::reset(const std::vector<TreeItem *> &items)
+{
+ beginResetModel();
+
+ initialize();
+
+ unsigned int counter = 0;
+ for (auto *item : items) {
+ item->setId(++counter);
+ root()->addChild(item);
+ }
+
+ endResetModel();
+}
+
+
+NodeTreeItem::NodeTreeItem(const QString &name, const QIcon &icon)
+ : TreeItem(name)
+ , m_icon(icon)
+{
+ Q_UNUSED(icon);
+}
+
+NodeTreeItem *NodeTreeItem::asNodeItem()
+{
+ return this;
+}
+
+QIcon NodeTreeItem::icon() const
+{
+ return m_icon;
+}
+
+
+PropertyTreeItem::PropertyTreeItem(const QString &name, const AnimationCurve &curve)
+ : TreeItem(name)
+ , m_curve(curve)
+{}
+
+PropertyTreeItem *PropertyTreeItem::asPropertyItem()
+{
+ return this;
+}
+
+AnimationCurve PropertyTreeItem::curve() const
+{
+ return m_curve;
+}
+
+void PropertyTreeItem::setCurve(const AnimationCurve &curve)
+{
+ m_curve = curve;
+}
+
+} // End namespace DesignTools.
diff --git a/src/curveeditor/curveeditormodel.h b/src/curveeditor/curveeditormodel.h
index 351aa73..5c0bb4e 100644
--- a/src/curveeditor/curveeditormodel.h
+++ b/src/curveeditor/curveeditormodel.h
@@ -25,7 +25,10 @@
#pragma once
-#include "curveeditorstyle.h"
+#include "detail/treeitem.h"
+#include "detail/treemodel.h"
+
+#include <QIcon>
#include <vector>
@@ -33,22 +36,66 @@ class QPointF;
namespace DesignTools {
+struct CurveEditorStyle;
+
class AnimationCurve;
-class CurveEditorModel
+class CurveEditorModel : public TreeModel
{
+ Q_OBJECT
+
+signals:
+ void curveChanged(PropertyTreeItem *item);
+
public:
virtual double minimumTime() const = 0;
virtual double maximumTime() const = 0;
- virtual double minimumValue() const = 0;
+ virtual CurveEditorStyle style() const = 0;
+
+public:
+ CurveEditorModel(QObject *parent = nullptr);
+
+ ~CurveEditorModel() override;
+
+ void setCurrentTime(uint frame);
+
+ void setCurve(unsigned int id, const AnimationCurve &curve);
+
+ void reset(const std::vector<TreeItem *> &items);
+};
+
+
+class NodeTreeItem : public TreeItem
+{
+public:
+ NodeTreeItem(const QString &name, const QIcon &icon);
+
+ NodeTreeItem *asNodeItem() override;
+
+ QIcon icon() const override;
+
+private:
+ QIcon m_icon;
+};
+
+
+class PropertyTreeItem : public TreeItem
+{
+public:
+ PropertyTreeItem(const QString &name, const AnimationCurve &curve);
+
+ PropertyTreeItem *asPropertyItem() override;
+
+ AnimationCurve curve() const;
- virtual double maximumValue() const = 0;
+ void setCurve(const AnimationCurve &curve);
- virtual AnimationCurve curve(int i) const = 0;
+private:
+ using TreeItem::addChild;
- virtual CurveEditorStyle style() const { return CurveEditorStyle(); }
+ AnimationCurve m_curve;
};
} // End namespace DesignTools.
diff --git a/src/curveeditor/curveeditorstyle.h b/src/curveeditor/curveeditorstyle.h
index 23fdaf8..f60948a 100644
--- a/src/curveeditor/curveeditorstyle.h
+++ b/src/curveeditor/curveeditorstyle.h
@@ -25,12 +25,23 @@
#pragma once
+#include <QBitmap>
#include <QBrush>
#include <QColor>
#include <QDialog>
+#include <QIcon>
namespace DesignTools {
+struct TreeItemStyleOption
+{
+ double margins;
+ QIcon pinnedIcon = QIcon(":/ICON_PINNED");
+ QIcon unpinnedIcon = QIcon(":/ICON_UNPINNED");
+ QIcon lockedIcon = QIcon(":/ICON_LOCKED");
+ QIcon unlockedIcon = QIcon(":/ICON_UNLOCKED");
+};
+
struct HandleItemStyleOption
{
double size = 10.0;
@@ -92,6 +103,17 @@ struct CurveEditorStyle
KeyframeItemStyleOption keyframeStyle;
CurveItemStyleOption curveStyle;
+
+ TreeItemStyleOption treeItemStyle;
};
+inline QPixmap pixmapFromIcon(const QIcon &icon, const QSize &size, const QColor &color)
+{
+ QPixmap pixmap = icon.pixmap(size);
+ QPixmap mask(pixmap.size());
+ mask.fill(color);
+ mask.setMask(pixmap.createMaskFromColor(Qt::transparent));
+ return mask;
+}
+
} // End namespace DesignTools.
diff --git a/src/curveeditor/colorcontrol.cpp b/src/curveeditor/detail/colorcontrol.cpp
index a833a4c..a833a4c 100644
--- a/src/curveeditor/colorcontrol.cpp
+++ b/src/curveeditor/detail/colorcontrol.cpp
diff --git a/src/curveeditor/colorcontrol.h b/src/curveeditor/detail/colorcontrol.h
index 54dfe19..54dfe19 100644
--- a/src/curveeditor/colorcontrol.h
+++ b/src/curveeditor/detail/colorcontrol.h
diff --git a/src/curveeditor/curveeditorstyledialog.cpp b/src/curveeditor/detail/curveeditorstyledialog.cpp
index 2629f24..fc34737 100644
--- a/src/curveeditor/curveeditorstyledialog.cpp
+++ b/src/curveeditor/detail/curveeditorstyledialog.cpp
@@ -199,7 +199,8 @@ void CurveEditorStyleDialog::emitStyleChanged()
void CurveEditorStyleDialog::printStyle()
{
auto toString = [](const QColor &color) {
- QString tmp = QString("QColor(%1, %2, %3)").arg(color.red()).arg(color.green()).arg(color.blue());
+ QString tmp
+ = QString("QColor(%1, %2, %3)").arg(color.red()).arg(color.green()).arg(color.blue());
return qPrintable(tmp);
};
diff --git a/src/curveeditor/curveeditorstyledialog.h b/src/curveeditor/detail/curveeditorstyledialog.h
index 645f545..645f545 100644
--- a/src/curveeditor/curveeditorstyledialog.h
+++ b/src/curveeditor/detail/curveeditorstyledialog.h
diff --git a/src/curveeditor/curveitem.cpp b/src/curveeditor/detail/curveitem.cpp
index 128b60e..2d8e462 100644
--- a/src/curveeditor/curveitem.cpp
+++ b/src/curveeditor/detail/curveitem.cpp
@@ -23,6 +23,7 @@
**
****************************************************************************/
#include "curveitem.h"
+#include "animationcurve.h"
#include "keyframeitem.h"
#include "utils.h"
@@ -33,18 +34,33 @@ namespace DesignTools {
CurveItem::CurveItem(QGraphicsItem *parent)
: QGraphicsObject(parent)
+ , m_id(0)
+ , m_style()
, m_transform()
, m_keyframes()
+ , m_selected(false)
+ , m_preselected(false)
+ , m_itemDirty(true)
+ , m_pathDirty(true)
{}
-CurveItem::CurveItem(const AnimationCurve &curve, QGraphicsItem *parent)
+CurveItem::CurveItem(unsigned int id, const AnimationCurve &curve, QGraphicsItem *parent)
: QGraphicsObject(parent)
+ , m_id(id)
+ , m_style()
, m_transform()
, m_keyframes()
+ , m_selected(false)
+ , m_preselected(false)
+ , m_itemDirty(true)
+ , m_pathDirty(true)
{
+ setAcceptHoverEvents(true);
+
auto emitCurveChanged = [this]() {
+ m_itemDirty = true;
+ m_pathDirty = true;
update();
- emit curveChanged(this->curve());
};
for (auto frame : curve.keyframes()) {
@@ -63,65 +79,81 @@ int CurveItem::type() const
QRectF CurveItem::boundingRect() const
{
- QRectF bounds;
-
- auto bbox = [&bounds](const Keyframe &frame) {
+ auto bbox = [](QRectF &bounds, const Keyframe &frame) {
grow(bounds, frame.position());
grow(bounds, frame.leftHandle());
grow(bounds, frame.rightHandle());
};
+ QRectF bounds;
for (auto *item : m_keyframes)
- bbox(item->keyframe());
+ bbox(bounds, item->keyframe());
return m_transform.mapRect(bounds);
}
-void CurveItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
+bool CurveItem::contains(const QPointF &point) const
{
- if (m_keyframes.size() > 1) {
- painter->save();
+ bool valid = false;
+ QPointF transformed(m_transform.inverted(&valid).map(point));
- QPen pen = painter->pen();
- pen.setWidthF(m_style.width);
- pen.setColor(isSelected() ? m_style.selectionColor : m_style.color);
- painter->setPen(pen);
+ double width = abs(20.0 / scaleY(m_transform));
- Keyframe previous = m_keyframes.front()->keyframe();
- Keyframe current;
- for (size_t i = 1; i < m_keyframes.size(); ++i) {
- current = m_keyframes[i]->keyframe();
+ if (valid)
+ return curve().intersects(transformed, width);
- QPainterPath path(m_transform.map(previous.position()));
+ return false;
+}
- 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()));
+void CurveItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
+{
+ if (m_keyframes.size() > 1) {
+ QPen pen = painter->pen();
+ pen.setWidthF(m_style.width);
+ pen.setColor(m_selected ? m_style.selectionColor : (m_preselected ? Qt::red : m_style.color));
- painter->drawPath(path);
+ painter->save();
+ painter->setPen(pen);
+ painter->drawPath(path());
- previous = current;
- }
+ // Tmp. Remove later.
+ painter->setPen(Qt::red);
+ for (auto p : curve().extrema())
+ painter->drawEllipse(m_transform.map(p), 6., 6.);
painter->restore();
}
}
+bool CurveItem::isDirty() const
+{
+ return m_itemDirty;
+}
+
+unsigned int CurveItem::id() const
+{
+ return m_id;
+}
+
AnimationCurve CurveItem::curve() const
{
std::vector<Keyframe> out;
- for (auto item : m_keyframes) {
+ out.reserve(m_keyframes.size());
+ for (auto item : m_keyframes)
out.push_back(item->keyframe());
- }
+
return out;
}
+void CurveItem::setDirty(bool dirty)
+{
+ m_itemDirty = dirty;
+}
+
QRectF CurveItem::setComponentTransform(const QTransform &transform)
{
+ m_pathDirty = true;
+
prepareGeometryChange();
m_transform = transform;
for (auto frame : m_keyframes)
@@ -138,4 +170,47 @@ void CurveItem::setStyle(const CurveEditorStyle &style)
frame->setStyle(style);
}
+QPainterPath CurveItem::path() const
+{
+ if (m_pathDirty) {
+ Keyframe previous = m_keyframes.front()->keyframe();
+ Keyframe current;
+
+ m_path = QPainterPath(m_transform.map(previous.position()));
+ for (size_t i = 1; i < m_keyframes.size(); ++i) {
+ current = m_keyframes[i]->keyframe();
+
+ if (previous.rightHandle().isNull() || current.leftHandle().isNull()) {
+ m_path.lineTo(m_transform.map(current.position()));
+ } else {
+ m_path.cubicTo(
+ m_transform.map(previous.rightHandle()),
+ m_transform.map(current.leftHandle()),
+ m_transform.map(current.position()));
+ }
+
+ previous = current;
+ }
+ m_pathDirty = false;
+ }
+
+ return m_path;
+}
+
+void CurveItem::setSelected(bool select)
+{
+ if (select != m_selected) {
+ m_selected = select;
+ update();
+ }
+}
+
+void CurveItem::setPreSelected(bool preSelect)
+{
+ if (preSelect != m_preselected) {
+ m_preselected = preSelect;
+ update();
+ }
+}
+
} // End namespace DesignTools.
diff --git a/src/curveeditor/curveitem.h b/src/curveeditor/detail/curveitem.h
index bae12e8..cf9b29f 100644
--- a/src/curveeditor/curveitem.h
+++ b/src/curveeditor/detail/curveitem.h
@@ -25,26 +25,23 @@
#pragma once
-#include "animationcurve.h"
#include "curveeditorstyle.h"
#include <QGraphicsObject>
namespace DesignTools {
+class AnimationCurve;
class KeyframeItem;
class CurveItem : public QGraphicsObject
{
Q_OBJECT
-signals:
- void curveChanged(const AnimationCurve &curve);
-
public:
CurveItem(QGraphicsItem *parent = nullptr);
- CurveItem(const AnimationCurve &curve, QGraphicsItem *parent = nullptr);
+ CurveItem(unsigned int id, const AnimationCurve &curve, QGraphicsItem *parent = nullptr);
~CurveItem() override;
@@ -54,22 +51,47 @@ public:
QRectF boundingRect() const override;
+ bool contains(const QPointF &point) const override;
+
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
+ bool isDirty() const;
+
+ unsigned int id() const;
+
AnimationCurve curve() const;
+ void setDirty(bool dirty);
+
QRectF setComponentTransform(const QTransform &transform);
void setStyle(const CurveEditorStyle &style);
+ void setSelected(bool select);
+
+ void setPreSelected(bool preSelect);
+
private:
- QTransform m_transform;
+ QPainterPath path() const;
+
+private:
+ unsigned int m_id;
CurveItemStyleOption m_style;
- AnimationCurve m_curve;
+ QTransform m_transform;
std::vector<KeyframeItem *> m_keyframes;
+
+ bool m_selected;
+
+ bool m_preselected;
+
+ bool m_itemDirty;
+
+ mutable bool m_pathDirty;
+
+ mutable QPainterPath m_path;
};
} // End namespace DesignTools.
diff --git a/src/curveeditor/detail/curvesegment.cpp b/src/curveeditor/detail/curvesegment.cpp
new file mode 100644
index 0000000..1bd0ad9
--- /dev/null
+++ b/src/curveeditor/detail/curvesegment.cpp
@@ -0,0 +1,280 @@
+/****************************************************************************
+**
+** 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 "curvesegment.h"
+
+#include <qmath.h>
+
+#include <assert.h>
+
+namespace DesignTools {
+
+class CubicPolynomial
+{
+public:
+ CubicPolynomial(double p0, double p1, double p2, double p3);
+
+ double evaluate(double x) const;
+
+ std::vector<double> extrema() const;
+
+ std::vector<double> roots() const;
+
+private:
+ double m_a;
+ double m_b;
+ double m_c;
+ double m_d;
+};
+
+CubicPolynomial::CubicPolynomial(double p0, double p1, double p2, double p3)
+ : m_a(p3 - 3.0 * p2 + 3.0 * p1 - p0)
+ , m_b(3.0 * p2 - 6.0 * p1 + 3.0 * p0)
+ , m_c(3.0 * p1 - 3.0 * p0)
+ , m_d(p0)
+{}
+
+std::vector<double> CubicPolynomial::extrema() const
+{
+ std::vector<double> out;
+
+ auto addValidValue = [&out](double value) {
+ if (!(std::isnan(value) || std::isinf(value)))
+ out.push_back(value);
+ };
+
+ // Find the roots of the first derivative of y.
+ auto pd2 = (2.0 * m_b) / (3.0 * m_a) / 2.0;
+ auto q = m_c / (3.0 * m_a);
+
+ auto radi = std::pow(pd2, 2.0) - q;
+
+ auto x1 = -pd2 + std::sqrt(radi);
+ auto x2 = -pd2 - std::sqrt(radi);
+
+ addValidValue(x1);
+ addValidValue(x2);
+
+ return out;
+}
+
+std::vector<double> CubicPolynomial::roots() const
+{
+ std::vector<double> out;
+
+ auto addValidValue = [&out](double value) {
+ if (!(std::isnan(value) || std::isinf(value)))
+ out.push_back(value);
+ };
+
+ if (m_a == 0.0) {
+ // Linear
+ if (m_b == 0.0) {
+ if (m_c != 0.0)
+ out.push_back(-m_d / m_c);
+ // Quadratic
+ } else {
+ const double p = m_c / m_b / 2.0;
+ const double q = m_d / m_b;
+ addValidValue(-p + std::sqrt(std::pow(p, 2.0) - q));
+ addValidValue(-p - std::sqrt(std::pow(p, 2.0) - q));
+ }
+ // Cubic
+ } else {
+ const double p = 3.0 * m_a * m_c - std::pow(m_b, 2.0);
+ const double q = 2.0 * std::pow(m_b, 3.0) - 9.0 * m_a * m_b * m_c
+ + 27.0 * std::pow(m_a, 2.0) * m_d;
+
+ auto disc = std::pow(q, 2.0) + 4.0 * std::pow(p, 3.0);
+
+ auto toX = [&](double y) { return (y - m_b) / (3.0 * m_a); };
+
+ // One real solution.
+ if (disc >= 0) {
+ auto u = (1.0 / 2.0)
+ * std::cbrt(-4.0 * q
+ + 4.0 * std::sqrt(std::pow(q, 2.0) + 4.0 * std::pow(p, 3.0)));
+ auto v = (1.0 / 2.0)
+ * std::cbrt(-4.0 * q
+ - 4.0 * std::sqrt(std::pow(q, 2.0) + 4.0 * std::pow(p, 3.0)));
+
+ addValidValue(toX(u + v));
+ // Three real solutions.
+ } else {
+ auto phi = acos(-q / (2 * std::sqrt(-std::pow(p, 3.0))));
+ auto y1 = std::sqrt(-p) * 2.0 * cos(phi / 3.0);
+ auto y2 = std::sqrt(-p) * 2.0 * cos((phi / 3.0) + (2.0 * M_PI / 3.0));
+ auto y3 = std::sqrt(-p) * 2.0 * cos((phi / 3.0) + (4.0 * M_PI / 3.0));
+
+ addValidValue(toX(y1));
+ addValidValue(toX(y2));
+ addValidValue(toX(y3));
+ }
+ }
+ return out;
+}
+
+CurveSegment::CurveSegment()
+ : m_left()
+ , m_right()
+{}
+
+CurveSegment::CurveSegment(const Keyframe &left, const Keyframe &right)
+ : m_left(left)
+ , m_right(right)
+{}
+
+bool CurveSegment::containsX(double x) const
+{
+ return m_left.position().x() <= x && m_right.position().x() >= x;
+}
+
+double evaluateForT(double t, double p0, double p1, double p2, double p3)
+{
+ assert(t >= 0. && t <= 1.);
+
+ const double it = 1.0 - t;
+
+ 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);
+}
+
+QPointF CurveSegment::evaluate(double t) const
+{
+ const double x = evaluateForT(
+ t,
+ m_left.position().x(),
+ m_left.rightHandle().x(),
+ m_right.leftHandle().x(),
+ m_right.position().x());
+
+ const double y = evaluateForT(
+ t,
+ m_left.position().y(),
+ m_left.rightHandle().y(),
+ m_right.leftHandle().y(),
+ m_right.position().y());
+
+ return QPointF(x, y);
+}
+
+std::vector<QPointF> CurveSegment::extrema() const
+{
+ std::vector<QPointF> out;
+
+ auto polynomial = CubicPolynomial(
+ m_left.position().y(),
+ m_left.rightHandle().y(),
+ m_right.leftHandle().y(),
+ m_right.position().y());
+
+ for (double t : polynomial.extrema()) {
+ if (t < 0.0 || t > 1.0)
+ continue;
+
+ const double x = evaluateForT(
+ t,
+ m_left.position().x(),
+ m_left.rightHandle().x(),
+ m_right.leftHandle().x(),
+ m_right.position().x());
+
+ const double y = evaluateForT(
+ t,
+ m_left.position().y(),
+ m_left.rightHandle().y(),
+ m_right.leftHandle().y(),
+ m_right.position().y());
+
+ out.push_back(QPointF(x, y));
+ }
+ return out;
+}
+
+std::vector<double> CurveSegment::yForX(double x) const
+{
+ std::vector<double> out;
+
+ auto polynomial = CubicPolynomial(
+ m_left.position().x() - x,
+ m_left.rightHandle().x() - x,
+ m_right.leftHandle().x() - x,
+ m_right.position().x() - x);
+
+ for (double t : polynomial.roots()) {
+ if (t < 0.0 || t > 1.0)
+ continue;
+
+ const double y = evaluateForT(
+ t,
+ m_left.position().y(),
+ m_left.rightHandle().y(),
+ m_right.leftHandle().y(),
+ m_right.position().y());
+
+ out.push_back(y);
+ }
+
+ return out;
+}
+
+std::vector<double> CurveSegment::xForY(double y) const
+{
+ std::vector<double> out;
+
+ auto polynomial = CubicPolynomial(
+ m_left.position().y() - y,
+ m_left.rightHandle().y() - y,
+ m_right.leftHandle().y() - y,
+ m_right.position().y() - y);
+
+ for (double t : polynomial.roots()) {
+ if (t < 0.0 || t > 1.0)
+ continue;
+
+ const double x = evaluateForT(
+ t,
+ m_left.position().x(),
+ m_left.rightHandle().x(),
+ m_right.leftHandle().x(),
+ m_right.position().x());
+
+ out.push_back(x);
+ }
+
+ return out;
+}
+
+void CurveSegment::setLeft(const Keyframe &frame)
+{
+ m_left = frame;
+}
+
+void CurveSegment::setRight(const Keyframe &frame)
+{
+ m_right = frame;
+}
+
+} // End namespace DesignTools.
diff --git a/src/curveeditor/detail/curvesegment.h b/src/curveeditor/detail/curvesegment.h
new file mode 100644
index 0000000..ce2d700
--- /dev/null
+++ b/src/curveeditor/detail/curvesegment.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** 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 "keyframe.h"
+
+#include <vector>
+
+class QPointF;
+
+namespace DesignTools {
+
+class CurveSegment
+{
+public:
+ CurveSegment();
+
+ CurveSegment(const Keyframe &first, const Keyframe &last);
+
+ bool containsX(double x) const;
+
+ QPointF evaluate(double t) const;
+
+ std::vector<QPointF> extrema() const;
+
+ std::vector<double> yForX(double x) const;
+
+ std::vector<double> xForY(double y) const;
+
+ void setLeft(const Keyframe &frame);
+
+ void setRight(const Keyframe &frame);
+
+private:
+ Keyframe m_left;
+
+ Keyframe m_right;
+};
+
+} // End namespace DesignTools.
diff --git a/src/curveeditor/detail/graphicsscene.cpp b/src/curveeditor/detail/graphicsscene.cpp
new file mode 100644
index 0000000..ddafaf4
--- /dev/null
+++ b/src/curveeditor/detail/graphicsscene.cpp
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** 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 "graphicsscene.h"
+#include "animationcurve.h"
+#include "curveitem.h"
+
+#include <QGraphicsSceneMouseEvent>
+
+namespace DesignTools {
+
+GraphicsScene::GraphicsScene(QObject *parent)
+ : QGraphicsScene(parent)
+ , m_dirty(true)
+ , m_limits()
+{}
+
+double GraphicsScene::minimumTime() const
+{
+ return limits().left();
+}
+
+double GraphicsScene::maximumTime() const
+{
+ return limits().right();
+}
+
+double GraphicsScene::minimumValue() const
+{
+ return limits().bottom();
+}
+
+double GraphicsScene::maximumValue() const
+{
+ return limits().top();
+}
+
+void GraphicsScene::addCurveItem(CurveItem *item)
+{
+ m_dirty = true;
+ addItem(item);
+}
+
+void GraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
+{
+ QGraphicsScene::mouseMoveEvent(mouseEvent);
+
+ if (!mouseEvent->isAccepted()) {
+ const auto itemList = items();
+ for (auto *item : itemList) {
+ if (auto *curveItem = qgraphicsitem_cast<CurveItem *>(item)) {
+ curveItem->setPreSelected(curveItem->contains(mouseEvent->scenePos()));
+ }
+ }
+ }
+}
+
+void GraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
+{
+ QGraphicsScene::mouseReleaseEvent(mouseEvent);
+
+ clearSelection();
+
+ const auto itemList = items();
+ for (auto *item : itemList) {
+ if (auto *curveItem = qgraphicsitem_cast<CurveItem *>(item)) {
+ if (curveItem->contains(mouseEvent->scenePos()))
+ curveItem->setSelected(true);
+
+ if (curveItem->isDirty()) {
+ m_dirty = true;
+ emit curveChanged(curveItem->id(), curveItem->curve());
+ curveItem->setDirty(false);
+ }
+ }
+ }
+}
+
+QRectF GraphicsScene::limits() const
+{
+ if (m_dirty) {
+ QPointF min(std::numeric_limits<double>::max(), std::numeric_limits<double>::max());
+ QPointF max(std::numeric_limits<double>::lowest(), std::numeric_limits<double>::lowest());
+
+ const auto itemList = items();
+ for (auto *item : itemList) {
+ if (auto *curveItem = qgraphicsitem_cast<CurveItem *>(item)) {
+ auto curve = curveItem->curve();
+ if (min.x() > curve.minimumTime())
+ min.rx() = curve.minimumTime();
+
+ if (min.y() > curve.minimumValue())
+ min.ry() = curve.minimumValue();
+
+ if (max.x() < curve.maximumTime())
+ max.rx() = curve.maximumTime();
+
+ if (max.y() < curve.maximumValue())
+ max.ry() = curve.maximumValue();
+ }
+ }
+
+ m_limits = QRectF(QPointF(min.x(), max.y()), QPointF(max.x(), min.y()));
+ m_dirty = false;
+ }
+ return m_limits;
+}
+
+void GraphicsScene::clearSelection()
+{
+ const auto itemList = items();
+ for (auto *item : itemList) {
+ if (auto *curveItem = qgraphicsitem_cast<CurveItem *>(item)) {
+ curveItem->setSelected(false);
+ }
+ }
+}
+
+} // End namespace DesignTools.
diff --git a/src/curveeditor/detail/graphicsscene.h b/src/curveeditor/detail/graphicsscene.h
new file mode 100644
index 0000000..7f80436
--- /dev/null
+++ b/src/curveeditor/detail/graphicsscene.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** 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 <QGraphicsScene>
+
+namespace DesignTools {
+
+class AnimationCurve;
+class CurveItem;
+
+class GraphicsScene : public QGraphicsScene
+{
+ Q_OBJECT
+
+signals:
+ void curveChanged(unsigned int id, const AnimationCurve &curve);
+
+public:
+ GraphicsScene(QObject *parent = nullptr);
+
+ double minimumTime() const;
+
+ double maximumTime() const;
+
+ double minimumValue() const;
+
+ double maximumValue() const;
+
+ void addCurveItem(CurveItem *item);
+
+protected:
+ void mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent) override;
+
+ void mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent) override;
+
+private:
+ using QGraphicsScene::addItem;
+
+ QRectF limits() const;
+
+ void clearSelection();
+
+ mutable bool m_dirty;
+
+ mutable QRectF m_limits;
+};
+
+} // End namespace DesignTools.
diff --git a/src/curveeditor/curveeditorview.cpp b/src/curveeditor/detail/graphicsview.cpp
index 0a54c82..e6dfb11 100644
--- a/src/curveeditor/curveeditorview.cpp
+++ b/src/curveeditor/detail/graphicsview.cpp
@@ -22,7 +22,7 @@
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
-#include "curveeditorview.h"
+#include "graphicsview.h"
#include "curveeditormodel.h"
#include "curveitem.h"
#include "utils.h"
@@ -35,7 +35,7 @@
namespace DesignTools {
-CurveEditorView::CurveEditorView(CurveEditorModel *model, QWidget *parent)
+GraphicsView::GraphicsView(CurveEditorModel *model, QWidget *parent)
: QGraphicsView(parent)
, m_scene()
, m_style(model->style())
@@ -50,15 +50,20 @@ CurveEditorView::CurveEditorView(CurveEditorModel *model, QWidget *parent)
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
- connect(&m_dialog, &CurveEditorStyleDialog::styleChanged, this, &CurveEditorView::setStyle);
+ connect(&m_dialog, &CurveEditorStyleDialog::styleChanged, this, &GraphicsView::setStyle);
- m_scene.addItem(new CurveItem(model->curve(0)));
+ auto itemSlot = [this](unsigned int id, const AnimationCurve &curve) {
+ applyZoom(m_zoomX, m_zoomY);
+ m_model->setCurve(id, curve);
+ };
+
+ connect(&m_scene, &GraphicsScene::curveChanged, itemSlot);
applyZoom(m_zoomX, m_zoomY);
update();
}
-void CurveEditorView::setStyle(const CurveEditorStyle &style)
+void GraphicsView::setStyle(const CurveEditorStyle &style)
{
m_style = style;
@@ -68,31 +73,40 @@ void CurveEditorView::setStyle(const CurveEditorStyle &style)
curveItem->setStyle(style);
}
- updateSceneRect();
applyZoom(m_zoomX, m_zoomY);
viewport()->update();
}
-void CurveEditorView::zoomX(double zoom)
+void GraphicsView::zoomX(double zoom)
{
applyZoom(zoom, m_zoomY);
- update();
+ viewport()->update();
}
-void CurveEditorView::zoomY(double zoom)
+void GraphicsView::zoomY(double zoom)
{
applyZoom(m_zoomX, zoom);
- update();
+ viewport()->update();
+}
+
+void GraphicsView::reset(const std::vector<CurveItem *> &items)
+{
+ m_scene.clear();
+ for (auto *item : items) {
+ m_scene.addCurveItem(item);
+ }
+
+ applyZoom(m_zoomX, m_zoomY);
+ viewport()->update();
}
-void CurveEditorView::resizeEvent(QResizeEvent *event)
+void GraphicsView::resizeEvent(QResizeEvent *event)
{
- updateSceneRect();
applyZoom(m_zoomX, m_zoomY);
QGraphicsView::resizeEvent(event);
}
-void CurveEditorView::contextMenuEvent(QContextMenuEvent *event)
+void GraphicsView::contextMenuEvent(QContextMenuEvent *event)
{
Q_UNUSED(event);
@@ -105,20 +119,22 @@ void CurveEditorView::contextMenuEvent(QContextMenuEvent *event)
menu.exec(event->globalPos());
}
-void CurveEditorView::drawForeground(QPainter *painter, const QRectF &rect)
+void GraphicsView::drawForeground(QPainter *painter, const QRectF &rect)
{
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);
+ if (abscissa.isValid())
+ drawTimeScale(painter, abscissa);
auto ordinate = QRectF(gap.bottomLeft(), rect.bottomLeft() + QPointF(gap.width(), 0.0));
- drawValueScale(painter, ordinate);
+ if (ordinate.isValid())
+ drawValueScale(painter, ordinate);
painter->fillRect(gap, m_style.backgroundAlternateBrush);
}
-void CurveEditorView::drawBackground(QPainter *painter, const QRectF &rect)
+void GraphicsView::drawBackground(QPainter *painter, const QRectF &rect)
{
painter->fillRect(rect, m_style.backgroundBrush);
painter->fillRect(scene()->sceneRect(), m_style.backgroundAlternateBrush);
@@ -128,27 +144,27 @@ void CurveEditorView::drawBackground(QPainter *painter, const QRectF &rect)
drawExtremaY(painter, rect);
}
-int CurveEditorView::mapTimeToX(double time)
+int GraphicsView::mapTimeToX(double time)
{
return std::round(time * scaleX(m_transform));
}
-int CurveEditorView::mapValueToY(double y)
+int GraphicsView::mapValueToY(double y)
{
return std::round(y * scaleY(m_transform));
}
-double CurveEditorView::mapXtoTime(int x)
+double GraphicsView::mapXtoTime(int x)
{
return static_cast<double>(x) / scaleX(m_transform);
}
-double CurveEditorView::mapYtoValue(int y)
+double GraphicsView::mapYtoValue(int y)
{
return static_cast<double>(y) / scaleY(m_transform);
}
-void CurveEditorView::applyZoom(double x, double y)
+void GraphicsView::applyZoom(double x, double y)
{
m_zoomX = x;
m_zoomY = y;
@@ -159,7 +175,7 @@ void CurveEditorView::applyZoom(double x, double y)
double scaleX = lerp(clamp(m_zoomX, 0.0, 1.0), xZoomedOut, xZoomedIn);
double canvasHeight = rect().height() - m_style.timeAxisHeight - 2 * m_style.canvasMargin - rect().height() / 10;
- double yZoomedOut = canvasHeight / (m_model->maximumValue() - m_model->minimumValue());
+ double yZoomedOut = canvasHeight / (m_scene.maximumValue() - m_scene.minimumValue());
double yZoomedIn = m_style.zoomInHeight;
double scaleY = lerp(clamp(m_zoomY, 0.0, 1.0), -yZoomedOut, -yZoomedIn);
@@ -173,7 +189,7 @@ void CurveEditorView::applyZoom(double x, double y)
updateSceneRect(sceneBounds);
}
-void CurveEditorView::updateSceneRect(const QRectF &rect)
+void GraphicsView::updateSceneRect(const QRectF &rect)
{
if (rect.isValid())
scene()->setSceneRect(rect);
@@ -187,21 +203,24 @@ void CurveEditorView::updateSceneRect(const QRectF &rect)
setSceneRect(sr);
}
-void CurveEditorView::drawGrid(QPainter *painter, const QRectF &rect)
+void GraphicsView::drawGrid(QPainter *painter, const QRectF &rect)
{
- painter->save();
- painter->setPen(m_style.gridColor);
-
QRectF gridRect = rect.adjusted(
m_style.valueAxisWidth + m_style.canvasMargin,
m_style.timeAxisHeight + m_style.canvasMargin,
-m_style.canvasMargin,
-m_style.canvasMargin);
+ if (!gridRect.isValid())
+ return;
+
auto drawVerticalLine = [painter, gridRect](double position) {
painter->drawLine(position, gridRect.top(), position, gridRect.bottom());
};
+ painter->save();
+ painter->setPen(m_style.gridColor);
+
double timeIncrement = timeLabelInterval(painter, m_model->maximumTime());
for (double i = m_model->minimumTime(); i <= m_model->maximumTime(); i += timeIncrement)
drawVerticalLine(mapTimeToX(i));
@@ -209,7 +228,7 @@ void CurveEditorView::drawGrid(QPainter *painter, const QRectF &rect)
painter->restore();
}
-void CurveEditorView::drawExtremaX(QPainter *painter, const QRectF &rect)
+void GraphicsView::drawExtremaX(QPainter *painter, const QRectF &rect)
{
auto drawVerticalLine = [rect, painter](double position) {
painter->drawLine(position, rect.top(), position, rect.bottom());
@@ -222,7 +241,7 @@ void CurveEditorView::drawExtremaX(QPainter *painter, const QRectF &rect)
painter->restore();
}
-void CurveEditorView::drawExtremaY(QPainter *painter, const QRectF &rect)
+void GraphicsView::drawExtremaY(QPainter *painter, const QRectF &rect)
{
auto drawHorizontalLine = [rect, painter](double position) {
painter->drawLine(rect.left(), position, rect.right(), position);
@@ -230,15 +249,15 @@ void CurveEditorView::drawExtremaY(QPainter *painter, const QRectF &rect)
painter->save();
painter->setPen(Qt::blue);
- drawHorizontalLine(mapValueToY(m_model->minimumValue()));
- drawHorizontalLine(mapValueToY(m_model->maximumValue()));
+ drawHorizontalLine(mapValueToY(m_scene.minimumValue()));
+ drawHorizontalLine(mapValueToY(m_scene.maximumValue()));
drawHorizontalLine(mapValueToY(0.0));
painter->restore();
}
-void CurveEditorView::drawTimeScale(QPainter *painter, const QRectF &rect)
+void GraphicsView::drawTimeScale(QPainter *painter, const QRectF &rect)
{
painter->save();
painter->setPen(m_style.fontColor);
@@ -264,7 +283,7 @@ void CurveEditorView::drawTimeScale(QPainter *painter, const QRectF &rect)
painter->restore();
}
-void CurveEditorView::drawValueScale(QPainter *painter, const QRectF &rect)
+void GraphicsView::drawValueScale(QPainter *painter, const QRectF &rect)
{
painter->save();
painter->setPen(m_style.fontColor);
@@ -281,12 +300,12 @@ void CurveEditorView::drawValueScale(QPainter *painter, const QRectF &rect)
painter->drawText(textRect, Qt::AlignCenter, valueText);
};
- paintLabeledTick(m_model->minimumValue());
- paintLabeledTick(m_model->maximumValue());
+ paintLabeledTick(m_scene.minimumValue());
+ paintLabeledTick(m_scene.maximumValue());
painter->restore();
}
-double CurveEditorView::timeLabelInterval(QPainter *painter, double maxTime)
+double GraphicsView::timeLabelInterval(QPainter *painter, double maxTime)
{
QFontMetrics fm(painter->font());
int minTextSpacing = fm.width(QString("X%1X").arg(maxTime));
diff --git a/src/curveeditor/curveeditorview.h b/src/curveeditor/detail/graphicsview.h
index fe35933..db9933e 100644
--- a/src/curveeditor/curveeditorview.h
+++ b/src/curveeditor/detail/graphicsview.h
@@ -27,20 +27,21 @@
#include "curveeditorstyle.h"
#include "curveeditorstyledialog.h"
+#include "graphicsscene.h"
-#include <QGraphicsScene>
#include <QGraphicsView>
namespace DesignTools {
+class CurveItem;
class CurveEditorModel;
-class CurveEditorView : public QGraphicsView
+class GraphicsView : public QGraphicsView
{
Q_OBJECT
public:
- CurveEditorView(CurveEditorModel *model, QWidget *parent = nullptr);
+ GraphicsView(CurveEditorModel *model, QWidget *parent = nullptr);
void setStyle(const CurveEditorStyle &style);
@@ -48,6 +49,8 @@ public:
void zoomY(double zoom);
+ void reset(const std::vector<CurveItem *> &items);
+
protected:
void resizeEvent(QResizeEvent *event) override;
@@ -83,7 +86,7 @@ private:
double timeLabelInterval(QPainter *painter, double maxTime);
private:
- QGraphicsScene m_scene;
+ GraphicsScene m_scene;
CurveEditorStyle m_style;
diff --git a/src/curveeditor/handleitem.cpp b/src/curveeditor/detail/handleitem.cpp
index 4653af6..d9abc77 100644
--- a/src/curveeditor/handleitem.cpp
+++ b/src/curveeditor/detail/handleitem.cpp
@@ -59,8 +59,7 @@ HandleItem::HandleItem(QGraphicsItem *parent)
setFlag(QGraphicsItem::ItemStacksBehindParent, true);
}
-HandleItem::~HandleItem()
-{ }
+HandleItem::~HandleItem() {}
int HandleItem::type() const
{
@@ -120,7 +119,6 @@ bool HandleItem::sceneEvent(QEvent *event)
};
switch (event->type()) {
-
case QEvent::GraphicsSceneMousePress:
if (!intersectsHandle())
event->ignore();
diff --git a/src/curveeditor/handleitem.h b/src/curveeditor/detail/handleitem.h
index 8e2ffd7..8e2ffd7 100644
--- a/src/curveeditor/handleitem.h
+++ b/src/curveeditor/detail/handleitem.h
diff --git a/src/curveeditor/keyframeitem.cpp b/src/curveeditor/detail/keyframeitem.cpp
index 867585c..867585c 100644
--- a/src/curveeditor/keyframeitem.cpp
+++ b/src/curveeditor/detail/keyframeitem.cpp
diff --git a/src/curveeditor/keyframeitem.h b/src/curveeditor/detail/keyframeitem.h
index 39221d2..88eb366 100644
--- a/src/curveeditor/keyframeitem.h
+++ b/src/curveeditor/detail/keyframeitem.h
@@ -25,8 +25,8 @@
#pragma once
-#include "animationcurve.h"
#include "curveeditorstyle.h"
+#include "keyframe.h"
#include <QGraphicsObject>
diff --git a/src/curveeditor/detail/treeitem.cpp b/src/curveeditor/detail/treeitem.cpp
new file mode 100644
index 0000000..c8f5360
--- /dev/null
+++ b/src/curveeditor/detail/treeitem.cpp
@@ -0,0 +1,188 @@
+/****************************************************************************
+**
+** 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 "treeitem.h"
+
+#include <QIcon>
+#include <QVariant>
+
+namespace DesignTools {
+
+TreeItem::TreeItem(const QString &name)
+ : m_name(name)
+ , m_id(0)
+ , m_locked(false)
+ , m_pinned(false)
+ , m_parent(nullptr)
+ , m_children()
+{}
+
+TreeItem::~TreeItem()
+{
+ m_parent = nullptr;
+
+ qDeleteAll(m_children);
+}
+
+QIcon TreeItem::icon() const
+{
+ return QIcon();
+}
+
+NodeTreeItem *TreeItem::asNodeItem()
+{
+ return nullptr;
+}
+
+PropertyTreeItem *TreeItem::asPropertyItem()
+{
+ return nullptr;
+}
+
+unsigned int TreeItem::id() const
+{
+ return m_id;
+}
+
+bool TreeItem::locked() const
+{
+ return m_locked;
+}
+
+bool TreeItem::pinned() const
+{
+ return m_pinned;
+}
+
+int TreeItem::row() const
+{
+ if (m_parent) {
+ for (size_t i = 0; i < m_parent->m_children.size(); ++i) {
+ if (m_parent->m_children[i] == this)
+ return i;
+ }
+ }
+
+ return 0;
+}
+
+int TreeItem::column() const
+{
+ return 0;
+}
+
+int TreeItem::rowCount() const
+{
+ return m_children.size();
+}
+
+int TreeItem::columnCount() const
+{
+ return 3;
+}
+
+TreeItem *TreeItem::parent() const
+{
+ return m_parent;
+}
+
+TreeItem *TreeItem::child(int row) const
+{
+ if (row < 0 || row >= static_cast<int>(m_children.size()))
+ return nullptr;
+
+ return m_children.at(row);
+}
+
+TreeItem *TreeItem::find(unsigned int id) const
+{
+ for (auto *child : m_children) {
+ if (child->id() == id)
+ return child;
+
+ if (auto *childsChild = child->find(id))
+ return childsChild;
+ }
+
+ return nullptr;
+}
+
+QVariant TreeItem::data(int column) const
+{
+ switch (column) {
+ case 0:
+ return QVariant(m_name);
+ case 1:
+ return QVariant(m_locked);
+ case 2:
+ return QVariant(m_pinned);
+ case 3:
+ return QVariant(m_id);
+ default:
+ return QVariant();
+ }
+}
+
+QVariant TreeItem::headerData(int column) const
+{
+ switch (column) {
+ case 0:
+ return QString("Name");
+ case 1:
+ return QString("L");
+ case 2:
+ return QString("P");
+ case 3:
+ return QString("Id");
+ default:
+ return QVariant();
+ }
+}
+
+void TreeItem::setId(unsigned int &id)
+{
+ m_id = id;
+
+ for (auto *child : m_children)
+ child->setId(++id);
+}
+
+void TreeItem::addChild(TreeItem *child)
+{
+ child->m_parent = this;
+ m_children.push_back(child);
+}
+
+void TreeItem::setLocked(bool locked)
+{
+ m_locked = locked;
+}
+
+void TreeItem::setPinned(bool pinned)
+{
+ m_pinned = pinned;
+}
+
+} // End namespace DesignTools.
diff --git a/src/curveeditor/detail/treeitem.h b/src/curveeditor/detail/treeitem.h
new file mode 100644
index 0000000..15a1014
--- /dev/null
+++ b/src/curveeditor/detail/treeitem.h
@@ -0,0 +1,102 @@
+
+/****************************************************************************
+**
+** 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 <QString>
+
+#include <vector>
+
+class QIcon;
+class QVariant;
+
+namespace DesignTools {
+
+class NodeTreeItem;
+class PropertyTreeItem;
+
+class TreeItem
+{
+public:
+ TreeItem(const QString &name);
+
+ virtual ~TreeItem();
+
+ virtual QIcon icon() const;
+
+ virtual NodeTreeItem *asNodeItem();
+
+ virtual PropertyTreeItem *asPropertyItem();
+
+ unsigned int id() const;
+
+ bool locked() const;
+
+ bool pinned() const;
+
+ int row() const;
+
+ int column() const;
+
+ int rowCount() const;
+
+ int columnCount() const;
+
+ TreeItem *parent() const;
+
+ TreeItem *child(int row) const;
+
+ TreeItem *find(unsigned int row) const;
+
+ QVariant data(int column) const;
+
+ QVariant headerData(int column) const;
+
+ void setId(unsigned int &id);
+
+ void addChild(TreeItem *child);
+
+ void setLocked(bool locked);
+
+ void setPinned(bool pinned);
+
+protected:
+ QString m_name;
+
+ unsigned int m_id;
+
+ bool m_locked;
+
+ bool m_pinned;
+
+ TreeItem *m_parent;
+
+ std::vector<TreeItem *> m_children;
+};
+
+} // End namespace DesignTools.
diff --git a/src/curveeditor/detail/treeitemdelegate.cpp b/src/curveeditor/detail/treeitemdelegate.cpp
new file mode 100644
index 0000000..21633dd
--- /dev/null
+++ b/src/curveeditor/detail/treeitemdelegate.cpp
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** 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 "treeitemdelegate.h"
+#include "treeitem.h"
+
+#include <QEvent>
+#include <QMouseEvent>
+#include <QPainter>
+
+namespace DesignTools {
+
+TreeItemDelegate::TreeItemDelegate(const CurveEditorStyle &style, QObject *parent)
+ : QStyledItemDelegate(parent)
+ , m_style(style)
+{}
+
+QSize TreeItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+ return QStyledItemDelegate::sizeHint(option, index);
+}
+
+void TreeItemDelegate::paint(QPainter *painter,
+ const QStyleOptionViewItem &option,
+ const QModelIndex &index) const
+{
+ if (index.column() == 1 || index.column() == 2) {
+
+ int height = option.rect.size().height();
+ QRect iconRect(QPoint(0, 0), QSize(height, height));
+ iconRect.moveCenter(option.rect.center());
+
+ auto *treeItem = static_cast<TreeItem *>(index.internalPointer());
+ if (option.state & QStyle::State_MouseOver && iconRect.contains(m_mousePos)) {
+
+ painter->fillRect(option.rect, option.backgroundBrush);
+
+ if (index.column() == 1) {
+
+ if (treeItem->locked()) {
+
+ QPixmap pixmap = pixmapFromIcon(
+ m_style.treeItemStyle.unlockedIcon,
+ iconRect.size(),
+ m_style.fontColor);
+
+ painter->drawPixmap(iconRect, pixmap);
+
+ } else {
+
+ QPixmap pixmap = pixmapFromIcon(
+ m_style.treeItemStyle.lockedIcon,
+ iconRect.size(),
+ m_style.fontColor);
+
+ painter->drawPixmap(iconRect, pixmap);
+ }
+
+ } else if (index.column() == 2) {
+
+ if (treeItem->pinned()) {
+
+ QPixmap pixmap = pixmapFromIcon(
+ m_style.treeItemStyle.unpinnedIcon,
+ iconRect.size(),
+ m_style.fontColor);
+
+ painter->drawPixmap(iconRect, pixmap);
+
+ } else {
+
+ QPixmap pixmap = pixmapFromIcon(
+ m_style.treeItemStyle.pinnedIcon,
+ iconRect.size(),
+ m_style.fontColor);
+
+ painter->drawPixmap(iconRect, pixmap);
+
+ }
+ }
+
+ } else {
+
+ if (treeItem->locked() && index.column() == 1) {
+
+ QPixmap pixmap = pixmapFromIcon(
+ m_style.treeItemStyle.lockedIcon,
+ iconRect.size(),
+ m_style.fontColor);
+
+ painter->drawPixmap(iconRect, pixmap);
+
+ } else if (treeItem->pinned() && index.column() == 2) {
+
+ QPixmap pixmap = pixmapFromIcon(
+ m_style.treeItemStyle.pinnedIcon,
+ iconRect.size(),
+ m_style.fontColor);
+
+ painter->drawPixmap(iconRect, pixmap);
+
+ }
+ }
+ } else {
+ QStyledItemDelegate::paint(painter, option, index);
+ }
+}
+
+void TreeItemDelegate::setStyle(const CurveEditorStyle &style)
+{
+ m_style = style;
+}
+
+bool TreeItemDelegate::editorEvent(QEvent *event,
+ QAbstractItemModel *model,
+ const QStyleOptionViewItem &option,
+ const QModelIndex &index)
+{
+ if (event->type() == QEvent::MouseMove)
+ m_mousePos = static_cast<QMouseEvent *>(event)->pos();
+
+ return QStyledItemDelegate::editorEvent(event, model, option, index);
+}
+
+} // End namespace DesignTools.
diff --git a/src/curveeditor/detail/treeitemdelegate.h b/src/curveeditor/detail/treeitemdelegate.h
new file mode 100644
index 0000000..6479f48
--- /dev/null
+++ b/src/curveeditor/detail/treeitemdelegate.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** 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 <QStyledItemDelegate>
+
+namespace DesignTools {
+
+class TreeItemDelegate : public QStyledItemDelegate
+{
+ Q_OBJECT
+
+public:
+ TreeItemDelegate(const CurveEditorStyle &style, QObject *parent = nullptr);
+
+ QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
+
+ void paint(
+ QPainter *painter,
+ const QStyleOptionViewItem &option,
+ const QModelIndex &index) const override;
+
+ void setStyle(const CurveEditorStyle &style);
+
+protected:
+ bool editorEvent(
+ QEvent *event,
+ QAbstractItemModel *model,
+ const QStyleOptionViewItem &option,
+ const QModelIndex &index) override;
+
+private:
+ CurveEditorStyle m_style;
+
+ QPoint m_mousePos;
+};
+
+} // End namespace DesignTools.
diff --git a/src/curveeditor/detail/treemodel.cpp b/src/curveeditor/detail/treemodel.cpp
new file mode 100644
index 0000000..1fc3fad
--- /dev/null
+++ b/src/curveeditor/detail/treemodel.cpp
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** 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 "treemodel.h"
+#include "treeitem.h"
+
+#include <QIcon>
+
+namespace DesignTools {
+
+TreeModel::TreeModel(QObject *parent)
+ : QAbstractItemModel(parent)
+ , m_root(new TreeItem("Root"))
+{}
+
+TreeModel::~TreeModel()
+{
+ if (m_root) {
+ delete m_root;
+ m_root = nullptr;
+ }
+}
+
+QVariant TreeModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+
+ TreeItem *item = static_cast<TreeItem *>(index.internalPointer());
+
+ if (role == Qt::DecorationRole && index.column() == 0)
+ return item->icon();
+
+ if (role != Qt::DisplayRole)
+ return QVariant();
+
+ return item->data(index.column());
+}
+
+QVariant TreeModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (role != Qt::DisplayRole)
+ return QVariant();
+
+ if (orientation == Qt::Horizontal)
+ return m_root->headerData(section);
+
+ return QVariant();
+}
+
+QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) const
+{
+ if (!hasIndex(row, column, parent))
+ return QModelIndex();
+
+ TreeItem *parentItem = m_root;
+
+ if (parent.isValid())
+ parentItem = static_cast<TreeItem *>(parent.internalPointer());
+
+ if (TreeItem *childItem = parentItem->child(row))
+ return createIndex(row, column, childItem);
+
+ return QModelIndex();
+}
+
+QModelIndex TreeModel::parent(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return QModelIndex();
+
+ TreeItem *childItem = static_cast<TreeItem *>(index.internalPointer());
+
+ if (TreeItem *parentItem = childItem->parent()) {
+ if (parentItem == m_root)
+ return QModelIndex();
+
+ return createIndex(parentItem->row(), 0, parentItem);
+ }
+ return QModelIndex();
+}
+
+int TreeModel::rowCount(const QModelIndex &parent) const
+{
+ if (parent.column() > 0)
+ return 0;
+
+ TreeItem *parentItem = m_root;
+
+ if (parent.isValid())
+ parentItem = static_cast<TreeItem *>(parent.internalPointer());
+
+ return parentItem->rowCount();
+}
+
+int TreeModel::columnCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return m_root->columnCount();
+}
+
+void TreeModel::initialize()
+{
+ if (m_root)
+ delete m_root;
+
+ m_root = new TreeItem("Root");
+}
+
+TreeItem *TreeModel::root()
+{
+ return m_root;
+}
+
+TreeItem *TreeModel::find(unsigned int id)
+{
+ return m_root->find(id);
+}
+
+} // End namespace DesignTools.
diff --git a/src/curveeditor/detail/treemodel.h b/src/curveeditor/detail/treemodel.h
new file mode 100644
index 0000000..13d2518
--- /dev/null
+++ b/src/curveeditor/detail/treemodel.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** 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 <QAbstractItemModel>
+
+#include <vector>
+
+namespace DesignTools {
+
+class TreeItem;
+
+class TreeModel : public QAbstractItemModel
+{
+ Q_OBJECT
+
+public:
+ TreeModel(QObject *parent = nullptr);
+
+ ~TreeModel() override;
+
+ QVariant data(const QModelIndex &index, int role) const override;
+
+ QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
+
+ QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
+
+ QModelIndex parent(const QModelIndex &index) const override;
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+
+ int columnCount(const QModelIndex &parent = QModelIndex()) const override;
+
+protected:
+ void initialize();
+
+ TreeItem *root();
+
+ TreeItem *find(unsigned int id);
+
+private:
+ TreeItem *m_root;
+};
+
+} // End namespace DesignTools.
diff --git a/src/curveeditor/detail/treeview.cpp b/src/curveeditor/detail/treeview.cpp
new file mode 100644
index 0000000..3b9a4ef
--- /dev/null
+++ b/src/curveeditor/detail/treeview.cpp
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** 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 "treeview.h"
+#include "curveeditormodel.h"
+#include "curveitem.h"
+#include "treeitem.h"
+#include "treeitemdelegate.h"
+
+#include <QHeaderView>
+#include <QMouseEvent>
+
+namespace DesignTools {
+
+TreeView::TreeView(CurveEditorModel *model, QWidget *parent)
+ : QTreeView(parent)
+{
+ setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
+ setUniformRowHeights(true);
+ setRootIsDecorated(false);
+ setMouseTracking(true);
+ setHeaderHidden(true);
+
+ model->setParent(this);
+ setModel(model);
+
+ auto expandItems = [this]() { expandAll(); };
+ connect(model, &QAbstractItemModel::modelReset, expandItems);
+
+ auto *delegate = new TreeItemDelegate(model->style(), this);
+ setItemDelegate(delegate);
+
+ setSelectionBehavior(QAbstractItemView::SelectRows);
+ setSelectionMode(QAbstractItemView::ExtendedSelection);
+
+ connect(selectionModel(), &QItemSelectionModel::selectionChanged, this, &TreeView::changeSelection);
+ setStyle(model->style());
+
+ header()->setSectionResizeMode(0, QHeaderView::Stretch);
+ header()->setSectionResizeMode(1, QHeaderView::Fixed);
+ header()->setSectionResizeMode(2, QHeaderView::Fixed);
+
+ header()->setStretchLastSection(false);
+ header()->resizeSection(1, 20);
+ header()->resizeSection(2, 20);
+}
+
+void TreeView::setStyle(const CurveEditorStyle &style)
+{
+ QPalette pal = palette();
+ pal.setBrush(QPalette::Base, style.backgroundBrush);
+ pal.setBrush(QPalette::Button, style.backgroundAlternateBrush);
+ pal.setBrush(QPalette::Text, style.fontColor);
+
+ // Tmp to see what happens on windows/macOS.
+ pal.setBrush(backgroundRole(), Qt::white);
+ pal.setBrush(foregroundRole(), Qt::white);
+
+ setPalette(pal);
+
+ if (auto *delegate = qobject_cast<TreeItemDelegate *>(itemDelegate()))
+ delegate->setStyle(style);
+}
+
+void TreeView::changeCurve(unsigned int id, const AnimationCurve &curve)
+{
+ if (auto *curveModel = qobject_cast<CurveEditorModel *>(model()))
+ curveModel->setCurve(id, curve);
+}
+
+void TreeView::changeSelection(const QItemSelection &selected, const QItemSelection &deselected)
+{
+ Q_UNUSED(selected);
+ Q_UNUSED(deselected);
+
+ std::vector<CurveItem *> curves;
+ for (auto index : selectedIndexes()) {
+ if (index.isValid() && index.column() == 0) {
+ auto *treeItem = static_cast<TreeItem *>(index.internalPointer());
+ if (auto *propertyItem = treeItem->asPropertyItem())
+ curves.push_back(new CurveItem(treeItem->id(), propertyItem->curve()));
+ }
+ }
+
+ emit curvesSelected(curves);
+}
+
+QSize TreeView::sizeHint() const
+{
+ return QSize(170, 300);
+}
+
+void TreeView::mousePressEvent(QMouseEvent *event)
+{
+ QModelIndex index = indexAt(event->pos());
+ if (index.isValid()) {
+ auto *treeItem = static_cast<TreeItem *>(index.internalPointer());
+ if (index.column() == 1)
+ treeItem->setLocked(!treeItem->locked());
+ else if (index.column() == 2)
+ treeItem->setPinned(!treeItem->pinned());
+ }
+ QTreeView::mousePressEvent(event);
+}
+
+} // End namespace DesignTools.
diff --git a/src/curveeditor/detail/treeview.h b/src/curveeditor/detail/treeview.h
new file mode 100644
index 0000000..9d3af64
--- /dev/null
+++ b/src/curveeditor/detail/treeview.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** 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 <QTreeView>
+
+namespace DesignTools {
+
+class AnimationCurve;
+class CurveEditorModel;
+class CurveItem;
+
+struct CurveEditorStyle;
+
+class TreeView : public QTreeView
+{
+ Q_OBJECT
+
+signals:
+ void curvesSelected(const std::vector<CurveItem *> &curves);
+
+public:
+ TreeView(CurveEditorModel *model, QWidget *parent = nullptr);
+
+ void changeCurve(unsigned int id, const AnimationCurve &curve);
+
+ void setStyle(const CurveEditorStyle &style);
+
+protected:
+ QSize sizeHint() const override;
+
+ void mousePressEvent(QMouseEvent *event) override;
+
+private:
+ void changeSelection(const QItemSelection &selected, const QItemSelection &deselected);
+};
+
+} // End namespace DesignTools.
diff --git a/src/curveeditor/utils.cpp b/src/curveeditor/detail/utils.cpp
index da74946..4933bcb 100644
--- a/src/curveeditor/utils.cpp
+++ b/src/curveeditor/detail/utils.cpp
@@ -24,6 +24,7 @@
**
****************************************************************************/
+#include <QPalette>
#include <QPointF>
#include <QRectF>
#include <QTransform>
@@ -75,4 +76,32 @@ QRectF bbox(const QRectF &rect, const QTransform &transform)
return out;
}
+QPalette singleColorPalette(const QColor &color)
+{
+ QPalette palette;
+ palette.setColor(QPalette::Window, color);
+ palette.setColor(QPalette::Background, color);
+ palette.setColor(QPalette::WindowText, color);
+ palette.setColor(QPalette::Foreground, color);
+ palette.setColor(QPalette::Base, color);
+ palette.setColor(QPalette::AlternateBase, color);
+ palette.setColor(QPalette::ToolTipBase, color);
+ palette.setColor(QPalette::ToolTipText, color);
+ palette.setColor(QPalette::Text, color);
+
+ palette.setColor(QPalette::Button, color);
+ palette.setColor(QPalette::ButtonText, color);
+ palette.setColor(QPalette::BrightText, color);
+ palette.setColor(QPalette::Light, color);
+ palette.setColor(QPalette::Midlight, color);
+ palette.setColor(QPalette::Dark, color);
+ palette.setColor(QPalette::Mid, color);
+ palette.setColor(QPalette::Shadow, color);
+ palette.setColor(QPalette::Highlight, color);
+ palette.setColor(QPalette::HighlightedText, color);
+ palette.setColor(QPalette::Link, color);
+ palette.setColor(QPalette::LinkVisited, color);
+ return palette;
+}
+
} // End namespace DesignTools.
diff --git a/src/curveeditor/utils.h b/src/curveeditor/detail/utils.h
index c8a44fb..450c805 100644
--- a/src/curveeditor/utils.h
+++ b/src/curveeditor/detail/utils.h
@@ -25,6 +25,8 @@
#pragma once
+class QColor;
+class QPalette;
class QPointF;
class QRectF;
class QTransform;
@@ -45,4 +47,6 @@ void grow(QRectF &rect, const QPointF &point);
QRectF bbox(const QRectF &rect, const QTransform &transform);
+QPalette singleColorPalette(const QColor &color);
+
} // End namespace DesignTools.
diff --git a/src/curveeditor/keyframe.cpp b/src/curveeditor/keyframe.cpp
new file mode 100644
index 0000000..8ff577c
--- /dev/null
+++ b/src/curveeditor/keyframe.cpp
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** 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 "keyframe.h"
+
+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;
+}
+
+} // End namespace DesignTools.
diff --git a/src/curveeditor/keyframe.h b/src/curveeditor/keyframe.h
new file mode 100644
index 0000000..5e60425
--- /dev/null
+++ b/src/curveeditor/keyframe.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** 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>
+
+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 m_leftHandle;
+
+ QPointF m_rightHandle;
+};
+
+} // End namespace DesignTools.