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