***************************************************************************/
#include "beziersplinewidget.h"
+#include "colortools.h"
+#include "dragvalue.h"
+#include "kdenlivesettings.h"
-#include <QPainter>
-#include <QMouseEvent>
+#include <QVBoxLayout>
-#include <KDebug>
+#include <KIcon>
+#include <KLocalizedString>
-BezierSplineWidget::BezierSplineWidget(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 BezierSplineWidget::spline()
+BezierSplineWidget::BezierSplineWidget(const QString& spline, QWidget* parent) :
+ QWidget(parent),
+ m_mode(ModeRGB),
+ m_showPixmap(true)
{
- return m_spline;
+ 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(QLatin1String("insert-link")));
+ m_ui.buttonZoomIn->setIcon(KIcon(QLatin1String("zoom-in")));
+ m_ui.buttonZoomOut->setIcon(KIcon(QLatin1String("zoom-out")));
+ m_ui.buttonGridChange->setIcon(KIcon(QLatin1String("view-grid")));
+ m_ui.buttonShowPixmap->setIcon(QIcon(QPixmap::fromImage(ColorTools::rgbCurvePlane(QSize(16, 16), ColorTools::COL_Luma, 0.8))));
+ m_ui.buttonResetSpline->setIcon(KIcon(QLatin1String("view-refresh")));
+ m_ui.buttonShowAllHandles->setIcon(KIcon(QLatin1String("draw-bezier-curves")));
+ m_ui.widgetPoint->setEnabled(false);
+
+ m_pX = new DragValue(i18n("In"), 0, 3, 0, 1, -1, QString(), false, this);
+ m_pX->setStep(0.001);
+ m_pY = new DragValue(i18n("Out"), 0, 3, 0, 1, -1, QString(), false, this);
+ m_pY->setStep(0.001);
+ m_h1X = new DragValue(i18n("X"), 0, 3, -2, 2, -1, QString(), false, this);
+ m_h1X->setStep(0.001);
+ m_h1Y = new DragValue(i18n("Y"), 0, 3, -2, 2, -1, QString(), false, this);
+ m_h1Y->setStep(0.001);
+ m_h2X = new DragValue(i18n("X"), 0, 3, -2, 2, -1, QString(), false, this);
+ m_h2X->setStep(0.001);
+ m_h2Y = new DragValue(i18n("Y"), 0, 3, -2, 2, -1, QString(), false, this);
+ m_h2Y->setStep(0.001);
+
+ m_ui.layoutP->addWidget(m_pX);
+ m_ui.layoutP->addWidget(m_pY);
+ m_ui.layoutH1->addWidget(new QLabel(i18n("Handle 1:")));
+ m_ui.layoutH1->addWidget(m_h1X);
+ m_ui.layoutH1->addWidget(m_h1Y);
+ m_ui.layoutH2->addWidget(new QLabel(i18n("Handle 2:")));
+ m_ui.layoutH2->addWidget(m_h2X);
+ m_ui.layoutH2->addWidget(m_h2Y);
+
+ CubicBezierSpline s;
+ s.fromString(spline);
+ m_edit.setSpline(s);
+
+ connect(&m_edit, SIGNAL(modified()), this, SIGNAL(modified()));
+ connect(&m_edit, SIGNAL(currentPoint(BPoint)), this, SLOT(slotUpdatePointEntries(BPoint)));
+
+ connect(m_pX, SIGNAL(valueChanged(double,bool)), this, SLOT(slotUpdatePointP(double,bool)));
+ connect(m_pY, SIGNAL(valueChanged(double,bool)), this, SLOT(slotUpdatePointP(double,bool)));
+ connect(m_h1X, SIGNAL(valueChanged(double,bool)), this, SLOT(slotUpdatePointH1(double,bool)));
+ connect(m_h1Y, SIGNAL(valueChanged(double,bool)), this, SLOT(slotUpdatePointH1(double,bool)));
+ connect(m_h2X, SIGNAL(valueChanged(double,bool)), this, SLOT(slotUpdatePointH2(double,bool)));
+ connect(m_h2Y, SIGNAL(valueChanged(double,bool)), this, SLOT(slotUpdatePointH2(double,bool)));
+
+ connect(m_ui.buttonLinkHandles, SIGNAL(toggled(bool)), this, SLOT(slotSetHandlesLinked(bool)));
+ connect(m_ui.buttonZoomIn, SIGNAL(clicked()), &m_edit, SLOT(slotZoomIn()));
+ connect(m_ui.buttonZoomOut, SIGNAL(clicked()), &m_edit, SLOT(slotZoomOut()));
+ connect(m_ui.buttonGridChange, SIGNAL(clicked()), this, SLOT(slotGridChange()));
+ connect(m_ui.buttonShowPixmap, SIGNAL(toggled(bool)), this, SLOT(slotShowPixmap(bool)));
+ connect(m_ui.buttonResetSpline, SIGNAL(clicked()), this, SLOT(slotResetSpline()));
+ connect(m_ui.buttonShowAllHandles, SIGNAL(toggled(bool)), this, SLOT(slotShowAllHandles(bool)));
+
+ m_edit.setGridLines(KdenliveSettings::bezier_gridlines());
+ m_ui.buttonShowPixmap->setChecked(KdenliveSettings::bezier_showpixmap());
+ slotShowPixmap(m_ui.buttonShowPixmap->isChecked());
+ m_ui.buttonShowAllHandles->setChecked(KdenliveSettings::bezier_showallhandles());
}
-void BezierSplineWidget::setSpline(const CubicBezierSpline& spline)
+QString BezierSplineWidget::spline() const
{
- // TODO: cleanup
- m_spline.fromString(spline.toString());
+ return m_edit.spline().toString();
}
-void BezierSplineWidget::paintEvent(QPaintEvent* event)
+void BezierSplineWidget::setMode(BezierSplineWidget::CurveModes mode)
{
- 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));
+ if (m_mode != mode) {
+ m_mode = mode;
+ if (m_showPixmap)
+ slotShowPixmap();
}
}
-void BezierSplineWidget::resizeEvent(QResizeEvent* event)
+void BezierSplineWidget::slotGridChange()
{
- m_spline.setPrecision(width());
- QWidget::resizeEvent(event);
+ m_edit.setGridLines((m_edit.gridLines() + 1) % 9);
+ KdenliveSettings::setBezier_gridlines(m_edit.gridLines());
}
-void BezierSplineWidget::mousePressEvent(QMouseEvent* event)
+void BezierSplineWidget::slotShowPixmap(bool show)
{
- 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 (m_showPixmap != show) {
+ m_showPixmap = show;
+ KdenliveSettings::setBezier_showpixmap(show);
+ if (show && (int)m_mode < 6)
+ m_edit.setPixmap(QPixmap::fromImage(ColorTools::rgbCurvePlane(m_edit.size(), static_cast<ColorTools::ColorsRGB>(m_mode), 1, palette().background().color().rgb())));
+ else if (show && m_mode == ModeHue)
+ m_edit.setPixmap(QPixmap::fromImage(ColorTools::hsvCurvePlane(m_edit.size(), QColor::fromHsv(200, 200, 200), ColorTools::COM_H, ColorTools::COM_H)));
+ else
+ m_edit.setPixmap(QPixmap());
}
+}
- 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;*/
+void BezierSplineWidget::slotUpdatePointEntries(const BPoint &p)
+{
+ blockSignals(true);
+ if (p == BPoint()) {
+ m_ui.widgetPoint->setEnabled(false);
} else {
- m_currentPointIndex = closestPointIndex;
- m_currentPointType = selectedPoint;
+ m_ui.widgetPoint->setEnabled(true);
+ m_pX->blockSignals(true);
+ m_pY->blockSignals(true);
+ m_h1X->blockSignals(true);
+ m_h1Y->blockSignals(true);
+ m_h2X->blockSignals(true);
+ m_h2Y->blockSignals(true);
+ m_pX->setValue(p.p.x());
+ m_pY->setValue(p.p.y());
+ m_h1X->setValue(p.h1.x());
+ m_h1Y->setValue(p.h1.y());
+ m_h2X->setValue(p.h2.x());
+ m_h2Y->setValue(p.h2.y());
+ m_pX->blockSignals(false);
+ m_pY->blockSignals(false);
+ m_h1X->blockSignals(false);
+ m_h1Y->blockSignals(false);
+ m_h2X->blockSignals(false);
+ m_h2Y->blockSignals(false);
+ m_ui.buttonLinkHandles->setChecked(p.handlesLinked);
}
+ blockSignals(false);
+}
- 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;
- }
+void BezierSplineWidget::slotUpdatePointP(double value, bool final)
+{
+ Q_UNUSED(value)
- 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;
+ BPoint p = m_edit.getCurrentPoint();
- m_mode = ModeDrag;
+ p.setP(QPointF(m_pX->value(), m_pY->value()));
- update();
+ m_edit.updateCurrentPoint(p, final);
}
-void BezierSplineWidget::mouseReleaseEvent(QMouseEvent* event)
+void BezierSplineWidget::slotUpdatePointH1(double value, bool final)
{
- if (event->button() != Qt::LeftButton)
- return;
+ Q_UNUSED(value)
- setCursor(Qt::ArrowCursor);
- m_mode = ModeNormal;
-
- emit modified();
+ BPoint p = m_edit.getCurrentPoint();
+
+ p.setH1(QPointF(m_h1X->value(), m_h1Y->value()));
+
+ m_edit.updateCurrentPoint(p, final);
}
-void BezierSplineWidget::mouseMoveEvent(QMouseEvent* event)
+void BezierSplineWidget::slotUpdatePointH2(double value, bool final)
{
- 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.);
- 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();*/
- update();
- }
+ Q_UNUSED(value)
+
+ BPoint p = m_edit.getCurrentPoint();
+
+ p.setH2(QPointF(m_h2X->value(), m_h2Y->value()));
+
+ m_edit.updateCurrentPoint(p, final);
}
-void BezierSplineWidget::leaveEvent(QEvent* event)
+void BezierSplineWidget::slotSetHandlesLinked(bool linked)
{
- QWidget::leaveEvent(event);
+ BPoint p = m_edit.getCurrentPoint();
+ p.handlesLinked = linked;
+ m_edit.updateCurrentPoint(p);
}
-int BezierSplineWidget::nearestPointInRange(QPointF p, int wWidth, int wHeight, BezierSplineWidget::point_types* sel)
+void BezierSplineWidget::slotResetSpline()
{
- 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;
- }
- }
+ m_edit.setSpline(CubicBezierSpline());
+}
- return -1;
+void BezierSplineWidget::slotShowAllHandles(bool show)
+{
+ m_edit.setShowAllHandles(show);
+ KdenliveSettings::setBezier_showallhandles(show);
}
#include "beziersplinewidget.moc"