File indexing completed on 2025-03-09 03:50:37

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2004-12-09
0007  * Description : image selection widget used by ratio crop tool.
0008  *
0009  * SPDX-FileCopyrightText: 2007      by Jaromir Malenko <malenko at email.cz>
0010  * SPDX-FileCopyrightText: 2008      by Roberto Castagnola <roberto dot castagnola at gmail dot com>
0011  * SPDX-FileCopyrightText: 2004-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0012  *
0013  * SPDX-License-Identifier: GPL-2.0-or-later
0014  *
0015  * ============================================================ */
0016 
0017 #define OPACITY  0.7
0018 #define RCOL     0xAA
0019 #define GCOL     0xAA
0020 #define BCOL     0xAA
0021 
0022 #define MINRANGE 0
0023 
0024 // Golden number (1+sqrt(5))/2
0025 #define PHI      1.61803398874989479F
0026 // 1/PHI
0027 #define INVPHI   0.61803398874989479F
0028 // DIN A sqrt(2)
0029 #define DINA     1.41421356237309504F
0030 
0031 #include "ratiocropwidget.h"
0032 
0033 // C++ includes
0034 
0035 #include <iostream>
0036 #include <cstdio>
0037 #include <cmath>
0038 #include <cstdlib>
0039 
0040 // Qt includes
0041 
0042 #include <QRegion>
0043 #include <QPainter>
0044 #include <QBrush>
0045 #include <QPixmap>
0046 #include <QImage>
0047 #include <QPen>
0048 #include <QPoint>
0049 #include <QTimer>
0050 #include <QSizePolicy>
0051 #include <QResizeEvent>
0052 #include <QMouseEvent>
0053 #include <QPaintEvent>
0054 
0055 // Local includes
0056 
0057 #include "digikam_debug.h"
0058 #include "dimg.h"
0059 
0060 namespace DigikamEditorRatioCropToolPlugin
0061 {
0062 
0063 class Q_DECL_HIDDEN RatioCropWidget::Private
0064 {
0065 public:
0066 
0067     enum ResizingMode
0068     {
0069         ResizingNone = 0,
0070         ResizingTopLeft,
0071         ResizingTopRight,
0072         ResizingBottomLeft,
0073         ResizingBottomRight
0074     };
0075 
0076     explicit Private()
0077       : drawGoldenSection       (false),
0078         drawGoldenSpiralSection (false),
0079         drawGoldenSpiral        (false),
0080         drawGoldenTriangle      (false),
0081         flipHorGoldenGuide      (false),
0082         flipVerGoldenGuide      (false),
0083         moving                  (false),
0084         autoOrientation         (false),
0085         preciseCrop             (false),
0086         isDrawingSelection      (false),
0087         guideLinesType          (0),
0088         guideSize               (1),
0089         currentAspectRatioType  (0),
0090         currentResizing         (ResizingNone),
0091         currentOrientation      (0),
0092         currentWidthRatioValue  (0),
0093         currentHeightRatioValue (0),
0094         pixmap                  (nullptr),
0095         iface                   (nullptr)
0096     {
0097     }
0098 
0099     // Golden guide types.
0100     bool        drawGoldenSection;
0101     bool        drawGoldenSpiralSection;
0102     bool        drawGoldenSpiral;
0103     bool        drawGoldenTriangle;
0104 
0105     // Golden guide translations.
0106     bool        flipHorGoldenGuide;
0107     bool        flipVerGoldenGuide;
0108 
0109     bool        moving;
0110     bool        autoOrientation;
0111     bool        preciseCrop;
0112 
0113     bool        isDrawingSelection;
0114 
0115     int         guideLinesType;
0116     int         guideSize;
0117 
0118     int         currentAspectRatioType;
0119     int         currentResizing;
0120     int         currentOrientation;
0121 
0122     float       currentWidthRatioValue;
0123     float       currentHeightRatioValue;
0124 
0125     QPoint      lastPos;
0126 
0127     QRect       rect;
0128     QRect       image;                   // Real image dimension.
0129     QRect       regionSelection;         // Real size image selection.
0130     QRect       localRegionSelection;    // Local size selection.
0131 
0132     // Draggable local region selection corners.
0133     QRect       localTopLeftCorner;
0134     QRect       localBottomLeftCorner;
0135     QRect       localTopRightCorner;
0136     QRect       localBottomRightCorner;
0137 
0138     QPixmap*    pixmap;
0139     QPixmap     grayOverLay;
0140     QPixmap     previewPixmap;
0141 
0142     QColor      guideColor;
0143     QColor      bgColor;
0144 
0145     DImg        preview;
0146 
0147     ImageIface* iface;
0148 };
0149 
0150 RatioCropWidget::RatioCropWidget(int w, int h, QWidget* const parent)
0151     : QWidget(parent),
0152       d      (new Private)
0153 {
0154     d->isDrawingSelection = true;
0155     d->bgColor            = palette().color(QPalette::Window);
0156     setup(w, h);
0157 }
0158 
0159 RatioCropWidget::RatioCropWidget(int w, int h, bool initDrawing, QWidget* const parent)
0160     : QWidget(parent),
0161       d      (new Private)
0162 {
0163     d->isDrawingSelection = initDrawing;
0164     setup(w, h);
0165 }
0166 
0167 RatioCropWidget::~RatioCropWidget()
0168 {
0169     delete d->iface;
0170     delete d->pixmap;
0171     delete d;
0172 }
0173 
0174 void RatioCropWidget::setup(int w, int h,
0175                                  int widthRatioValue, int heightRatioValue,
0176                                  int aspectRatio, int orient,
0177                                  int guideLinesType)
0178 {
0179     setMinimumSize(w, h);
0180     setMouseTracking(true);
0181     setAttribute(Qt::WA_DeleteOnClose);
0182 
0183     d->currentAspectRatioType  = aspectRatio;
0184     d->currentWidthRatioValue  = widthRatioValue;
0185     d->currentHeightRatioValue = heightRatioValue;
0186     d->currentOrientation      = orient;
0187     d->guideLinesType          = guideLinesType;
0188     d->autoOrientation         = false;
0189     d->preciseCrop             = false;
0190     d->moving                  = true;
0191     reverseRatioValues();
0192 
0193     d->iface   = new ImageIface(QSize(w, h));
0194     d->preview = d->iface->preview();
0195     d->preview.setIccProfile(d->iface->original()->getIccProfile());
0196     d->preview.convertToEightBit();
0197 
0198     d->pixmap  = new QPixmap(w, h);
0199     d->image   = QRect(0, 0, d->iface->originalSize().width(), d->iface->originalSize().height());
0200     d->rect    = QRect((w-d->preview.width()) /2,
0201                        (h-d->preview.height())/2,
0202                        d->preview.width(), d->preview.height());
0203 
0204     updatePixmap();
0205     setGoldenGuideTypes(true, false, false, false, false, false);
0206 }
0207 
0208 ImageIface* RatioCropWidget::imageIface() const
0209 {
0210     return d->iface;
0211 }
0212 
0213 void RatioCropWidget::resizeEvent(QResizeEvent* e)
0214 {
0215     delete d->pixmap;
0216 
0217     int w      = e->size().width();
0218     int h      = e->size().height();
0219     d->preview = d->iface->setPreviewSize(QSize(w, h));
0220     d->preview.setIccProfile(d->iface->original()->getIccProfile());
0221     d->preview.convertToEightBit();
0222 
0223     d->pixmap  = new QPixmap(w, h);
0224     d->rect    = QRect((w-d->preview.width()) /2,
0225                        (h-d->preview.height())/2,
0226                        d->preview.width(), d->preview.height());
0227 
0228     // Drawing the gray overlay
0229 
0230     {
0231         DImg image = d->preview.copy();
0232         uchar* ptr = image.bits();
0233         uchar  r, g, b;
0234 
0235         int xlow  = d->rect.left();
0236         int xhigh = d->rect.right();
0237         int ylow  = d->rect.top();
0238         int yhigh = d->rect.bottom();
0239 
0240         for (int y = ylow ; y <= yhigh ; ++y)
0241         {
0242             for (int x = xlow ; x <= xhigh ; ++x)
0243             {
0244                 b = ptr[0];
0245                 g = ptr[1];
0246                 r = ptr[2];
0247 
0248                 r += (uchar)((RCOL - r) * OPACITY);
0249                 g += (uchar)((GCOL - g) * OPACITY);
0250                 b += (uchar)((BCOL - b) * OPACITY);
0251 
0252                 ptr[0] = b;
0253                 ptr[1] = g;
0254                 ptr[2] = r;
0255 
0256                 ptr+=4;
0257             }
0258         }
0259 
0260         d->grayOverLay   = image.convertToPixmap();
0261         d->previewPixmap = d->iface->convertToPixmap(d->preview);
0262     }
0263 
0264     updatePixmap();
0265 }
0266 
0267 int RatioCropWidget::getOriginalImageWidth() const
0268 {
0269     return d->image.width();
0270 }
0271 
0272 int RatioCropWidget::getOriginalImageHeight() const
0273 {
0274     return d->image.height();
0275 }
0276 
0277 QRect RatioCropWidget::getRegionSelection() const
0278 {
0279     return d->regionSelection;
0280 }
0281 
0282 int RatioCropWidget::getMinWidthRange() const
0283 {
0284     return MINRANGE;
0285 }
0286 
0287 int RatioCropWidget::getMinHeightRange() const
0288 {
0289     return MINRANGE;
0290 }
0291 
0292 int RatioCropWidget::getMaxWidthRange() const
0293 {
0294     int maxW = d->image.width() - d->regionSelection.left();
0295 
0296     if (d->currentAspectRatioType != RATIONONE)
0297     {
0298         // Compute max width taking aspect ratio into account
0299 
0300         int t = d->currentWidthRatioValue > d->currentHeightRatioValue ? 1 : 0;
0301         int h = d->image.height() - d->regionSelection.top();
0302         int w = (int)rint((h + t) * d->currentWidthRatioValue /
0303                           d->currentHeightRatioValue) - t;
0304 
0305         if (w < maxW)
0306         {
0307             maxW = w;
0308         }
0309     }
0310 
0311     // Return max width adjusted if a precise crop is wanted
0312 
0313     return computePreciseSize(maxW, (int)d->currentWidthRatioValue);
0314 }
0315 
0316 int RatioCropWidget::getMaxHeightRange() const
0317 {
0318     int maxH = d->image.height() - d->regionSelection.top();
0319 
0320     if (d->currentAspectRatioType != RATIONONE)
0321     {
0322         // Compute max height taking aspect ratio into account
0323 
0324         int t = d->currentHeightRatioValue > d->currentWidthRatioValue ? 1 : 0;
0325         int w = d->image.width() - d->regionSelection.left();
0326         int h = (int)rint((w + t) * d->currentHeightRatioValue /
0327                           d->currentWidthRatioValue) - t;
0328 
0329         if (h < maxH)
0330         {
0331             maxH = h;
0332         }
0333     }
0334 
0335     // Return max height adjusted if a precise crop is wanted
0336 
0337     return computePreciseSize(maxH, (int)d->currentHeightRatioValue);
0338 }
0339 
0340 int RatioCropWidget::getWidthStep() const
0341 {
0342     if (d->preciseCrop && preciseCropAvailable())
0343     {
0344         return (int)d->currentWidthRatioValue;
0345     }
0346     else
0347     {
0348         return 1;
0349     }
0350 }
0351 
0352 int RatioCropWidget::getHeightStep() const
0353 {
0354     if (d->preciseCrop && preciseCropAvailable())
0355     {
0356         return (int)d->currentHeightRatioValue;
0357     }
0358     else
0359     {
0360         return 1;
0361     }
0362 }
0363 
0364 /**
0365  * Draw a new centered selection with half width (if orientation = Landscape)
0366  * or with half height (if orientation = Portrait)
0367  */
0368 void RatioCropWidget::resetSelection()
0369 {
0370     d->regionSelection.setWidth(d->image.width()/2);
0371     d->regionSelection.setHeight(d->image.height()/2);
0372     applyAspectRatio(d->currentOrientation == Portrait, false);
0373 
0374     setCenterSelection(CenterImage);
0375 }
0376 
0377 void RatioCropWidget::setCenterSelection(int centerType)
0378 {
0379     // Adjust selection size if bigger than real image
0380 
0381     if (d->regionSelection.height() > d->image.height())
0382     {
0383         d->regionSelection.setHeight(d->image.height());
0384         applyAspectRatio(true, false);
0385     }
0386 
0387     if (d->regionSelection.width() > d->image.width())
0388     {
0389         d->regionSelection.setWidth(d->image.width());
0390         applyAspectRatio(false, false);
0391     }
0392 
0393     // Set center point for selection
0394 
0395     QPoint center = d->image.center();
0396 
0397     switch (centerType)
0398     {
0399         case CenterWidth:
0400         {
0401             center.setY(d->regionSelection.center().y());
0402             break;
0403         }
0404 
0405         case CenterHeight:
0406         {
0407             center.setX(d->regionSelection.center().x());
0408             break;
0409         }
0410     }
0411 
0412     d->regionSelection.moveCenter(center);
0413 
0414     // Repaint
0415 
0416     updatePixmap();
0417     update();
0418     regionSelectionChanged();
0419 }
0420 
0421 /**
0422  * Draw a new centered selection with max size
0423  */
0424 void RatioCropWidget::maxAspectSelection()
0425 {
0426     d->regionSelection.setWidth(d->image.width());
0427     d->regionSelection.setHeight(d->image.height());
0428 
0429     if (d->currentAspectRatioType != RATIONONE)
0430     {
0431         applyAspectRatio(d->currentOrientation == Portrait, false);
0432     }
0433 
0434     setCenterSelection(CenterImage);
0435 }
0436 
0437 void RatioCropWidget::setGoldenGuideTypes(bool drawGoldenSection,  bool drawGoldenSpiralSection,
0438                                           bool drawGoldenSpiral,   bool drawGoldenTriangle,
0439                                           bool flipHorGoldenGuide, bool flipVerGoldenGuide)
0440 {
0441     d->drawGoldenSection       = drawGoldenSection;
0442     d->drawGoldenSpiralSection = drawGoldenSpiralSection;
0443     d->drawGoldenSpiral        = drawGoldenSpiral;
0444     d->drawGoldenTriangle      = drawGoldenTriangle;
0445     d->flipHorGoldenGuide      = flipHorGoldenGuide;
0446     d->flipVerGoldenGuide      = flipVerGoldenGuide;
0447 }
0448 
0449 void RatioCropWidget::setBackgroundColor(const QColor& bg)
0450 {
0451     d->bgColor = bg;
0452     updatePixmap();
0453     update();
0454 }
0455 
0456 void RatioCropWidget::slotGuideLines(int guideLinesType)
0457 {
0458     d->guideLinesType = guideLinesType;
0459     updatePixmap();
0460     update();
0461 }
0462 
0463 void RatioCropWidget::slotChangeGuideColor(const QColor& color)
0464 {
0465     d->guideColor = color;
0466     updatePixmap();
0467     update();
0468 }
0469 
0470 void RatioCropWidget::slotChangeGuideSize(int size)
0471 {
0472     d->guideSize = size;
0473     updatePixmap();
0474     update();
0475 }
0476 
0477 void RatioCropWidget::setSelectionOrientation(int orient)
0478 {
0479     d->currentOrientation = orient;
0480     reverseRatioValues();
0481     applyAspectRatio(true);
0482 
0483     Q_EMIT signalSelectionOrientationChanged(d->currentOrientation);
0484 }
0485 
0486 void RatioCropWidget::setSelectionAspectRatioType(int aspectRatioType)
0487 {
0488     d->currentAspectRatioType = aspectRatioType;
0489 
0490     // Set ratio values
0491 
0492     switch (aspectRatioType)
0493     {
0494         case RATIO01X01:
0495         {
0496             d->currentHeightRatioValue = 1.0;
0497             d->currentWidthRatioValue  = 1.0;
0498             break;
0499         }
0500 
0501         case RATIO02x01:
0502         {
0503             d->currentHeightRatioValue = 2.0;
0504             d->currentWidthRatioValue  = 1.0;
0505             break;
0506         }
0507 
0508         case RATIO02x03:
0509         {
0510             d->currentHeightRatioValue = 2.0;
0511             d->currentWidthRatioValue  = 3.0;
0512             break;
0513         }
0514 
0515         case RATIO03X01:
0516         {
0517             d->currentHeightRatioValue = 3.0;
0518             d->currentWidthRatioValue  = 1.0;
0519             break;
0520         }
0521 
0522         case RATIO03X04:
0523         {
0524             d->currentHeightRatioValue = 3.0;
0525             d->currentWidthRatioValue  = 4.0;
0526             break;
0527         }
0528 
0529         case RATIO04X01:
0530         {
0531             d->currentHeightRatioValue = 4.0;
0532             d->currentWidthRatioValue  = 1.0;
0533             break;
0534         }
0535 
0536         case RATIO04X05:
0537         {
0538             d->currentHeightRatioValue = 4.0;
0539             d->currentWidthRatioValue  = 5.0;
0540             break;
0541         }
0542 
0543         case RATIO05x07:
0544         {
0545             d->currentHeightRatioValue = 5.0;
0546             d->currentWidthRatioValue  = 7.0;
0547             break;
0548         }
0549 
0550         case RATIO07x10:
0551         {
0552             d->currentHeightRatioValue = 7.0;
0553             d->currentWidthRatioValue  = 10.0;
0554             break;
0555         }
0556 
0557         case RATIO08x05:
0558         {
0559             d->currentHeightRatioValue = 8.0;
0560             d->currentWidthRatioValue  = 5.0;
0561             break;
0562         }
0563 
0564         case RATIO16x09:
0565         {
0566             d->currentHeightRatioValue = 16.0;
0567             d->currentWidthRatioValue  = 9.0;
0568             break;
0569         }
0570 
0571         case RATIODINA0:
0572         {
0573             d->currentHeightRatioValue = 1.0;
0574             d->currentWidthRatioValue  = DINA;
0575             break;
0576         }
0577 
0578         case RATIOGOLDEN:
0579         {
0580             d->currentHeightRatioValue = 1.0;
0581             d->currentWidthRatioValue  = PHI;
0582             break;
0583         }
0584 
0585         case RATIOCURRENT:
0586         {
0587             d->currentHeightRatioValue = d->image.height();
0588             d->currentWidthRatioValue  = d->image.width();
0589             break;
0590         }
0591     }
0592 
0593     reverseRatioValues();
0594     applyAspectRatio(false);
0595 }
0596 
0597 void RatioCropWidget::setSelectionAspectRatioValue(int widthRatioValue, int heightRatioValue)
0598 {
0599     int gdc = widthRatioValue;
0600 
0601     // Compute greatest common divisor using Euclidean algorithm
0602 
0603     for (int tmp, mod = heightRatioValue; mod != 0; mod = tmp % mod)
0604     {
0605         tmp = gdc;
0606         gdc = mod;
0607     }
0608 
0609     d->currentWidthRatioValue  = widthRatioValue  / gdc;
0610     d->currentHeightRatioValue = heightRatioValue / gdc;
0611     d->currentAspectRatioType  = RATIOCUSTOM;
0612 
0613     // Fix orientation
0614 
0615     if (d->autoOrientation)
0616     {
0617         if      ((heightRatioValue > widthRatioValue) &&
0618                  (d->currentOrientation == Landscape))
0619         {
0620             d->currentOrientation = Portrait;
0621 
0622             Q_EMIT signalSelectionOrientationChanged(d->currentOrientation);
0623         }
0624         else if ((widthRatioValue > heightRatioValue) &&
0625                  (d->currentOrientation == Portrait))
0626         {
0627             d->currentOrientation = Landscape;
0628 
0629             Q_EMIT signalSelectionOrientationChanged(d->currentOrientation);
0630         }
0631     }
0632     else
0633     {
0634         reverseRatioValues();
0635     }
0636 
0637     applyAspectRatio(false);
0638 }
0639 
0640 void RatioCropWidget::reverseRatioValues()
0641 {
0642     // Reverse ratio values if needed
0643 
0644     if (((d->currentWidthRatioValue > d->currentHeightRatioValue)  &&
0645          (d->currentOrientation == Portrait))                      ||
0646          ((d->currentHeightRatioValue > d->currentWidthRatioValue) &&
0647           (d->currentOrientation == Landscape)))
0648     {
0649         float tmp                  = d->currentWidthRatioValue;
0650         d->currentWidthRatioValue  = d->currentHeightRatioValue;
0651         d->currentHeightRatioValue = tmp;
0652     }
0653 }
0654 
0655 bool RatioCropWidget::preciseCropAvailable() const
0656 {
0657     // Define when precise crop feature can be used
0658     // No needed when aspect ratio is 1:1
0659 
0660     switch (d->currentAspectRatioType)
0661     {
0662         case RATIONONE:
0663         case RATIO01X01:
0664         case RATIODINA0:
0665         case RATIOGOLDEN:
0666         {
0667             return false;
0668         }
0669 
0670         case RATIOCUSTOM:
0671         {
0672             return (d->currentWidthRatioValue != d->currentHeightRatioValue);
0673         }
0674 
0675         default:
0676         {
0677             return true;
0678         }
0679     }
0680 }
0681 
0682 void RatioCropWidget::setPreciseCrop(bool precise)
0683 {
0684     d->preciseCrop = precise;
0685     applyAspectRatio(false, true);
0686     regionSelectionChanged();
0687 }
0688 
0689 void RatioCropWidget::setAutoOrientation(bool orientation)
0690 {
0691     d->autoOrientation = orientation;
0692 }
0693 
0694 void RatioCropWidget::setSelectionX(int x)
0695 {
0696     d->regionSelection.moveLeft(x);
0697     regionSelectionMoved();
0698 }
0699 
0700 void RatioCropWidget::setSelectionY(int y)
0701 {
0702     d->regionSelection.moveTop(y);
0703     regionSelectionMoved();
0704 }
0705 
0706 void RatioCropWidget::setSelectionWidth(int w)
0707 {
0708     d->regionSelection.setWidth(w);
0709     applyAspectRatio(false, true);
0710 
0711     regionSelectionChanged();
0712 }
0713 
0714 void RatioCropWidget::setSelectionHeight(int h)
0715 {
0716     d->regionSelection.setHeight(h);
0717     applyAspectRatio(true, true);
0718 
0719     regionSelectionChanged();
0720 }
0721 
0722 QPoint RatioCropWidget::convertPoint(const QPoint& pm, bool localToReal) const
0723 {
0724     return convertPoint(pm.x(), pm.y(), localToReal);
0725 }
0726 
0727 QPoint RatioCropWidget::convertPoint(int x, int y, bool localToReal) const
0728 {
0729     int pmX, pmY;
0730 
0731     if (localToReal)
0732     {
0733         pmX = (int)((x - d->rect.left()) * (float)d->image.width() /
0734                     (float)d->preview.width());
0735 
0736         pmY = (int)((y - d->rect.top()) * (float)d->image.height() /
0737                     (float)d->preview.height());
0738     }
0739     else
0740     {
0741         pmX = (int)(d->rect.left() + (x * (float)d->preview.width() /
0742                                       (float)d->image.width()));
0743 
0744         pmY = (int)(d->rect.top() + (y * (float)d->preview.height() /
0745                                      (float)d->image.height()));
0746     }
0747 
0748     return QPoint(pmX, pmY);
0749 }
0750 
0751 int RatioCropWidget::computePreciseSize(int size, int step) const
0752 {
0753     // Adjust size if precise crop is wanted
0754 
0755     if (d->preciseCrop && preciseCropAvailable())
0756     {
0757         size = int(size / step) * step;
0758     }
0759 
0760     return size;
0761 }
0762 
0763 void RatioCropWidget::applyAspectRatio(bool useHeight, bool repaintWidget)
0764 {
0765     // Save selection area for re-adjustment after changing width and height.
0766 
0767     QRect oldRegionSelection = d->regionSelection;
0768 
0769     if (!useHeight)  // Width changed.
0770     {
0771         int w = computePreciseSize(d->regionSelection.width(),
0772                                    (int)d->currentWidthRatioValue);
0773 
0774         d->regionSelection.setWidth(w);
0775 
0776         switch (d->currentAspectRatioType)
0777         {
0778             case RATIONONE:
0779             {
0780                 break;
0781             }
0782 
0783             default:
0784             {
0785                 d->regionSelection.setHeight((int)
0786                                              rint(w * d->currentHeightRatioValue /
0787                                                   d->currentWidthRatioValue));
0788                 break;
0789             }
0790         }
0791     }
0792     else      // Height changed.
0793     {
0794         int h = computePreciseSize(d->regionSelection.height(),
0795                                    (int)d->currentHeightRatioValue);
0796 
0797         d->regionSelection.setHeight(h);
0798 
0799         switch (d->currentAspectRatioType)
0800         {
0801             case RATIONONE:
0802             {
0803                 break;
0804             }
0805 
0806             default:
0807             {
0808                 d->regionSelection.setWidth((int)
0809                                             rint(h * d->currentWidthRatioValue /
0810                                                  d->currentHeightRatioValue));
0811                 break;
0812             }
0813         }
0814     }
0815 
0816     // If we change selection size by a corner, re-adjust the opposite corner position.
0817 
0818     switch (d->currentResizing)
0819     {
0820         case Private::ResizingTopLeft:
0821         {
0822             d->regionSelection.moveBottomRight(oldRegionSelection.bottomRight());
0823             break;
0824         }
0825 
0826         case Private::ResizingTopRight:
0827         {
0828             d->regionSelection.moveBottomLeft(oldRegionSelection.bottomLeft());
0829             break;
0830         }
0831 
0832         case Private::ResizingBottomLeft:
0833         {
0834             d->regionSelection.moveTopRight(oldRegionSelection.topRight());
0835             break;
0836         }
0837 
0838         case Private::ResizingBottomRight:
0839         {
0840             d->regionSelection.moveTopLeft(oldRegionSelection.topLeft());
0841             break;
0842         }
0843     }
0844 
0845     if (repaintWidget)
0846     {
0847         updatePixmap();
0848         update();
0849     }
0850 }
0851 
0852 void RatioCropWidget::normalizeRegion()
0853 {
0854     // Perform normalization of selection area.
0855 
0856     if (d->regionSelection.left() < d->image.left())
0857     {
0858         d->regionSelection.moveLeft(d->image.left());
0859     }
0860 
0861     if (d->regionSelection.top() < d->image.top())
0862     {
0863         d->regionSelection.moveTop(d->image.top());
0864     }
0865 
0866     if (d->regionSelection.right() > d->image.right())
0867     {
0868         d->regionSelection.moveRight(d->image.right());
0869     }
0870 
0871     if (d->regionSelection.bottom() > d->image.bottom())
0872     {
0873         d->regionSelection.moveBottom(d->image.bottom());
0874     }
0875 }
0876 
0877 void RatioCropWidget::regionSelectionMoved()
0878 {
0879     normalizeRegion();
0880 
0881     updatePixmap();
0882     update();
0883 
0884     Q_EMIT signalSelectionMoved(d->regionSelection);
0885 }
0886 
0887 void RatioCropWidget::regionSelectionChanged()
0888 {
0889     // Compute the intersection of selection region and image region
0890 
0891     QRect cut = d->regionSelection & d->image;
0892 
0893     // Adjust selection size if it was cropped
0894 
0895     if (d->regionSelection.width() > cut.width())
0896     {
0897         d->regionSelection = cut;
0898         applyAspectRatio(false);
0899     }
0900 
0901     if (d->regionSelection.height() > cut.height())
0902     {
0903         d->regionSelection = cut;
0904         applyAspectRatio(true);
0905     }
0906 
0907     Q_EMIT signalSelectionChanged(d->regionSelection);
0908 }
0909 
0910 void RatioCropWidget::drawRulesOfThirds(QPainter& p, const int& xThird, const int& yThird)
0911 {
0912 
0913     p.drawLine(d->localRegionSelection.left() + xThird,   d->localRegionSelection.top(),
0914                d->localRegionSelection.left() + xThird,   d->localRegionSelection.bottom());
0915     p.drawLine(d->localRegionSelection.left() + 2*xThird, d->localRegionSelection.top(),
0916                d->localRegionSelection.left() + 2*xThird, d->localRegionSelection.bottom());
0917 
0918     p.drawLine(d->localRegionSelection.left(),  d->localRegionSelection.top() + yThird,
0919                d->localRegionSelection.right(), d->localRegionSelection.top() + yThird);
0920     p.drawLine(d->localRegionSelection.left(),  d->localRegionSelection.top() + 2*yThird,
0921                d->localRegionSelection.right(), d->localRegionSelection.top() + 2*yThird);
0922 
0923 }
0924 
0925 void RatioCropWidget::drawRulesOfCenter(QPainter& p, const int& xHalf, const int& yHalf)
0926 {
0927     p.drawLine(d->localRegionSelection.left() + xHalf, d->localRegionSelection.top(),
0928                d->localRegionSelection.left() + xHalf, d->localRegionSelection.bottom());
0929 
0930     p.drawLine(d->localRegionSelection.left(),  d->localRegionSelection.top() + yHalf,
0931                d->localRegionSelection.right(), d->localRegionSelection.top() + yHalf);
0932 }
0933 
0934 void RatioCropWidget::drawDiagonalMethod(QPainter& p, const int& w, const int& h)
0935 {
0936     p.setRenderHint(QPainter::Antialiasing);
0937 
0938     if (w > h)
0939     {
0940         p.drawLine(0, 0, h, h);
0941         p.drawLine(0, h, h, 0);
0942         p.drawLine(w-h, 0, w, h);
0943         p.drawLine(w-h, h, w, 0);
0944     }
0945     else
0946     {
0947         p.drawLine(0, 0, w, w);
0948         p.drawLine(0, w, w, 0);
0949         p.drawLine(0, h-w, w, h);
0950         p.drawLine(0, h, w, h-w);
0951     }
0952 }
0953 
0954 void RatioCropWidget::drawHarmoniousTriangles(QPainter& p, const int& dst)
0955 {
0956     p.setRenderHint(QPainter::Antialiasing);
0957 
0958     p.drawLine(-d->localRegionSelection.width()/2, -d->localRegionSelection.height()/2,
0959                 d->localRegionSelection.width()/2,  d->localRegionSelection.height()/2);
0960 
0961     p.drawLine(-d->localRegionSelection.width()/2 + dst, -d->localRegionSelection.height()/2,
0962                -d->localRegionSelection.width()/2,        d->localRegionSelection.height()/2);
0963 
0964     p.drawLine(d->localRegionSelection.width()/2,       -d->localRegionSelection.height()/2,
0965                d->localRegionSelection.width()/2 - dst,  d->localRegionSelection.height()/2);
0966 }
0967 
0968 void RatioCropWidget::drawGoldenMean(QPainter& p, const QRect& R1,
0969                                           const QRect& R2, const QRect& R3, const QRect& R4,
0970                                           const QRect& R5, const QRect& R6, const QRect& R7)
0971 {
0972     p.setRenderHint(QPainter::Antialiasing);
0973 
0974     // Drawing Golden sections.
0975 
0976     if (d->drawGoldenSection)
0977     {
0978         // horizontal lines:
0979 
0980         p.drawLine(R1.left(), R2.top(),
0981                    R2.right(), R2.top());
0982 
0983         p.drawLine(R1.left(), R1.top() + R2.height(),
0984                    R2.right(), R1.top() + R2.height());
0985 
0986         // vertical lines:
0987 
0988         p.drawLine(R1.right(), R1.top(),
0989                    R1.right(), R1.bottom());
0990 
0991         p.drawLine(R1.left()+R2.width(), R1.top(),
0992                    R1.left()+R2.width(), R1.bottom());
0993     }
0994 
0995     // Drawing Golden triangle guides.
0996 
0997     if (d->drawGoldenTriangle)
0998     {
0999         p.drawLine(R1.left(),  R1.bottom(),
1000                    R2.right(), R1.top());
1001 
1002         p.drawLine(R1.left(), R1.top(),
1003                    R2.right() - R1.width(), R1.bottom());
1004 
1005         p.drawLine(R1.left() + R1.width(), R1.top(),
1006                    R2.right(), R1.bottom());
1007     }
1008 
1009     // Drawing Golden spiral sections.
1010 
1011     if (d->drawGoldenSpiralSection)
1012     {
1013         p.drawLine(R1.topRight(),   R1.bottomRight());
1014         p.drawLine(R2.topLeft(),    R2.topRight());
1015         p.drawLine(R3.topLeft(),    R3.bottomLeft());
1016         p.drawLine(R4.bottomLeft(), R4.bottomRight());
1017         p.drawLine(R5.topRight(),   R5.bottomRight());
1018         p.drawLine(R6.topLeft(),    R6.topRight());
1019         p.drawLine(R7.topLeft(),    R7.bottomLeft());
1020     }
1021 
1022     // Drawing Golden Spiral.
1023 
1024     if (d->drawGoldenSpiral)
1025     {
1026         p.drawArc(R1.left(),
1027                   R1.top() - R1.height(),
1028                   2*R1.width(), 2*R1.height(),
1029                   180*16, 90*16);
1030 
1031         p.drawArc(R2.right()  - 2*R2.width(),
1032                   R1.bottom() - 2*R2.height(),
1033                   2*R2.width(), 2*R2.height(),
1034                   270*16, 90*16);
1035 
1036         p.drawArc(R2.right() - 2*R3.width(),
1037                   R3.top(),
1038                   2*R3.width(), 2*R3.height(),
1039                   0, 90*16);
1040 
1041         p.drawArc(R4.left(),
1042                   R4.top(),
1043                   2*R4.width(), 2*R4.height(),
1044                   90*16, 90*16);
1045 
1046         p.drawArc(R5.left(),
1047                   R5.top() - R5.height(),
1048                   2*R5.width(), 2*R5.height(),
1049                   180*16, 90*16);
1050 
1051         p.drawArc(R6.left() - R6.width(),
1052                   R6.top()  - R6.height(),
1053                   2*R6.width(), 2*R6.height(),
1054                   270*16, 90*16);
1055 
1056         p.drawArc(R7.left() - R7.width(),
1057                   R7.top(),
1058                   2*R7.width(), 2*R7.height(),
1059                   0, 90*16);
1060     }
1061 }
1062 
1063 void RatioCropWidget::updatePixmap()
1064 {
1065     // Updated local selection region.
1066 
1067     d->localRegionSelection.setTopLeft(convertPoint(d->regionSelection.topLeft(), false));
1068     d->localRegionSelection.setBottomRight(convertPoint(d->regionSelection.bottomRight(), false));
1069 
1070     // Updated dragging corners region.
1071 
1072     d->localTopLeftCorner.setRect(d->localRegionSelection.left(),          d->localRegionSelection.top(),        8, 8);
1073     d->localBottomLeftCorner.setRect(d->localRegionSelection.left(),       d->localRegionSelection.bottom() - 7, 8, 8);
1074     d->localTopRightCorner.setRect(d->localRegionSelection.right() - 7,    d->localRegionSelection.top(),        8, 8);
1075     d->localBottomRightCorner.setRect(d->localRegionSelection.right() - 7, d->localRegionSelection.bottom() - 7, 8, 8);
1076 
1077     // Drawing background.
1078 
1079     d->pixmap->fill(d->bgColor);
1080 
1081     if (d->preview.isNull())
1082     {
1083         return;
1084     }
1085 
1086     int sx = d->localRegionSelection.left() - d->rect.left();
1087     int sy = d->localRegionSelection.top()  - d->rect.top();
1088     int dw = d->localRegionSelection.width();
1089     int dh = d->localRegionSelection.height();
1090 
1091     QPainter p(d->pixmap);
1092     p.drawPixmap(d->rect.x(), d->rect.y(), d->grayOverLay);
1093 
1094     // Stop here if no selection to draw
1095 
1096     if (d->regionSelection.isEmpty() || !d->isDrawingSelection)
1097     {
1098         return;
1099     }
1100 
1101     // Now draw the image.
1102 
1103     p.drawPixmap(d->localRegionSelection.left(), d->localRegionSelection.top(), d->previewPixmap,
1104                  sx, sy, dw, dh);
1105 
1106     // Drawing selection borders.
1107 
1108     p.setPen(QPen(QColor(250, 250, 255), 1, Qt::SolidLine));
1109     p.drawRect(d->localRegionSelection);
1110 
1111     // Drawing selection corners.
1112 
1113     p.drawRect(d->localTopLeftCorner);
1114     p.drawRect(d->localBottomLeftCorner);
1115     p.drawRect(d->localTopRightCorner);
1116     p.drawRect(d->localBottomRightCorner);
1117 
1118     // Drawing guide lines.
1119 
1120     // Constraint drawing only on local selection region.
1121     // This is needed because arcs and incurved lines can draw
1122     // outside a little of local selection region.
1123 
1124     p.setClipping(true);
1125     p.setClipRect(d->localRegionSelection);
1126 
1127     switch (d->guideLinesType)
1128     {
1129         case RulesOfThirds:
1130         {
1131             int xThird = d->localRegionSelection.width()  / 3;
1132             int yThird = d->localRegionSelection.height() / 3;
1133 
1134             p.setPen(QPen(Qt::white, d->guideSize, Qt::SolidLine));
1135             drawRulesOfThirds(p, xThird, yThird);
1136 
1137             p.setPen(QPen(d->guideColor, d->guideSize, Qt::DotLine));
1138             drawRulesOfThirds(p, xThird, yThird);
1139             break;
1140         }
1141 
1142         case DiagonalMethod:
1143         {
1144             // Move coordinates to top, left
1145 
1146             p.translate(d->localRegionSelection.topLeft().x(), d->localRegionSelection.topLeft().y());
1147 
1148             int w = d->localRegionSelection.width();
1149             int h = d->localRegionSelection.height();
1150 
1151             p.setPen(QPen(Qt::white, d->guideSize, Qt::SolidLine));
1152             drawDiagonalMethod(p, w, h);
1153 
1154             p.setPen(QPen(d->guideColor, d->guideSize, Qt::DotLine));
1155             drawDiagonalMethod(p, w, h);
1156             break;
1157         }
1158 
1159         case HarmoniousTriangles:
1160         {
1161             // Move coordinates to local center selection.
1162 
1163             p.translate(d->localRegionSelection.center().x(), d->localRegionSelection.center().y());
1164 
1165             // Flip horizontal.
1166 
1167             if (d->flipHorGoldenGuide)
1168             {
1169                 p.scale(-1, 1);
1170             }
1171 
1172             // Flip vertical.
1173 
1174             if (d->flipVerGoldenGuide)
1175             {
1176                 p.scale(1, -1);
1177             }
1178 
1179             float w = (float)d->localRegionSelection.width();
1180             float h = (float)d->localRegionSelection.height();
1181             int dst = (int)((h*cos(atan(w/h)) / (cos(atan(h/w)))));
1182 
1183             p.setPen(QPen(Qt::white, d->guideSize, Qt::SolidLine));
1184             drawHarmoniousTriangles(p, dst);
1185 
1186             p.setPen(QPen(d->guideColor, d->guideSize, Qt::DotLine));
1187             drawHarmoniousTriangles(p, dst);
1188             break;
1189         }
1190 
1191         case GoldenMean:
1192         {
1193             // Move coordinates to local center selection.
1194 
1195             p.translate(d->localRegionSelection.center().x(), d->localRegionSelection.center().y());
1196 
1197             // Flip horizontal.
1198 
1199             if (d->flipHorGoldenGuide)
1200             {
1201                 p.scale(-1, 1);
1202             }
1203 
1204             // Flip vertical.
1205 
1206             if (d->flipVerGoldenGuide)
1207             {
1208                 p.scale(1, -1);
1209             }
1210 
1211             int w   = d->localRegionSelection.width();
1212             int h   = d->localRegionSelection.height();
1213 
1214             // lengths for the golden mean and half the sizes of the region:
1215 
1216             int w_g = (int)(w*INVPHI);
1217             int h_g = (int)(h*INVPHI);
1218             int w_2 = w/2;
1219             int h_2 = h/2;
1220 
1221             QRect R1(-w_2, -h_2, w_g, h);
1222 
1223             // w - 2*w_2 corrects for one-pixel difference
1224             // so that R2.right() is really at the right end of the region
1225 
1226             QRect R2(w_g-w_2, h_2-h_g, w-w_g+1-(w - 2*w_2), h_g);
1227 
1228             QRect R3((int)(w_2 - R2.width()*INVPHI), -h_2,
1229                      (int)(R2.width()*INVPHI), h - R2.height());
1230             QRect R4(R2.x(), R1.y(), R3.x() - R2.x(),
1231                      (int)(R3.height()*INVPHI));
1232             QRect R5(R4.x(), R4.bottom(), (int)(R4.width()*INVPHI),
1233                      R3.height() - R4.height());
1234             QRect R6(R5.x() + R5.width(), R5.bottom() - (int)(R5.height()*INVPHI),
1235                      R3.x() - R5.right(), (int)(R5.height()*INVPHI));
1236             QRect R7(R6.right() - (int)(R6.width()*INVPHI), R4.bottom(),
1237                      (int)(R6.width()*INVPHI), R5.height() - R6.height());
1238 
1239             p.setPen(QPen(Qt::white, d->guideSize, Qt::SolidLine));
1240             drawGoldenMean(p, R1, R2, R3, R4, R5, R6, R7);
1241 
1242             p.setPen(QPen(d->guideColor, d->guideSize, Qt::DotLine));
1243             drawGoldenMean(p, R1, R2, R3, R4, R5, R6, R7);
1244 
1245             break;
1246         }
1247 
1248         case CenterLines:
1249         {
1250             int xHalf = d->localRegionSelection.width()  / 2;
1251             int yHalf = d->localRegionSelection.height() / 2;
1252 
1253             p.setPen(QPen(Qt::white, d->guideSize, Qt::SolidLine));
1254             drawRulesOfCenter(p, xHalf, yHalf);
1255 
1256             p.setPen(QPen(d->guideColor, d->guideSize, Qt::DotLine));
1257             drawRulesOfCenter(p, xHalf, yHalf);
1258             break;
1259         }
1260     }
1261 
1262     p.setClipping(false);
1263 
1264     p.end();
1265 }
1266 
1267 void RatioCropWidget::paintEvent(QPaintEvent*)
1268 {
1269     QPainter p(this);
1270     p.drawPixmap(0, 0, *d->pixmap);
1271     p.end();
1272 }
1273 
1274 QPoint RatioCropWidget::opposite() const
1275 {
1276     QPoint opp;
1277 
1278     switch (d->currentResizing)
1279     {
1280         case Private::ResizingTopRight:
1281         {
1282             opp = d->regionSelection.bottomLeft();
1283             break;
1284         }
1285 
1286         case Private::ResizingBottomLeft:
1287         {
1288             opp = d->regionSelection.topRight();
1289             break;
1290         }
1291 
1292         case Private::ResizingBottomRight:
1293         {
1294             opp = d->regionSelection.topLeft();
1295             break;
1296         }
1297 
1298         case Private::ResizingTopLeft:
1299         default:
1300         {
1301             opp = d->regionSelection.bottomRight();
1302             break;
1303         }
1304     }
1305 
1306     return opp;
1307 }
1308 
1309 float RatioCropWidget::distance(const QPoint& a, const QPoint& b) const
1310 {
1311     return sqrt(pow(a.x() - b.x(), 2) + pow(a.y() - b.y(), 2));
1312 }
1313 
1314 void RatioCropWidget::setCursorResizing()
1315 {
1316     switch (d->currentResizing)
1317     {
1318         case Private::ResizingTopLeft:
1319         {
1320             setCursor(Qt::SizeFDiagCursor);
1321             break;
1322         }
1323 
1324         case Private::ResizingTopRight:
1325         {
1326             setCursor(Qt::SizeBDiagCursor);
1327             break;
1328         }
1329 
1330         case Private::ResizingBottomLeft:
1331         {
1332             setCursor(Qt::SizeBDiagCursor);
1333             break;
1334         }
1335 
1336         case Private::ResizingBottomRight:
1337         {
1338             setCursor(Qt::SizeFDiagCursor);
1339             break;
1340         }
1341     }
1342 }
1343 
1344 void RatioCropWidget::placeSelection(const QPoint& pm, bool symmetric, const QPoint& center)
1345 {
1346     // Set orientation
1347 
1348     if (d->autoOrientation)
1349     {
1350         QPoint rel = pm - opposite();
1351 
1352         if (abs(rel.x()) > abs(rel.y()))
1353         {
1354             if (d->currentOrientation == Portrait)
1355             {
1356                 d->currentOrientation = Landscape;
1357                 reverseRatioValues();
1358 
1359                 Q_EMIT signalSelectionOrientationChanged(d->currentOrientation);
1360             }
1361         }
1362         else
1363         {
1364             if (d->currentOrientation == Landscape)
1365             {
1366                 d->currentOrientation = Portrait;
1367                 reverseRatioValues();
1368 
1369                 Q_EMIT signalSelectionOrientationChanged(d->currentOrientation);
1370             }
1371         }
1372     }
1373 
1374     // Place the corner at the mouse
1375     // If a symmetric selection is wanted, place opposite corner to
1376     // the center, double selection size and move it to old center after
1377     // computing aspect ratio.
1378 
1379     switch (d->currentResizing)
1380     {
1381         case Private::ResizingTopLeft:
1382         {
1383             // Place corners to the proper position
1384 
1385             d->regionSelection.setTopLeft(pm);
1386 
1387             if (symmetric)
1388             {
1389                 d->regionSelection.setBottomRight(center);
1390             }
1391 
1392             break;
1393         }
1394 
1395         case Private::ResizingTopRight:
1396         {
1397             d->regionSelection.setTopRight(pm);
1398 
1399             if (symmetric)
1400             {
1401                 d->regionSelection.setBottomLeft(center);
1402             }
1403 
1404             break;
1405         }
1406 
1407         case Private::ResizingBottomLeft:
1408         {
1409             d->regionSelection.setBottomLeft(pm);
1410 
1411             if (symmetric)
1412             {
1413                 d->regionSelection.setTopRight(center);
1414             }
1415 
1416             break;
1417         }
1418 
1419         case Private::ResizingBottomRight:
1420         {
1421             d->regionSelection.setBottomRight(pm);
1422 
1423             if (symmetric)
1424             {
1425                 d->regionSelection.setTopLeft(center);
1426             }
1427 
1428             break;
1429         }
1430     }
1431 
1432     if (symmetric)
1433     {
1434         d->regionSelection.setSize(d->regionSelection.size()*2);
1435     }
1436 
1437     applyAspectRatio(d->currentOrientation == Portrait, false);
1438 
1439     if (symmetric)
1440     {
1441         d->regionSelection.moveCenter(center);
1442     }
1443 
1444     // Repaint
1445 
1446     updatePixmap();
1447     update();
1448 }
1449 
1450 void RatioCropWidget::mousePressEvent(QMouseEvent* e)
1451 {
1452     if (e->button() == Qt::LeftButton)
1453     {
1454 
1455 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
1456 
1457         QPoint pm        = QPoint(e->position().toPoint().x(), e->position().toPoint().y());
1458 
1459 #else
1460 
1461         QPoint pm        = QPoint(e->x(), e->y());
1462 
1463 #endif
1464 
1465         QPoint pmVirtual = convertPoint(pm);
1466         d->moving        = false;
1467 
1468         if ((e->modifiers() & Qt::ShiftModifier) == Qt::ShiftModifier)
1469         {
1470             bool symmetric  = (e->modifiers() & Qt::ControlModifier) == Qt::ControlModifier;
1471             QPoint center   = d->regionSelection.center();
1472 
1473             // Find the closest corner
1474 
1475             const QPoint points[] =
1476                               {
1477                                 d->regionSelection.topLeft(),
1478                                 d->regionSelection.topRight(),
1479                                 d->regionSelection.bottomLeft(),
1480                                 d->regionSelection.bottomRight()
1481                               };
1482 
1483             const int resizings[] =
1484                               {
1485                                 Private::ResizingTopLeft,
1486                                 Private::ResizingTopRight,
1487                                 Private::ResizingBottomLeft,
1488                                 Private::ResizingBottomRight
1489                               };
1490 
1491             float dist      = -1.0f;
1492             float dist2     =  0.0f;
1493 
1494             for (int i = 0 ; i < 4 ; ++i)
1495             {
1496                 QPoint point = points[i];
1497                 dist2        = distance(pmVirtual, point);
1498 
1499                 if ((dist2 < dist) || (d->currentResizing == Private::ResizingNone))
1500                 {
1501                     dist               = dist2;
1502                     d->currentResizing = resizings[i];
1503                 }
1504             }
1505 
1506             setCursorResizing();
1507 
1508             placeSelection(pmVirtual, symmetric, center);
1509         }
1510         else
1511         {
1512             if      (d->localTopLeftCorner.contains(pm))
1513             {
1514                 d->currentResizing = Private::ResizingTopLeft;
1515             }
1516             else if (d->localTopRightCorner.contains(pm))
1517             {
1518                 d->currentResizing = Private::ResizingTopRight;
1519             }
1520             else if (d->localBottomLeftCorner.contains(pm))
1521             {
1522                 d->currentResizing = Private::ResizingBottomLeft;
1523             }
1524             else if (d->localBottomRightCorner.contains(pm))
1525             {
1526                 d->currentResizing = Private::ResizingBottomRight;
1527             }
1528             else
1529             {
1530                 d->lastPos = pmVirtual;
1531                 setCursor(Qt::SizeAllCursor);
1532 
1533                 if (d->regionSelection.contains(pmVirtual))
1534                 {
1535                     d->moving = true;
1536                 }
1537                 else
1538                 {
1539                     d->regionSelection.moveCenter(pmVirtual);
1540                     normalizeRegion();
1541                     updatePixmap();
1542                     update();
1543                 }
1544             }
1545         }
1546     }
1547 }
1548 
1549 void RatioCropWidget::mouseReleaseEvent(QMouseEvent*)
1550 {
1551     if      (d->currentResizing != Private::ResizingNone)
1552     {
1553         setCursor(Qt::ArrowCursor);
1554         regionSelectionChanged();
1555         d->currentResizing = Private::ResizingNone;
1556     }
1557     else if (d->regionSelection.contains(d->lastPos))
1558     {
1559         setCursor(Qt::SizeAllCursor);
1560         regionSelectionMoved();
1561     }
1562     else
1563     {
1564         setCursor(Qt::ArrowCursor);
1565         regionSelectionMoved();
1566     }
1567 }
1568 
1569 void RatioCropWidget::mouseMoveEvent(QMouseEvent* e)
1570 {
1571     if (e->buttons() & Qt::LeftButton)
1572     {
1573         if (d->moving)
1574         {
1575             setCursor(Qt::SizeAllCursor);
1576 
1577 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
1578 
1579             QPoint newPos = convertPoint(e->position().toPoint().x(), e->position().toPoint().y());
1580 
1581 #else
1582 
1583             QPoint newPos = convertPoint(e->x(), e->y());
1584 
1585 #endif
1586 
1587             d->regionSelection.translate(newPos.x() - d->lastPos.x(),
1588                                          newPos.y() - d->lastPos.y());
1589 
1590             d->lastPos = newPos;
1591 
1592             normalizeRegion();
1593 
1594             updatePixmap();
1595             update();
1596         }
1597         else
1598         {
1599 
1600 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
1601 
1602             QPoint pmVirtual = convertPoint(e->position().toPoint().x(), e->position().toPoint().y());
1603 
1604 #else
1605 
1606             QPoint pmVirtual = convertPoint(e->x(), e->y());
1607 
1608 #endif
1609 
1610             if (d->currentResizing == Private::ResizingNone)
1611             {
1612                 d->regionSelection.setTopLeft(pmVirtual);
1613                 d->regionSelection.setBottomRight(pmVirtual);
1614                 d->currentResizing = Private::ResizingTopLeft; // set to anything
1615             }
1616 
1617             QPoint center  = d->regionSelection.center();
1618             bool symmetric = (e->modifiers() & Qt::ControlModifier) == Qt::ControlModifier;
1619 
1620             // Change resizing mode
1621 
1622             QPoint opp = symmetric ? center : opposite();
1623             QPoint dir = pmVirtual - opp;
1624 
1625             if      ((dir.x() > 0) && (dir.y() > 0) && (d->currentResizing != Private::ResizingBottomRight))
1626             {
1627                 d->currentResizing = Private::ResizingBottomRight;
1628                 d->regionSelection.setTopLeft(opp);
1629                 setCursor(Qt::SizeFDiagCursor);
1630             }
1631             else if ((dir.x() > 0) && (dir.y() < 0) && (d->currentResizing != Private::ResizingTopRight))
1632             {
1633                 d->currentResizing = Private::ResizingTopRight;
1634                 d->regionSelection.setBottomLeft(opp);
1635                 setCursor(Qt::SizeBDiagCursor);
1636             }
1637             else if ((dir.x() < 0) && (dir.y() > 0) && (d->currentResizing != Private::ResizingBottomLeft))
1638             {
1639                 d->currentResizing = Private::ResizingBottomLeft;
1640                 d->regionSelection.setTopRight(opp);
1641                 setCursor(Qt::SizeBDiagCursor);
1642             }
1643             else if ((dir.x() < 0) && (dir.y() < 0) && (d->currentResizing != Private::ResizingTopLeft))
1644             {
1645                 d->currentResizing = Private::ResizingTopLeft;
1646                 d->regionSelection.setBottomRight(opp);
1647                 setCursor(Qt::SizeFDiagCursor);
1648             }
1649             else
1650             {
1651                 if      ((dir.x() == 0) && (dir.y() == 0))
1652                 {
1653                     setCursor(Qt::SizeAllCursor);
1654                 }
1655                 else if (dir.x() == 0)
1656                 {
1657                     setCursor(Qt::SizeHorCursor);
1658                 }
1659                 else if (dir.y() == 0)
1660                 {
1661                     setCursor(Qt::SizeVerCursor);
1662                 }
1663             }
1664 
1665             placeSelection(pmVirtual, symmetric, center);
1666         }
1667     }
1668     else
1669     {
1670 
1671 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
1672 
1673         if      (d->localTopLeftCorner.contains(e->position().toPoint().x(), e->position().toPoint().y()) ||
1674                  d->localBottomRightCorner.contains(e->position().toPoint().x(), e->position().toPoint().y()))
1675         {
1676             setCursor(Qt::SizeFDiagCursor);
1677         }
1678         else if (d->localTopRightCorner.contains(e->position().toPoint().x(), e->position().toPoint().y()) ||
1679                  d->localBottomLeftCorner.contains(e->position().toPoint().x(), e->position().toPoint().y()))
1680         {
1681             setCursor(Qt::SizeBDiagCursor);
1682         }
1683         else if (d->localRegionSelection.contains(e->position().toPoint().x(), e->position().toPoint().y()))
1684         {
1685             setCursor(Qt::SizeAllCursor);
1686         }
1687 
1688 #else
1689 
1690         if      (d->localTopLeftCorner.contains(e->x(), e->y()) ||
1691                  d->localBottomRightCorner.contains(e->x(), e->y()))
1692         {
1693             setCursor(Qt::SizeFDiagCursor);
1694         }
1695         else if (d->localTopRightCorner.contains(e->x(), e->y()) ||
1696                  d->localBottomLeftCorner.contains(e->x(), e->y()))
1697         {
1698             setCursor(Qt::SizeBDiagCursor);
1699         }
1700         else if (d->localRegionSelection.contains(e->x(), e->y()))
1701         {
1702             setCursor(Qt::SizeAllCursor);
1703         }
1704 
1705 #endif
1706 
1707         else
1708         {
1709             setCursor(Qt::ArrowCursor);
1710         }
1711     }
1712 }
1713 
1714 void RatioCropWidget::setIsDrawingSelection(bool draw)
1715 {
1716     d->isDrawingSelection = draw;
1717 }
1718 
1719 } // namespace DigikamEditorRatioCropToolPlugin
1720 
1721 #include "moc_ratiocropwidget.cpp"