diff --git a/src/Editor/KSCropArea.cpp b/src/Editor/KSCropArea.cpp index 780ffaa..81bd7a2 100644 --- a/src/Editor/KSCropArea.cpp +++ b/src/Editor/KSCropArea.cpp @@ -1,368 +1,377 @@ /* * Copyright (C) 2007 Luca Gugelmann * Copyright (C) 2015 Boudhayan Gupta * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Library General Public License version 2 as * published by the Free Software Foundation * * This program 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 Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "KSCropArea.h" KSCropArea::KSCropArea(QQuickItem *parent) : QQuickPaintedItem(parent), mNoPaint(false), mCropRect(0, 0, 0, 0), mMouseOverHandle(nullptr) { mTLHandle = mTRHandle = mBLHandle = mBRHandle = QRect(0, 0, 15, 15); mLHandle = mRHandle = QRect(0, 0, 10, 20); mTHandle = mBHandle = QRect(0, 0, 20, 10); mHandles = { &mTLHandle, &mTRHandle, &mBLHandle, &mBRHandle, &mLHandle, &mTHandle, &mRHandle, &mBHandle }; setAcceptedMouseButtons(Qt::AllButtons); setAcceptHoverEvents(true); setAntialiasing(true); } void KSCropArea::paint(QPainter *painter) { updateHandles(); - if (!mNoPaint) { + if (!mNoPaint && !(mCropRect.isEmpty() || mCropRect.isNull())) { painter->save(); QRegion drawRegion(boundingRect().toRect()); // first draw the overlay painter->setClipRegion(drawRegion - mCropRect); painter->setBrush(QBrush(QColor(0, 0, 0, 127))); painter->setRenderHint(QPainter::Antialiasing); painter->drawRect(boundingRect()); // then draw the border QRegion borderRegion(mCropRect); borderRegion -= mCropRect.adjusted(1, 1, -1, -1); painter->setClipRegion(borderRegion); painter->setBrush(QBrush(QColor(0, 0, 0))); painter->drawRect(mCropRect); // draw the handles if ((mCropRect.height() > 20) && (mCropRect.width() > 20)) { drawHandles(painter, QColor(0, 0, 0)); } // done painter->restore(); } } // property accessors bool KSCropArea::noPaint() const { return mNoPaint; } int KSCropArea::cropX() const { return mCropRect.x(); } int KSCropArea::cropY() const { return mCropRect.y(); } int KSCropArea::cropWidth() const { return mCropRect.width(); } int KSCropArea::cropHeight() const { return mCropRect.height(); } // property mutators void KSCropArea::setNoPaint(const bool &noPaint) { mNoPaint = noPaint; update(); } void KSCropArea::setCropX(const int &x) { mCropRect.setX(x); update(); } void KSCropArea::setCropY(const int &y) { mCropRect.setY(y); update(); } void KSCropArea::setCropWidth(const int &width) { mCropRect.setWidth(width); update(); } void KSCropArea::setCropHeight(const int &height) { mCropRect.setHeight(height); update(); } // mouse event handlers void KSCropArea::mousePressEvent(QMouseEvent *event) { + if (event->button() == Qt::RightButton) { + update(); + return; + } + if (!mCropRect.contains(event->pos())) { mCropRect = QRect(event->pos(), event->pos()); mMouseOverHandle = &mBRHandle; } else if (mMouseOverHandle == nullptr) { mMoveDelta = event->pos() - mCropRect.topLeft(); setCursor(Qt::ClosedHandCursor); } update(); } void KSCropArea::mouseMoveEvent(QMouseEvent *event) { if (mMouseOverHandle == nullptr) { // moving the whole selection QRect r = boundingRect().toRect(); r.setBottomRight(r.bottomRight() - QPoint(mCropRect.width(), mCropRect.height()) + QPoint(1, 1)); if (!(r.isNull() || r.isEmpty()) && r.isValid()) { const QPoint newTopLeft = limitPointToRect(event->pos() - mMoveDelta, r); if (newTopLeft == mCropRect.topLeft()) { mMoveDelta = event->pos() - mCropRect.topLeft(); } else { mCropRect.moveTo(newTopLeft); } } } else { // dragging a handle QRect r = mCropRect; if (mMouseOverHandle == &mTLHandle) { if (event->pos().x() <= r.right() && event->pos().y() <= r.bottom()) { r.setTopLeft(event->pos()); } else if (event->pos().x() <= r.right() && event->pos().y() > r.bottom()) { r.setLeft(event->pos().x()); r.setTop(r.bottom()); r.setBottom(event->pos().y()); mMouseOverHandle = &mBLHandle; } else if (event->pos().x() > r.right() && event->pos().y() <= r.bottom()) { r.setTop(event->pos().y()); r.setLeft(r.right()); r.setRight(event->pos().x()); mMouseOverHandle = &mTRHandle; } else { r.setTopLeft(r.bottomRight()); r.setBottomRight(event->pos()); mMouseOverHandle = &mBRHandle; } r = r.normalized(); } else if (mMouseOverHandle == &mTRHandle) { if (event->pos().x() >= r.left() && event->pos().y() <= r.bottom()) { r.setTopRight(event->pos()); } else if (event->pos().x() >= r.left() && event->pos().y() > r.bottom()) { r.setRight(event->pos().x()); r.setTop(r.bottom()); r.setBottom(event->pos().y()); mMouseOverHandle = &mBRHandle; } else if (event->pos().x() < r.left() && event->pos().y() <= r.bottom()) { r.setTop(event->pos().y()); r.setRight(r.left()); r.setLeft(event->pos().x()); mMouseOverHandle = &mTLHandle; } else { r.setTopRight(r.bottomLeft()); r.setBottomLeft(event->pos()); mMouseOverHandle = &mBLHandle; } r = r.normalized(); } else if (mMouseOverHandle == &mBLHandle) { if (event->pos().x() <= r.right() && event->pos().y() >= r.top()) { r.setBottomLeft(event->pos()); } else if (event->pos().x() <= r.left() && event->pos().y() < r.top()) { r.setLeft(event->pos().x()); r.setBottom(r.top()); r.setTop(event->pos().y()); mMouseOverHandle = &mTLHandle; } else if (event->pos().x() > r.left() && event->pos().y() >= r.top()) { r.setBottom(event->pos().y()); r.setLeft(r.right()); r.setRight(event->pos().x()); mMouseOverHandle = &mBRHandle; } else { r.setBottomLeft(r.topRight()); r.setTopRight(event->pos()); mMouseOverHandle = &mTRHandle; } r = r.normalized(); } else if (mMouseOverHandle == &mBRHandle) { if (event->pos().x() >= r.left() && event->pos().y() >= r.top()) { r.setBottomRight(event->pos()); } else if (event->pos().x() >= r.left() && event->pos().y() < r.top()) { r.setRight(event->pos().x()); r.setBottom(r.top()); r.setTop(event->pos().y()); mMouseOverHandle = &mTRHandle; } else if (event->pos().x() < r.left() && event->pos().y() >= r.top()) { r.setBottom(event->pos().y()); r.setRight(r.left()); r.setLeft(event->pos().x()); mMouseOverHandle = &mBLHandle; } else { r.setBottomRight(r.topLeft()); r.setTopLeft(event->pos()); mMouseOverHandle = &mTLHandle; } r = r.normalized(); } else if (mMouseOverHandle == &mTHandle) { if (event->pos().y() <= r.bottom()) { r.setTop(event->pos().y()); } else { r.setTop(r.bottom()); r.setBottom(event->pos().y()); mMouseOverHandle = &mBHandle; } r = r.normalized(); } else if (mMouseOverHandle == &mRHandle) { if (event->pos().x() >= r.left()) { r.setRight(event->pos().x()); } else { r.setRight(r.left()); r.setLeft(event->pos().x()); mMouseOverHandle = &mLHandle; } r = r.normalized(); } else if (mMouseOverHandle == &mLHandle) { if (event->pos().x() <= r.right()) { r.setLeft(event->pos().x()); } else { r.setLeft(r.right()); r.setRight(event->pos().x()); mMouseOverHandle = &mRHandle; } r = r.normalized(); } else if (mMouseOverHandle == &mBHandle) { if (event->pos().y() >= r.top()) { r.setBottom(event->pos().y()); } else { r.setBottom(r.top()); r.setTop(event->pos().y()); mMouseOverHandle = &mTHandle; } r = r.normalized(); } mCropRect = r.normalized(); setResizeCursors(); } update(); emitCropRectChangedSignals(); } void KSCropArea::mouseReleaseEvent(QMouseEvent *event) { if (mMouseOverHandle == nullptr && mCropRect.contains(event->pos())) { setCursor(Qt::OpenHandCursor); } + if (event->button() == Qt::RightButton && !(mCropRect.contains(event->pos()))) { + mCropRect = QRect(0, 0, 0, 0); + } + update(); emitCropRectChangedSignals(); } void KSCropArea::hoverMoveEvent(QHoverEvent *event) { for (auto r: mHandles) { if (r->contains(event->pos())) { mMouseOverHandle = r; setResizeCursors(); return; } } mMouseOverHandle = nullptr; if (mCropRect.contains(event->pos())) { setCursor(Qt::OpenHandCursor); } else { setCursor(Qt::CrossCursor); } } // utility functions void KSCropArea::setResizeCursors() { if (mMouseOverHandle == &mTLHandle || mMouseOverHandle == &mBRHandle) { setCursor(Qt::SizeFDiagCursor); } else if (mMouseOverHandle == &mTRHandle || mMouseOverHandle == &mBLHandle) { setCursor(Qt::SizeBDiagCursor); } else if (mMouseOverHandle == &mLHandle || mMouseOverHandle == &mRHandle) { setCursor(Qt::SizeHorCursor); } else if (mMouseOverHandle == &mTHandle || mMouseOverHandle == &mBHandle) { setCursor(Qt::SizeVerCursor); } } inline void KSCropArea::drawTriangle(QPainter *painter, const QColor &color, const QPoint &a, const QPoint &b, const QPoint &c) { painter->save(); painter->setClipping(false); QPainterPath path; path.moveTo(a); path.lineTo(b); path.lineTo(c); path.lineTo(a); painter->setPen(Qt::NoPen); painter->fillPath(path, QBrush(color)); painter->setClipping(true); painter->restore(); } void KSCropArea::updateHandles() { QRect r = mCropRect; mTLHandle.moveTopLeft(r.topLeft()); mTRHandle.moveTopRight(r.topRight()); mBLHandle.moveBottomLeft(r.bottomLeft()); mBRHandle.moveBottomRight(r.bottomRight()); mLHandle.moveTopLeft(QPoint(r.x(), r.y() + (r.height() / 2) - (mLHandle.height() / 2))); mTHandle.moveTopLeft(QPoint(r.x() + (r.width() / 2) - (mTHandle.width() / 2), r.y())); mRHandle.moveTopRight(QPoint(r.right(), r.y() + (r.height() / 2) - (mRHandle.height() / 2))); mBHandle.moveBottomLeft(QPoint(r.x() + (r.width() / 2) - (mBHandle.width() / 2), r.bottom())); } void KSCropArea::drawHandles(QPainter *painter, const QColor &color) { drawTriangle(painter, color, mTLHandle.topLeft(), mTLHandle.topRight(), mTLHandle.bottomLeft()); drawTriangle(painter, color, mTRHandle.topRight(), mTRHandle.topLeft(), mTRHandle.bottomRight()); drawTriangle(painter, color, mBLHandle.topLeft(), mBLHandle.bottomLeft(), mBLHandle.bottomRight()); drawTriangle(painter, color, mBRHandle.topRight(), mBRHandle.bottomRight(), mBRHandle.bottomLeft()); drawTriangle(painter, color, mTHandle.topLeft(), mTHandle.topRight(), (mTHandle.bottomLeft() + mTHandle.bottomRight()) / 2); drawTriangle(painter, color, mBHandle.bottomLeft(), mBHandle.bottomRight(), (mBHandle.topLeft() + mBHandle.topRight()) / 2); drawTriangle(painter, color, mLHandle.topLeft(), mLHandle.bottomLeft(), (mLHandle.topRight() + mLHandle.bottomRight()) / 2); drawTriangle(painter, color, mRHandle.topRight(), mRHandle.bottomRight(), (mRHandle.topLeft() + mRHandle.bottomLeft()) / 2); } QPoint KSCropArea::limitPointToRect(const QPoint &p, const QRect &r) const { QPoint q; q.setX(p.x() < r.x() ? r.x() : p.x() < r.right() ? p.x() : r.right()); q.setY(p.y() < r.y() ? r.y() : p.y() < r.bottom() ? p.y() : r.bottom()); return q; } void KSCropArea::emitCropRectChangedSignals() { emit cropXChanged(mCropRect.x()); emit cropYChanged(mCropRect.y()); emit cropWidthChanged(mCropRect.width()); emit cropHeightChanged(mCropRect.height()); }