X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fbeziercurve%2Fbeziersplineeditor.cpp;h=4ef7ea12aba79e3d7d405105837a7435a8125519;hb=b2f9e475053bd6719b74f718a4385a1edd9c1795;hp=3250feca4557b25b6c682ad6bd1bbc87dd07893e;hpb=af171e1cebd954b281ce78a8fc4fd5e38887a1ac;p=kdenlive diff --git a/src/beziercurve/beziersplineeditor.cpp b/src/beziercurve/beziersplineeditor.cpp index 3250feca..4ef7ea12 100644 --- a/src/beziercurve/beziersplineeditor.cpp +++ b/src/beziercurve/beziersplineeditor.cpp @@ -27,6 +27,7 @@ BezierSplineEditor::BezierSplineEditor(QWidget* parent) : m_mode(ModeNormal), m_zoomLevel(0), m_gridLines(3), + m_showAllHandles(true), m_pixmapCache(NULL), m_pixmapIsDirty(true), m_currentPointIndex(-1) @@ -51,11 +52,10 @@ CubicBezierSpline BezierSplineEditor::spline() void BezierSplineEditor::setSpline(const CubicBezierSpline& spline) { - int precision = m_spline.getPrecision(); m_spline = spline; - m_spline.setPrecision(precision); m_currentPointIndex = -1; m_mode = ModeNormal; + emit currentPoint(BPoint()); emit modified(); update(); } @@ -74,6 +74,7 @@ void BezierSplineEditor::updateCurrentPoint(const BPoint& p) m_spline.setPoint(m_currentPointIndex, p); // during validation the point might have changed emit currentPoint(m_spline.points()[m_currentPointIndex]); + emit modified(); update(); } } @@ -99,6 +100,12 @@ void BezierSplineEditor::slotZoomOut() update(); } +void BezierSplineEditor::setShowAllHandles(bool show) +{ + m_showAllHandles = show; + update(); +} + int BezierSplineEditor::gridLines() { return m_gridLines; @@ -116,6 +123,9 @@ void BezierSplineEditor::paintEvent(QPaintEvent* event) QPainter p(this); + /* + * Zoom + */ int wWidth = width() - 1; int wHeight = height() - 1; int offset = 1/8. * m_zoomLevel * (wWidth > wHeight ? wWidth : wHeight); @@ -171,74 +181,70 @@ void BezierSplineEditor::paintEvent(QPaintEvent* event) */ p.drawLine(QLineF(0, wHeight, wWidth, 0)); + + /* + * Prepare Spline, Points + */ + int max = m_spline.points().count() - 1; + if (max < 1) + return; + BPoint point(m_spline.getPoint(0, wWidth, wHeight, true)); + /* * Spline */ - double prevY = wHeight - m_spline.value(0.) * wHeight; - double prevX = 0.; - double curY; - double normalizedX = -1; - int x; + BPoint next; - 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; + QPainterPath splinePath(QPointF(point.p.x(), point.p.y())); + for (int i = 0; i < max; ++i) { + point = m_spline.getPoint(i, wWidth, wHeight, true); + next = m_spline.getPoint(i + 1, wWidth, wHeight, true); + splinePath.cubicTo(point.h2, next.h1, next.p); } - p.drawLine(QLineF(prevX, prevY , - x, wHeight - m_spline.value(1.0, true) * wHeight)); + p.setPen(QPen(Qt::black, 1, Qt::SolidLine)); + p.drawPath(splinePath); + /* * Points + Handles */ - int max = m_spline.points().count() - 1; p.setPen(QPen(Qt::red, 1, Qt::SolidLine)); - BPoint point; - QPolygon handle(4); - handle.setPoints(4, - 1, -2, - 4, 1, - 1, 4, - -2, 1); + + QPolygonF handle = QPolygonF() << QPointF(0, -3) << QPointF(3, 0) << QPointF(0, 3) << QPointF(-3, 0); #if QT_VERSION < 0x040600 - QPolygon tmp; + QPolygonF tmp; #endif + for (int i = 0; i <= max; ++i) { - point = m_spline.points().at(i); + point = m_spline.getPoint(i, wWidth, wHeight, true); + if (i == m_currentPointIndex) { + // selected point: fill p and handles p.setBrush(QBrush(QColor(Qt::red), Qt::SolidPattern)); + // connect p and handles with lines if (i != 0) - p.drawLine(QLineF(point.h1.x() * wWidth, wHeight - point.h1.y() * wHeight, point.p.x() * wWidth, wHeight - point.p.y() * wHeight)); + p.drawLine(QLineF(point.h1.x(), point.h1.y(), point.p.x(),point.p.y())); if (i != max) - p.drawLine(QLineF(point.p.x() * wWidth, wHeight - point.p.y() * wHeight, point.h2.x() * wWidth, wHeight - point.h2.y() * wHeight)); + p.drawLine(QLineF(point.p.x(), point.p.y(), point.h2.x(), point.h2.y())); } - p.drawEllipse(QRectF(point.p.x() * wWidth - 3, - wHeight - 3 - point.p.y() * wHeight, 6, 6)); - if (i != 0) { + p.drawEllipse(QRectF(point.p.x() - 3, + point.p.y() - 3, 6, 6)); + if (i != 0 && (i == m_currentPointIndex || m_showAllHandles)) { #if QT_VERSION >= 0x040600 - p.drawConvexPolygon(handle.translated(point.h1.x() * wWidth, wHeight - point.h1.y() * wHeight)); + p.drawConvexPolygon(handle.translated(point.h1.x(), point.h1.y())); #else tmp = handle; - tmp.translate(point.h1.x() * wWidth, wHeight - point.h1.y() * wHeight); + tmp.translate(point.h1.x(), point.h1.y()); p.drawConvexPolygon(tmp); #endif } - if (i != max) { + if (i != max && (i == m_currentPointIndex || m_showAllHandles)) { #if QT_VERSION >= 0x040600 - p.drawConvexPolygon(handle.translated(point.h2.x() * wWidth, wHeight - point.h2.y() * wHeight)); + p.drawConvexPolygon(handle.translated(point.h2.x(), point.h2.y())); #else tmp = handle; - tmp.translate(handle.translated(point.h2.x() * wWidth, wHeight - point.h2.y() * wHeight); + tmp.translate(point.h2.x(), point.h2.y()); p.drawConvexPolygon(tmp); #endif } @@ -250,7 +256,6 @@ void BezierSplineEditor::paintEvent(QPaintEvent* event) void BezierSplineEditor::resizeEvent(QResizeEvent* event) { - m_spline.setPrecision(width() > height() ? width() : height()); m_pixmapIsDirty = true; QWidget::resizeEvent(event); } @@ -287,11 +292,9 @@ void BezierSplineEditor::mousePressEvent(QMouseEvent* event) } 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_currentPointIndex = m_spline.addPoint(BPoint(QPointF(x-0.05, y-0.05), + QPointF(x, y), + QPointF(x+0.05, y+0.05))); m_currentPointType = PTypeP; } else { m_currentPointIndex = closestPointIndex; @@ -299,36 +302,17 @@ void BezierSplineEditor::mousePressEvent(QMouseEvent* event) } 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_grabPOriginal = point; if (m_currentPointIndex > 0) m_grabPPrevious = m_spline.points()[m_currentPointIndex - 1]; if (m_currentPointIndex < m_spline.points().count() - 1) m_grabPNext = m_spline.points()[m_currentPointIndex + 1]; - m_grabOffsetX = p.x() - x; - m_grabOffsetY = p.y() - y; + m_grabOffsetX = point[(int)m_currentPointType].x() - x; + m_grabOffsetY = point[(int)m_currentPointType].y() - y; + + point[(int)m_currentPointType] = QPointF(x + m_grabOffsetX, y + m_grabOffsetY); - 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); m_mode = ModeDrag; @@ -371,7 +355,7 @@ void BezierSplineEditor::mouseMoveEvent(QMouseEvent* event) } else { // Else, drag the selected point setCursor(Qt::CrossCursor); - + x += m_grabOffsetX; y += m_grabOffsetY; @@ -382,12 +366,12 @@ void BezierSplineEditor::mouseMoveEvent(QMouseEvent* event) case PTypeH1: rightX = point.p.x(); if (m_currentPointIndex == 0) - leftX = -1000; + leftX = -4; else leftX = m_spline.points()[m_currentPointIndex - 1].p.x(); x = qBound(leftX, x, rightX); - point.h1 = QPointF(x, y); + point.setH1(QPointF(x, y)); break; case PTypeP: @@ -403,22 +387,23 @@ void BezierSplineEditor::mouseMoveEvent(QMouseEvent* event) // try to restore point.h1 = m_grabPOriginal.h1; point.h2 = m_grabPOriginal.h2; - // and then move them by same offset + // and move by same offset + // (using update handle in point.setP won't work because the offset between new and old point is very small) point.h1 += QPointF(x, y) - m_grabPOriginal.p; point.h2 += QPointF(x, y) - m_grabPOriginal.p; - point.p = QPointF(x, y); + point.setP(QPointF(x, y), false); break; case PTypeH2: leftX = point.p.x(); if (m_currentPointIndex == m_spline.points().count() - 1) - rightX = 1001; + rightX = 5; else rightX = m_spline.points()[m_currentPointIndex + 1].p.x(); x = qBound(leftX, x, rightX); - point.h2 = QPointF(x, y); + point.setH2(QPointF(x, y)); }; int index = m_currentPointIndex; @@ -467,41 +452,21 @@ int BezierSplineEditor::nearestPointInRange(QPointF p, int wWidth, int wHeight, double distanceSquared; // find out distance using the Pythagorean theorem 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; + for (int j = 0; j < 3; ++j) { + distanceSquared = pow(point[j].x() - p.x(), 2) + pow(point[j].y() - p.y(), 2); + if (distanceSquared < nearestDistanceSquared) { + nearestIndex = i; + nearestDistanceSquared = distanceSquared; + selectedPoint = (point_types)j; + } } ++i; } - if (nearestIndex >= 0) { + if (nearestIndex >= 0 && (nearestIndex == m_currentPointIndex || selectedPoint == PTypeP || m_showAllHandles)) { + // a point was found and it is not a hidden handle 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 < 5 && qAbs(p.y() - p2.y()) * wHeight < 5) { + if (qAbs(p.x() - point[(int)selectedPoint].x()) * wWidth < 5 && qAbs(p.y() - point[(int)selectedPoint].y()) * wHeight < 5) { *sel = selectedPoint; return nearestIndex; }