aboutsummaryrefslogtreecommitdiffstats
path: root/tools/qmleasing
diff options
context:
space:
mode:
Diffstat (limited to 'tools/qmleasing')
-rw-r--r--tools/qmleasing/Button.qml177
-rw-r--r--tools/qmleasing/easing.qml219
-rw-r--r--tools/qmleasing/import.ui139
-rw-r--r--tools/qmleasing/main.cpp73
-rw-r--r--tools/qmleasing/mainwindow.cpp169
-rw-r--r--tools/qmleasing/mainwindow.h (renamed from tools/qmleasing/TextField.qml)65
-rw-r--r--tools/qmleasing/pane.ui112
-rw-r--r--tools/qmleasing/preview.qml148
-rw-r--r--tools/qmleasing/properties.ui138
-rw-r--r--tools/qmleasing/qmleasing.pro17
-rw-r--r--tools/qmleasing/resources.qrc4
-rw-r--r--tools/qmleasing/segmentproperties.cpp128
-rw-r--r--tools/qmleasing/segmentproperties.h94
-rw-r--r--tools/qmleasing/splineeditor.cpp714
-rw-r--r--tools/qmleasing/splineeditor.h143
15 files changed, 2020 insertions, 320 deletions
diff --git a/tools/qmleasing/Button.qml b/tools/qmleasing/Button.qml
new file mode 100644
index 0000000000..f90e8a39b7
--- /dev/null
+++ b/tools/qmleasing/Button.qml
@@ -0,0 +1,177 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Item {
+ id: button
+
+ signal clicked
+
+ Rectangle {
+ id: normalBackground
+ radius: 4
+ anchors.fill: parent
+ smooth: true
+ gradient: Gradient {
+ GradientStop {
+ position: 0
+ color: "#afafaf"
+ }
+
+ GradientStop {
+ position: 0.460
+ color: "#808080"
+ }
+
+ GradientStop {
+ position: 1
+ color: "#adadad"
+ }
+ }
+ border.color: "#000000"
+ }
+
+
+ Rectangle {
+ id: hoveredBackground
+ x: 2
+ y: -8
+ radius: 4
+ opacity: 0
+ gradient: Gradient {
+ GradientStop {
+ position: 0
+ color: "#cacaca"
+ }
+
+ GradientStop {
+ position: 0.460
+ color: "#a2a2a2"
+ }
+
+ GradientStop {
+ position: 1
+ color: "#c8c8c8"
+ }
+ }
+ smooth: true
+ anchors.fill: parent
+ border.color: "#000000"
+ }
+
+
+ Rectangle {
+ id: pressedBackground
+ x: -8
+ y: 2
+ radius: 4
+ opacity: 0
+ gradient: Gradient {
+ GradientStop {
+ position: 0
+ color: "#8b8b8b"
+ }
+
+ GradientStop {
+ position: 0.470
+ color: "#626161"
+ }
+
+ GradientStop {
+ position: 1
+ color: "#8f8e8e"
+ }
+ }
+ smooth: true
+ anchors.fill: parent
+ border.color: "#000000"
+ }
+ states: [
+ State {
+ name: "hovered"
+
+ PropertyChanges {
+ target: normalBackground
+ opacity: 0
+ }
+
+ PropertyChanges {
+ target: hoveredBackground
+ opacity: 1
+ }
+ },
+ State {
+ name: "pressed"
+
+ PropertyChanges {
+ target: normalBackground
+ opacity: 0
+ }
+
+ PropertyChanges {
+ target: pressedBackground
+ opacity: 1
+ }
+ }
+ ]
+
+ Text {
+ color: "#e8e8e8"
+ text: qsTr("Play")
+ anchors.fill: parent
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ font.bold: true
+ font.pixelSize: 20
+ }
+
+ MouseArea {
+ hoverEnabled: true
+ anchors.fill: parent
+ onEntered: button.state = "hovered"
+ onExited: button.state = ""
+ onClicked: {
+ button.state = "pressed"
+ button.clicked();
+ }
+ }
+}
diff --git a/tools/qmleasing/easing.qml b/tools/qmleasing/easing.qml
deleted file mode 100644
index 8bed5ba9ef..0000000000
--- a/tools/qmleasing/easing.qml
+++ /dev/null
@@ -1,219 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** 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 Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-import QtQuick 2.0
-import EasingPlot 1.0
-
-Rectangle {
- width: 775; height: 550
-
- function precision(n)
- {
- var str = n.toPrecision(3);
- while (str.length > 1 && (str[str.length - 1] == "0" || str[str.length - 1] == "."))
- str = str.substr(0, str.length - 1);
- return str;
- }
-
- function updateEasing() {
- var ini = Math.min(100, Math.max(0, Number(in_inf.text)));
- var outi = Math.min(100, Math.max(0, Number(out_inf.text)));
-
- var ins = Number(in_slope.text);
- var outs = Number(out_slope.text);
-
- var p1 = [ (ini / 100), (ini / 100) * ins ];
- var p2 = [ 1 - (outi / 100), 1 - (outi / 100) * outs ];
-
- text.text = "[ " + precision(p1[0]) + ", " + precision(p1[1]) + ", " + precision(p2[0]) + ", " + precision(p2[1]) + ", 1, 1 ]";
- }
-
- Rectangle {
- id: border
- width: 500; height: 500
- x: 25; y: 25
- border.color: "lightsteelblue"
- border.width: 3
- radius: 5
- color: "transparent"
-
- EasingPlot {
- id: plot
-
- anchors.centerIn: parent
- width: parent.width - 10
- height: parent.height - 10
-
- easing.type: "Bezier"
- easing.bezierCurve: eval(text.text)
- }
-
- }
-
- Text {
- text: "<u>After Effects curve</u>"
- anchors.horizontalCenter: text.horizontalCenter
- anchors.bottom: column.top
- anchors.bottomMargin: 14
- }
-
- Column {
- id: column
-
- y: 70
- anchors.right: parent.right
- anchors.rightMargin: 25
- spacing: 5
- TextField {
- id: in_inf
- focus: true
- name: "Input influence:"
- text: "33"
- anchors.right: parent.right
- KeyNavigation.tab: in_slope
- KeyNavigation.backtab: text
- onTextChanged: updateEasing();
- }
- TextField {
- id: in_slope
- name: "Input slope:"
- text: "0"
- anchors.right: parent.right
- KeyNavigation.tab: out_inf
- KeyNavigation.backtab: in_inf
- onTextChanged: updateEasing();
- }
- TextField {
- id: out_inf
- name: "Output influence:"
- text: "33"
- anchors.right: parent.right
- KeyNavigation.tab: out_slope
- KeyNavigation.backtab: in_slope
- onTextChanged: updateEasing();
- }
- TextField {
- id: out_slope
- name: "Output slope:"
- text: "0"
- anchors.right: parent.right
- KeyNavigation.tab: text
- KeyNavigation.backtab: out_info
- onTextChanged: updateEasing();
- }
- }
-
- Text {
- text: "<u>QML Bezier curve</u>"
- anchors.horizontalCenter: text.horizontalCenter
- anchors.bottom: text.top
- anchors.bottomMargin: 10
- }
-
- TextEdit {
- id: text
- x: 200
- width: 200
- height: 200
-
- Rectangle {
- x: -2; y: -2
- width: parent.width + 4
- height: parent.height + 4
- color: "transparent"
- border.color: text.activeFocus?"green":"lightgreen"
-
- border.width: 3
- radius: 5
- }
-
- wrapMode: "WordWrap"
-
- anchors.top: column.bottom
- anchors.topMargin: 50
- anchors.right: column.right
- KeyNavigation.tab: in_inf
- KeyNavigation.backtab: out_slope
- }
-
-
- Item {
- anchors.left: text.left
- anchors.top: text.bottom
- anchors.topMargin: 35
- width: text.width
- height: rect.height
-
- Rectangle {
- color: "gray"
- width: 50; height: 50
- id: rect
-
- NumberAnimation on x {
- id: animation
- running: false
- easing: plot.easing
- duration: 1000
- }
-
- radius: 5
- }
-
- MouseArea {
- anchors.fill: parent
- onClicked: {
- if (rect.x < 5) {
- animation.to = text.width - rect.width;
- } else {
- animation.to = 0;
- }
- animation.start();
- }
- }
-
- Text {
- anchors.centerIn: parent
- text: "Click to Try"
- }
- }
-
- Component.onCompleted: updateEasing();
-}
diff --git a/tools/qmleasing/import.ui b/tools/qmleasing/import.ui
new file mode 100644
index 0000000000..86b80e241d
--- /dev/null
+++ b/tools/qmleasing/import.ui
@@ -0,0 +1,139 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ImportDialog</class>
+ <widget class="QDialog" name="ImportDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>164</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Import After Effects Curve</string>
+ </property>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="geometry">
+ <rect>
+ <x>40</x>
+ <y>130</y>
+ <width>341</width>
+ <height>32</height>
+ </rect>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ <widget class="QWidget" name="formLayoutWidget">
+ <property name="geometry">
+ <rect>
+ <x>20</x>
+ <y>10</y>
+ <width>361</width>
+ <height>101</height>
+ </rect>
+ </property>
+ <layout class="QFormLayout" name="formLayout">
+ <property name="labelAlignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Input Influence:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Output Influence:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Output Slope:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="inInfluenceEdit">
+ <property name="text">
+ <string>33</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="inSlopeEdit">
+ <property name="text">
+ <string>0</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="outInfluenceEdit">
+ <property name="text">
+ <string>33</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLineEdit" name="outSlopeEdit">
+ <property name="text">
+ <string>0</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Input Slope:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>ImportDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>ImportDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/tools/qmleasing/main.cpp b/tools/qmleasing/main.cpp
index 60a6f37f55..212b9b1fd2 100644
--- a/tools/qmleasing/main.cpp
+++ b/tools/qmleasing/main.cpp
@@ -39,78 +39,17 @@
**
****************************************************************************/
-#include <QPainter>
-#include <QtQuick/QQuickView>
-#include <QGuiApplication>
-#include <QEasingCurve>
-#include <QtQuick/QQuickPaintedItem>
+#include "mainwindow.h"
-class EasingPlot : public QQuickPaintedItem
-{
- Q_OBJECT
- Q_PROPERTY(QEasingCurve easing READ easing WRITE setEasing NOTIFY easingChanged);
-
-public:
- EasingPlot();
-
- QEasingCurve easing() const;
- void setEasing(const QEasingCurve &);
-
-signals:
- void easingChanged();
-
-protected:
- virtual void paint(QPainter *painter);
-
-private:
- QEasingCurve m_easing;
-};
-
-EasingPlot::EasingPlot()
-{
-}
-
-QEasingCurve EasingPlot::easing() const
-{
- return m_easing;
-}
-
-void EasingPlot::setEasing(const QEasingCurve &e)
-{
- if (m_easing == e)
- return;
-
- m_easing = e;
- emit easingChanged();
-
- update();
-}
-
-void EasingPlot::paint(QPainter *painter)
-{
- QPointF lastPoint(0, 0);
-
- for (int ii = 1; ii <= 100; ++ii) {
- qreal value = m_easing.valueForProgress(qreal(ii) / 100.);
-
- QPointF currentPoint(width() * qreal(ii) / 100., value * (height() - 1));
- painter->drawLine(lastPoint, currentPoint);
-
- lastPoint = currentPoint;
- }
-}
+#include <QApplication>
int main(int argc, char ** argv)
{
- QGuiApplication app(argc, argv);
-
- qmlRegisterType<EasingPlot>("EasingPlot", 1, 0, "EasingPlot");
+ QApplication app(argc, argv);
- QQuickView view;
- view.setSource(QUrl("qrc:/easing.qml"));
- view.show();
+ MainWindow mainWindow;
+ mainWindow.show();
+ mainWindow.showQuickView();
return app.exec();
}
-
-#include "main.moc"
diff --git a/tools/qmleasing/mainwindow.cpp b/tools/qmleasing/mainwindow.cpp
new file mode 100644
index 0000000000..3cf6d224b9
--- /dev/null
+++ b/tools/qmleasing/mainwindow.cpp
@@ -0,0 +1,169 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "mainwindow.h"
+#include "splineeditor.h"
+#include <QtQuick/QQuickView>
+#include <QtQuick>
+#include <QtQml/QQmlContext>
+#include <QEasingCurve>
+#include <QHBoxLayout>
+#include <QVBoxLayout>
+#include <QDoubleValidator>
+#include <QDialog>
+
+MainWindow::MainWindow(QWidget *parent) :
+ QMainWindow(parent)
+{
+ SplineEditor *splineEditor = new SplineEditor(this);
+
+ QWidget *mainWidget = new QWidget(this);
+
+ setCentralWidget(mainWidget);
+
+ QHBoxLayout *hboxLayout = new QHBoxLayout(mainWidget);
+ QVBoxLayout *vboxLayout = new QVBoxLayout();
+
+ mainWidget->setLayout(hboxLayout);
+ hboxLayout->addLayout(vboxLayout);
+
+ QWidget *propertyWidget = new QWidget(this);
+ ui_properties.setupUi(propertyWidget);
+
+ ui_properties.spinBox->setMinimum(50);
+ ui_properties.spinBox->setMaximum(10000);
+ ui_properties.spinBox->setValue(500);
+
+ hboxLayout->addWidget(propertyWidget);
+
+ m_placeholder = new QWidget(this);
+
+ m_placeholder->setFixedSize(quickView.size());
+
+ vboxLayout->addWidget(splineEditor);
+ vboxLayout->addWidget(m_placeholder);
+
+ ui_properties.plainTextEdit->setPlainText(splineEditor->generateCode());
+ connect(splineEditor, SIGNAL(easingCurveCodeChanged(QString)), ui_properties.plainTextEdit, SLOT(setPlainText(QString)));
+
+ quickView.rootContext()->setContextProperty(QLatin1String("spinBox"), ui_properties.spinBox);
+
+ foreach (const QString &name, splineEditor->presetNames())
+ ui_properties.comboBox->addItem(name);
+
+ connect(ui_properties.comboBox, SIGNAL(currentIndexChanged(QString)), splineEditor, SLOT(setPreset(QString)));
+
+ splineEditor->setPreset(ui_properties.comboBox->currentText());
+
+ QVBoxLayout *groupBoxLayout = new QVBoxLayout(ui_properties.groupBox);
+ groupBoxLayout->setMargin(0);
+ ui_properties.groupBox->setLayout(groupBoxLayout);
+
+ groupBoxLayout->addWidget(splineEditor->pointListWidget());
+ m_splineEditor = splineEditor;
+ connect(ui_properties.plainTextEdit, SIGNAL(textChanged()), this, SLOT(textEditTextChanged()));
+
+ QDialog* importDialog = new QDialog(this);
+ ui_import.setupUi(importDialog);
+ ui_import.inInfluenceEdit->setValidator(new QDoubleValidator(this));
+ ui_import.inSlopeEdit->setValidator(new QDoubleValidator(this));
+ ui_import.outInfluenceEdit->setValidator(new QDoubleValidator(this));
+ ui_import.outSlopeEdit->setValidator(new QDoubleValidator(this));
+ connect(ui_properties.importButton, SIGNAL(clicked()), importDialog, SLOT(show()));
+ connect(importDialog, SIGNAL(finished(int)), this, SLOT(importData(int)));
+
+ connect(this, SIGNAL(close()), this, SLOT(doClose()));
+ initQml();
+}
+
+void MainWindow::showQuickView()
+{
+ const int margin = 16;
+ quickView.setPosition(pos() + QPoint(0, frameGeometry().height() + margin));
+
+ quickView.raise();
+ quickView.show();
+}
+
+void MainWindow::textEditTextChanged()
+{
+ m_splineEditor->setEasingCurve(ui_properties.plainTextEdit->toPlainText().trimmed());
+}
+
+void MainWindow::moveEvent(QMoveEvent *event)
+{
+ QMainWindow::moveEvent(event);
+ showQuickView();
+}
+
+void MainWindow::resizeEvent(QResizeEvent *event)
+{
+ QMainWindow::resizeEvent(event);
+ showQuickView();
+}
+
+void MainWindow::initQml()
+{
+ quickView.setFlags(Qt::FramelessWindowHint);
+ quickView.rootContext()->setContextProperty(QLatin1String("editor"), m_splineEditor);
+ quickView.setSource(QUrl("qrc:/preview.qml"));
+ quickView.show();
+}
+
+void MainWindow::closeEvent(QCloseEvent *)
+{
+ quickView.close();
+}
+
+void MainWindow::importData(int result)
+{
+ if (!result)
+ return;
+ double ii = ui_import.inInfluenceEdit->text().toDouble();
+ double is = ui_import.inSlopeEdit->text().toDouble();
+ double oi = ui_import.outInfluenceEdit->text().toDouble();
+ double os = ui_import.outSlopeEdit->text().toDouble();
+ ii = qBound<double>(0., ii, 100.) / 100.;
+ oi = qBound<double>(0., oi, 100.) / 100.;
+ QString generatedString = QString("[%1,%2,%3,%4,1,1]").arg(ii, 0, 'f', 3)
+ .arg(ii*is,0,'f',3).arg(1-oi, 0, 'f', 3).arg(1-(oi*os), 0, 'f', 3);
+ ui_properties.plainTextEdit->setPlainText(generatedString);
+}
diff --git a/tools/qmleasing/TextField.qml b/tools/qmleasing/mainwindow.h
index 7fedab8a03..f2fcc61167 100644
--- a/tools/qmleasing/TextField.qml
+++ b/tools/qmleasing/mainwindow.h
@@ -3,7 +3,7 @@
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
-** This file is part of the QtQml module of the Qt Toolkit.
+** This file is part of the tools applications of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
@@ -39,38 +39,43 @@
**
****************************************************************************/
-import QtQuick 2.0
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
-FocusScope {
- width: input.x + input.width
- height: border.height
+#include <QMainWindow>
+#include <QtQuick/QQuickView>
+#include "ui_properties.h"
+#include "ui_import.h"
- property alias name: name.text
- property alias text: input.text
+class SplineEditor;
- Text {
- id: name
- height: parent.height
- }
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+public:
+ explicit MainWindow(QWidget *parent = 0);
- TextInput {
- id: input
- anchors.left: name.right
- anchors.leftMargin: 4
- focus: true
- width: 50
- horizontalAlignment: "AlignRight"
- Rectangle {
- id: border
- x: -2; y: -2
- width: parent.width + 4
- height: parent.height + 4
- color: "transparent"
- border.color: input.activeFocus?"green":"lightgreen"
+ void showQuickView();
- border.width: 3
- radius: 5
- }
- }
-}
+signals:
+public slots:
+ void textEditTextChanged();
+ void importData(int result);
+
+protected:
+ virtual void moveEvent(QMoveEvent *event);
+ virtual void resizeEvent(QResizeEvent *event);
+ virtual void closeEvent(QCloseEvent *event);
+ void initQml();
+
+private:
+ QQuickView quickView;
+ QWidget *m_placeholder;
+ Ui_Properties ui_properties;
+ Ui_ImportDialog ui_import;
+ SplineEditor *m_splineEditor;
+
+};
+
+#endif // MAINWINDOW_H
diff --git a/tools/qmleasing/pane.ui b/tools/qmleasing/pane.ui
new file mode 100644
index 0000000000..1500589192
--- /dev/null
+++ b/tools/qmleasing/pane.ui
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Pane</class>
+ <widget class="QWidget" name="Pane">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>416</width>
+ <height>47</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="font">
+ <font>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>p1</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QWidget" name="widget" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="spacing">
+ <number>4</number>
+ </property>
+ <property name="margin">
+ <number>2</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label_x">
+ <property name="text">
+ <string>x</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDoubleSpinBox" name="p1_x">
+ <property name="decimals">
+ <number>4</number>
+ </property>
+ <property name="singleStep">
+ <double>0.010000000000000</double>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_y">
+ <property name="text">
+ <string>y</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDoubleSpinBox" name="p1_y">
+ <property name="decimals">
+ <number>4</number>
+ </property>
+ <property name="minimum">
+ <double>-10.000000000000000</double>
+ </property>
+ <property name="maximum">
+ <double>10.000000000000000</double>
+ </property>
+ <property name="singleStep">
+ <double>0.010000000000000</double>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QCheckBox" name="smooth">
+ <property name="text">
+ <string>smooth</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="3" alignment="Qt::AlignVCenter">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>99</width>
+ <height>10</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/tools/qmleasing/preview.qml b/tools/qmleasing/preview.qml
new file mode 100644
index 0000000000..7194b1e0e0
--- /dev/null
+++ b/tools/qmleasing/preview.qml
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+
+Item {
+ id: root
+ width: 800
+ height: 100
+
+ Rectangle {
+ gradient: Gradient {
+ GradientStop {
+ position: 0
+ color: "#aaa7a7"
+ }
+
+ GradientStop {
+ position: 0.340
+ color: "#a4a4a4"
+ }
+
+ GradientStop {
+ position: 1
+ color: "#6b6b6b"
+ }
+ }
+ anchors.fill: parent
+ }
+
+ Button {
+ id: button
+
+ x: 19
+ y: 20
+ width: 133
+ height: 61
+ onClicked: {
+ if (root.state ==="")
+ root.state = "moved";
+ else
+ root.state = "";
+ }
+ }
+
+ Rectangle {
+ id: groove
+ x: 163
+ y: 20
+ width: 622
+ height: 61
+ color: "#919191"
+ radius: 4
+ border.color: "#adadad"
+
+ Rectangle {
+ id: rectangle
+ x: 9
+ y: 9
+ width: 46
+ height: 46
+ color: "#3045b7"
+ radius: 4
+ border.width: 2
+ smooth: true
+ border.color: "#9ea0bb"
+ anchors.bottomMargin: 6
+ anchors.topMargin: 9
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ }
+ }
+ states: [
+ State {
+ name: "moved"
+
+ PropertyChanges {
+ target: rectangle
+ x: 567
+ y: 9
+ anchors.bottomMargin: 6
+ anchors.topMargin: 9
+ }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ from: ""
+ to: "moved"
+ SequentialAnimation {
+ PropertyAnimation {
+ easing: editor.easingCurve
+ property: "x"
+ duration: spinBox.value
+ }
+ }
+ },
+ Transition {
+ from: "moved"
+ to: ""
+ PropertyAnimation {
+ easing: editor.easingCurve
+ property: "x"
+ duration: spinBox.value
+ }
+
+ }
+ ]
+}
diff --git a/tools/qmleasing/properties.ui b/tools/qmleasing/properties.ui
new file mode 100644
index 0000000000..ea28df33ac
--- /dev/null
+++ b/tools/qmleasing/properties.ui
@@ -0,0 +1,138 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Properties</class>
+ <widget class="QWidget" name="Properties">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>487</width>
+ <height>627</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="2">
+ <spacer name="spacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>13</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Duration</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" colspan="2">
+ <widget class="QSpinBox" name="spinBox"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Code</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" colspan="2">
+ <widget class="QPlainTextEdit" name="plainTextEdit">
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>128</height>
+ </size>
+ </property>
+ <property name="readOnly">
+ <bool>false</bool>
+ </property>
+ <property name="plainText">
+ <string notr="true"/>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Presets</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" colspan="2">
+ <widget class="QComboBox" name="comboBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="1">
+ <spacer name="spacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="9" column="0" colspan="3">
+ <widget class="QGroupBox" name="groupBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>400</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="title">
+ <string>Control Points</string>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0" colspan="3">
+ <widget class="QPushButton" name="importButton">
+ <property name="text">
+ <string>Import AfterEffects Curve</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/tools/qmleasing/qmleasing.pro b/tools/qmleasing/qmleasing.pro
index b43071c4ed..eadcb304c4 100644
--- a/tools/qmleasing/qmleasing.pro
+++ b/tools/qmleasing/qmleasing.pro
@@ -1,6 +1,19 @@
-QT += qml quick
+QT += qml quick widgets
CONFIG -= app_bundle
-SOURCES += main.cpp
+SOURCES += main.cpp \
+ splineeditor.cpp \
+ mainwindow.cpp \
+ segmentproperties.cpp
RESOURCES = $$PWD/resources.qrc
+
+HEADERS += \
+ splineeditor.h \
+ mainwindow.h \
+ segmentproperties.h
+
+FORMS += \
+ properties.ui \
+ pane.ui \
+ import.ui
diff --git a/tools/qmleasing/resources.qrc b/tools/qmleasing/resources.qrc
index c7a67b838c..c184af4662 100644
--- a/tools/qmleasing/resources.qrc
+++ b/tools/qmleasing/resources.qrc
@@ -1,6 +1,6 @@
<RCC>
<qresource prefix="/">
- <file>easing.qml</file>
- <file>TextField.qml</file>
+ <file>preview.qml</file>
+ <file>Button.qml</file>
</qresource>
</RCC>
diff --git a/tools/qmleasing/segmentproperties.cpp b/tools/qmleasing/segmentproperties.cpp
new file mode 100644
index 0000000000..8dff50e8a5
--- /dev/null
+++ b/tools/qmleasing/segmentproperties.cpp
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "segmentproperties.h"
+#include "splineeditor.h"
+
+SegmentProperties::SegmentProperties(QWidget *parent) :
+ QWidget(parent), m_splineEditor(0), m_blockSignals(false)
+{
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ layout->setMargin(0);
+ layout->setSpacing(2);
+ setLayout(layout);
+ {
+ QWidget *widget = new QWidget(this);
+ m_ui_pane_c1.setupUi(widget);
+ m_ui_pane_c1.label->setText("c1");
+ m_ui_pane_c1.smooth->setVisible(false);
+ layout->addWidget(widget);
+
+ connect(m_ui_pane_c1.p1_x, SIGNAL(valueChanged(double)), this, SLOT(c1Updated()));
+ connect(m_ui_pane_c1.p1_y, SIGNAL(valueChanged(double)), this, SLOT(c1Updated()));
+ }
+ {
+ QWidget *widget = new QWidget(this);
+ m_ui_pane_c2.setupUi(widget);
+ m_ui_pane_c2.label->setText("c2");
+ m_ui_pane_c2.smooth->setVisible(false);
+ layout->addWidget(widget);
+
+ connect(m_ui_pane_c2.p1_x, SIGNAL(valueChanged(double)), this, SLOT(c2Updated()));
+ connect(m_ui_pane_c2.p1_y, SIGNAL(valueChanged(double)), this, SLOT(c2Updated()));
+ }
+ {
+ QWidget *widget = new QWidget(this);
+ m_ui_pane_p.setupUi(widget);
+ m_ui_pane_p.label->setText("p1");
+ layout->addWidget(widget);
+
+ connect(m_ui_pane_p.smooth, SIGNAL(toggled(bool)), this, SLOT(pUpdated()));
+ connect(m_ui_pane_p.p1_x, SIGNAL(valueChanged(double)), this, SLOT(pUpdated()));
+ connect(m_ui_pane_p.p1_y, SIGNAL(valueChanged(double)), this, SLOT(pUpdated()));
+ }
+}
+
+void SegmentProperties::c1Updated()
+{
+ if (m_splineEditor && !m_blockSignals) {
+ QPointF c1(m_ui_pane_c1.p1_x->value(), m_ui_pane_c1.p1_y->value());
+ m_splineEditor->setControlPoint(m_segment * 3, c1);
+ }
+}
+
+void SegmentProperties::c2Updated()
+{
+ if (m_splineEditor && !m_blockSignals) {
+ QPointF c2(m_ui_pane_c2.p1_x->value(), m_ui_pane_c2.p1_y->value());
+ m_splineEditor->setControlPoint(m_segment * 3 + 1, c2);
+ }
+}
+
+void SegmentProperties::pUpdated()
+{
+ if (m_splineEditor && !m_blockSignals) {
+ QPointF p(m_ui_pane_p.p1_x->value(), m_ui_pane_p.p1_y->value());
+ bool smooth = m_ui_pane_p.smooth->isChecked();
+ m_splineEditor->setControlPoint(m_segment * 3 + 2, p);
+ m_splineEditor->setSmooth(m_segment, smooth);
+ }
+}
+
+void SegmentProperties::invalidate()
+{
+ m_blockSignals = true;
+
+ m_ui_pane_p.label->setText(QLatin1String("p") + QString::number(m_segment));
+ m_ui_pane_p.smooth->setChecked(m_smooth);
+ m_ui_pane_p.smooth->parentWidget()->setEnabled(!m_last);
+
+ m_ui_pane_c1.p1_x->setValue(m_points.at(0).x());
+ m_ui_pane_c1.p1_y->setValue(m_points.at(0).y());
+
+ m_ui_pane_c2.p1_x->setValue(m_points.at(1).x());
+ m_ui_pane_c2.p1_y->setValue(m_points.at(1).y());
+
+ m_ui_pane_p.p1_x->setValue(m_points.at(2).x());
+ m_ui_pane_p.p1_y->setValue(m_points.at(2).y());
+
+ m_blockSignals = false;
+}
diff --git a/tools/qmleasing/segmentproperties.h b/tools/qmleasing/segmentproperties.h
new file mode 100644
index 0000000000..8e6701245e
--- /dev/null
+++ b/tools/qmleasing/segmentproperties.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SEGMENTPROPERTIES_H
+#define SEGMENTPROPERTIES_H
+
+#include <QWidget>
+#include <ui_pane.h>
+
+class SplineEditor;
+
+class SegmentProperties : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit SegmentProperties(QWidget *parent = 0);
+ void setSplineEditor(SplineEditor *splineEditor)
+ {
+ m_splineEditor = splineEditor;
+ }
+
+ void setSegment(int segment, QVector<QPointF> points, bool smooth, bool last)
+ {
+ m_segment = segment;
+ m_points = points;
+ m_smooth = smooth;
+ m_last = last;
+ invalidate();
+ }
+
+signals:
+
+public slots:
+
+private slots:
+ void c1Updated();
+ void c2Updated();
+ void pUpdated();
+
+private:
+ void invalidate();
+
+ Ui_Pane m_ui_pane_c1;
+ Ui_Pane m_ui_pane_c2;
+ Ui_Pane m_ui_pane_p;
+
+ SplineEditor *m_splineEditor;
+ QVector<QPointF> m_points;
+ int m_segment;
+ bool m_smooth;
+ bool m_last;
+
+ bool m_blockSignals;
+};
+
+#endif // SEGMENTPROPERTIES_H
diff --git a/tools/qmleasing/splineeditor.cpp b/tools/qmleasing/splineeditor.cpp
new file mode 100644
index 0000000000..5d1ee8bd31
--- /dev/null
+++ b/tools/qmleasing/splineeditor.cpp
@@ -0,0 +1,714 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "splineeditor.h"
+#include "segmentproperties.h"
+
+#include <QPainter>
+#include <QMouseEvent>
+#include <QContextMenuEvent>
+#include <QDebug>
+#include <QApplication>
+
+const int canvasWidth = 640;
+const int canvasHeight = 320;
+
+const int canvasMargin = 160;
+
+SplineEditor::SplineEditor(QWidget *parent) :
+ QWidget(parent), m_pointListWidget(0), m_block(false)
+{
+ setFixedSize(canvasWidth + canvasMargin * 2, canvasHeight + canvasMargin * 2);
+
+ m_controlPoints.append(QPointF(0.4, 0.075));
+ m_controlPoints.append(QPointF(0.45,0.24));
+ m_controlPoints.append(QPointF(0.5,0.5));
+
+ m_controlPoints.append(QPointF(0.55,0.76));
+ m_controlPoints.append(QPointF(0.7,0.9));
+ m_controlPoints.append(QPointF(1.0, 1.0));
+
+ m_numberOfSegments = 2;
+
+ m_activeControlPoint = -1;
+
+ m_mouseDrag = false;
+
+ m_pointContextMenu = new QMenu(this);
+ m_deleteAction = new QAction(tr("Delete point"), m_pointContextMenu);
+ m_smoothAction = new QAction(tr("Smooth point"), m_pointContextMenu);
+ m_cornerAction = new QAction(tr("Corner point"), m_pointContextMenu);
+
+ m_smoothAction->setCheckable(true);
+
+ m_pointContextMenu->addAction(m_deleteAction);
+ m_pointContextMenu->addAction(m_smoothAction);
+ m_pointContextMenu->addAction(m_cornerAction);
+
+ m_curveContextMenu = new QMenu(this);
+
+ m_addPoint = new QAction(tr("Add point"), m_pointContextMenu);
+
+ m_curveContextMenu->addAction(m_addPoint);
+
+ initPresets();
+
+ invalidateSmoothList();
+}
+
+static inline QPointF mapToCanvas(const QPointF &point)
+{
+ return QPointF(point.x() * canvasWidth + canvasMargin,
+ canvasHeight - point.y() * canvasHeight + canvasMargin);
+}
+
+static inline QPointF mapFromCanvas(const QPointF &point)
+{
+ return QPointF((point.x() - canvasMargin) / canvasWidth ,
+ 1 - (point.y() - canvasMargin) / canvasHeight);
+}
+
+static inline void paintControlPoint(const QPointF &controlPoint, QPainter *painter, bool edit,
+ bool realPoint, bool active, bool smooth)
+{
+ int pointSize = 4;
+
+ if (active)
+ painter->setBrush(QColor(140, 140, 240, 255));
+ else
+ painter->setBrush(QColor(120, 120, 220, 255));
+
+ if (realPoint) {
+ pointSize = 6;
+ painter->setBrush(QColor(80, 80, 210, 150));
+ }
+
+ painter->setPen(QColor(50, 50, 50, 140));
+
+ if (!edit)
+ painter->setBrush(QColor(160, 80, 80, 250));
+
+ if (smooth) {
+ painter->drawEllipse(QRectF(mapToCanvas(controlPoint).x() - pointSize + 0.5,
+ mapToCanvas(controlPoint).y() - pointSize + 0.5,
+ pointSize * 2, pointSize * 2));
+ } else {
+ painter->drawRect(QRectF(mapToCanvas(controlPoint).x() - pointSize + 0.5,
+ mapToCanvas(controlPoint).y() - pointSize + 0.5,
+ pointSize * 2, pointSize * 2));
+ }
+}
+
+static inline bool indexIsRealPoint(int i)
+{
+ return !((i + 1) % 3);
+}
+
+static inline int pointForControlPoint(int i)
+{
+ if ((i % 3) == 0)
+ return i - 1;
+
+ if ((i % 3) == 1)
+ return i + 1;
+
+ return i;
+}
+
+void drawCleanLine(QPainter *painter, const QPoint p1, QPoint p2)
+{
+ painter->drawLine(p1 + QPointF(0.5 , 0.5), p2 + QPointF(0.5, 0.5));
+}
+
+void SplineEditor::paintEvent(QPaintEvent *)
+{
+ QPainter painter(this);
+
+ QPen pen(Qt::black);
+ pen.setWidth(1);
+ painter.fillRect(0,0,width() - 1, height() - 1, QBrush(Qt::white));
+ painter.drawRect(0,0,width() - 1, height() - 1);
+
+ painter.setRenderHint(QPainter::Antialiasing);
+
+ pen = QPen(Qt::gray);
+ pen.setWidth(1);
+ pen.setStyle(Qt::DashLine);
+ painter.setPen(pen);
+ drawCleanLine(&painter,mapToCanvas(QPoint(0, 0)).toPoint(), mapToCanvas(QPoint(1, 0)).toPoint());
+ drawCleanLine(&painter,mapToCanvas(QPoint(0, 1)).toPoint(), mapToCanvas(QPoint(1, 1)).toPoint());
+
+ for (int i = 0; i < m_numberOfSegments; i++) {
+ QPainterPath path;
+ QPointF p0;
+
+ if (i == 0)
+ p0 = mapToCanvas(QPointF(0.0, 0.0));
+ else
+ p0 = mapToCanvas(m_controlPoints.at(i * 3 - 1));
+
+ path.moveTo(p0);
+
+ QPointF p1 = mapToCanvas(m_controlPoints.at(i * 3));
+ QPointF p2 = mapToCanvas(m_controlPoints.at(i * 3 + 1));
+ QPointF p3 = mapToCanvas(m_controlPoints.at(i * 3 + 2));
+ path.cubicTo(p1, p2, p3);
+ painter.strokePath(path, QPen(QBrush(Qt::black), 2));
+
+ QPen pen(Qt::black);
+ pen.setWidth(1);
+ pen.setStyle(Qt::DashLine);
+ painter.setPen(pen);
+ painter.drawLine(p0, p1);
+ painter.drawLine(p3, p2);
+ }
+
+ paintControlPoint(QPointF(0.0, 0.0), &painter, false, true, false, false);
+ paintControlPoint(QPointF(1.0, 1.0), &painter, false, true, false, false);
+
+ for (int i = 0; i < m_controlPoints.count() - 1; ++i)
+ paintControlPoint(m_controlPoints.at(i),
+ &painter,
+ true,
+ indexIsRealPoint(i),
+ i == m_activeControlPoint,
+ isControlPointSmooth(i));
+}
+
+void SplineEditor::mousePressEvent(QMouseEvent *e)
+{
+ if (e->button() == Qt::LeftButton) {
+ m_activeControlPoint = findControlPoint(e->pos());
+
+ if (m_activeControlPoint != -1) {
+ mouseMoveEvent(e);
+ }
+ m_mousePress = e->pos();
+ e->accept();
+ }
+}
+
+void SplineEditor::mouseReleaseEvent(QMouseEvent *e)
+{
+ if (e->button() == Qt::LeftButton) {
+ m_activeControlPoint = -1;
+
+ m_mouseDrag = false;
+ e->accept();
+ }
+}
+
+void SplineEditor::contextMenuEvent(QContextMenuEvent *e)
+{
+ int index = findControlPoint(e->pos());
+
+ if (index > 0 && indexIsRealPoint(index)) {
+ m_smoothAction->setChecked(isControlPointSmooth(index));
+ QAction* action = m_pointContextMenu->exec(e->globalPos());
+ if (action == m_deleteAction)
+ deletePoint(index);
+ else if (action == m_smoothAction)
+ smoothPoint(index);
+ else if (action == m_cornerAction)
+ cornerPoint(index);
+ } else {
+ QAction* action = m_curveContextMenu->exec(e->globalPos());
+ if (action == m_addPoint)
+ addPoint(e->pos());
+ }
+}
+
+void SplineEditor::invalidate()
+{
+ QEasingCurve easingCurve(QEasingCurve::BezierSpline);
+
+ for (int i = 0; i < m_numberOfSegments; ++i) {
+ easingCurve.addCubicBezierSegment(m_controlPoints.at(i * 3),
+ m_controlPoints.at(i * 3 + 1),
+ m_controlPoints.at(i * 3 + 2));
+ }
+ setEasingCurve(easingCurve);
+ invalidateSegmentProperties();
+}
+
+void SplineEditor::invalidateSmoothList()
+{
+ m_smoothList.clear();
+
+ for (int i = 0; i < (m_numberOfSegments - 1); ++i)
+ m_smoothList.append(isSmooth(i * 3 + 2));
+
+}
+
+void SplineEditor::invalidateSegmentProperties()
+{
+ for (int i = 0; i < m_numberOfSegments; ++i) {
+ SegmentProperties *segmentProperties = m_segmentProperties.at(i);
+ bool smooth = false;
+ if (i < (m_numberOfSegments - 1)) {
+ smooth = m_smoothList.at(i);
+ }
+ segmentProperties->setSegment(i, m_controlPoints.mid(i * 3, 3), smooth, i == (m_numberOfSegments - 1));
+ }
+}
+
+QHash<QString, QEasingCurve> SplineEditor::presets() const
+{
+ return m_presets;
+}
+
+QString SplineEditor::generateCode()
+{
+ QString s = QLatin1String("[");
+ foreach (const QPointF &point, m_controlPoints) {
+ s += QString::number(point.x(), 'g', 2) + "," + QString::number(point.y(), 'g', 3) + ",";
+ }
+ s.chop(1); //removing last ","
+ s += "]";
+
+ return s;
+}
+
+QStringList SplineEditor::presetNames() const
+{
+ return m_presets.keys();
+}
+
+QWidget *SplineEditor::pointListWidget()
+{
+ if (!m_pointListWidget) {
+ setupPointListWidget();
+ }
+
+ return m_pointListWidget;
+}
+
+int SplineEditor::findControlPoint(const QPoint &point)
+{
+ int pointIndex = -1;
+ qreal distance = -1;
+ for (int i = 0; i<m_controlPoints.size() - 1; ++i) {
+ qreal d = QLineF(point, mapToCanvas(m_controlPoints.at(i))).length();
+ if ((distance < 0 && d < 10) || d < distance) {
+ distance = d;
+ pointIndex = i;
+ }
+ }
+ return pointIndex;
+}
+
+static inline bool veryFuzzyCompare(qreal r1, qreal r2)
+{
+ if (qFuzzyCompare(r1, 2))
+ return true;
+
+ int r1i = qRound(r1 * 20);
+ int r2i = qRound(r2 * 20);
+
+ if (qFuzzyCompare(qreal(r1i) / 20, qreal(r2i) / 20))
+ return true;
+
+ return false;
+}
+
+bool SplineEditor::isSmooth(int i) const
+{
+ if (i == 0)
+ return false;
+
+ QPointF p = m_controlPoints.at(i);
+ QPointF p_before = m_controlPoints.at(i - 1);
+ QPointF p_after = m_controlPoints.at(i + 1);
+
+ QPointF v1 = p_after - p;
+ v1 = v1 / v1.manhattanLength(); //normalize
+
+ QPointF v2 = p - p_before;
+ v2 = v2 / v2.manhattanLength(); //normalize
+
+ return veryFuzzyCompare(v1.x(), v2.x()) && veryFuzzyCompare(v1.y(), v2.y());
+}
+
+void SplineEditor::smoothPoint(int index)
+{
+ if (m_smoothAction->isChecked()) {
+
+ QPointF before = QPointF(0,0);
+ if (index > 3)
+ before = m_controlPoints.at(index - 3);
+
+ QPointF after = QPointF(1.0, 1.0);
+ if ((index + 3) < m_controlPoints.count())
+ after = m_controlPoints.at(index + 3);
+
+ QPointF tangent = (after - before) / 6;
+
+ QPointF thisPoint = m_controlPoints.at(index);
+
+ if (index > 0)
+ m_controlPoints[index - 1] = thisPoint - tangent;
+
+ if (index + 1 < m_controlPoints.count())
+ m_controlPoints[index + 1] = thisPoint + tangent;
+
+ m_smoothList[index / 3] = true;
+ } else {
+ m_smoothList[index / 3] = false;
+ }
+ invalidate();
+ update();
+}
+
+void SplineEditor::cornerPoint(int index)
+{
+ QPointF before = QPointF(0,0);
+ if (index > 3)
+ before = m_controlPoints.at(index - 3);
+
+ QPointF after = QPointF(1.0, 1.0);
+ if ((index + 3) < m_controlPoints.count())
+ after = m_controlPoints.at(index + 3);
+
+ QPointF thisPoint = m_controlPoints.at(index);
+
+ if (index > 0)
+ m_controlPoints[index - 1] = (before - thisPoint) / 3 + thisPoint;
+
+ if (index + 1 < m_controlPoints.count())
+ m_controlPoints[index + 1] = (after - thisPoint) / 3 + thisPoint;
+
+ m_smoothList[(index) / 3] = false;
+ invalidate();
+}
+
+void SplineEditor::deletePoint(int index)
+{
+ m_controlPoints.remove(index - 1, 3);
+ m_numberOfSegments--;
+
+ invalidateSmoothList();
+ setupPointListWidget();
+ invalidate();
+}
+
+void SplineEditor::addPoint(const QPointF point)
+{
+ QPointF newPos = mapFromCanvas(point);
+ int splitIndex = 0;
+ for (int i=0; i < m_controlPoints.size() - 1; ++i) {
+ if (indexIsRealPoint(i) && m_controlPoints.at(i).x() > newPos.x()) {
+ break;
+ } else if (indexIsRealPoint(i))
+ splitIndex = i;
+ }
+ QPointF before = QPointF(0,0);
+ if (splitIndex > 0)
+ before = m_controlPoints.at(splitIndex);
+
+ QPointF after = QPointF(1.0, 1.0);
+ if ((splitIndex + 3) < m_controlPoints.count())
+ after = m_controlPoints.at(splitIndex + 3);
+
+ if (splitIndex > 0) {
+ m_controlPoints.insert(splitIndex + 2, (newPos + after) / 2);
+ m_controlPoints.insert(splitIndex + 2, newPos);
+ m_controlPoints.insert(splitIndex + 2, (newPos + before) / 2);
+ } else {
+ m_controlPoints.insert(splitIndex + 1, (newPos + after) / 2);
+ m_controlPoints.insert(splitIndex + 1, newPos);
+ m_controlPoints.insert(splitIndex + 1, (newPos + before) / 2);
+ }
+ m_numberOfSegments++;
+
+ invalidateSmoothList();
+ setupPointListWidget();
+ invalidate();
+}
+
+void SplineEditor::initPresets()
+{
+ const QPointF endPoint(1.0, 1.0);
+ {
+ QEasingCurve easingCurve(QEasingCurve::BezierSpline);
+ easingCurve.addCubicBezierSegment(QPointF(0.4, 0.075), QPointF(0.45, 0.24), QPointF(0.5, 0.5));
+ easingCurve.addCubicBezierSegment(QPointF(0.55, 0.76), QPointF(0.7, 0.9), endPoint);
+ m_presets.insert(tr("Standard Easing"), easingCurve);
+ }
+
+ {
+ QEasingCurve easingCurve(QEasingCurve::BezierSpline);
+ easingCurve.addCubicBezierSegment(QPointF(0.43, 0.0025), QPointF(0.65, 1), endPoint);
+ m_presets.insert(tr("Simple"), easingCurve);
+ }
+
+ {
+ QEasingCurve easingCurve(QEasingCurve::BezierSpline);
+ easingCurve.addCubicBezierSegment(QPointF(0.43, 0.0025), QPointF(0.38, 0.51), QPointF(0.57, 0.99));
+ easingCurve.addCubicBezierSegment(QPointF(0.8, 0.69), QPointF(0.65, 1), endPoint);
+ m_presets.insert(tr("Simple Bounce"), easingCurve);
+ }
+
+ {
+ QEasingCurve easingCurve(QEasingCurve::BezierSpline);
+ easingCurve.addCubicBezierSegment(QPointF(0.4, 0.075), QPointF(0.64, -0.0025), QPointF(0.74, 0.23));
+ easingCurve.addCubicBezierSegment(QPointF(0.84, 0.46), QPointF(0.91, 0.77), endPoint);
+ m_presets.insert(tr("Slow in fast out"), easingCurve);
+ }
+
+ {
+ QEasingCurve easingCurve(QEasingCurve::BezierSpline);
+ easingCurve.addCubicBezierSegment(QPointF(0.43, 0.0025), QPointF(0.47, 0.51), QPointF(0.59, 0.94));
+ easingCurve.addCubicBezierSegment(QPointF(0.84, 0.95), QPointF( 0.99, 0.94), endPoint);
+ m_presets.insert(tr("Snapping"), easingCurve);
+ }
+
+ {
+ QEasingCurve easingCurve(QEasingCurve::BezierSpline);
+ easingCurve.addCubicBezierSegment(QPointF( 0.38, 0.35),QPointF(0.38, 0.7), QPointF(0.45, 0.99));
+ easingCurve.addCubicBezierSegment(QPointF(0.48, 0.66), QPointF(0.62, 0.62), QPointF(0.66, 0.99));
+ easingCurve.addCubicBezierSegment(QPointF(0.69, 0.76), QPointF(0.77, 0.76), QPointF(0.79, 0.99));
+ easingCurve.addCubicBezierSegment(QPointF(0.83, 0.91), QPointF(0.87, 0.92), QPointF(0.91, 0.99));
+ easingCurve.addCubicBezierSegment(QPointF(0.95, 0.95), QPointF(0.97, 0.94), endPoint);
+ m_presets.insert(tr("Complex Bounce"), easingCurve);
+ }
+
+ {
+ QEasingCurve easingCurve4(QEasingCurve::BezierSpline);
+ easingCurve4.addCubicBezierSegment(QPointF(0.12, -0.12),QPointF(0.23, -0.19), QPointF( 0.35, -0.09));
+ easingCurve4.addCubicBezierSegment(QPointF(0.47, 0.005), QPointF(0.52, 1), QPointF(0.62, 1.1));
+ easingCurve4.addCubicBezierSegment(QPointF(0.73, 1.2), QPointF(0.91,1 ), endPoint);
+ m_presets.insert(tr("Overshoot"), easingCurve4);
+ }
+}
+
+void SplineEditor::setupPointListWidget()
+{
+ if (!m_pointListWidget)
+ m_pointListWidget = new QScrollArea(this);
+
+ if (m_pointListWidget->widget())
+ delete m_pointListWidget->widget();
+
+ m_pointListWidget->setFrameStyle(QFrame::NoFrame);
+ m_pointListWidget->setWidgetResizable(true);
+ m_pointListWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+
+ m_pointListWidget->setWidget(new QWidget(m_pointListWidget));
+ QVBoxLayout *layout = new QVBoxLayout(m_pointListWidget->widget());
+ layout->setMargin(0);
+ layout->setSpacing(2);
+ m_pointListWidget->widget()->setLayout(layout);
+
+ m_segmentProperties.clear();
+
+ { //implicit 0,0
+ QWidget *widget = new QWidget(m_pointListWidget->widget());
+ Ui_Pane pane;
+ pane.setupUi(widget);
+ pane.p1_x->setValue(0);
+ pane.p1_y->setValue(0);
+ layout->addWidget(widget);
+ pane.label->setText("p0");
+ widget->setEnabled(false);
+ }
+
+ for (int i = 0; i < m_numberOfSegments; ++i) {
+ SegmentProperties *segmentProperties = new SegmentProperties(m_pointListWidget->widget());
+ layout->addWidget(segmentProperties);
+ bool smooth = false;
+ if (i < (m_numberOfSegments - 1)) {
+ smooth = m_smoothList.at(i);
+ }
+ segmentProperties->setSegment(i, m_controlPoints.mid(i * 3, 3), smooth, i == (m_numberOfSegments - 1));
+ segmentProperties->setSplineEditor(this);
+ m_segmentProperties << segmentProperties;
+ }
+ layout->addSpacerItem(new QSpacerItem(10, 10, QSizePolicy::Expanding, QSizePolicy::Expanding));
+
+ m_pointListWidget->viewport()->show();
+ m_pointListWidget->viewport()->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ m_pointListWidget->show();
+}
+
+bool SplineEditor::isControlPointSmooth(int i) const
+{
+ if (i == 0)
+ return false;
+
+ if (i == m_controlPoints.count() - 1)
+ return false;
+
+ if (m_numberOfSegments == 1)
+ return false;
+
+ int index = pointForControlPoint(i);
+
+ if (index == 0)
+ return false;
+
+ if (index == m_controlPoints.count() - 1)
+ return false;
+
+ return m_smoothList.at(index / 3);
+}
+
+QPointF limitToCanvas(const QPointF point)
+{
+ qreal left = -qreal( canvasMargin) / qreal(canvasWidth);
+ qreal width = 1.0 - 2.0 * left;
+
+ qreal top = -qreal( canvasMargin) / qreal(canvasHeight);
+ qreal height = 1.0 - 2.0 * top;
+
+ QPointF p = point;
+ QRectF r(left, top, width, height);
+
+ if (p.x() > r.right()) {
+ p.setX(r.right());
+ }
+ if (p.x() < r.left()) {
+ p.setX(r.left());
+ }
+ if (p.y() < r.top()) {
+ p.setY(r.top());
+ }
+ if (p.y() > r.bottom()) {
+ p.setY(r.bottom());
+ }
+ return p;
+}
+
+void SplineEditor::mouseMoveEvent(QMouseEvent *e)
+{
+ // If we've moved more then 25 pixels, assume user is dragging
+ if (!m_mouseDrag && QPoint(m_mousePress - e->pos()).manhattanLength() > qApp->startDragDistance())
+ m_mouseDrag = true;
+
+ QPointF p = mapFromCanvas(e->pos());
+
+ if (m_mouseDrag && m_activeControlPoint >= 0 && m_activeControlPoint < m_controlPoints.size()) {
+ p = limitToCanvas(p);
+ if (indexIsRealPoint(m_activeControlPoint)) {
+ //move also the tangents
+ QPointF targetPoint = p;
+ QPointF distance = targetPoint - m_controlPoints[m_activeControlPoint];
+ m_controlPoints[m_activeControlPoint] = targetPoint;
+ m_controlPoints[m_activeControlPoint - 1] += distance;
+ m_controlPoints[m_activeControlPoint + 1] += distance;
+ } else {
+ if (!isControlPointSmooth(m_activeControlPoint)) {
+ m_controlPoints[m_activeControlPoint] = p;
+ } else {
+ QPointF targetPoint = p;
+ QPointF distance = targetPoint - m_controlPoints[m_activeControlPoint];
+ m_controlPoints[m_activeControlPoint] = p;
+
+ if ((m_activeControlPoint > 1) && (m_activeControlPoint % 3) == 0) { //right control point
+ m_controlPoints[m_activeControlPoint - 2] -= distance;
+ } else if ((m_activeControlPoint < (m_controlPoints.count() - 2)) //left control point
+ && (m_activeControlPoint % 3) == 1) {
+ m_controlPoints[m_activeControlPoint + 2] -= distance;
+ }
+ }
+ }
+ invalidate();
+ }
+}
+
+void SplineEditor::setEasingCurve(const QEasingCurve &easingCurve)
+{
+ if (m_easingCurve == easingCurve)
+ return;
+ m_block = true;
+ m_easingCurve = easingCurve;
+ m_controlPoints = m_easingCurve.toCubicSpline();
+ m_numberOfSegments = m_controlPoints.count() / 3;
+ update();
+ emit easingCurveChanged();
+
+ const QString code = generateCode();
+ emit easingCurveCodeChanged(code);
+
+ m_block = false;
+}
+
+void SplineEditor::setPreset(const QString &name)
+{
+ setEasingCurve(m_presets.value(name));
+ invalidateSmoothList();
+ setupPointListWidget();
+}
+
+void SplineEditor::setEasingCurve(const QString &code)
+{
+ if (m_block)
+ return;
+ if (code.left(1) == QLatin1String("[") && code.right(1) == QLatin1String("]")) {
+ QString cleanCode = code;
+ cleanCode.remove(0, 1);
+ cleanCode.chop(1);
+ const QStringList stringList = cleanCode.split(QLatin1Char(','), QString::SkipEmptyParts);
+ if (stringList.count() >= 6 && (stringList.count() % 6 == 0)) {
+ QList<qreal> realList;
+ foreach (const QString &string, stringList) {
+ bool ok;
+ realList.append(string.toDouble(&ok));
+ if (!ok)
+ return;
+ }
+ QList<QPointF> points;
+ for (int i = 0; i < realList.count() / 2; ++i)
+ points.append(QPointF(realList.at(i * 2), realList.at(i * 2 + 1)));
+ if (points.last() == QPointF(1.0, 1.0)) {
+ QEasingCurve easingCurve(QEasingCurve::BezierSpline);
+
+ for (int i = 0; i < points.count() / 3; ++i) {
+ easingCurve.addCubicBezierSegment(points.at(i * 3),
+ points.at(i * 3 + 1),
+ points.at(i * 3 + 2));
+ }
+ setEasingCurve(easingCurve);
+ invalidateSmoothList();
+ setupPointListWidget();
+ }
+ }
+ }
+}
diff --git a/tools/qmleasing/splineeditor.h b/tools/qmleasing/splineeditor.h
new file mode 100644
index 0000000000..301fa1c0d2
--- /dev/null
+++ b/tools/qmleasing/splineeditor.h
@@ -0,0 +1,143 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SPLINEEDITOR_H
+#define SPLINEEDITOR_H
+
+#include <QWidget>
+#include <QMenu>
+#include <QAction>
+#include <QScrollArea>
+
+#include <QEasingCurve>
+#include <QHash>
+
+class SegmentProperties;
+
+class SplineEditor : public QWidget
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QEasingCurve easingCurve READ easingCurve WRITE setEasingCurve NOTIFY easingCurveChanged);
+
+public:
+ explicit SplineEditor(QWidget *parent = 0);
+ QString generateCode();
+ QStringList presetNames() const;
+ QWidget *pointListWidget();
+
+ void setControlPoint(int index, const QPointF &point)
+ {
+ m_controlPoints[index] = point;
+ update();
+ }
+
+ void setSmooth(int index, bool smooth)
+ {
+ m_smoothAction->setChecked(smooth);
+ smoothPoint(index * 3 + 2);
+ //update();
+ }
+
+signals:
+ void easingCurveChanged();
+ void easingCurveCodeChanged(const QString &code);
+
+
+public slots:
+ void setEasingCurve(const QEasingCurve &easingCurve);
+ void setPreset(const QString &name);
+ void setEasingCurve(const QString &code);
+
+protected:
+ void paintEvent(QPaintEvent *);
+ void mousePressEvent(QMouseEvent *);
+ void mouseMoveEvent(QMouseEvent *);
+ void mouseReleaseEvent(QMouseEvent *);
+ void contextMenuEvent(QContextMenuEvent *);
+
+ void invalidate();
+ void invalidateSmoothList();
+ void invalidateSegmentProperties();
+
+ QEasingCurve easingCurve() const
+ { return m_easingCurve; }
+
+ QHash<QString, QEasingCurve> presets() const;
+
+private:
+ int findControlPoint(const QPoint &point);
+ bool isSmooth(int i) const;
+
+ void smoothPoint( int index);
+ void cornerPoint( int index);
+ void deletePoint(int index);
+ void addPoint(const QPointF point);
+
+ void initPresets();
+
+ void setupPointListWidget();
+
+ bool isControlPointSmooth(int i) const;
+
+ QEasingCurve m_easingCurve;
+ QVector<QPointF> m_controlPoints;
+ QVector<bool> m_smoothList;
+ int m_numberOfSegments;
+ int m_activeControlPoint;
+ bool m_mouseDrag;
+ QPoint m_mousePress;
+ QHash<QString, QEasingCurve> m_presets;
+
+ QMenu *m_pointContextMenu;
+ QMenu *m_curveContextMenu;
+ QAction *m_deleteAction;
+ QAction *m_smoothAction;
+ QAction *m_cornerAction;
+ QAction *m_addPoint;
+
+ QScrollArea *m_pointListWidget;
+
+ QList<SegmentProperties*> m_segmentProperties;
+ bool m_block;
+};
+
+#endif // SPLINEEDITOR_H