]> git.sesse.net Git - kdenlive/commitdiff
Bézier spline:
authorTill Theato <root@ttill.de>
Sat, 1 Jan 2011 21:06:59 +0000 (21:06 +0000)
committerTill Theato <root@ttill.de>
Sat, 1 Jan 2011 21:06:59 +0000 (21:06 +0000)
- rename BezierSplineWidget to BezierSplineEditor
- add BezierSplineWidget containing the editor and more controls (for now spinboxes for the values)

svn path=/trunk/kdenlive/; revision=5233

src/CMakeLists.txt
src/beziercurve/beziersplineeditor.cpp [new file with mode: 0644]
src/beziercurve/beziersplineeditor.h [new file with mode: 0644]
src/beziercurve/beziersplinewidget.cpp
src/beziercurve/beziersplinewidget.h
src/beziercurve/cubicbezierspline.h
src/effectstackedit.cpp
src/widgets/bezierspline_ui.ui [new file with mode: 0644]

index 9952bd0ceac672ad6b5eb64ae37414e4d49bcae9..a50e08ffba3ac2016d27c305320368d3ee643350 100644 (file)
@@ -123,6 +123,7 @@ kde4_add_ui_files(kdenlive_UI
   widgets/audiospectrum_ui.ui
   widgets/spectrogram_ui.ui
   widgets/smconfig_ui.ui
+  widgets/bezierspline_ui.ui
 )
 
 set(kdenlive_SRCS
@@ -263,6 +264,7 @@ set(kdenlive_SRCS
   kiss_fft/kiss_fft.c
   kiss_fft/tools/kiss_fftr.c
   beziercurve/cubicbezierspline.cpp
+  beziercurve/beziersplineeditor.cpp
   beziercurve/beziersplinewidget.cpp
 )
 
diff --git a/src/beziercurve/beziersplineeditor.cpp b/src/beziercurve/beziersplineeditor.cpp
new file mode 100644 (file)
index 0000000..351a6c6
--- /dev/null
@@ -0,0 +1,381 @@
+/***************************************************************************
+ *   Copyright (C) 2010 by Till Theato (root@ttill.de)                     *
+ *   This file is part of Kdenlive (www.kdenlive.org).                     *
+ *                                                                         *
+ *   Kdenlive is free software: you can redistribute it and/or modify      *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation, either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   Kdenlive is distributed in the hope that it will be useful,           *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with Kdenlive.  If not, see <http://www.gnu.org/licenses/>.     *
+ ***************************************************************************/
+
+#include "beziersplineeditor.h"
+
+#include <QPainter>
+#include <QMouseEvent>
+
+#include <KDebug>
+
+BezierSplineEditor::BezierSplineEditor(QWidget* parent) :
+        QWidget(parent),
+        m_mode(ModeNormal),
+        m_currentPointIndex(-1)
+{
+    setMouseTracking(true);
+    setAutoFillBackground(false);
+    setAttribute(Qt::WA_OpaquePaintEvent);
+    setMinimumSize(150, 150);
+    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+}
+
+CubicBezierSpline BezierSplineEditor::spline()
+{
+    return m_spline;
+}
+
+void BezierSplineEditor::setSpline(const CubicBezierSpline& spline)
+{
+    // TODO: cleanup
+    m_spline.fromString(spline.toString());
+}
+
+BPoint BezierSplineEditor::getCurrentPoint()
+{
+    if (m_currentPointIndex >= 0)
+        return m_spline.points()[m_currentPointIndex];
+    else
+        return BPoint();
+}
+
+void BezierSplineEditor::updateCurrentPoint(const BPoint& p)
+{
+    if (m_currentPointIndex >= 0) {
+        m_spline.setPoint(m_currentPointIndex, p);
+        // during validation the point might have changed
+        emit currentPoint(m_spline.points()[m_currentPointIndex]);
+        update();
+    }
+}
+
+void BezierSplineEditor::paintEvent(QPaintEvent* event)
+{
+    Q_UNUSED(event);
+
+    QPainter p(this);
+
+    p.fillRect(rect(), palette().background());
+
+    int    wWidth = width() - 1;
+    int    wHeight = height() - 1;
+
+    /*
+     * Spline
+     */
+    double prevY = wHeight - m_spline.value(0.) * wHeight;
+    double prevX = 0.;
+    double curY;
+    double normalizedX = -1;
+    int x;
+    
+    p.setPen(QPen(Qt::black, 1, Qt::SolidLine));
+    for (x = 0 ; x < wWidth ; ++x) {
+        normalizedX = x / (double)wWidth;
+        curY = wHeight - m_spline.value(normalizedX, true) * wHeight;
+        
+        /*
+         * Keep in mind that QLineF rounds doubles
+         * to ints mathematically, not just rounds down
+         * like in C
+         */
+        p.drawLine(QLineF(prevX, prevY,
+                          x, curY));
+        prevX = x;
+        prevY = curY;
+    }
+    p.drawLine(QLineF(prevX, prevY ,
+                      x, wHeight - m_spline.value(1.0, true) * wHeight));
+
+    /*
+     * Points + Handles
+     */
+    p.setPen(QPen(Qt::red, 1, Qt::SolidLine));
+    BPoint point;
+    QPolygon handle(4);
+    handle.setPoints(4,
+                     1,  -2,
+                     4,  1,
+                     1,  4,
+                     -2, 1);
+    for (int i = 0; i < m_spline.points().count(); ++i) {
+        point = m_spline.points().at(i);
+        if (i == m_currentPointIndex)
+            p.setBrush(QBrush(QColor(Qt::red), Qt::SolidPattern));
+
+        p.drawConvexPolygon(handle.translated(point.h1.x() * wWidth, wHeight - point.h1.y() * wHeight));
+        p.drawEllipse(QRectF(point.p.x() * wWidth - 3,
+                            wHeight - 3 - point.p.y() * wHeight, 6, 6));
+        p.drawConvexPolygon(handle.translated(point.h2.x() * wWidth, wHeight - point.h2.y() * wHeight));
+
+        if ( i == m_currentPointIndex)
+            p.setBrush(QBrush(Qt::NoBrush));
+    }
+}
+
+void BezierSplineEditor::resizeEvent(QResizeEvent* event)
+{
+    m_spline.setPrecision(width());
+    QWidget::resizeEvent(event);
+}
+
+void BezierSplineEditor::mousePressEvent(QMouseEvent* event)
+{
+    double x = event->pos().x() / (double)(width() - 1);
+    double y = 1.0 - event->pos().y() / (double)(height() - 1);
+
+    point_types selectedPoint;
+    int closestPointIndex = nearestPointInRange(QPointF(x, y), width(), height(), &selectedPoint);
+
+    if (event->button() == Qt::RightButton && closestPointIndex > 0 && closestPointIndex < m_spline.points().count() - 1 && selectedPoint == PTypeP) {
+        m_spline.removePoint(closestPointIndex);
+        setCursor(Qt::ArrowCursor);
+        m_mode = ModeNormal;
+        if (closestPointIndex < m_currentPointIndex)
+            --m_currentPointIndex;
+        update();
+        if (m_currentPointIndex >= 0)
+            emit currentPoint(m_spline.points()[m_currentPointIndex]);
+        else
+            emit currentPoint(BPoint());
+        emit modified();
+        return;
+    } else if (event->button() != Qt::LeftButton) {
+        return;
+    }
+
+    if (closestPointIndex < 0) {
+        BPoint po;
+        po.p = QPointF(x, y);
+        po.h1 = QPointF(x-0.05, y-0.05);
+        po.h2 = QPointF(x+0.05, y+0.05);
+        m_currentPointIndex = m_spline.addPoint(po);
+        m_currentPointType = PTypeP;
+        /*if (!d->jumpOverExistingPoints(newPoint, -1)) return;*/
+    } else {
+        m_currentPointIndex = closestPointIndex;
+        m_currentPointType = selectedPoint;
+    }
+
+    BPoint point = m_spline.points()[m_currentPointIndex];
+    QPointF p;
+    switch (m_currentPointType) {
+    case PTypeH1:
+        p = point.h1;
+        break;
+    case PTypeP:
+        p = point.p;
+        break;
+    case PTypeH2:
+        p = point.h2;
+    }
+
+    m_grabOriginalX = p.x();
+    m_grabOriginalY = p.y();
+    m_grabOffsetX = p.x() - x;
+    m_grabOffsetY = p.y() - y;
+
+    switch (m_currentPointType) {
+        case PTypeH1:
+            point.h1 = QPointF(x + m_grabOffsetX, y + m_grabOffsetY);
+            break;
+        case PTypeP:
+            point.p = QPointF(x + m_grabOffsetX, y + m_grabOffsetY);
+            break;
+        case PTypeH2:
+            point.h2 = QPointF(x + m_grabOffsetX, y + m_grabOffsetY);
+    }
+    m_spline.setPoint(m_currentPointIndex, point);
+
+    //d->m_draggedAwayPointIndex = -1;
+
+    m_mode = ModeDrag;
+
+    emit currentPoint(point);
+    update();
+}
+
+void BezierSplineEditor::mouseReleaseEvent(QMouseEvent* event)
+{
+    if (event->button() != Qt::LeftButton)
+        return;
+
+    setCursor(Qt::ArrowCursor);
+    m_mode = ModeNormal;
+
+    emit modified();
+}
+
+void BezierSplineEditor::mouseMoveEvent(QMouseEvent* event)
+{
+    double x = event->pos().x() / (double)(width() - 1);
+    double y = 1.0 - event->pos().y() / (double)(height() - 1);
+    
+    if (m_mode == ModeNormal) { // If no point is selected set the the cursor shape if on top
+        point_types type;
+        int nearestPointIndex = nearestPointInRange(QPointF(x, y), width(), height(), &type);
+        
+        if (nearestPointIndex < 0)
+            setCursor(Qt::ArrowCursor);
+        else
+            setCursor(Qt::CrossCursor);
+    } else { // Else, drag the selected point
+        /*bool crossedHoriz = event->pos().x() - width() > MOUSE_AWAY_THRES ||
+        event->pos().x() < -MOUSE_AWAY_THRES;
+        bool crossedVert =  event->pos().y() - height() > MOUSE_AWAY_THRES ||
+        event->pos().y() < -MOUSE_AWAY_THRES;
+        
+        bool removePoint = (crossedHoriz || crossedVert);
+        
+        if (!removePoint && d->m_draggedAwayPointIndex >= 0) {
+            // point is no longer dragged away so reinsert it
+            QPointF newPoint(d->m_draggedAwayPoint);
+            d->m_grab_point_index = d->m_curve.addPoint(newPoint);
+            d->m_draggedAwayPointIndex = -1;
+        }
+        
+        if (removePoint &&
+            (d->m_draggedAwayPointIndex >= 0))
+            return;
+        */
+        
+        setCursor(Qt::CrossCursor);
+        
+        x += m_grabOffsetX;
+        y += m_grabOffsetY;
+        
+        double leftX, rightX;
+        BPoint point = m_spline.points()[m_currentPointIndex];
+        switch (m_currentPointType) {
+        case PTypeH1:
+            rightX = point.p.x();
+            if (m_currentPointIndex == 0)
+                leftX = -1000;
+            else
+                leftX = m_spline.points()[m_currentPointIndex - 1].p.x();
+            x = qBound(leftX, x, rightX);
+            point.h1 = QPointF(x, y);
+            break;
+        case PTypeP:
+            if (m_currentPointIndex == 0) {
+                leftX = 0.0;
+                rightX = 0.0;
+                /*if (d->m_curve.points().count() > 1)
+                 *           rightX = d->m_curve.points()[d->m_grab_point_index + 1].x() - POINT_AREA;
+                 *       else
+                 *           rightX = 1.0;*/
+            } else if (m_currentPointIndex == m_spline.points().count() - 1) {
+                leftX = 1.0;//m_spline.points()[m_currentPointIndex - 1].p.x();
+                rightX = 1.0;
+            } else {
+                //// the 1E-4 addition so we can grab the dot later.
+                leftX = m_spline.points()[m_currentPointIndex - 1].p.x();// + POINT_AREA;
+                rightX = m_spline.points()[m_currentPointIndex + 1].p.x();// - POINT_AREA;
+            }
+            x = qBound(leftX, x, rightX);
+            y = qBound(0., y, 1.);
+
+            // move handles by same offset
+            point.h1 += QPointF(x, y) - point.p;
+            point.h2 += QPointF(x, y) - point.p;
+
+            point.p = QPointF(x, y);
+            break;
+        case PTypeH2:
+            leftX = point.p.x();
+            if (m_currentPointIndex == m_spline.points().count() - 1)
+                rightX = 1001;
+            else
+                rightX = m_spline.points()[m_currentPointIndex + 1].p.x();
+            x = qBound(leftX, x, rightX);
+            point.h2 = QPointF(x, y);
+        };
+
+        m_spline.setPoint(m_currentPointIndex, point);
+        
+        /*if (removePoint && d->m_curve.points().count() > 2) {
+            d->m_draggedAwayPoint = d->m_curve.points()[d->m_grab_point_index];
+            d->m_draggedAwayPointIndex = d->m_grab_point_index;
+            d->m_curve.removePoint(d->m_grab_point_index);
+            d->m_grab_point_index = bounds(d->m_grab_point_index, 0, d->m_curve.points().count() - 1);
+        }
+        
+        d->setCurveModified();*/
+        emit currentPoint(point);
+        update();
+    }
+}
+
+void BezierSplineEditor::leaveEvent(QEvent* event)
+{
+    QWidget::leaveEvent(event);
+}
+
+int BezierSplineEditor::nearestPointInRange(QPointF p, int wWidth, int wHeight, BezierSplineEditor::point_types* sel)
+{
+    double nearestDistanceSquared = 1000;
+    point_types selectedPoint;
+    int nearestIndex = -1;
+    int i = 0;
+
+    double distanceSquared;
+    foreach(const BPoint & point, m_spline.points()) {
+        distanceSquared = pow(point.h1.x() - p.x(), 2) + pow(point.h1.y() - p.y(), 2);
+        if (distanceSquared < nearestDistanceSquared) {
+            nearestIndex = i;
+            nearestDistanceSquared = distanceSquared;
+            selectedPoint = PTypeH1;
+        }
+        distanceSquared = pow(point.p.x() - p.x(), 2) + pow(point.p.y() - p.y(), 2);
+        if (distanceSquared < nearestDistanceSquared) {
+            nearestIndex = i;
+            nearestDistanceSquared = distanceSquared;
+            selectedPoint = PTypeP;
+        }
+        distanceSquared = pow(point.h2.x() - p.x(), 2) + pow(point.h2.y() - p.y(), 2);
+        if (distanceSquared < nearestDistanceSquared) {
+            nearestIndex = i;
+            nearestDistanceSquared = distanceSquared;
+            selectedPoint = PTypeH2;
+        }
+        ++i;
+    }
+
+    if (nearestIndex >= 0) {
+        BPoint point = m_spline.points()[nearestIndex];
+        QPointF p2;
+        switch (selectedPoint) {
+        case PTypeH1:
+            p2 = point.h1;
+            break;
+        case PTypeP:
+            p2 = point.p;
+            break;
+        case PTypeH2:
+            p2 = point.h2;
+        }
+        if (qAbs(p.x() - p2.x()) * (wWidth - 1) < 5 && qAbs(p.y() - p2.y()) * (wHeight - 1) < 5) {
+            *sel = selectedPoint;
+            return nearestIndex;
+        }
+    }
+
+    return -1;
+}
+
+#include "beziersplineeditor.moc"
diff --git a/src/beziercurve/beziersplineeditor.h b/src/beziercurve/beziersplineeditor.h
new file mode 100644 (file)
index 0000000..1c8229d
--- /dev/null
@@ -0,0 +1,71 @@
+/***************************************************************************
+ *   Copyright (C) 2010 by Till Theato (root@ttill.de)                     *
+ *   This file is part of Kdenlive (www.kdenlive.org).                     *
+ *                                                                         *
+ *   Kdenlive is free software: you can redistribute it and/or modify      *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation, either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ *   Kdenlive is distributed in the hope that it will be useful,           *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with Kdenlive.  If not, see <http://www.gnu.org/licenses/>.     *
+ ***************************************************************************/
+
+#ifndef BEZIERSPLINEEDITOR_H
+#define BEZIERSPLINEEDITOR_H
+
+#include "cubicbezierspline.h"
+
+#include <QtCore>
+#include <QWidget>
+
+class BezierSplineEditor : public QWidget
+{
+    Q_OBJECT
+
+public:
+    BezierSplineEditor(QWidget* parent = 0);
+
+    CubicBezierSpline spline();
+    void setSpline(const CubicBezierSpline &spline);
+
+    BPoint getCurrentPoint();
+    void updateCurrentPoint(const BPoint &p);
+
+protected:
+    //void keyPressEvent(QKeyEvent *event);
+    void paintEvent(QPaintEvent *event);
+    void mousePressEvent(QMouseEvent *event);
+    void mouseReleaseEvent(QMouseEvent * event);
+    void mouseMoveEvent(QMouseEvent * event);
+    void leaveEvent(QEvent *event);
+    void resizeEvent(QResizeEvent *event);
+
+private:
+    CubicBezierSpline m_spline;
+    enum modes { ModeDrag, ModeNormal };
+    enum point_types { PTypeH1, PTypeP, PTypeH2 };
+    modes m_mode;
+    int m_currentPointIndex;
+    point_types m_currentPointType;
+    double m_grabOffsetX;
+    double m_grabOffsetY;
+    double m_grabOriginalX;
+    double m_grabOriginalY;
+    //QPointF m_draggedAwayPoint;
+    //int m_draggedAwayPointIndex;
+
+    //inline void drawGrid(QPainter &p, int width, int height);
+    int nearestPointInRange(QPointF p, int wWidth, int wHeight, point_types *sel);
+
+signals:
+    void modified();
+    void currentPoint(const BPoint &p);
+};
+
+#endif
index efc9b00089beaa03f8637e43543c51042ecf842e..e784e04459a0959942aa8dfdb5acfce392ae794b 100644 (file)
 
 #include "beziersplinewidget.h"
 
-#include <QPainter>
-#include <QMouseEvent>
+#include <QVBoxLayout>
 
-#include <KDebug>
+#include <KIcon>
 
-BezierSplineWidget::BezierSplineWidget(QWidget* parent) :
-        QWidget(parent),
-        m_mode(ModeNormal),
-        m_currentPointIndex(-1)
+BezierSplineWidget::BezierSplineWidget(const QString& spline, QWidget* parent) :
+        QWidget(parent)
 {
-    setMouseTracking(true);
-    setAutoFillBackground(false);
-    setAttribute(Qt::WA_OpaquePaintEvent);
-    setMinimumSize(150, 150);
-    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+    QVBoxLayout *layout = new QVBoxLayout(this);
+    layout->addWidget(&m_edit);
+    QWidget *widget = new QWidget(this);
+    m_ui.setupUi(widget);
+    layout->addWidget(widget);
+
+    m_ui.buttonLinkHandles->setIcon(KIcon("insert-link"));
+    m_ui.buttonLinkHandles->setEnabled(false);
+    m_ui.widgetPoint->setEnabled(false);
+
+    CubicBezierSpline s;
+    s.fromString(spline);
+    m_edit.setSpline(s);
+
+    connect(&m_edit, SIGNAL(modified()), this, SIGNAL(modified()));
+    connect(&m_edit, SIGNAL(currentPoint(const BPoint&)), this, SLOT(slotUpdatePoint(const BPoint&)));
+
+    connect(m_ui.spinPX, SIGNAL(editingFinished()), this, SLOT(slotUpdateSpline()));
+    connect(m_ui.spinPY, SIGNAL(editingFinished()), this, SLOT(slotUpdateSpline()));
+    connect(m_ui.spinH1X, SIGNAL(editingFinished()), this, SLOT(slotUpdateSpline()));
+    connect(m_ui.spinH1Y, SIGNAL(editingFinished()), this, SLOT(slotUpdateSpline()));
+    connect(m_ui.spinH2X, SIGNAL(editingFinished()), this, SLOT(slotUpdateSpline()));
+    connect(m_ui.spinH2Y, SIGNAL(editingFinished()), this, SLOT(slotUpdateSpline()));
 }
 
-CubicBezierSpline BezierSplineWidget::spline()
+QString BezierSplineWidget::spline()
 {
-    return m_spline;
+    return m_edit.spline().toString();
 }
 
-void BezierSplineWidget::setSpline(const CubicBezierSpline& spline)
+void BezierSplineWidget::slotUpdatePoint(const BPoint &p)
 {
-    // TODO: cleanup
-    m_spline.fromString(spline.toString());
-}
-
-void BezierSplineWidget::paintEvent(QPaintEvent* event)
-{
-    Q_UNUSED(event);
-
-    QPainter p(this);
-
-    p.fillRect(rect(), palette().background());
-
-    int    wWidth = width() - 1;
-    int    wHeight = height() - 1;
-
-    /*
-     * Spline
-     */
-    double prevY = wHeight - m_spline.value(0.) * wHeight;
-    double prevX = 0.;
-    double curY;
-    double normalizedX = -1;
-    int x;
-    
-    p.setPen(QPen(Qt::black, 1, Qt::SolidLine));
-    for (x = 0 ; x < wWidth ; ++x) {
-        normalizedX = x / (double)wWidth;
-        curY = wHeight - m_spline.value(normalizedX, true) * wHeight;
-        
-        /*
-         * Keep in mind that QLineF rounds doubles
-         * to ints mathematically, not just rounds down
-         * like in C
-         */
-        p.drawLine(QLineF(prevX, prevY,
-                          x, curY));
-        prevX = x;
-        prevY = curY;
-    }
-    p.drawLine(QLineF(prevX, prevY ,
-                      x, wHeight - m_spline.value(1.0, true) * wHeight));
-
-    /*
-     * Points + Handles
-     */
-    p.setPen(QPen(Qt::red, 1, Qt::SolidLine));
-    BPoint point;
-    QPolygon handle(4);
-    handle.setPoints(4,
-                     1,  -2,
-                     4,  1,
-                     1,  4,
-                     -2, 1);
-    for (int i = 0; i < m_spline.points().count(); ++i) {
-        point = m_spline.points().at(i);
-        if (i == m_currentPointIndex)
-            p.setBrush(QBrush(QColor(Qt::red), Qt::SolidPattern));
-
-        p.drawConvexPolygon(handle.translated(point.h1.x() * wWidth, wHeight - point.h1.y() * wHeight));
-        p.drawEllipse(QRectF(point.p.x() * wWidth - 3,
-                            wHeight - 3 - point.p.y() * wHeight, 6, 6));
-        p.drawConvexPolygon(handle.translated(point.h2.x() * wWidth, wHeight - point.h2.y() * wHeight));
-
-        if ( i == m_currentPointIndex)
-            p.setBrush(QBrush(Qt::NoBrush));
-    }
-}
-
-void BezierSplineWidget::resizeEvent(QResizeEvent* event)
-{
-    m_spline.setPrecision(width());
-    QWidget::resizeEvent(event);
-}
-
-void BezierSplineWidget::mousePressEvent(QMouseEvent* event)
-{
-    double x = event->pos().x() / (double)(width() - 1);
-    double y = 1.0 - event->pos().y() / (double)(height() - 1);
-
-    point_types selectedPoint;
-    int closestPointIndex = nearestPointInRange(QPointF(x, y), width(), height(), &selectedPoint);
-
-    if (event->button() == Qt::RightButton && closestPointIndex > 0 && closestPointIndex < m_spline.points().count() - 1 && selectedPoint == PTypeP) {
-        m_spline.removePoint(closestPointIndex);
-        setCursor(Qt::ArrowCursor);
-        m_mode = ModeNormal;
-        if (closestPointIndex < m_currentPointIndex)
-            --m_currentPointIndex;
-        update();
-        emit modified();
-        return;
-    } else if (event->button() != Qt::LeftButton) {
-        return;
-    }
-
-    if (closestPointIndex < 0) {
-        BPoint po;
-        po.p = QPointF(x, y);
-        po.h1 = QPointF(x-0.05, y-0.05);
-        po.h2 = QPointF(x+0.05, y+0.05);
-        m_currentPointIndex = m_spline.addPoint(po);
-        m_currentPointType = PTypeP;
-        /*if (!d->jumpOverExistingPoints(newPoint, -1)) return;*/
+    blockSignals(true);
+    if (p == BPoint()) {
+        m_ui.widgetPoint->setEnabled(false);
     } else {
-        m_currentPointIndex = closestPointIndex;
-        m_currentPointType = selectedPoint;
-    }
-
-    BPoint point = m_spline.points()[m_currentPointIndex];
-    QPointF p;
-    switch (m_currentPointType) {
-    case PTypeH1:
-        p = point.h1;
-        break;
-    case PTypeP:
-        p = point.p;
-        break;
-    case PTypeH2:
-        p = point.h2;
+        m_ui.widgetPoint->setEnabled(true);
+        m_ui.spinPX->setValue(qRound(p.p.x() * 255));
+        m_ui.spinPY->setValue(qRound(p.p.y() * 255));
+        m_ui.spinH1X->setValue(qRound(p.h1.x() * 255));
+        m_ui.spinH1Y->setValue(qRound(p.h1.y() * 255));
+        m_ui.spinH2X->setValue(qRound(p.h2.x() * 255));
+        m_ui.spinH2Y->setValue(qRound(p.h2.y() * 255));
     }
-
-    m_grabOriginalX = p.x();
-    m_grabOriginalY = p.y();
-    m_grabOffsetX = p.x() - x;
-    m_grabOffsetY = p.y() - y;
-
-    switch (m_currentPointType) {
-        case PTypeH1:
-            point.h1 = QPointF(x + m_grabOffsetX, y + m_grabOffsetY);
-            break;
-        case PTypeP:
-            point.p = QPointF(x + m_grabOffsetX, y + m_grabOffsetY);
-            break;
-        case PTypeH2:
-            point.h2 = QPointF(x + m_grabOffsetX, y + m_grabOffsetY);
-    }
-    m_spline.setPoint(m_currentPointIndex, point);
-
-    //d->m_draggedAwayPointIndex = -1;
-
-    m_mode = ModeDrag;
-
-    update();
+    blockSignals(false);
 }
 
-void BezierSplineWidget::mouseReleaseEvent(QMouseEvent* event)
+void BezierSplineWidget::slotUpdateSpline()
 {
-    if (event->button() != Qt::LeftButton)
-        return;
+    BPoint p = m_edit.getCurrentPoint();
 
-    setCursor(Qt::ArrowCursor);
-    m_mode = ModeNormal;
-    
-    emit modified();
-}
-
-void BezierSplineWidget::mouseMoveEvent(QMouseEvent* event)
-{
-    double x = event->pos().x() / (double)(width() - 1);
-    double y = 1.0 - event->pos().y() / (double)(height() - 1);
-    
-    if (m_mode == ModeNormal) { // If no point is selected set the the cursor shape if on top
-        point_types type;
-        int nearestPointIndex = nearestPointInRange(QPointF(x, y), width(), height(), &type);
-        
-        if (nearestPointIndex < 0)
-            setCursor(Qt::ArrowCursor);
-        else
-            setCursor(Qt::CrossCursor);
-    } else { // Else, drag the selected point
-        /*bool crossedHoriz = event->pos().x() - width() > MOUSE_AWAY_THRES ||
-        event->pos().x() < -MOUSE_AWAY_THRES;
-        bool crossedVert =  event->pos().y() - height() > MOUSE_AWAY_THRES ||
-        event->pos().y() < -MOUSE_AWAY_THRES;
-        
-        bool removePoint = (crossedHoriz || crossedVert);
-        
-        if (!removePoint && d->m_draggedAwayPointIndex >= 0) {
-            // point is no longer dragged away so reinsert it
-            QPointF newPoint(d->m_draggedAwayPoint);
-            d->m_grab_point_index = d->m_curve.addPoint(newPoint);
-            d->m_draggedAwayPointIndex = -1;
-        }
-        
-        if (removePoint &&
-            (d->m_draggedAwayPointIndex >= 0))
-            return;
-        */
-        
-        setCursor(Qt::CrossCursor);
-        
-        x += m_grabOffsetX;
-        y += m_grabOffsetY;
-        
-        double leftX, rightX;
-        BPoint point = m_spline.points()[m_currentPointIndex];
-        switch (m_currentPointType) {
-        case PTypeH1:
-            rightX = point.p.x();
-            if (m_currentPointIndex == 0)
-                leftX = -1000;
-            else
-                leftX = m_spline.points()[m_currentPointIndex - 1].p.x();
-            x = qBound(leftX, x, rightX);
-            point.h1 = QPointF(x, y);
-            break;
-        case PTypeP:
-            if (m_currentPointIndex == 0) {
-                leftX = 0.0;
-                rightX = 0.0;
-                /*if (d->m_curve.points().count() > 1)
-                 *           rightX = d->m_curve.points()[d->m_grab_point_index + 1].x() - POINT_AREA;
-                 *       else
-                 *           rightX = 1.0;*/
-            } else if (m_currentPointIndex == m_spline.points().count() - 1) {
-                leftX = 1.0;//m_spline.points()[m_currentPointIndex - 1].p.x();
-                rightX = 1.0;
-            } else {
-                //// the 1E-4 addition so we can grab the dot later.
-                leftX = m_spline.points()[m_currentPointIndex - 1].p.x();// + POINT_AREA;
-                rightX = m_spline.points()[m_currentPointIndex + 1].p.x();// - POINT_AREA;
-            }
-            x = qBound(leftX, x, rightX);
-            y = qBound(0., y, 1.);
+    // check for every value, so we do not lose too much info through rounding
+    if (m_ui.spinPX->value() != qRound(p.p.x() * 255))
+        p.p.setX(m_ui.spinPX->value() / 255.);
+    if (m_ui.spinPY->value() != qRound(p.p.y() * 255))
+        p.p.setY(m_ui.spinPY->value() / 255.);
 
-            // move handles by same offset
-            point.h1 += QPointF(x, y) - point.p;
-            point.h2 += QPointF(x, y) - point.p;
+    if (m_ui.spinH1X->value() != qRound(p.h1.x() * 255))
+        p.h1.setX(m_ui.spinH1X->value() / 255.);
+    if (m_ui.spinH1Y->value() != qRound(p.h1.y() * 255))
+        p.h1.setY(m_ui.spinH1Y->value() / 255.);
 
-            point.p = QPointF(x, y);
-            break;
-        case PTypeH2:
-            leftX = point.p.x();
-            if (m_currentPointIndex == m_spline.points().count() - 1)
-                rightX = 1001;
-            else
-                rightX = m_spline.points()[m_currentPointIndex + 1].p.x();
-            x = qBound(leftX, x, rightX);
-            point.h2 = QPointF(x, y);
-        };
+    if (m_ui.spinH2X->value() != qRound(p.h2.x() * 255))
+        p.h2.setX(m_ui.spinH2X->value() / 255.);
+    if (m_ui.spinH2Y->value() != qRound(p.h2.y() * 255))
+        p.h2.setY(m_ui.spinH2Y->value() / 255.);
 
-        m_spline.setPoint(m_currentPointIndex, point);
-        
-        /*if (removePoint && d->m_curve.points().count() > 2) {
-            d->m_draggedAwayPoint = d->m_curve.points()[d->m_grab_point_index];
-            d->m_draggedAwayPointIndex = d->m_grab_point_index;
-            d->m_curve.removePoint(d->m_grab_point_index);
-            d->m_grab_point_index = bounds(d->m_grab_point_index, 0, d->m_curve.points().count() - 1);
-        }
-        
-        d->setCurveModified();*/
-        update();
-    }
-}
-
-void BezierSplineWidget::leaveEvent(QEvent* event)
-{
-    QWidget::leaveEvent(event);
-}
-
-int BezierSplineWidget::nearestPointInRange(QPointF p, int wWidth, int wHeight, BezierSplineWidget::point_types* sel)
-{
-    double nearestDistanceSquared = 1000;
-    point_types selectedPoint;
-    int nearestIndex = -1;
-    int i = 0;
-
-    double distanceSquared;
-    foreach(const BPoint & point, m_spline.points()) {
-        distanceSquared = pow(point.h1.x() - p.x(), 2) + pow(point.h1.y() - p.y(), 2);
-        if (distanceSquared < nearestDistanceSquared) {
-            nearestIndex = i;
-            nearestDistanceSquared = distanceSquared;
-            selectedPoint = PTypeH1;
-        }
-        distanceSquared = pow(point.p.x() - p.x(), 2) + pow(point.p.y() - p.y(), 2);
-        if (distanceSquared < nearestDistanceSquared) {
-            nearestIndex = i;
-            nearestDistanceSquared = distanceSquared;
-            selectedPoint = PTypeP;
-        }
-        distanceSquared = pow(point.h2.x() - p.x(), 2) + pow(point.h2.y() - p.y(), 2);
-        if (distanceSquared < nearestDistanceSquared) {
-            nearestIndex = i;
-            nearestDistanceSquared = distanceSquared;
-            selectedPoint = PTypeH2;
-        }
-        ++i;
-    }
-
-    if (nearestIndex >= 0) {
-        BPoint point = m_spline.points()[nearestIndex];
-        QPointF p2;
-        switch (selectedPoint) {
-        case PTypeH1:
-            p2 = point.h1;
-            break;
-        case PTypeP:
-            p2 = point.p;
-            break;
-        case PTypeH2:
-            p2 = point.h2;
-        }
-        if (qAbs(p.x() - p2.x()) * (wWidth - 1) < 5 && qAbs(p.y() - p2.y()) * (wHeight - 1) < 5) {
-            *sel = selectedPoint;
-            return nearestIndex;
-        }
-    }
-
-    return -1;
+    m_edit.updateCurrentPoint(p);
+    emit modified();
 }
 
 #include "beziersplinewidget.moc"
index 245db9688e59a3c2f604f2d8c969814a9542b652..5c4ba0de22dc7f6f3c24ee70f7b65d9eee6aef89 100644 (file)
@@ -20,6 +20,8 @@
 #define BEZIERSPLINEWIDGET_H
 
 #include "cubicbezierspline.h"
+#include "beziersplineeditor.h"
+#include "ui_bezierspline_ui.h"
 
 #include <QtCore>
 #include <QWidget>
 class BezierSplineWidget : public QWidget
 {
     Q_OBJECT
-
+    
 public:
-    BezierSplineWidget(QWidget* parent = 0);
+    BezierSplineWidget(const QString &spline, QWidget* parent = 0);
 
-    CubicBezierSpline spline();
-    void setSpline(const CubicBezierSpline &spline);
+    QString spline();
 
-protected:
-    //void keyPressEvent(QKeyEvent *event);
-    void paintEvent(QPaintEvent *event);
-    void mousePressEvent(QMouseEvent *event);
-    void mouseReleaseEvent(QMouseEvent * event);
-    void mouseMoveEvent(QMouseEvent * event);
-    void leaveEvent(QEvent *event);
-    void resizeEvent(QResizeEvent *event);
+private slots:
+    void slotUpdatePoint(const BPoint &p);
+    void slotUpdateSpline();
 
 private:
-    CubicBezierSpline m_spline;
-    enum modes { ModeDrag, ModeNormal };
-    enum point_types { PTypeH1, PTypeP, PTypeH2 };
-    modes m_mode;
-    int m_currentPointIndex;
-    point_types m_currentPointType;
-    double m_grabOffsetX;
-    double m_grabOffsetY;
-    double m_grabOriginalX;
-    double m_grabOriginalY;
-    //QPointF m_draggedAwayPoint;
-    //int m_draggedAwayPointIndex;
-
-    //inline void drawGrid(QPainter &p, int width, int height);
-    int nearestPointInRange(QPointF p, int wWidth, int wHeight, point_types *sel);
+    Ui::BezierSpline_UI m_ui;
+    BezierSplineEditor m_edit;
 
 signals:
     void modified();
index 078066e29cc20f8d47ba2eda471ca233d5d907ed..4ddd0ce807869001d5d386504e57a4e9bc72b2ea 100644 (file)
@@ -29,6 +29,7 @@ public:
     QPointF p;      // point
     QPointF h2;     // handle 2
 
+    BPoint() { p = QPointF(-1,-1); } // makes it illegal -> cannot be equal any point
     bool operator==(const BPoint &point) const { return point.h1 == h1 && point.p == p && point.h2 == h2; }
 };
 
index 6e4cbc8aa7fd8a79fe50091789f70d6e5ec86cdc..458f53c2ad5591f8d2845c727fe78fb2b5fe8e7c 100644 (file)
@@ -35,7 +35,6 @@
 #include "doubleparameterwidget.h"
 #include "cornerswidget.h"
 #include "beziercurve/beziersplinewidget.h"
-#include "beziercurve/cubicbezierspline.h"
 
 #include <KDebug>
 #include <KLocale>
@@ -384,10 +383,7 @@ void EffectStackEdit::transferParamDesc(const QDomElement d, int pos, int in, in
             if (!depends.isEmpty())
                 meetDependency(paramName, type, EffectsList::parameter(e, depends));
         } else if (type == "bezier_spline") {
-            BezierSplineWidget *widget = new BezierSplineWidget(this);
-            CubicBezierSpline spline;
-            spline.fromString(value);
-            widget->setSpline(spline);
+            BezierSplineWidget *widget = new BezierSplineWidget(value, this);
             stretch = false;
             m_vbox->addWidget(widget);
             m_valueItems[paramName] = widget;
@@ -675,7 +671,7 @@ void EffectStackEdit::collectAllParameters()
                 meetDependency(paramName, type, EffectsList::parameter(newparam, depends));
         } else if (type == "bezier_spline") {
             BezierSplineWidget *widget = (BezierSplineWidget*)m_valueItems.value(paramName);
-            setValue = widget->spline().toString();
+            setValue = widget->spline();
         } else if (type == "corners") {
             CornersWidget *corners = ((CornersWidget*)m_valueItems.value(paramName));
             QString xName = pa.attributes().namedItem("xpoints").nodeValue();
diff --git a/src/widgets/bezierspline_ui.ui b/src/widgets/bezierspline_ui.ui
new file mode 100644 (file)
index 0000000..6e9f4cb
--- /dev/null
@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>BezierSpline_UI</class>
+ <widget class="QWidget" name="BezierSpline_UI">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>471</width>
+    <height>84</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="1" column="5">
+    <widget class="QWidget" name="widgetPoint" native="true">
+     <layout class="QGridLayout" name="gridLayout_2">
+      <item row="0" column="0" colspan="9">
+       <widget class="QWidget" name="widget" native="true">
+        <layout class="QHBoxLayout" name="horizontalLayout">
+         <property name="margin">
+          <number>0</number>
+         </property>
+         <item>
+          <spacer name="horizontalSpacer">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+         <item>
+          <widget class="QSpinBox" name="spinPX">
+           <property name="toolTip">
+            <string>Point In</string>
+           </property>
+           <property name="maximum">
+            <number>255</number>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QLabel" name="label">
+           <property name="text">
+            <string>Point</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <widget class="QSpinBox" name="spinPY">
+           <property name="toolTip">
+            <string>Point Out</string>
+           </property>
+           <property name="maximum">
+            <number>255</number>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <spacer name="horizontalSpacer_2">
+           <property name="orientation">
+            <enum>Qt::Horizontal</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>40</width>
+             <height>20</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+        </layout>
+       </widget>
+      </item>
+      <item row="1" column="0">
+       <widget class="QSpinBox" name="spinH1X">
+        <property name="toolTip">
+         <string>Handle 1 X</string>
+        </property>
+        <property name="minimum">
+         <number>-100</number>
+        </property>
+        <property name="maximum">
+         <number>400</number>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="1">
+       <widget class="QLabel" name="label_2">
+        <property name="toolTip">
+         <string>Handle 1</string>
+        </property>
+        <property name="text">
+         <string>H1</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="2">
+       <widget class="QSpinBox" name="spinH1Y">
+        <property name="toolTip">
+         <string>Handle 1 Y</string>
+        </property>
+        <property name="minimum">
+         <number>-100</number>
+        </property>
+        <property name="maximum">
+         <number>400</number>
+        </property>
+        <property name="value">
+         <number>0</number>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="3">
+       <spacer name="horizontalSpacer_3">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>40</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item row="1" column="4">
+       <widget class="QToolButton" name="buttonLinkHandles">
+        <property name="toolTip">
+         <string>Link the Handles' position so you draw a line through Handle -&gt; Point -&gt; Handle.&lt;br /&gt;Results in a natural spline.</string>
+        </property>
+        <property name="text">
+         <string>...</string>
+        </property>
+        <property name="checkable">
+         <bool>true</bool>
+        </property>
+        <property name="autoRaise">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="5">
+       <spacer name="horizontalSpacer_4">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>40</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item row="1" column="6">
+       <widget class="QSpinBox" name="spinH2X">
+        <property name="toolTip">
+         <string>Handle 2 X</string>
+        </property>
+        <property name="minimum">
+         <number>-100</number>
+        </property>
+        <property name="maximum">
+         <number>400</number>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="7">
+       <widget class="QLabel" name="label_3">
+        <property name="toolTip">
+         <string>Handle 2</string>
+        </property>
+        <property name="text">
+         <string>H2</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="8">
+       <widget class="QSpinBox" name="spinH2Y">
+        <property name="toolTip">
+         <string>Handle 2 Y</string>
+        </property>
+        <property name="minimum">
+         <number>-100</number>
+        </property>
+        <property name="maximum">
+         <number>400</number>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>