1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2004-12-09
7  * Description : image selection widget used by ratio crop tool.
8  *
9  * Copyright (C) 2007      by Jaromir Malenko <malenko at email.cz>
10  * Copyright (C) 2008      by Roberto Castagnola <roberto dot castagnola at gmail dot com>
11  * Copyright (C) 2004-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
12  *
13  * This program is free software; you can redistribute it
14  * and/or modify it under the terms of the GNU General
15  * Public License as published by the Free Software Foundation;
16  * either version 2, or (at your option)
17  * any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * ============================================================ */
25 
26 #define OPACITY  0.7
27 #define RCOL     0xAA
28 #define GCOL     0xAA
29 #define BCOL     0xAA
30 
31 #define MINRANGE 0
32 
33 // Golden number (1+sqrt(5))/2
34 #define PHI      1.61803398874989479F
35 // 1/PHI
36 #define INVPHI   0.61803398874989479F
37 // DIN A sqrt(2)
38 #define DINA     1.41421356237309504F
39 
40 #include "ratiocropwidget.h"
41 
42 // C++ includes
43 
44 #include <iostream>
45 #include <cstdio>
46 #include <cmath>
47 #include <cstdlib>
48 
49 // Qt includes
50 
51 #include <QRegion>
52 #include <QColor>
53 #include <QPainter>
54 #include <QBrush>
55 #include <QPixmap>
56 #include <QImage>
57 #include <QPen>
58 #include <QPoint>
59 #include <QTimer>
60 #include <QSizePolicy>
61 #include <QResizeEvent>
62 #include <QMouseEvent>
63 #include <QPaintEvent>
64 
65 // Local includes
66 
67 #include "digikam_debug.h"
68 #include "dimg.h"
69 
70 namespace DigikamEditorRatioCropToolPlugin
71 {
72 
73 class Q_DECL_HIDDEN RatioCropWidget::Private
74 {
75 public:
76 
77     enum ResizingMode
78     {
79         ResizingNone = 0,
80         ResizingTopLeft,
81         ResizingTopRight,
82         ResizingBottomLeft,
83         ResizingBottomRight
84     };
85 
Private()86     explicit Private()
87       : drawGoldenSection       (false),
88         drawGoldenSpiralSection (false),
89         drawGoldenSpiral        (false),
90         drawGoldenTriangle      (false),
91         flipHorGoldenGuide      (false),
92         flipVerGoldenGuide      (false),
93         moving                  (false),
94         autoOrientation         (false),
95         preciseCrop             (false),
96         isDrawingSelection      (false),
97         guideLinesType          (0),
98         guideSize               (1),
99         currentAspectRatioType  (0),
100         currentResizing         (ResizingNone),
101         currentOrientation      (0),
102         currentWidthRatioValue  (0),
103         currentHeightRatioValue (0),
104         pixmap                  (nullptr),
105         iface                   (nullptr)
106     {
107     }
108 
109     // Golden guide types.
110     bool        drawGoldenSection;
111     bool        drawGoldenSpiralSection;
112     bool        drawGoldenSpiral;
113     bool        drawGoldenTriangle;
114 
115     // Golden guide translations.
116     bool        flipHorGoldenGuide;
117     bool        flipVerGoldenGuide;
118 
119     bool        moving;
120     bool        autoOrientation;
121     bool        preciseCrop;
122 
123     bool        isDrawingSelection;
124 
125     int         guideLinesType;
126     int         guideSize;
127 
128     int         currentAspectRatioType;
129     int         currentResizing;
130     int         currentOrientation;
131 
132     float       currentWidthRatioValue;
133     float       currentHeightRatioValue;
134 
135     QPoint      lastPos;
136 
137     QRect       rect;
138     QRect       image;                   // Real image dimension.
139     QRect       regionSelection;         // Real size image selection.
140     QRect       localRegionSelection;    // Local size selection.
141 
142     // Draggable local region selection corners.
143     QRect       localTopLeftCorner;
144     QRect       localBottomLeftCorner;
145     QRect       localTopRightCorner;
146     QRect       localBottomRightCorner;
147 
148     QPixmap*    pixmap;
149     QPixmap     grayOverLay;
150     QPixmap     previewPixmap;
151 
152     QColor      guideColor;
153     QColor      bgColor;
154 
155     DImg        preview;
156 
157     ImageIface* iface;
158 };
159 
RatioCropWidget(int w,int h,QWidget * const parent)160 RatioCropWidget::RatioCropWidget(int w, int h, QWidget* const parent)
161     : QWidget(parent),
162       d      (new Private)
163 {
164     d->isDrawingSelection = true;
165     d->bgColor            = palette().color(QPalette::Window);
166     setup(w, h);
167 }
168 
RatioCropWidget(int w,int h,bool initDrawing,QWidget * const parent)169 RatioCropWidget::RatioCropWidget(int w, int h, bool initDrawing, QWidget* const parent)
170     : QWidget(parent),
171       d      (new Private)
172 {
173     d->isDrawingSelection = initDrawing;
174     setup(w, h);
175 }
176 
~RatioCropWidget()177 RatioCropWidget::~RatioCropWidget()
178 {
179     delete d->iface;
180     delete d->pixmap;
181     delete d;
182 }
183 
setup(int w,int h,int widthRatioValue,int heightRatioValue,int aspectRatio,int orient,int guideLinesType)184 void RatioCropWidget::setup(int w, int h,
185                                  int widthRatioValue, int heightRatioValue,
186                                  int aspectRatio, int orient,
187                                  int guideLinesType)
188 {
189     setMinimumSize(w, h);
190     setMouseTracking(true);
191     setAttribute(Qt::WA_DeleteOnClose);
192 
193     d->currentAspectRatioType  = aspectRatio;
194     d->currentWidthRatioValue  = widthRatioValue;
195     d->currentHeightRatioValue = heightRatioValue;
196     d->currentOrientation      = orient;
197     d->guideLinesType          = guideLinesType;
198     d->autoOrientation         = false;
199     d->preciseCrop             = false;
200     d->moving                  = true;
201     reverseRatioValues();
202 
203     d->iface   = new ImageIface(QSize(w, h));
204     d->preview = d->iface->preview();
205     d->preview.setIccProfile(d->iface->original()->getIccProfile());
206     d->preview.convertToEightBit();
207 
208     d->pixmap  = new QPixmap(w, h);
209     d->image   = QRect(0, 0, d->iface->originalSize().width(), d->iface->originalSize().height());
210     d->rect    = QRect((w-d->preview.width()) /2,
211                        (h-d->preview.height())/2,
212                        d->preview.width(), d->preview.height());
213 
214     updatePixmap();
215     setGoldenGuideTypes(true, false, false, false, false, false);
216 }
217 
imageIface() const218 ImageIface* RatioCropWidget::imageIface() const
219 {
220     return d->iface;
221 }
222 
resizeEvent(QResizeEvent * e)223 void RatioCropWidget::resizeEvent(QResizeEvent* e)
224 {
225     delete d->pixmap;
226 
227     int w      = e->size().width();
228     int h      = e->size().height();
229     d->preview = d->iface->setPreviewSize(QSize(w, h));
230     d->preview.setIccProfile(d->iface->original()->getIccProfile());
231     d->preview.convertToEightBit();
232 
233     d->pixmap  = new QPixmap(w, h);
234     d->rect    = QRect((w-d->preview.width()) /2,
235                        (h-d->preview.height())/2,
236                        d->preview.width(), d->preview.height());
237 
238     // Drawing the gray overlay
239 
240     {
241         DImg image = d->preview.copy();
242         uchar* ptr = image.bits();
243         uchar  r, g, b;
244 
245         int xlow  = d->rect.left();
246         int xhigh = d->rect.right();
247         int ylow  = d->rect.top();
248         int yhigh = d->rect.bottom();
249 
250         for (int y = ylow ; y <= yhigh ; ++y)
251         {
252             for (int x = xlow ; x <= xhigh ; ++x)
253             {
254                 b = ptr[0];
255                 g = ptr[1];
256                 r = ptr[2];
257 
258                 r += (uchar)((RCOL - r) * OPACITY);
259                 g += (uchar)((GCOL - g) * OPACITY);
260                 b += (uchar)((BCOL - b) * OPACITY);
261 
262                 ptr[0] = b;
263                 ptr[1] = g;
264                 ptr[2] = r;
265 
266                 ptr+=4;
267             }
268         }
269 
270         d->grayOverLay   = image.convertToPixmap();
271         d->previewPixmap = d->iface->convertToPixmap(d->preview);
272     }
273 
274     updatePixmap();
275 }
276 
getOriginalImageWidth() const277 int RatioCropWidget::getOriginalImageWidth() const
278 {
279     return d->image.width();
280 }
281 
getOriginalImageHeight() const282 int RatioCropWidget::getOriginalImageHeight() const
283 {
284     return d->image.height();
285 }
286 
getRegionSelection() const287 QRect RatioCropWidget::getRegionSelection() const
288 {
289     return d->regionSelection;
290 }
291 
getMinWidthRange() const292 int RatioCropWidget::getMinWidthRange() const
293 {
294     return MINRANGE;
295 }
296 
getMinHeightRange() const297 int RatioCropWidget::getMinHeightRange() const
298 {
299     return MINRANGE;
300 }
301 
getMaxWidthRange() const302 int RatioCropWidget::getMaxWidthRange() const
303 {
304     int maxW = d->image.width() - d->regionSelection.left();
305 
306     if (d->currentAspectRatioType != RATIONONE)
307     {
308         // Compute max width taking aspect ratio into account
309 
310         int t = d->currentWidthRatioValue > d->currentHeightRatioValue ? 1 : 0;
311         int h = d->image.height() - d->regionSelection.top();
312         int w = (int)rint((h + t) * d->currentWidthRatioValue /
313                           d->currentHeightRatioValue) - t;
314 
315         if (w < maxW)
316         {
317             maxW = w;
318         }
319     }
320 
321     // Return max width adjusted if a precise crop is wanted
322 
323     return computePreciseSize(maxW, (int)d->currentWidthRatioValue);
324 }
325 
getMaxHeightRange() const326 int RatioCropWidget::getMaxHeightRange() const
327 {
328     int maxH = d->image.height() - d->regionSelection.top();
329 
330     if (d->currentAspectRatioType != RATIONONE)
331     {
332         // Compute max height taking aspect ratio into account
333 
334         int t = d->currentHeightRatioValue > d->currentWidthRatioValue ? 1 : 0;
335         int w = d->image.width() - d->regionSelection.left();
336         int h = (int)rint((w + t) * d->currentHeightRatioValue /
337                           d->currentWidthRatioValue) - t;
338 
339         if (h < maxH)
340         {
341             maxH = h;
342         }
343     }
344 
345     // Return max height adjusted if a precise crop is wanted
346 
347     return computePreciseSize(maxH, (int)d->currentHeightRatioValue);
348 }
349 
getWidthStep() const350 int RatioCropWidget::getWidthStep() const
351 {
352     if (d->preciseCrop && preciseCropAvailable())
353     {
354         return (int)d->currentWidthRatioValue;
355     }
356     else
357     {
358         return 1;
359     }
360 }
361 
getHeightStep() const362 int RatioCropWidget::getHeightStep() const
363 {
364     if (d->preciseCrop && preciseCropAvailable())
365     {
366         return (int)d->currentHeightRatioValue;
367     }
368     else
369     {
370         return 1;
371     }
372 }
373 
374 /**
375  * Draw a new centered selection with half width (if orientation = Landscape)
376  * or with half height (if orientation = Portrait)
377  */
resetSelection()378 void RatioCropWidget::resetSelection()
379 {
380     d->regionSelection.setWidth(d->image.width()/2);
381     d->regionSelection.setHeight(d->image.height()/2);
382     applyAspectRatio(d->currentOrientation == Portrait, false);
383 
384     setCenterSelection(CenterImage);
385 }
386 
setCenterSelection(int centerType)387 void RatioCropWidget::setCenterSelection(int centerType)
388 {
389     // Adjust selection size if bigger than real image
390 
391     if (d->regionSelection.height() > d->image.height())
392     {
393         d->regionSelection.setHeight(d->image.height());
394         applyAspectRatio(true, false);
395     }
396 
397     if (d->regionSelection.width() > d->image.width())
398     {
399         d->regionSelection.setWidth(d->image.width());
400         applyAspectRatio(false, false);
401     }
402 
403     // Set center point for selection
404 
405     QPoint center = d->image.center();
406 
407     switch (centerType)
408     {
409         case CenterWidth:
410             center.setY(d->regionSelection.center().y());
411             break;
412 
413         case CenterHeight:
414             center.setX(d->regionSelection.center().x());
415             break;
416     }
417 
418     d->regionSelection.moveCenter(center);
419 
420     // Repaint
421 
422     updatePixmap();
423     update();
424     regionSelectionChanged();
425 }
426 
427 /**
428  * Draw a new centered selection with max size
429  */
maxAspectSelection()430 void RatioCropWidget::maxAspectSelection()
431 {
432     d->regionSelection.setWidth(d->image.width());
433     d->regionSelection.setHeight(d->image.height());
434 
435     if (d->currentAspectRatioType != RATIONONE)
436     {
437         applyAspectRatio(d->currentOrientation == Portrait, false);
438     }
439 
440     setCenterSelection(CenterImage);
441 }
442 
setGoldenGuideTypes(bool drawGoldenSection,bool drawGoldenSpiralSection,bool drawGoldenSpiral,bool drawGoldenTriangle,bool flipHorGoldenGuide,bool flipVerGoldenGuide)443 void RatioCropWidget::setGoldenGuideTypes(bool drawGoldenSection,  bool drawGoldenSpiralSection,
444                                           bool drawGoldenSpiral,   bool drawGoldenTriangle,
445                                           bool flipHorGoldenGuide, bool flipVerGoldenGuide)
446 {
447     d->drawGoldenSection       = drawGoldenSection;
448     d->drawGoldenSpiralSection = drawGoldenSpiralSection;
449     d->drawGoldenSpiral        = drawGoldenSpiral;
450     d->drawGoldenTriangle      = drawGoldenTriangle;
451     d->flipHorGoldenGuide      = flipHorGoldenGuide;
452     d->flipVerGoldenGuide      = flipVerGoldenGuide;
453 }
454 
setBackgroundColor(const QColor & bg)455 void RatioCropWidget::setBackgroundColor(const QColor& bg)
456 {
457     d->bgColor = bg;
458     updatePixmap();
459     update();
460 }
461 
slotGuideLines(int guideLinesType)462 void RatioCropWidget::slotGuideLines(int guideLinesType)
463 {
464     d->guideLinesType = guideLinesType;
465     updatePixmap();
466     update();
467 }
468 
slotChangeGuideColor(const QColor & color)469 void RatioCropWidget::slotChangeGuideColor(const QColor& color)
470 {
471     d->guideColor = color;
472     updatePixmap();
473     update();
474 }
475 
slotChangeGuideSize(int size)476 void RatioCropWidget::slotChangeGuideSize(int size)
477 {
478     d->guideSize = size;
479     updatePixmap();
480     update();
481 }
482 
setSelectionOrientation(int orient)483 void RatioCropWidget::setSelectionOrientation(int orient)
484 {
485     d->currentOrientation = orient;
486     reverseRatioValues();
487     applyAspectRatio(true);
488     emit signalSelectionOrientationChanged(d->currentOrientation);
489 }
490 
setSelectionAspectRatioType(int aspectRatioType)491 void RatioCropWidget::setSelectionAspectRatioType(int aspectRatioType)
492 {
493     d->currentAspectRatioType = aspectRatioType;
494 
495     // Set ratio values
496 
497     switch (aspectRatioType)
498     {
499         case RATIO01X01:
500             d->currentHeightRatioValue = 1.0;
501             d->currentWidthRatioValue  = 1.0;
502             break;
503 
504         case RATIO02x01:
505             d->currentHeightRatioValue = 2.0;
506             d->currentWidthRatioValue  = 1.0;
507             break;
508 
509         case RATIO02x03:
510             d->currentHeightRatioValue = 2.0;
511             d->currentWidthRatioValue  = 3.0;
512             break;
513 
514         case RATIO03X01:
515             d->currentHeightRatioValue = 3.0;
516             d->currentWidthRatioValue  = 1.0;
517             break;
518 
519         case RATIO03X04:
520             d->currentHeightRatioValue = 3.0;
521             d->currentWidthRatioValue  = 4.0;
522             break;
523 
524         case RATIO04X01:
525             d->currentHeightRatioValue = 4.0;
526             d->currentWidthRatioValue  = 1.0;
527             break;
528 
529         case RATIO04X05:
530             d->currentHeightRatioValue = 4.0;
531             d->currentWidthRatioValue  = 5.0;
532             break;
533 
534         case RATIO05x07:
535             d->currentHeightRatioValue = 5.0;
536             d->currentWidthRatioValue  = 7.0;
537             break;
538 
539         case RATIO07x10:
540             d->currentHeightRatioValue = 7.0;
541             d->currentWidthRatioValue  = 10.0;
542             break;
543 
544         case RATIO08x05:
545             d->currentHeightRatioValue = 8.0;
546             d->currentWidthRatioValue  = 5.0;
547             break;
548 
549         case RATIO16x09:
550             d->currentHeightRatioValue = 16.0;
551             d->currentWidthRatioValue  = 9.0;
552             break;
553 
554         case RATIODINA0:
555             d->currentHeightRatioValue = 1.0;
556             d->currentWidthRatioValue  = DINA;
557             break;
558 
559         case RATIOGOLDEN:
560             d->currentHeightRatioValue = 1.0;
561             d->currentWidthRatioValue  = PHI;
562             break;
563 
564         case RATIOCURRENT:
565             d->currentHeightRatioValue = d->image.height();
566             d->currentWidthRatioValue  = d->image.width();
567             break;
568     }
569 
570     reverseRatioValues();
571     applyAspectRatio(false);
572 }
573 
setSelectionAspectRatioValue(int widthRatioValue,int heightRatioValue)574 void RatioCropWidget::setSelectionAspectRatioValue(int widthRatioValue, int heightRatioValue)
575 {
576     int gdc = widthRatioValue;
577 
578     // Compute greatest common divisor using Euclidean algorithm
579 
580     for (int tmp, mod = heightRatioValue; mod != 0; mod = tmp % mod)
581     {
582         tmp = gdc;
583         gdc = mod;
584     }
585 
586     d->currentWidthRatioValue  = widthRatioValue  / gdc;
587     d->currentHeightRatioValue = heightRatioValue / gdc;
588     d->currentAspectRatioType  = RATIOCUSTOM;
589 
590     // Fix orientation
591 
592     if (d->autoOrientation)
593     {
594         if      ((heightRatioValue > widthRatioValue) &&
595                  (d->currentOrientation == Landscape))
596         {
597             d->currentOrientation = Portrait;
598             emit signalSelectionOrientationChanged(d->currentOrientation);
599         }
600         else if ((widthRatioValue > heightRatioValue) &&
601                  (d->currentOrientation == Portrait))
602         {
603             d->currentOrientation = Landscape;
604             emit signalSelectionOrientationChanged(d->currentOrientation);
605         }
606     }
607     else
608     {
609         reverseRatioValues();
610     }
611 
612     applyAspectRatio(false);
613 }
614 
reverseRatioValues()615 void RatioCropWidget::reverseRatioValues()
616 {
617     // Reverse ratio values if needed
618 
619     if (((d->currentWidthRatioValue > d->currentHeightRatioValue)  &&
620          (d->currentOrientation == Portrait))                      ||
621          ((d->currentHeightRatioValue > d->currentWidthRatioValue) &&
622           (d->currentOrientation == Landscape)))
623     {
624         float tmp                  = d->currentWidthRatioValue;
625         d->currentWidthRatioValue  = d->currentHeightRatioValue;
626         d->currentHeightRatioValue = tmp;
627     }
628 }
629 
preciseCropAvailable() const630 bool RatioCropWidget::preciseCropAvailable() const
631 {
632     // Define when precise crop feature can be used
633     // No needed when aspect ratio is 1:1
634 
635     switch (d->currentAspectRatioType)
636     {
637         case RATIONONE:
638         case RATIO01X01:
639         case RATIODINA0:
640         case RATIOGOLDEN:
641             return false;
642 
643         case RATIOCUSTOM:
644             return (d->currentWidthRatioValue != d->currentHeightRatioValue);
645 
646         default:
647             return true;
648     }
649 }
650 
setPreciseCrop(bool precise)651 void RatioCropWidget::setPreciseCrop(bool precise)
652 {
653     d->preciseCrop = precise;
654     applyAspectRatio(false, true);
655     regionSelectionChanged();
656 }
657 
setAutoOrientation(bool orientation)658 void RatioCropWidget::setAutoOrientation(bool orientation)
659 {
660     d->autoOrientation = orientation;
661 }
662 
setSelectionX(int x)663 void RatioCropWidget::setSelectionX(int x)
664 {
665     d->regionSelection.moveLeft(x);
666     regionSelectionMoved();
667 }
668 
setSelectionY(int y)669 void RatioCropWidget::setSelectionY(int y)
670 {
671     d->regionSelection.moveTop(y);
672     regionSelectionMoved();
673 }
674 
setSelectionWidth(int w)675 void RatioCropWidget::setSelectionWidth(int w)
676 {
677     d->regionSelection.setWidth(w);
678     applyAspectRatio(false, true);
679 
680     regionSelectionChanged();
681 }
682 
setSelectionHeight(int h)683 void RatioCropWidget::setSelectionHeight(int h)
684 {
685     d->regionSelection.setHeight(h);
686     applyAspectRatio(true, true);
687 
688     regionSelectionChanged();
689 }
690 
convertPoint(const QPoint & pm,bool localToReal) const691 QPoint RatioCropWidget::convertPoint(const QPoint& pm, bool localToReal) const
692 {
693     return convertPoint(pm.x(), pm.y(), localToReal);
694 }
695 
convertPoint(int x,int y,bool localToReal) const696 QPoint RatioCropWidget::convertPoint(int x, int y, bool localToReal) const
697 {
698     int pmX, pmY;
699 
700     if (localToReal)
701     {
702         pmX = (int)((x - d->rect.left()) * (float)d->image.width() /
703                     (float)d->preview.width());
704 
705         pmY = (int)((y - d->rect.top()) * (float)d->image.height() /
706                     (float)d->preview.height());
707     }
708     else
709     {
710         pmX = (int)(d->rect.left() + (x * (float)d->preview.width() /
711                                       (float)d->image.width()));
712 
713         pmY = (int)(d->rect.top() + (y * (float)d->preview.height() /
714                                      (float)d->image.height()));
715     }
716 
717     return QPoint(pmX, pmY);
718 }
719 
computePreciseSize(int size,int step) const720 int RatioCropWidget::computePreciseSize(int size, int step) const
721 {
722     // Adjust size if precise crop is wanted
723 
724     if (d->preciseCrop && preciseCropAvailable())
725     {
726         size = int(size / step) * step;
727     }
728 
729     return size;
730 }
731 
applyAspectRatio(bool useHeight,bool repaintWidget)732 void RatioCropWidget::applyAspectRatio(bool useHeight, bool repaintWidget)
733 {
734     // Save selection area for re-adjustment after changing width and height.
735 
736     QRect oldRegionSelection = d->regionSelection;
737 
738     if (!useHeight)  // Width changed.
739     {
740         int w = computePreciseSize(d->regionSelection.width(),
741                                    (int)d->currentWidthRatioValue);
742 
743         d->regionSelection.setWidth(w);
744 
745         switch (d->currentAspectRatioType)
746         {
747             case RATIONONE:
748                 break;
749 
750             default:
751                 d->regionSelection.setHeight((int)
752                                              rint(w * d->currentHeightRatioValue /
753                                                   d->currentWidthRatioValue));
754                 break;
755         }
756     }
757     else      // Height changed.
758     {
759         int h = computePreciseSize(d->regionSelection.height(),
760                                    (int)d->currentHeightRatioValue);
761 
762         d->regionSelection.setHeight(h);
763 
764         switch (d->currentAspectRatioType)
765         {
766             case RATIONONE:
767                 break;
768 
769             default:
770                 d->regionSelection.setWidth((int)
771                                             rint(h * d->currentWidthRatioValue /
772                                                  d->currentHeightRatioValue));
773                 break;
774         }
775     }
776 
777     // If we change selection size by a corner, re-adjust the opposite corner position.
778 
779     switch (d->currentResizing)
780     {
781         case Private::ResizingTopLeft:
782             d->regionSelection.moveBottomRight(oldRegionSelection.bottomRight());
783             break;
784 
785         case Private::ResizingTopRight:
786             d->regionSelection.moveBottomLeft(oldRegionSelection.bottomLeft());
787             break;
788 
789         case Private::ResizingBottomLeft:
790             d->regionSelection.moveTopRight(oldRegionSelection.topRight());
791             break;
792 
793         case Private::ResizingBottomRight:
794             d->regionSelection.moveTopLeft(oldRegionSelection.topLeft());
795             break;
796     }
797 
798     if (repaintWidget)
799     {
800         updatePixmap();
801         update();
802     }
803 }
804 
normalizeRegion()805 void RatioCropWidget::normalizeRegion()
806 {
807     // Perform normalization of selection area.
808 
809     if (d->regionSelection.left() < d->image.left())
810     {
811         d->regionSelection.moveLeft(d->image.left());
812     }
813 
814     if (d->regionSelection.top() < d->image.top())
815     {
816         d->regionSelection.moveTop(d->image.top());
817     }
818 
819     if (d->regionSelection.right() > d->image.right())
820     {
821         d->regionSelection.moveRight(d->image.right());
822     }
823 
824     if (d->regionSelection.bottom() > d->image.bottom())
825     {
826         d->regionSelection.moveBottom(d->image.bottom());
827     }
828 }
829 
regionSelectionMoved()830 void RatioCropWidget::regionSelectionMoved()
831 {
832     normalizeRegion();
833 
834     updatePixmap();
835     update();
836 
837     emit signalSelectionMoved(d->regionSelection);
838 }
839 
regionSelectionChanged()840 void RatioCropWidget::regionSelectionChanged()
841 {
842     // Compute the intersection of selection region and image region
843 
844     QRect cut = d->regionSelection & d->image;
845 
846     // Adjust selection size if it was cropped
847 
848     if (d->regionSelection.width() > cut.width())
849     {
850         d->regionSelection = cut;
851         applyAspectRatio(false);
852     }
853 
854     if (d->regionSelection.height() > cut.height())
855     {
856         d->regionSelection = cut;
857         applyAspectRatio(true);
858     }
859 
860     emit signalSelectionChanged(d->regionSelection);
861 }
862 
drawRulesOfThirds(QPainter & p,const int & xThird,const int & yThird)863 void RatioCropWidget::drawRulesOfThirds(QPainter& p, const int& xThird, const int& yThird)
864 {
865 
866     p.drawLine(d->localRegionSelection.left() + xThird,   d->localRegionSelection.top(),
867                d->localRegionSelection.left() + xThird,   d->localRegionSelection.bottom());
868     p.drawLine(d->localRegionSelection.left() + 2*xThird, d->localRegionSelection.top(),
869                d->localRegionSelection.left() + 2*xThird, d->localRegionSelection.bottom());
870 
871     p.drawLine(d->localRegionSelection.left(),  d->localRegionSelection.top() + yThird,
872                d->localRegionSelection.right(), d->localRegionSelection.top() + yThird);
873     p.drawLine(d->localRegionSelection.left(),  d->localRegionSelection.top() + 2*yThird,
874                d->localRegionSelection.right(), d->localRegionSelection.top() + 2*yThird);
875 
876 }
877 
drawDiagonalMethod(QPainter & p,const int & w,const int & h)878 void RatioCropWidget::drawDiagonalMethod(QPainter& p, const int& w, const int& h)
879 {
880     p.setRenderHint(QPainter::Antialiasing);
881 
882     if (w > h)
883     {
884         p.drawLine(0, 0, h, h);
885         p.drawLine(0, h, h, 0);
886         p.drawLine(w-h, 0, w, h);
887         p.drawLine(w-h, h, w, 0);
888     }
889     else
890     {
891         p.drawLine(0, 0, w, w);
892         p.drawLine(0, w, w, 0);
893         p.drawLine(0, h-w, w, h);
894         p.drawLine(0, h, w, h-w);
895     }
896 }
897 
drawHarmoniousTriangles(QPainter & p,const int & dst)898 void RatioCropWidget::drawHarmoniousTriangles(QPainter& p, const int& dst)
899 {
900     p.setRenderHint(QPainter::Antialiasing);
901 
902     p.drawLine(-d->localRegionSelection.width()/2, -d->localRegionSelection.height()/2,
903                 d->localRegionSelection.width()/2,  d->localRegionSelection.height()/2);
904 
905     p.drawLine(-d->localRegionSelection.width()/2 + dst, -d->localRegionSelection.height()/2,
906                -d->localRegionSelection.width()/2,        d->localRegionSelection.height()/2);
907 
908     p.drawLine(d->localRegionSelection.width()/2,       -d->localRegionSelection.height()/2,
909                d->localRegionSelection.width()/2 - dst,  d->localRegionSelection.height()/2);
910 }
911 
drawGoldenMean(QPainter & p,const QRect & R1,const QRect & R2,const QRect & R3,const QRect & R4,const QRect & R5,const QRect & R6,const QRect & R7)912 void RatioCropWidget::drawGoldenMean(QPainter& p, const QRect& R1,
913                                           const QRect& R2, const QRect& R3, const QRect& R4,
914                                           const QRect& R5, const QRect& R6, const QRect& R7)
915 {
916     p.setRenderHint(QPainter::Antialiasing);
917 
918     // Drawing Golden sections.
919 
920     if (d->drawGoldenSection)
921     {
922         // horizontal lines:
923 
924         p.drawLine(R1.left(), R2.top(),
925                    R2.right(), R2.top());
926 
927         p.drawLine(R1.left(), R1.top() + R2.height(),
928                    R2.right(), R1.top() + R2.height());
929 
930         // vertical lines:
931 
932         p.drawLine(R1.right(), R1.top(),
933                    R1.right(), R1.bottom());
934 
935         p.drawLine(R1.left()+R2.width(), R1.top(),
936                    R1.left()+R2.width(), R1.bottom());
937     }
938 
939     // Drawing Golden triangle guides.
940 
941     if (d->drawGoldenTriangle)
942     {
943         p.drawLine(R1.left(),  R1.bottom(),
944                    R2.right(), R1.top());
945 
946         p.drawLine(R1.left(), R1.top(),
947                    R2.right() - R1.width(), R1.bottom());
948 
949         p.drawLine(R1.left() + R1.width(), R1.top(),
950                    R2.right(), R1.bottom());
951     }
952 
953     // Drawing Golden spiral sections.
954 
955     if (d->drawGoldenSpiralSection)
956     {
957         p.drawLine(R1.topRight(),   R1.bottomRight());
958         p.drawLine(R2.topLeft(),    R2.topRight());
959         p.drawLine(R3.topLeft(),    R3.bottomLeft());
960         p.drawLine(R4.bottomLeft(), R4.bottomRight());
961         p.drawLine(R5.topRight(),   R5.bottomRight());
962         p.drawLine(R6.topLeft(),    R6.topRight());
963         p.drawLine(R7.topLeft(),    R7.bottomLeft());
964     }
965 
966     // Drawing Golden Spiral.
967 
968     if (d->drawGoldenSpiral)
969     {
970         p.drawArc(R1.left(),
971                   R1.top() - R1.height(),
972                   2*R1.width(), 2*R1.height(),
973                   180*16, 90*16);
974 
975         p.drawArc(R2.right()  - 2*R2.width(),
976                   R1.bottom() - 2*R2.height(),
977                   2*R2.width(), 2*R2.height(),
978                   270*16, 90*16);
979 
980         p.drawArc(R2.right() - 2*R3.width(),
981                   R3.top(),
982                   2*R3.width(), 2*R3.height(),
983                   0, 90*16);
984 
985         p.drawArc(R4.left(),
986                   R4.top(),
987                   2*R4.width(), 2*R4.height(),
988                   90*16, 90*16);
989 
990         p.drawArc(R5.left(),
991                   R5.top() - R5.height(),
992                   2*R5.width(), 2*R5.height(),
993                   180*16, 90*16);
994 
995         p.drawArc(R6.left() - R6.width(),
996                   R6.top()  - R6.height(),
997                   2*R6.width(), 2*R6.height(),
998                   270*16, 90*16);
999 
1000         p.drawArc(R7.left() - R7.width(),
1001                   R7.top(),
1002                   2*R7.width(), 2*R7.height(),
1003                   0, 90*16);
1004     }
1005 }
1006 
updatePixmap()1007 void RatioCropWidget::updatePixmap()
1008 {
1009     // Updated local selection region.
1010 
1011     d->localRegionSelection.setTopLeft(convertPoint(d->regionSelection.topLeft(), false));
1012     d->localRegionSelection.setBottomRight(convertPoint(d->regionSelection.bottomRight(), false));
1013 
1014     // Updated dragging corners region.
1015 
1016     d->localTopLeftCorner.setRect(d->localRegionSelection.left(),          d->localRegionSelection.top(),        8, 8);
1017     d->localBottomLeftCorner.setRect(d->localRegionSelection.left(),       d->localRegionSelection.bottom() - 7, 8, 8);
1018     d->localTopRightCorner.setRect(d->localRegionSelection.right() - 7,    d->localRegionSelection.top(),        8, 8);
1019     d->localBottomRightCorner.setRect(d->localRegionSelection.right() - 7, d->localRegionSelection.bottom() - 7, 8, 8);
1020 
1021     // Drawing background.
1022 
1023     d->pixmap->fill(d->bgColor);
1024 
1025     if (d->preview.isNull())
1026     {
1027         return;
1028     }
1029 
1030     int sx = d->localRegionSelection.left() - d->rect.left();
1031     int sy = d->localRegionSelection.top()  - d->rect.top();
1032     int dw = d->localRegionSelection.width();
1033     int dh = d->localRegionSelection.height();
1034 
1035     QPainter p(d->pixmap);
1036     p.drawPixmap(d->rect.x(), d->rect.y(), d->grayOverLay);
1037 
1038     // Stop here if no selection to draw
1039 
1040     if (d->regionSelection.isEmpty() || !d->isDrawingSelection)
1041     {
1042         return;
1043     }
1044 
1045     // Now draw the image.
1046 
1047     p.drawPixmap(d->localRegionSelection.left(), d->localRegionSelection.top(), d->previewPixmap,
1048                  sx, sy, dw, dh);
1049 
1050     // Drawing selection borders.
1051 
1052     p.setPen(QPen(QColor(250, 250, 255), 1, Qt::SolidLine));
1053     p.drawRect(d->localRegionSelection);
1054 
1055     // Drawing selection corners.
1056 
1057     p.drawRect(d->localTopLeftCorner);
1058     p.drawRect(d->localBottomLeftCorner);
1059     p.drawRect(d->localTopRightCorner);
1060     p.drawRect(d->localBottomRightCorner);
1061 
1062     // Drawing guide lines.
1063 
1064     // Constraint drawing only on local selection region.
1065     // This is needed because arcs and incurved lines can draw
1066     // outside a little of local selection region.
1067 
1068     p.setClipping(true);
1069     p.setClipRect(d->localRegionSelection);
1070 
1071     switch (d->guideLinesType)
1072     {
1073         case RulesOfThirds:
1074         {
1075             int xThird = d->localRegionSelection.width()  / 3;
1076             int yThird = d->localRegionSelection.height() / 3;
1077 
1078             p.setPen(QPen(Qt::white, d->guideSize, Qt::SolidLine));
1079             drawRulesOfThirds(p, xThird, yThird);
1080 
1081             p.setPen(QPen(d->guideColor, d->guideSize, Qt::DotLine));
1082             drawRulesOfThirds(p, xThird, yThird);
1083             break;
1084         }
1085 
1086         case DiagonalMethod:
1087         {
1088             // Move coordinates to top, left
1089 
1090             p.translate(d->localRegionSelection.topLeft().x(), d->localRegionSelection.topLeft().y());
1091 
1092             int w = d->localRegionSelection.width();
1093             int h = d->localRegionSelection.height();
1094 
1095             p.setPen(QPen(Qt::white, d->guideSize, Qt::SolidLine));
1096             drawDiagonalMethod(p, w, h);
1097 
1098             p.setPen(QPen(d->guideColor, d->guideSize, Qt::DotLine));
1099             drawDiagonalMethod(p, w, h);
1100             break;
1101         }
1102 
1103         case HarmoniousTriangles:
1104         {
1105             // Move coordinates to local center selection.
1106 
1107             p.translate(d->localRegionSelection.center().x(), d->localRegionSelection.center().y());
1108 
1109             // Flip horizontal.
1110 
1111             if (d->flipHorGoldenGuide)
1112             {
1113                 p.scale(-1, 1);
1114             }
1115 
1116             // Flip vertical.
1117 
1118             if (d->flipVerGoldenGuide)
1119             {
1120                 p.scale(1, -1);
1121             }
1122 
1123             float w = (float)d->localRegionSelection.width();
1124             float h = (float)d->localRegionSelection.height();
1125             int dst = (int)((h*cos(atan(w/h)) / (cos(atan(h/w)))));
1126 
1127             p.setPen(QPen(Qt::white, d->guideSize, Qt::SolidLine));
1128             drawHarmoniousTriangles(p, dst);
1129 
1130             p.setPen(QPen(d->guideColor, d->guideSize, Qt::DotLine));
1131             drawHarmoniousTriangles(p, dst);
1132             break;
1133         }
1134 
1135         case GoldenMean:
1136         {
1137             // Move coordinates to local center selection.
1138 
1139             p.translate(d->localRegionSelection.center().x(), d->localRegionSelection.center().y());
1140 
1141             // Flip horizontal.
1142 
1143             if (d->flipHorGoldenGuide)
1144             {
1145                 p.scale(-1, 1);
1146             }
1147 
1148             // Flip vertical.
1149 
1150             if (d->flipVerGoldenGuide)
1151             {
1152                 p.scale(1, -1);
1153             }
1154 
1155             int w   = d->localRegionSelection.width();
1156             int h   = d->localRegionSelection.height();
1157 
1158             // lengths for the golden mean and half the sizes of the region:
1159 
1160             int w_g = (int)(w*INVPHI);
1161             int h_g = (int)(h*INVPHI);
1162             int w_2 = w/2;
1163             int h_2 = h/2;
1164 
1165             QRect R1(-w_2, -h_2, w_g, h);
1166 
1167             // w - 2*w_2 corrects for one-pixel difference
1168             // so that R2.right() is really at the right end of the region
1169 
1170             QRect R2(w_g-w_2, h_2-h_g, w-w_g+1-(w - 2*w_2), h_g);
1171 
1172             QRect R3((int)(w_2 - R2.width()*INVPHI), -h_2,
1173                      (int)(R2.width()*INVPHI), h - R2.height());
1174             QRect R4(R2.x(), R1.y(), R3.x() - R2.x(),
1175                      (int)(R3.height()*INVPHI));
1176             QRect R5(R4.x(), R4.bottom(), (int)(R4.width()*INVPHI),
1177                      R3.height() - R4.height());
1178             QRect R6(R5.x() + R5.width(), R5.bottom() - (int)(R5.height()*INVPHI),
1179                      R3.x() - R5.right(), (int)(R5.height()*INVPHI));
1180             QRect R7(R6.right() - (int)(R6.width()*INVPHI), R4.bottom(),
1181                      (int)(R6.width()*INVPHI), R5.height() - R6.height());
1182 
1183             p.setPen(QPen(Qt::white, d->guideSize, Qt::SolidLine));
1184             drawGoldenMean(p, R1, R2, R3, R4, R5, R6, R7);
1185 
1186             p.setPen(QPen(d->guideColor, d->guideSize, Qt::DotLine));
1187             drawGoldenMean(p, R1, R2, R3, R4, R5, R6, R7);
1188 
1189             break;
1190         }
1191     }
1192 
1193     p.setClipping(false);
1194 
1195     p.end();
1196 }
1197 
paintEvent(QPaintEvent *)1198 void RatioCropWidget::paintEvent(QPaintEvent*)
1199 {
1200     QPainter p(this);
1201     p.drawPixmap(0, 0, *d->pixmap);
1202     p.end();
1203 }
1204 
opposite() const1205 QPoint RatioCropWidget::opposite() const
1206 {
1207     QPoint opp;
1208 
1209     switch (d->currentResizing)
1210     {
1211         case Private::ResizingTopRight:
1212             opp = d->regionSelection.bottomLeft();
1213             break;
1214 
1215         case Private::ResizingBottomLeft:
1216             opp = d->regionSelection.topRight();
1217             break;
1218 
1219         case Private::ResizingBottomRight:
1220             opp = d->regionSelection.topLeft();
1221             break;
1222 
1223         case Private::ResizingTopLeft:
1224         default:
1225             opp = d->regionSelection.bottomRight();
1226             break;
1227     }
1228 
1229     return opp;
1230 }
1231 
distance(const QPoint & a,const QPoint & b) const1232 float RatioCropWidget::distance(const QPoint& a, const QPoint& b) const
1233 {
1234     return sqrt(pow(a.x() - b.x(), 2) + pow(a.y() - b.y(), 2));
1235 }
1236 
setCursorResizing()1237 void RatioCropWidget::setCursorResizing()
1238 {
1239     switch (d->currentResizing)
1240     {
1241         case Private::ResizingTopLeft:
1242             setCursor(Qt::SizeFDiagCursor);
1243             break;
1244 
1245         case Private::ResizingTopRight:
1246             setCursor(Qt::SizeBDiagCursor);
1247             break;
1248 
1249         case Private::ResizingBottomLeft:
1250             setCursor(Qt::SizeBDiagCursor);
1251             break;
1252 
1253         case Private::ResizingBottomRight:
1254             setCursor(Qt::SizeFDiagCursor);
1255             break;
1256     }
1257 }
1258 
placeSelection(const QPoint & pm,bool symmetric,const QPoint & center)1259 void RatioCropWidget::placeSelection(const QPoint& pm, bool symmetric, const QPoint& center)
1260 {
1261     // Set orientation
1262 
1263     if (d->autoOrientation)
1264     {
1265         QPoint rel = pm - opposite();
1266 
1267         if (abs(rel.x()) > abs(rel.y()))
1268         {
1269             if (d->currentOrientation == Portrait)
1270             {
1271                 d->currentOrientation = Landscape;
1272                 reverseRatioValues();
1273                 emit signalSelectionOrientationChanged(d->currentOrientation);
1274             }
1275         }
1276         else
1277         {
1278             if (d->currentOrientation == Landscape)
1279             {
1280                 d->currentOrientation = Portrait;
1281                 reverseRatioValues();
1282                 emit signalSelectionOrientationChanged(d->currentOrientation);
1283             }
1284         }
1285     }
1286 
1287     // Place the corner at the mouse
1288     // If a symmetric selection is wanted, place opposite corner to
1289     // the center, double selection size and move it to old center after
1290     // computing aspect ratio.
1291 
1292     switch (d->currentResizing)
1293     {
1294         case Private::ResizingTopLeft:
1295 
1296             // Place corners to the proper position
1297 
1298             d->regionSelection.setTopLeft(pm);
1299 
1300             if (symmetric)
1301             {
1302                 d->regionSelection.setBottomRight(center);
1303             }
1304 
1305             break;
1306 
1307         case Private::ResizingTopRight:
1308 
1309             d->regionSelection.setTopRight(pm);
1310 
1311             if (symmetric)
1312             {
1313                 d->regionSelection.setBottomLeft(center);
1314             }
1315 
1316             break;
1317 
1318         case Private::ResizingBottomLeft:
1319 
1320             d->regionSelection.setBottomLeft(pm);
1321 
1322             if (symmetric)
1323             {
1324                 d->regionSelection.setTopRight(center);
1325             }
1326 
1327             break;
1328 
1329         case Private::ResizingBottomRight:
1330 
1331             d->regionSelection.setBottomRight(pm);
1332 
1333             if (symmetric)
1334             {
1335                 d->regionSelection.setTopLeft(center);
1336             }
1337 
1338             break;
1339     }
1340 
1341     if (symmetric)
1342     {
1343         d->regionSelection.setSize(d->regionSelection.size()*2);
1344     }
1345 
1346     applyAspectRatio(d->currentOrientation == Portrait, false);
1347 
1348     if (symmetric)
1349     {
1350         d->regionSelection.moveCenter(center);
1351     }
1352 
1353     // Repaint
1354 
1355     updatePixmap();
1356     update();
1357 }
1358 
mousePressEvent(QMouseEvent * e)1359 void RatioCropWidget::mousePressEvent(QMouseEvent* e)
1360 {
1361     if (e->button() == Qt::LeftButton)
1362     {
1363         QPoint pm        = QPoint(e->x(), e->y());
1364         QPoint pmVirtual = convertPoint(pm);
1365         d->moving        = false;
1366 
1367         if ((e->modifiers() & Qt::ShiftModifier) == Qt::ShiftModifier)
1368         {
1369             bool symmetric  = (e->modifiers() & Qt::ControlModifier) == Qt::ControlModifier;
1370             QPoint center   = d->regionSelection.center();
1371 
1372             // Find the closest corner
1373 
1374             QPoint points[] = {
1375                                 d->regionSelection.topLeft(),
1376                                 d->regionSelection.topRight(),
1377                                 d->regionSelection.bottomLeft(),
1378                                 d->regionSelection.bottomRight()
1379                               };
1380 
1381             int resizings[] = {
1382                                 Private::ResizingTopLeft,
1383                                 Private::ResizingTopRight,
1384                                 Private::ResizingBottomLeft,
1385                                 Private::ResizingBottomRight
1386                               };
1387 
1388             float dist      = -1.0f;
1389             float dist2     =  0.0f;
1390 
1391             for (int i = 0 ; i < 4 ; ++i)
1392             {
1393                 QPoint point = points[i];
1394                 dist2        = distance(pmVirtual, point);
1395 
1396                 if ((dist2 < dist) || (d->currentResizing == Private::ResizingNone))
1397                 {
1398                     dist               = dist2;
1399                     d->currentResizing = resizings[i];
1400                 }
1401             }
1402 
1403             setCursorResizing();
1404 
1405             placeSelection(pmVirtual, symmetric, center);
1406 
1407         }
1408         else
1409         {
1410             if      (d->localTopLeftCorner.contains(pm))
1411             {
1412                 d->currentResizing = Private::ResizingTopLeft;
1413             }
1414             else if (d->localTopRightCorner.contains(pm))
1415             {
1416                 d->currentResizing = Private::ResizingTopRight;
1417             }
1418             else if (d->localBottomLeftCorner.contains(pm))
1419             {
1420                 d->currentResizing = Private::ResizingBottomLeft;
1421             }
1422             else if (d->localBottomRightCorner.contains(pm))
1423             {
1424                 d->currentResizing = Private::ResizingBottomRight;
1425             }
1426             else
1427             {
1428                 d->lastPos = pmVirtual;
1429                 setCursor(Qt::SizeAllCursor);
1430 
1431                 if (d->regionSelection.contains(pmVirtual))
1432                 {
1433                     d->moving = true;
1434                 }
1435                 else
1436                 {
1437                     d->regionSelection.moveCenter(pmVirtual);
1438                     normalizeRegion();
1439                     updatePixmap();
1440                     update();
1441                 }
1442             }
1443         }
1444     }
1445 }
1446 
mouseReleaseEvent(QMouseEvent *)1447 void RatioCropWidget::mouseReleaseEvent(QMouseEvent*)
1448 {
1449     if      (d->currentResizing != Private::ResizingNone)
1450     {
1451         setCursor(Qt::ArrowCursor);
1452         regionSelectionChanged();
1453         d->currentResizing = Private::ResizingNone;
1454     }
1455     else if (d->regionSelection.contains(d->lastPos))
1456     {
1457         setCursor(Qt::SizeAllCursor);
1458         regionSelectionMoved();
1459     }
1460     else
1461     {
1462         setCursor(Qt::ArrowCursor);
1463         regionSelectionMoved();
1464     }
1465 }
1466 
mouseMoveEvent(QMouseEvent * e)1467 void RatioCropWidget::mouseMoveEvent(QMouseEvent* e)
1468 {
1469     if (e->buttons() & Qt::LeftButton)
1470     {
1471         if (d->moving)
1472         {
1473             setCursor(Qt::SizeAllCursor);
1474             QPoint newPos = convertPoint(e->x(), e->y());
1475 
1476             d->regionSelection.translate(newPos.x() - d->lastPos.x(),
1477                                          newPos.y() - d->lastPos.y());
1478 
1479             d->lastPos = newPos;
1480 
1481             normalizeRegion();
1482 
1483             updatePixmap();
1484             update();
1485         }
1486         else
1487         {
1488             QPoint pmVirtual = convertPoint(e->x(), e->y());
1489 
1490             if (d->currentResizing == Private::ResizingNone)
1491             {
1492                 d->regionSelection.setTopLeft(pmVirtual);
1493                 d->regionSelection.setBottomRight(pmVirtual);
1494                 d->currentResizing = Private::ResizingTopLeft; // set to anything
1495             }
1496 
1497             QPoint center  = d->regionSelection.center();
1498             bool symmetric = (e->modifiers() & Qt::ControlModifier) == Qt::ControlModifier;
1499 
1500             // Change resizing mode
1501 
1502             QPoint opp = symmetric ? center : opposite();
1503             QPoint dir = pmVirtual - opp;
1504 
1505             if      (dir.x() > 0 && dir.y() > 0 && d->currentResizing != Private::ResizingBottomRight)
1506             {
1507                 d->currentResizing = Private::ResizingBottomRight;
1508                 d->regionSelection.setTopLeft(opp);
1509                 setCursor(Qt::SizeFDiagCursor);
1510             }
1511             else if (dir.x() > 0 && dir.y() < 0 && d->currentResizing != Private::ResizingTopRight)
1512             {
1513                 d->currentResizing = Private::ResizingTopRight;
1514                 d->regionSelection.setBottomLeft(opp);
1515                 setCursor(Qt::SizeBDiagCursor);
1516             }
1517             else if (dir.x() < 0 && dir.y() > 0 && d->currentResizing != Private::ResizingBottomLeft)
1518             {
1519                 d->currentResizing = Private::ResizingBottomLeft;
1520                 d->regionSelection.setTopRight(opp);
1521                 setCursor(Qt::SizeBDiagCursor);
1522             }
1523             else if (dir.x() < 0 && dir.y() < 0 && d->currentResizing != Private::ResizingTopLeft)
1524             {
1525                 d->currentResizing = Private::ResizingTopLeft;
1526                 d->regionSelection.setBottomRight(opp);
1527                 setCursor(Qt::SizeFDiagCursor);
1528             }
1529             else
1530             {
1531                 if      (dir.x() == 0 && dir.y() == 0)
1532                 {
1533                     setCursor(Qt::SizeAllCursor);
1534                 }
1535                 else if (dir.x() == 0)
1536                 {
1537                     setCursor(Qt::SizeHorCursor);
1538                 }
1539                 else if (dir.y() == 0)
1540                 {
1541                     setCursor(Qt::SizeVerCursor);
1542                 }
1543             }
1544 
1545             placeSelection(pmVirtual, symmetric, center);
1546         }
1547     }
1548     else
1549     {
1550         if      (d->localTopLeftCorner.contains(e->x(), e->y()) ||
1551                  d->localBottomRightCorner.contains(e->x(), e->y()))
1552         {
1553             setCursor(Qt::SizeFDiagCursor);
1554         }
1555         else if (d->localTopRightCorner.contains(e->x(), e->y()) ||
1556                  d->localBottomLeftCorner.contains(e->x(), e->y()))
1557         {
1558             setCursor(Qt::SizeBDiagCursor);
1559         }
1560         else if (d->localRegionSelection.contains(e->x(), e->y()))
1561         {
1562             setCursor(Qt::SizeAllCursor);
1563         }
1564         else
1565         {
1566             setCursor(Qt::ArrowCursor);
1567         }
1568     }
1569 }
1570 
setIsDrawingSelection(bool draw)1571 void RatioCropWidget::setIsDrawingSelection(bool draw)
1572 {
1573     d->isDrawingSelection = draw;
1574 }
1575 
1576 } // namespace DigikamEditorRatioCropToolPlugin
1577