summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKnud Dollereder <knud.dollereder@qt.io>2019-02-25 12:37:44 +0100
committerKnud Dollereder <knud.dollereder@qt.io>2019-02-26 10:16:10 +0000
commitd64e872b61cfeb0f7bc36e21b2b98e5ff10f580a (patch)
tree99958d8a9f5aaf50b94d33b32ba262a9357e85dc
parenteb031b8ef94da5601dc3e1e133d9abe2c8dfbd5b (diff)
Introduce TreeView
Provide example of intended usage. Move code, not intended for the client into subfolder detail. Add resources. (currently only temporary icons) Add evaluator functions to the AnimationCurve class. Change-Id: I9a8787af219d648d40181adc7433708030294628 Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
-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.