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