File indexing completed on 2024-05-12 16:34:23

0001 /* This file is part of the KDE project
0002    Copyright 2011 Silvio Heinrich <plassy@web.de>
0003 
0004    This library is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU Library General Public
0006    License as published by the Free Software Foundation; either
0007    version 2 of the License, or (at your option) any later version.
0008 
0009    This library is distributed in the hope that it will be useful,
0010    but WITHOUT ANY WARRANTY; without even the implied warranty of
0011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012    Library General Public License for more details.
0013 
0014    You should have received a copy of the GNU Library General Public License
0015    along with this library; see the file COPYING.LIB.  If not, write to
0016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017    Boston, MA 02110-1301, USA.
0018 */
0019 
0020 #include "CropWidget.h"
0021 #include "PictureShape.h"
0022 #include "KoImageData.h"
0023 
0024 #include <KoClipPath.h>
0025 
0026 #include <QPainter>
0027 #include <QResizeEvent>
0028 
0029 qreal calcScale(const QSizeF& imgSize, const QSizeF viewSize, bool fitView)
0030 {
0031     if (qFuzzyCompare(imgSize.width(), qreal(0)) || qFuzzyCompare(imgSize.height(), qreal(0)) ||
0032         qFuzzyCompare(viewSize.width(), qreal(0)) || qFuzzyCompare(viewSize.height(), qreal(0))) {
0033         return 1;
0034     }
0035 
0036     qreal viewAspect = viewSize.width() / viewSize.height();
0037     qreal imgAspect = imgSize.width() / imgSize.height();
0038 
0039     if (fitView) {
0040         if (viewAspect > imgAspect) {
0041             return viewSize.height() / imgSize.height();
0042         }
0043         else {
0044             return viewSize.width()  / imgSize.width();
0045         }
0046     }
0047     else {
0048         if (viewAspect > imgAspect) {
0049             return viewSize.width()  / imgSize.width();
0050         }
0051         else {
0052             return viewSize.height() / imgSize.height();
0053         }
0054     }
0055 }
0056 
0057 QRectF centerRectHorizontally(const QRectF& rect, const QSizeF viewSize)
0058 {
0059     QSizeF diff = viewSize - rect.size();
0060     return QRectF(diff.width() / 2.0, rect.y(), rect.width(), rect.height());
0061 }
0062 
0063 bool compareRects(const QRectF &a, const QRectF &b, qreal epsilon)
0064 {
0065     qreal x = qAbs(a.x() - b.x());
0066     qreal y = qAbs(a.y() - b.y());
0067     qreal w = qAbs(a.width() - b.width());
0068     qreal h = qAbs(a.height() - b.height());
0069 
0070     return x <= epsilon && y <= epsilon && w <= epsilon && h <= epsilon;
0071 }
0072 
0073 // ---------------------------------------------------------------- //
0074 
0075 CropWidget::CropWidget(QWidget *parent):
0076     QWidget(parent)
0077     , m_pictureShape(0)
0078     , m_isMousePressed(false)
0079     , m_undoLast(false)
0080 {
0081     setMinimumSize(100, 100);
0082     setMouseTracking(true);
0083 }
0084 
0085 void CropWidget::paintEvent(QPaintEvent *event)
0086 {
0087     Q_UNUSED(event);
0088 
0089     if(!m_pictureShape || m_imageRect.isNull())
0090         return;
0091 
0092     QPainter painter(this);
0093     QImage image = m_pictureShape->imageData()->image();
0094 
0095     painter.translate(m_imageRect.topLeft());
0096     painter.scale(m_imageRect.width(), m_imageRect.height());
0097 
0098     painter.drawImage(QRectF(0, 0, 1, 1), image);
0099 
0100     painter.setBrush(QColor(0, 0, 0, 127));
0101     painter.setPen(Qt::NoPen);
0102     painter.drawPolygon(QPolygonF(QRectF(0, 0, 1 , 1)).subtracted(m_selectionRect.getRect()));
0103 
0104     painter.setBrush(Qt::NoBrush);
0105     painter.setPen(QPen(this->palette().color(QPalette::Highlight), 0));
0106     painter.drawRect(m_selectionRect.getRect());
0107 
0108     painter.setBrush(QBrush(this->palette().color(QPalette::Highlight).darker()));
0109     for (int i=0; i<m_selectionRect.getNumHandles(); ++i)
0110         painter.drawRect(m_selectionRect.getHandleRect(m_selectionRect.getHandleFlags(i)));
0111 
0112     KoClipPath *clipPath = m_pictureShape->clipPath();
0113     if (clipPath) {
0114         painter.scale(0.01, 0.01); // the path is defined in 100x100 equaling shapesize
0115         painter.setBrush(Qt::NoBrush);
0116         painter.setPen(QPen(Qt::red, 0));
0117         painter.drawPath(clipPath->path());
0118     }
0119 
0120 }
0121 
0122 void CropWidget::mousePressEvent(QMouseEvent *event)
0123 {
0124     m_selectionRect.beginDragging(toUniformCoord(event->localPos()));
0125     m_isMousePressed = true;
0126 }
0127 
0128 void CropWidget::mouseMoveEvent(QMouseEvent *event)
0129 {
0130     QPointF pos = toUniformCoord(event->localPos());
0131     SelectionRect::HandleFlags flags = m_selectionRect.getHandleFlags(pos);
0132 
0133     switch (flags)
0134     {
0135     case SelectionRect::TOP_HANDLE:
0136     case SelectionRect::BOTTOM_HANDLE:
0137         QWidget::setCursor(Qt::SizeVerCursor);
0138         break;
0139 
0140     case SelectionRect::LEFT_HANDLE:
0141     case SelectionRect::RIGHT_HANDLE:
0142         QWidget::setCursor(Qt::SizeHorCursor);
0143         break;
0144 
0145     case SelectionRect::LEFT_HANDLE|SelectionRect::TOP_HANDLE:
0146     case SelectionRect::RIGHT_HANDLE|SelectionRect::BOTTOM_HANDLE:
0147         QWidget::setCursor(Qt::SizeFDiagCursor);
0148         break;
0149 
0150     case SelectionRect::LEFT_HANDLE|SelectionRect::BOTTOM_HANDLE:
0151     case SelectionRect::RIGHT_HANDLE|SelectionRect::TOP_HANDLE:
0152         QWidget::setCursor(Qt::SizeBDiagCursor);
0153         break;
0154 
0155     case SelectionRect::INSIDE_RECT:
0156         QWidget::setCursor(Qt::SizeAllCursor);
0157         break;
0158 
0159     default:
0160         QWidget::setCursor(Qt::ArrowCursor);
0161         break;
0162     }
0163 
0164     if (m_isMousePressed) {
0165         m_selectionRect.doDragging(pos);
0166         update();
0167         emitCropRegionChanged();
0168     }
0169 }
0170 
0171 void CropWidget::mouseReleaseEvent(QMouseEvent *event)
0172 {
0173     Q_UNUSED(event);
0174     m_selectionRect.finishDragging();
0175     m_isMousePressed = false;
0176     emitCropRegionChanged();
0177     m_undoLast = false; // we are done dragging
0178 }
0179 
0180 void CropWidget::resizeEvent(QResizeEvent* event)
0181 {
0182     Q_UNUSED(event);
0183     calcImageRect();
0184 }
0185 
0186 void CropWidget::setPictureShape(PictureShape *shape)
0187 {
0188     m_pictureShape = shape;
0189 
0190     calcImageRect();
0191     m_oldSelectionRect = shape->cropRect();
0192     m_selectionRect.setRect(shape->cropRect());
0193     m_selectionRect.setConstrainingRect(QRectF(0, 0, 1, 1));
0194     m_selectionRect.setHandleSize(0.04);
0195     //emit sigCropRegionChanged(shape->cropRect());
0196     update();
0197 }
0198 
0199 void CropWidget::setCropRect(const QRectF &rect)
0200 {
0201     m_selectionRect.setRect(rect);
0202     emitCropRegionChanged();
0203 }
0204 
0205 void CropWidget::setKeepPictureProportion(bool keepProportion)
0206 {
0207     qreal aspect = keepProportion ? (m_pictureShape->size().width() / m_pictureShape->size().height()) : 0.0;
0208     m_selectionRect.setConstrainingAspectRatio(aspect);
0209     emitCropRegionChanged();
0210 }
0211 
0212 void CropWidget::maximizeCroppedArea()
0213 {
0214     m_selectionRect.setRect(QRectF(0, 0, 1, 1));
0215     emitCropRegionChanged();
0216 }
0217 
0218 QPointF CropWidget::toUniformCoord(const QPointF& coord) const
0219 {
0220     QPointF result = coord - m_imageRect.topLeft();
0221     return QPointF(result.x() / m_imageRect.width(), result.y() / m_imageRect.height());
0222 }
0223 
0224 QPointF CropWidget::fromUniformCoord(const QPointF& coord) const
0225 {
0226     return m_imageRect.topLeft() + QPointF(coord.x()*m_imageRect.width(), coord.y()*m_imageRect.height());
0227 }
0228 
0229 void CropWidget::emitCropRegionChanged()
0230 {
0231     if (!compareRects(m_oldSelectionRect, m_selectionRect.getRect(), 0.01)) {
0232         m_oldSelectionRect = m_selectionRect.getRect();
0233         emit sigCropRegionChanged(m_selectionRect.getRect(), m_undoLast);
0234         update();
0235 
0236         m_undoLast = m_isMousePressed;
0237     }
0238 }
0239 
0240 void CropWidget::calcImageRect()
0241 {
0242     if (m_pictureShape) {
0243         QSizeF imageSize = m_pictureShape->imageData()->image().size();
0244         imageSize = imageSize * calcScale(imageSize, size(), true);
0245         m_imageRect = centerRectHorizontally (QRect(0, 0, imageSize.width(), imageSize.height()), size());
0246         m_selectionRect.setAspectRatio(m_imageRect.width() / m_imageRect.height());
0247     }
0248     else {
0249         m_imageRect = QRectF();
0250     }
0251 }