aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorThomas Hartmann <Thomas.Hartmann@nokia.com>2012-03-13 10:27:59 +0100
committerQt by Nokia <qt-info@nokia.com>2012-03-13 14:00:45 +0100
commita920803631d1788dc563f243a3780899d1ac2af2 (patch)
treee39c7e51da8e67d3fdd63873c660ace6c8ee585e /tools
parentc0f032de776685d62286e8a86496bc03fb9922c9 (diff)
Adding a custom easing curve editor to declarative tools
Change-Id: Ic8ef77792d74ec99b23d85cd8888e0190acc3e10 Reviewed-by: Thomas Hartmann <Thomas.Hartmann@nokia.com> Reviewed-by: Alessandro Portale <alessandro.portale@nokia.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/easingcurveeditor/Button.qml177
-rw-r--r--tools/easingcurveeditor/easingcurveeditor.pro25
-rw-r--r--tools/easingcurveeditor/main.cpp55
-rw-r--r--tools/easingcurveeditor/mainwindow.cpp136
-rw-r--r--tools/easingcurveeditor/mainwindow.h77
-rw-r--r--tools/easingcurveeditor/pane.ui112
-rw-r--r--tools/easingcurveeditor/preview.qml148
-rw-r--r--tools/easingcurveeditor/properties.ui131
-rw-r--r--tools/easingcurveeditor/resources.qrc6
-rw-r--r--tools/easingcurveeditor/segmentproperties.cpp128
-rw-r--r--tools/easingcurveeditor/segmentproperties.h94
-rw-r--r--tools/easingcurveeditor/splineeditor.cpp714
-rw-r--r--tools/easingcurveeditor/splineeditor.h143
-rw-r--r--tools/tools.pro2
14 files changed, 1947 insertions, 1 deletions
diff --git a/tools/easingcurveeditor/Button.qml b/tools/easingcurveeditor/Button.qml
new file mode 100644
index 0000000000..a47809a2d1
--- /dev/null
+++ b/tools/easingcurveeditor/Button.qml
@@ -0,0 +1,177 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $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/easingcurveeditor/easingcurveeditor.pro b/tools/easingcurveeditor/easingcurveeditor.pro
new file mode 100644
index 0000000000..0a266d0aee
--- /dev/null
+++ b/tools/easingcurveeditor/easingcurveeditor.pro
@@ -0,0 +1,25 @@
+TEMPLATE = app
+DEPENDPATH += .
+INCLUDEPATH += .
+
+QT += declarative quick widgets
+CONFIG -= app_bundle
+
+# Input
+SOURCES += main.cpp \
+ splineeditor.cpp \
+ mainwindow.cpp \
+ segmentproperties.cpp
+
+RESOURCES = $$PWD/resources.qrc
+
+HEADERS += \
+ splineeditor.h \
+ mainwindow.h \
+ ui_properties.h \
+ ui_pane.h \
+ segmentproperties.h
+
+FORMS += \
+ properties.ui \
+ pane.ui
diff --git a/tools/easingcurveeditor/main.cpp b/tools/easingcurveeditor/main.cpp
new file mode 100644
index 0000000000..05e8ace53a
--- /dev/null
+++ b/tools/easingcurveeditor/main.cpp
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QApplication>
+#include <mainwindow.h>
+
+
+int main(int argc, char ** argv)
+{
+ QApplication app(argc, argv);
+
+ MainWindow mainWindow;
+ mainWindow.show();
+ mainWindow.showQuickView();
+
+ return app.exec();
+}
diff --git a/tools/easingcurveeditor/mainwindow.cpp b/tools/easingcurveeditor/mainwindow.cpp
new file mode 100644
index 0000000000..569b74ae29
--- /dev/null
+++ b/tools/easingcurveeditor/mainwindow.cpp
@@ -0,0 +1,136 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "mainwindow.h"
+#include "splineeditor.h"
+#include <QtQuick/QQuickView>
+#include <QtQuick>
+#include <QtQml/QQmlContext>
+#include <QEasingCurve>
+#include <QHBoxLayout>
+#include <QVBoxLayout>
+
+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()));
+ initQml();
+}
+
+void MainWindow::showQuickView()
+{
+ const int margin = 16;
+ quickView.move(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.setWindowFlags(Qt::FramelessWindowHint);
+ quickView.rootContext()->setContextProperty(QLatin1String("editor"), m_splineEditor);
+ quickView.setSource(QUrl("qrc:/preview.qml"));
+ quickView.show();
+}
diff --git a/tools/easingcurveeditor/mainwindow.h b/tools/easingcurveeditor/mainwindow.h
new file mode 100644
index 0000000000..44591d33cc
--- /dev/null
+++ b/tools/easingcurveeditor/mainwindow.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+#include <QtQuick/QQuickView>
+#include "ui_properties.h"
+
+class SplineEditor;
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+public:
+ explicit MainWindow(QWidget *parent = 0);
+
+ void showQuickView();
+
+signals:
+
+public slots:
+ void textEditTextChanged();
+
+protected:
+ virtual void moveEvent(QMoveEvent *event);
+ virtual void resizeEvent(QResizeEvent *event);
+ void initQml();
+
+private:
+ QQuickView quickView;
+ QWidget *m_placeholder;
+ Ui_Properties ui_properties;
+ SplineEditor *m_splineEditor;
+
+};
+
+#endif // MAINWINDOW_H
diff --git a/tools/easingcurveeditor/pane.ui b/tools/easingcurveeditor/pane.ui
new file mode 100644
index 0000000000..1500589192
--- /dev/null
+++ b/tools/easingcurveeditor/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/easingcurveeditor/preview.qml b/tools/easingcurveeditor/preview.qml
new file mode 100644
index 0000000000..61f4862e76
--- /dev/null
+++ b/tools/easingcurveeditor/preview.qml
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $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/easingcurveeditor/properties.ui b/tools/easingcurveeditor/properties.ui
new file mode 100644
index 0000000000..af96e9c7a1
--- /dev/null
+++ b/tools/easingcurveeditor/properties.ui
@@ -0,0 +1,131 @@
+<?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="4" 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="5" 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>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/tools/easingcurveeditor/resources.qrc b/tools/easingcurveeditor/resources.qrc
new file mode 100644
index 0000000000..c184af4662
--- /dev/null
+++ b/tools/easingcurveeditor/resources.qrc
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource prefix="/">
+ <file>preview.qml</file>
+ <file>Button.qml</file>
+ </qresource>
+</RCC>
diff --git a/tools/easingcurveeditor/segmentproperties.cpp b/tools/easingcurveeditor/segmentproperties.cpp
new file mode 100644
index 0000000000..886d4636aa
--- /dev/null
+++ b/tools/easingcurveeditor/segmentproperties.cpp
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $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/easingcurveeditor/segmentproperties.h b/tools/easingcurveeditor/segmentproperties.h
new file mode 100644
index 0000000000..4d86be3882
--- /dev/null
+++ b/tools/easingcurveeditor/segmentproperties.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $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/easingcurveeditor/splineeditor.cpp b/tools/easingcurveeditor/splineeditor.cpp
new file mode 100644
index 0000000000..dbd32dd63a
--- /dev/null
+++ b/tools/easingcurveeditor/splineeditor.cpp
@@ -0,0 +1,714 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "splineeditor.h"
+
+#include <QPainter>
+#include <QMouseEvent>
+#include <QContextMenuEvent>
+#include <QDebug>
+#include <QApplication>
+#include <segmentproperties.h>
+
+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.cubicBezierSpline().toVector();
+ 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/easingcurveeditor/splineeditor.h b/tools/easingcurveeditor/splineeditor.h
new file mode 100644
index 0000000000..81f2dfd1ce
--- /dev/null
+++ b/tools/easingcurveeditor/splineeditor.h
@@ -0,0 +1,143 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the tools applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia 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.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $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
diff --git a/tools/tools.pro b/tools/tools.pro
index 34e90ed816..186c7e9c3b 100644
--- a/tools/tools.pro
+++ b/tools/tools.pro
@@ -1,5 +1,5 @@
TEMPLATE = subdirs
-SUBDIRS += qmlscene qmlplugindump qmlmin qmleasing qmlprofiler
+SUBDIRS += qmlscene qmlplugindump qmlmin qmleasing qmlprofiler easingcurveeditor
contains(QT_CONFIG, qmltest): SUBDIRS += qmltestrunner