File indexing completed on 2025-01-19 03:55:43
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2009-12-13 0007 * Description : a widget to preview image effect. 0008 * 0009 * SPDX-FileCopyrightText: 2009-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0010 * SPDX-FileCopyrightText: 2008 by Kare Sars <kare dot sars at iki dot fi> 0011 * SPDX-FileCopyrightText: 2012 by Benjamin Girault <benjamin dot girault at gmail dot com> 0012 * 0013 * SPDX-License-Identifier: GPL-2.0-or-later 0014 * 0015 * ============================================================ */ 0016 0017 #include "dpreviewimage.h" 0018 0019 // Qt includes 0020 0021 #include <QAction> 0022 #include <QLabel> 0023 #include <QTimer> 0024 #include <QImage> 0025 #include <QPaintEvent> 0026 #include <QPainter> 0027 #include <QPixmap> 0028 #include <QGraphicsScene> 0029 #include <QWheelEvent> 0030 #include <QScrollBar> 0031 #include <QToolBar> 0032 #include <QIcon> 0033 0034 // KDE includes 0035 0036 #include <klocalizedstring.h> 0037 0038 // Local includes 0039 0040 #include "digikam_debug.h" 0041 #include "dimg.h" 0042 #include "previewloadthread.h" 0043 0044 namespace Digikam 0045 { 0046 0047 static const qreal selMargin = 8.0; 0048 static const QPointF boundMargin(selMargin, selMargin); 0049 0050 class Q_DECL_HIDDEN DSelectionItem::Private 0051 { 0052 public: 0053 0054 explicit Private() 0055 : maxX (0.0), 0056 maxY (0.0), 0057 hasMaxX (false), 0058 hasMaxY (false), 0059 hasMax (false), 0060 invZoom (1.0), 0061 selMargin (0.0), 0062 showAnchors (true) 0063 { 0064 } 0065 0066 QPen penDark; 0067 QPen penLight; 0068 QPen penAnchors; 0069 QRectF rect; 0070 qreal maxX; 0071 qreal maxY; 0072 bool hasMaxX; 0073 bool hasMaxY; 0074 bool hasMax; 0075 qreal invZoom; 0076 qreal selMargin; 0077 QRectF anchorTopLeft; 0078 QRectF anchorTopRight; 0079 QRectF anchorBottomLeft; 0080 QRectF anchorBottomRight; 0081 QLineF anchorTop; 0082 QLineF anchorBottom; 0083 QLineF anchorLeft; 0084 QLineF anchorRight; 0085 bool showAnchors; 0086 }; 0087 0088 DSelectionItem::DSelectionItem(const QRectF& rect) 0089 : QGraphicsItem(), 0090 d (new Private) 0091 { 0092 d->selMargin = selMargin; 0093 setRect(rect); 0094 0095 d->penDark.setColor(Qt::black); 0096 d->penDark.setStyle(Qt::SolidLine); 0097 d->penLight.setColor(Qt::white); 0098 d->penLight.setStyle(Qt::DashLine); 0099 d->penAnchors.setColor(Qt::white); 0100 d->penAnchors.setStyle(Qt::SolidLine); 0101 } 0102 0103 DSelectionItem::~DSelectionItem() 0104 { 0105 delete d; 0106 } 0107 0108 void DSelectionItem::saveZoom(qreal zoom) 0109 { 0110 if (zoom < 0.00001) 0111 { 0112 zoom = 0.00001; 0113 } 0114 0115 d->invZoom = 1 / zoom; 0116 d->selMargin = selMargin * d->invZoom; 0117 0118 updateAnchors(); 0119 } 0120 0121 void DSelectionItem::setMaxRight(qreal maxX) 0122 { 0123 d->maxX = maxX; 0124 d->hasMaxX = true; 0125 0126 if (d->hasMaxY) 0127 { 0128 d->hasMax = true; 0129 } 0130 } 0131 0132 void DSelectionItem::setMaxBottom(qreal maxY) 0133 { 0134 d->maxY = maxY; 0135 d->hasMaxY = true; 0136 0137 if (d->hasMaxX) 0138 { 0139 d->hasMax = true; 0140 } 0141 } 0142 0143 DSelectionItem::Intersects DSelectionItem::intersects(QPointF& point) 0144 { 0145 0146 if ((point.x() < (d->rect.left() - d->selMargin)) || 0147 (point.x() > (d->rect.right() + d->selMargin)) || 0148 (point.y() < (d->rect.top() - d->selMargin)) || 0149 (point.y() > (d->rect.bottom() + d->selMargin))) 0150 { 0151 d->showAnchors = false; 0152 update(); 0153 return None; 0154 } 0155 0156 d->showAnchors = true; 0157 update(); 0158 0159 if (point.x() < (d->rect.left() + d->selMargin)) 0160 { 0161 if (point.y() < (d->rect.top() + d->selMargin)) 0162 { 0163 return TopLeft; 0164 } 0165 0166 if (point.y() > (d->rect.bottom() - d->selMargin)) 0167 { 0168 return BottomLeft; 0169 } 0170 0171 return Left; 0172 } 0173 0174 if (point.x() > (d->rect.right() - d->selMargin)) 0175 { 0176 if (point.y() < (d->rect.top() + d->selMargin)) 0177 { 0178 return TopRight; 0179 } 0180 0181 if (point.y() > (d->rect.bottom() - d->selMargin)) 0182 { 0183 return BottomRight; 0184 } 0185 0186 return Right; 0187 } 0188 0189 if (point.y() < (d->rect.top() + d->selMargin)) 0190 { 0191 return Top; 0192 } 0193 0194 if (point.y() > (d->rect.bottom()-d->selMargin)) 0195 { 0196 return Bottom; 0197 } 0198 0199 return Move; 0200 } 0201 0202 void DSelectionItem::setRect(const QRectF& rect) 0203 { 0204 prepareGeometryChange(); 0205 d->rect = rect; 0206 d->rect = d->rect.normalized(); 0207 0208 if (d->hasMax) 0209 { 0210 if (d->rect.top() < 0) 0211 { 0212 d->rect.setTop(0); 0213 } 0214 0215 if (d->rect.left() < 0) 0216 { 0217 d->rect.setLeft(0); 0218 } 0219 0220 if (d->rect.right() > d->maxX) 0221 { 0222 d->rect.setRight(d->maxX); 0223 } 0224 0225 if (d->rect.bottom() > d->maxY) 0226 { 0227 d->rect.setBottom(d->maxY); 0228 } 0229 } 0230 0231 updateAnchors(); 0232 } 0233 0234 QPointF DSelectionItem::fixTranslation(QPointF dp) const 0235 { 0236 if ((d->rect.left() + dp.x()) < 0) 0237 { 0238 dp.setX(-d->rect.left()); 0239 } 0240 0241 if ((d->rect.top() + dp.y()) < 0) 0242 { 0243 dp.setY(-d->rect.top()); 0244 } 0245 0246 if ((d->rect.right() + dp.x()) > d->maxX) 0247 { 0248 dp.setX(d->maxX - d->rect.right()); 0249 } 0250 0251 if ((d->rect.bottom() + dp.y()) > d->maxY) 0252 { 0253 dp.setY(d->maxY - d->rect.bottom()); 0254 } 0255 0256 return dp; 0257 } 0258 0259 QRectF DSelectionItem::rect() const 0260 { 0261 return d->rect; 0262 } 0263 0264 QRectF DSelectionItem::boundingRect() const 0265 { 0266 return QRectF(d->rect.topLeft() - boundMargin, d->rect.bottomRight() + boundMargin); 0267 } 0268 0269 void DSelectionItem::paint(QPainter* painter, const QStyleOptionGraphicsItem*, QWidget*) 0270 { 0271 painter->setPen(d->penDark); 0272 painter->drawRect(d->rect); 0273 0274 painter->setPen(d->penLight); 0275 painter->drawRect(d->rect); 0276 0277 if (d->showAnchors) 0278 { 0279 painter->setPen(d->penAnchors); 0280 painter->setOpacity(0.4); 0281 0282 if (!d->anchorTop.isNull()) 0283 { 0284 painter->drawLine(d->anchorTop); 0285 } 0286 0287 if (!d->anchorBottom.isNull()) 0288 { 0289 painter->drawLine(d->anchorBottom); 0290 } 0291 0292 if (!d->anchorLeft.isNull()) 0293 { 0294 painter->drawLine(d->anchorLeft); 0295 } 0296 0297 if (!d->anchorRight.isNull()) 0298 { 0299 painter->drawLine(d->anchorRight); 0300 } 0301 0302 painter->setOpacity(0.4); 0303 0304 if (!d->anchorTopLeft.isNull()) 0305 { 0306 painter->fillRect(d->anchorTopLeft, Qt::white); 0307 } 0308 0309 if (!d->anchorTopRight.isNull()) 0310 { 0311 painter->fillRect(d->anchorTopRight, Qt::white); 0312 } 0313 0314 if (!d->anchorBottomLeft.isNull()) 0315 { 0316 painter->fillRect(d->anchorBottomLeft, Qt::white); 0317 } 0318 0319 if (!d->anchorBottomRight.isNull()) 0320 { 0321 painter->fillRect(d->anchorBottomRight, Qt::white); 0322 } 0323 } 0324 } 0325 0326 void DSelectionItem::updateAnchors() 0327 { 0328 QPointF moveDown(0.0, d->selMargin); 0329 QPointF moveRight(d->selMargin, 0.0); 0330 bool verticalCondition = (d->rect.height() - 3 * d->selMargin) > 0; 0331 bool horizontalCondition = (d->rect.width() - 3 * d->selMargin) > 0; 0332 0333 if (verticalCondition) 0334 { 0335 if (horizontalCondition) 0336 { 0337 d->anchorTop = QLineF(d->rect.topLeft() + moveDown, 0338 d->rect.topRight() + moveDown); 0339 d->anchorBottom = QLineF(d->rect.bottomLeft() - moveDown, 0340 d->rect.bottomRight() - moveDown); 0341 d->anchorLeft = QLineF(d->rect.topLeft() + moveRight, 0342 d->rect.bottomLeft() + moveRight); 0343 d->anchorRight = QLineF(d->rect.topRight() - moveRight, 0344 d->rect.bottomRight() - moveRight); 0345 0346 d->anchorTopLeft = QRectF(d->rect.topLeft(), 0347 d->rect.topLeft() + moveDown + moveRight); 0348 d->anchorTopRight = QRectF(d->rect.topRight() - moveRight, 0349 d->rect.topRight() + moveDown); 0350 d->anchorBottomLeft = QRectF(d->rect.bottomLeft() - moveDown, 0351 d->rect.bottomLeft() + moveRight); 0352 d->anchorBottomRight = QRectF(d->rect.bottomRight() - moveDown - moveRight, 0353 d->rect.bottomRight()); 0354 } 0355 else 0356 { 0357 // Only the top & bottom lines & middle line plus two corners are drawn 0358 0359 d->anchorTop = QLineF(d->rect.topLeft() + moveDown, 0360 d->rect.topRight() + moveDown); 0361 d->anchorBottom = QLineF(d->rect.bottomLeft() - moveDown, 0362 d->rect.bottomRight() - moveDown); 0363 d->anchorLeft = QLineF(d->rect.topLeft() + QPointF(d->rect.width() / 2.0, 0.0), 0364 d->rect.bottomLeft() + QPointF(d->rect.width() / 2.0, 0.0)); 0365 d->anchorRight = QLineF(); 0366 0367 d->anchorTopLeft = QRectF(d->rect.topLeft(), 0368 d->rect.topRight() + moveDown); 0369 d->anchorTopRight = QRectF(); 0370 d->anchorBottomLeft = QRectF(d->rect.bottomLeft() - moveDown, 0371 d->rect.bottomRight()); 0372 d->anchorBottomRight = QRectF(); 0373 } 0374 } 0375 else 0376 { 0377 if (horizontalCondition) 0378 { 0379 // Only the left & right lines & middle line plus two corners are drawn 0380 0381 d->anchorTop = QLineF(d->rect.topLeft() + QPointF(0.0, d->rect.height() / 2.0), 0382 d->rect.topRight() + QPointF(0.0, d->rect.height() / 2.0)); 0383 d->anchorBottom = QLineF(); 0384 d->anchorLeft = QLineF(d->rect.topLeft() + moveRight, 0385 d->rect.bottomLeft() + moveRight); 0386 d->anchorRight = QLineF(d->rect.topRight() - moveRight, 0387 d->rect.bottomRight() - moveRight); 0388 0389 d->anchorTopLeft = QRectF(d->rect.topLeft(), 0390 d->rect.bottomLeft() + moveRight); 0391 d->anchorTopRight = QRectF(d->rect.topRight() - moveRight, 0392 d->rect.bottomRight()); 0393 d->anchorBottomLeft = QRectF(); 0394 d->anchorBottomRight = QRectF(); 0395 } 0396 else 0397 { 0398 d->anchorTop = QLineF(); 0399 d->anchorBottom = QLineF(); 0400 d->anchorLeft = QLineF(); 0401 d->anchorRight = QLineF(); 0402 0403 d->anchorTopLeft = QRectF(); 0404 d->anchorTopRight = QRectF(); 0405 d->anchorBottomLeft = QRectF(); 0406 d->anchorBottomRight = QRectF(); 0407 } 0408 } 0409 } 0410 0411 // ------------------------------------------------------------------------------------------------- 0412 0413 class Q_DECL_HIDDEN DPreviewImage::Private 0414 { 0415 public: 0416 0417 enum 0418 { 0419 NONE, 0420 LOOKAROUND, 0421 DRAWSELECTION, 0422 EXPANDORSHRINK, 0423 MOVESELECTION 0424 } 0425 mouseDragAction; 0426 0427 public: 0428 0429 explicit Private() 0430 : mouseDragAction(NONE), 0431 lastdx (0), 0432 lastdy (0), 0433 scene (nullptr), 0434 pixmapItem (nullptr), 0435 selection (nullptr), 0436 enableSelection(false), 0437 mouseZone (DSelectionItem::None), 0438 zoomInAction (nullptr), 0439 zoomOutAction (nullptr), 0440 zoom2FitAction (nullptr), 0441 toolBar (nullptr), 0442 highLightLeft (nullptr), 0443 highLightRight (nullptr), 0444 highLightTop (nullptr), 0445 highLightBottom(nullptr), 0446 highLightArea (nullptr) 0447 { 0448 } 0449 0450 int lastdx; 0451 int lastdy; 0452 0453 QGraphicsScene* scene; 0454 QGraphicsPixmapItem* pixmapItem; 0455 DSelectionItem* selection; 0456 bool enableSelection; 0457 DSelectionItem::Intersects mouseZone; 0458 QPointF lastMousePoint; 0459 0460 QAction* zoomInAction; 0461 QAction* zoomOutAction; 0462 QAction* zoom2FitAction; 0463 0464 QToolBar* toolBar; 0465 0466 QGraphicsRectItem* highLightLeft; 0467 QGraphicsRectItem* highLightRight; 0468 QGraphicsRectItem* highLightTop; 0469 QGraphicsRectItem* highLightBottom; 0470 QGraphicsRectItem* highLightArea; 0471 }; 0472 0473 DPreviewImage::DPreviewImage(QWidget* const parent) 0474 : QGraphicsView(parent), 0475 d (new Private) 0476 { 0477 setAttribute(Qt::WA_DeleteOnClose); 0478 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); 0479 setMouseTracking(true); 0480 setCacheMode(QGraphicsView::CacheBackground); 0481 0482 d->scene = new QGraphicsScene; 0483 d->pixmapItem = new QGraphicsPixmapItem; 0484 0485 d->selection = new DSelectionItem(QRectF()); 0486 d->selection->setZValue(10); 0487 d->selection->setVisible(false); 0488 d->enableSelection = false; 0489 0490 d->scene->addItem(d->pixmapItem); 0491 setScene(d->scene); 0492 0493 d->highLightTop = new QGraphicsRectItem; 0494 d->highLightBottom = new QGraphicsRectItem; 0495 d->highLightRight = new QGraphicsRectItem; 0496 d->highLightLeft = new QGraphicsRectItem; 0497 d->highLightArea = new QGraphicsRectItem; 0498 0499 d->highLightTop->setOpacity(0.4); 0500 d->highLightBottom->setOpacity(0.4); 0501 d->highLightRight->setOpacity(0.4); 0502 d->highLightLeft->setOpacity(0.4); 0503 d->highLightArea->setOpacity(0.6); 0504 0505 d->highLightTop->setPen(Qt::NoPen); 0506 d->highLightBottom->setPen(Qt::NoPen); 0507 d->highLightRight->setPen(Qt::NoPen); 0508 d->highLightLeft->setPen(Qt::NoPen); 0509 d->highLightArea->setPen(Qt::NoPen); 0510 0511 d->highLightTop->setBrush(QBrush(Qt::black)); 0512 d->highLightBottom->setBrush(QBrush(Qt::black)); 0513 d->highLightRight->setBrush(QBrush(Qt::black)); 0514 d->highLightLeft->setBrush(QBrush(Qt::black)); 0515 0516 d->scene->addItem(d->selection); 0517 d->scene->addItem(d->highLightTop); 0518 d->scene->addItem(d->highLightBottom); 0519 d->scene->addItem(d->highLightRight); 0520 d->scene->addItem(d->highLightLeft); 0521 d->scene->addItem(d->highLightArea); 0522 0523 d->mouseZone = DSelectionItem::None; 0524 0525 // create context menu 0526 0527 d->zoomInAction = new QAction(QIcon::fromTheme(QLatin1String("zoom-in")), i18nc("@action", "Zoom In"), this); 0528 d->zoomInAction->setToolTip(i18nc("@info", "Zoom In")); 0529 d->zoomInAction->setShortcut(Qt::Key_Plus); 0530 0531 connect(d->zoomInAction, &QAction::triggered, 0532 this, &DPreviewImage::slotZoomIn); 0533 0534 d->zoomOutAction = new QAction(QIcon::fromTheme(QLatin1String("zoom-out")), i18nc("@action", "Zoom Out"), this); 0535 d->zoomOutAction->setToolTip(i18nc("@info", "Zoom Out")); 0536 d->zoomOutAction->setShortcut(Qt::Key_Minus); 0537 0538 connect(d->zoomOutAction, &QAction::triggered, 0539 this, &DPreviewImage::slotZoomOut); 0540 0541 d->zoom2FitAction = new QAction(QIcon::fromTheme(QLatin1String("zoom-fit-best")), i18nc("@action", "Zoom to Fit"), this); 0542 d->zoom2FitAction->setToolTip(i18nc("@info", "Zoom to Fit")); 0543 d->zoom2FitAction->setShortcut(Qt::Key_Asterisk); 0544 0545 connect(d->zoom2FitAction, &QAction::triggered, 0546 this, &DPreviewImage::slotZoom2Fit); 0547 0548 addAction(d->zoomInAction); 0549 addAction(d->zoomOutAction); 0550 addAction(d->zoom2FitAction); 0551 setContextMenuPolicy(Qt::ActionsContextMenu); 0552 0553 // Create ToolBar 0554 0555 d->toolBar = new QToolBar(this); 0556 d->toolBar->addAction(d->zoomInAction); 0557 d->toolBar->addAction(d->zoomOutAction); 0558 d->toolBar->addAction(d->zoom2FitAction); 0559 d->toolBar->hide(); 0560 d->toolBar->installEventFilter(this); 0561 0562 horizontalScrollBar()->installEventFilter(this); 0563 verticalScrollBar()->installEventFilter(this); 0564 } 0565 0566 DPreviewImage::~DPreviewImage() 0567 { 0568 delete d; 0569 } 0570 0571 bool DPreviewImage::setImage(const QImage& img) const 0572 { 0573 if (!img.isNull()) 0574 { 0575 d->pixmapItem->setPixmap(QPixmap::fromImage(img)); 0576 d->pixmapItem->setShapeMode(QGraphicsPixmapItem::BoundingRectShape); 0577 d->scene->setSceneRect(0, 0, img.width(), img.height()); 0578 return true; 0579 } 0580 0581 return false; 0582 } 0583 0584 void DPreviewImage::enableSelectionArea(bool b) 0585 { 0586 d->enableSelection = b; 0587 } 0588 0589 QRectF DPreviewImage::getSelectionArea() const 0590 { 0591 return d->selection->rect(); 0592 } 0593 0594 void DPreviewImage::setSelectionArea(const QRectF& rectangle) 0595 { 0596 d->selection->setRect(rectangle); 0597 0598 if (!d->selection->isVisible()) 0599 d->selection->setVisible(true); 0600 } 0601 0602 bool DPreviewImage::load(const QUrl& file) const 0603 { 0604 DImg dimg = PreviewLoadThread::loadHighQualitySynchronously(file.toLocalFile()); 0605 bool ret = setImage(dimg.copyQImage()); 0606 0607 if (ret && d->enableSelection) 0608 { 0609 qCDebug(DIGIKAM_GENERAL_LOG) << d->scene->height() << " " << d->scene->width(); 0610 d->selection->setMaxRight(d->scene->width()); 0611 d->selection->setMaxBottom(d->scene->height()); 0612 d->selection->setRect(d->scene->sceneRect()); 0613 } 0614 0615 return ret; 0616 } 0617 0618 void DPreviewImage::slotZoomIn() 0619 { 0620 scale(1.5, 1.5); 0621 d->selection->saveZoom(transform().m11()); 0622 d->zoom2FitAction->setDisabled(false); 0623 } 0624 0625 void DPreviewImage::slotZoomOut() 0626 { 0627 scale(1.0 / 1.5, 1.0 / 1.5); 0628 d->selection->saveZoom(transform().m11()); 0629 d->zoom2FitAction->setDisabled(false); 0630 } 0631 0632 void DPreviewImage::slotZoom2Fit() 0633 { 0634 fitInView(d->pixmapItem->boundingRect(), Qt::KeepAspectRatio); 0635 d->selection->saveZoom(transform().m11()); 0636 d->zoom2FitAction->setDisabled(true); 0637 } 0638 0639 void DPreviewImage::slotSetTLX(float ratio) 0640 { 0641 if (!d->selection->isVisible()) 0642 { 0643 return; // only correct the selection if it is visible 0644 } 0645 0646 QRectF rect = d->selection->rect(); 0647 rect.setLeft(ratio * d->scene->width()); 0648 d->selection->setRect(rect); 0649 updateSelVisibility(); 0650 } 0651 0652 void DPreviewImage::slotSetTLY(float ratio) 0653 { 0654 if (!d->selection->isVisible()) 0655 { 0656 return; // only correct the selection if it is visible 0657 } 0658 0659 QRectF rect = d->selection->rect(); 0660 rect.setTop(ratio * d->scene->height()); 0661 d->selection->setRect(rect); 0662 updateSelVisibility(); 0663 } 0664 0665 void DPreviewImage::slotSetBRX(float ratio) 0666 { 0667 if (!d->selection->isVisible()) 0668 { 0669 return; // only correct the selection if it is visible 0670 } 0671 0672 QRectF rect = d->selection->rect(); 0673 rect.setRight(ratio * d->scene->width()); 0674 d->selection->setRect(rect); 0675 updateSelVisibility(); 0676 } 0677 0678 void DPreviewImage::slotSetBRY(float ratio) 0679 { 0680 if (!d->selection->isVisible()) 0681 { 0682 return; // only correct the selection if it is visible 0683 } 0684 0685 QRectF rect = d->selection->rect(); 0686 rect.setBottom(ratio * d->scene->height()); 0687 d->selection->setRect(rect); 0688 updateSelVisibility(); 0689 } 0690 0691 void DPreviewImage::slotSetSelection(float tl_x, float tl_y, float br_x, float br_y) 0692 { 0693 QRectF rect; 0694 rect.setCoords(tl_x * d->scene->width(), 0695 tl_y * d->scene->height(), 0696 br_x * d->scene->width(), 0697 br_y * d->scene->height()); 0698 0699 d->selection->setRect(rect); 0700 updateSelVisibility(); 0701 } 0702 0703 void DPreviewImage::slotClearActiveSelection() 0704 { 0705 d->selection->setRect(QRectF(0, 0, 0, 0)); 0706 d->selection->setVisible(false); 0707 } 0708 0709 void DPreviewImage::slotSetHighlightArea(float tl_x, float tl_y, float br_x, float br_y) 0710 { 0711 QRectF rect; 0712 0713 // Left reason for rect: setCoords(x1,y1,x2,y2) != setRect(x1,x2, width, height) 0714 0715 rect.setCoords(0, 0716 0, 0717 tl_x * d->scene->width(), 0718 d->scene->height()); 0719 d->highLightLeft->setRect(rect); 0720 0721 // Right 0722 0723 rect.setCoords(br_x * d->scene->width(), 0724 0, 0725 d->scene->width(), 0726 d->scene->height()); 0727 d->highLightRight->setRect(rect); 0728 0729 // Top 0730 0731 rect.setCoords(tl_x * d->scene->width(), 0732 0, 0733 br_x * d->scene->width(), 0734 tl_y * d->scene->height()); 0735 d->highLightTop->setRect(rect); 0736 0737 // Bottom 0738 0739 rect.setCoords(tl_x * d->scene->width(), 0740 br_y * d->scene->height(), 0741 br_x * d->scene->width(), 0742 d->scene->height()); 0743 d->highLightBottom->setRect(rect); 0744 0745 // Area 0746 0747 rect.setCoords(tl_x * d->scene->width(), 0748 tl_y* d->scene->height(), 0749 br_x * d->scene->width(), 0750 br_y* d->scene->height()); 0751 0752 d->highLightArea->setRect(rect); 0753 0754 d->highLightLeft->show(); 0755 d->highLightRight->show(); 0756 d->highLightTop->show(); 0757 d->highLightBottom->show(); 0758 0759 // the highlight area is hidden until setHighlightShown is called. 0760 0761 d->highLightArea->hide(); 0762 } 0763 0764 void DPreviewImage::slotSetHighlightShown(int percentage, const QColor& highLightColor) 0765 { 0766 if (percentage >= 100) 0767 { 0768 d->highLightArea->hide(); 0769 return; 0770 } 0771 0772 d->highLightArea->setBrush(highLightColor); 0773 0774 qreal diff = d->highLightBottom->rect().top() - d->highLightTop->rect().bottom(); 0775 diff -= (diff * percentage) / 100; 0776 0777 QRectF rect = d->highLightArea->rect(); 0778 rect.setTop(d->highLightBottom->rect().top() - diff); 0779 0780 d->highLightArea->setRect(rect); 0781 0782 d->highLightArea->show(); 0783 } 0784 0785 void DPreviewImage::slotClearHighlight() 0786 { 0787 d->highLightLeft->hide(); 0788 d->highLightRight->hide(); 0789 d->highLightTop->hide(); 0790 d->highLightBottom->hide(); 0791 d->highLightArea->hide(); 0792 } 0793 0794 void DPreviewImage::wheelEvent(QWheelEvent* e) 0795 { 0796 if (e->modifiers() == Qt::ControlModifier) 0797 { 0798 if (e->angleDelta().y() > 0) 0799 { 0800 slotZoomIn(); 0801 } 0802 else 0803 { 0804 slotZoomOut(); 0805 } 0806 } 0807 else 0808 { 0809 QGraphicsView::wheelEvent(e); 0810 } 0811 } 0812 0813 void DPreviewImage::mousePressEvent(QMouseEvent* e) 0814 { 0815 if (e->button() & Qt::LeftButton) 0816 { 0817 0818 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) 0819 0820 d->lastdx = e->position().toPoint().x(); 0821 d->lastdy = e->position().toPoint().y(); 0822 QPointF scenePoint = mapToScene(e->position().toPoint()); 0823 0824 #else 0825 0826 d->lastdx = e->x(); 0827 d->lastdy = e->y(); 0828 QPointF scenePoint = mapToScene(e->pos()); 0829 0830 #endif 0831 0832 d->lastMousePoint = scenePoint; 0833 0834 if (e->modifiers() != Qt::ControlModifier && d->enableSelection) 0835 { 0836 if (!d->selection->isVisible() || !d->selection->contains(scenePoint)) 0837 { 0838 // Beginning of a selection area change 0839 0840 d->mouseDragAction = Private::DRAWSELECTION; 0841 d->selection->setVisible(true); 0842 d->selection->setRect(QRectF(scenePoint, QSizeF(0, 0))); 0843 d->mouseZone = DSelectionItem::BottomRight; 0844 } 0845 else if (d->selection->isVisible() && 0846 d->mouseZone != DSelectionItem::None && 0847 d->mouseZone != DSelectionItem::Move) 0848 { 0849 // Modification of the selection area 0850 0851 d->mouseDragAction = Private::EXPANDORSHRINK; 0852 } 0853 else 0854 { 0855 // Selection movement called by QGraphicsView 0856 0857 d->mouseDragAction = Private::MOVESELECTION; 0858 } 0859 0860 updateHighlight(); 0861 } 0862 else 0863 { 0864 // Beginning of moving around the picture 0865 0866 d->mouseDragAction = Private::LOOKAROUND; 0867 setCursor(Qt::ClosedHandCursor); 0868 } 0869 } 0870 0871 QGraphicsView::mousePressEvent(e); 0872 } 0873 0874 void DPreviewImage::mouseReleaseEvent(QMouseEvent* e) 0875 { 0876 if (e->button() & Qt::LeftButton) 0877 { 0878 if (d->mouseDragAction == Private::DRAWSELECTION) 0879 { 0880 // Stop and setup the selection area 0881 // Only one case: small rectangle that we drop 0882 0883 if ((d->selection->rect().width() < 0.001) || 0884 (d->selection->rect().height() < 0.001)) 0885 { 0886 slotClearActiveSelection(); 0887 } 0888 } 0889 0890 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) 0891 0892 if (!d->selection->isVisible() || !d->selection->contains(e->position().toPoint())) 0893 0894 #else 0895 0896 if (!d->selection->isVisible() || !d->selection->contains(e->pos())) 0897 0898 #endif 0899 0900 { 0901 setCursor(Qt::CrossCursor); 0902 } 0903 } 0904 0905 d->mouseDragAction = Private::NONE; 0906 updateHighlight(); 0907 0908 QGraphicsView::mouseReleaseEvent(e); 0909 } 0910 0911 void DPreviewImage::mouseMoveEvent(QMouseEvent* e) 0912 { 0913 0914 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) 0915 0916 QPointF scenePoint = mapToScene(e->position().toPoint()); 0917 0918 #else 0919 0920 QPointF scenePoint = mapToScene(e->pos()); 0921 0922 #endif 0923 0924 if (e->buttons() & Qt::LeftButton) 0925 { 0926 if (d->mouseDragAction == Private::LOOKAROUND) 0927 { 0928 0929 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) 0930 0931 int dx = e->position().toPoint().x() - d->lastdx; 0932 int dy = e->position().toPoint().y() - d->lastdy; 0933 0934 #else 0935 0936 int dx = e->x() - d->lastdx; 0937 int dy = e->y() - d->lastdy; 0938 0939 #endif 0940 0941 verticalScrollBar()->setValue(verticalScrollBar()->value() - dy); 0942 horizontalScrollBar()->setValue(horizontalScrollBar()->value() - dx); 0943 0944 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) 0945 0946 d->lastdx = e->position().toPoint().x(); 0947 d->lastdy = e->position().toPoint().y(); 0948 0949 #else 0950 0951 d->lastdx = e->x(); 0952 d->lastdy = e->y(); 0953 0954 #endif 0955 0956 } 0957 else if (d->mouseDragAction == Private::DRAWSELECTION || 0958 d->mouseDragAction == Private::EXPANDORSHRINK || 0959 d->mouseDragAction == Private::MOVESELECTION) 0960 { 0961 ensureVisible(QRectF(scenePoint, QSizeF(0, 0)), 1, 1); 0962 QRectF rect = d->selection->rect(); 0963 0964 switch (d->mouseZone) 0965 { 0966 case DSelectionItem::None: 0967 { 0968 // should not be here :) 0969 break; 0970 } 0971 0972 case DSelectionItem::Top: 0973 { 0974 if (scenePoint.y() < rect.bottom()) 0975 { 0976 rect.setTop(scenePoint.y()); 0977 } 0978 else 0979 { 0980 d->mouseZone = DSelectionItem::Bottom; 0981 rect.setTop(rect.bottom()); 0982 } 0983 0984 break; 0985 } 0986 0987 case DSelectionItem::TopRight: 0988 { 0989 if (scenePoint.x() > rect.left()) 0990 { 0991 rect.setRight(scenePoint.x()); 0992 } 0993 else 0994 { 0995 d->mouseZone = DSelectionItem::TopLeft; 0996 setCursor(Qt::SizeFDiagCursor); 0997 rect.setRight(rect.left()); 0998 } 0999 1000 if (scenePoint.y() < rect.bottom()) 1001 { 1002 rect.setTop(scenePoint.y()); 1003 } 1004 else 1005 { 1006 if (d->mouseZone != DSelectionItem::TopLeft) 1007 { 1008 d->mouseZone = DSelectionItem::BottomRight; 1009 setCursor(Qt::SizeFDiagCursor); 1010 } 1011 else 1012 { 1013 d->mouseZone = DSelectionItem::BottomLeft; 1014 setCursor(Qt::SizeBDiagCursor); 1015 } 1016 1017 rect.setTop(rect.bottom()); 1018 } 1019 1020 break; 1021 } 1022 1023 case DSelectionItem::Right: 1024 { 1025 if (scenePoint.x() > rect.left()) 1026 { 1027 rect.setRight(scenePoint.x()); 1028 } 1029 else 1030 { 1031 d->mouseZone = DSelectionItem::Left; 1032 rect.setRight(rect.left()); 1033 } 1034 1035 break; 1036 } 1037 1038 case DSelectionItem::BottomRight: 1039 { 1040 if (scenePoint.x() > rect.left()) 1041 { 1042 rect.setRight(scenePoint.x()); 1043 } 1044 else 1045 { 1046 d->mouseZone = DSelectionItem::BottomLeft; 1047 setCursor(Qt::SizeBDiagCursor); 1048 rect.setRight(rect.left()); 1049 } 1050 1051 if (scenePoint.y() > rect.top()) 1052 { 1053 rect.setBottom(scenePoint.y()); 1054 } 1055 else 1056 { 1057 if (d->mouseZone != DSelectionItem::BottomLeft) 1058 { 1059 d->mouseZone = DSelectionItem::TopRight; 1060 setCursor(Qt::SizeBDiagCursor); 1061 } 1062 else 1063 { 1064 d->mouseZone = DSelectionItem::TopLeft; 1065 setCursor(Qt::SizeFDiagCursor); 1066 } 1067 1068 rect.setBottom(rect.top()); 1069 } 1070 1071 break; 1072 } 1073 1074 case DSelectionItem::Bottom: 1075 { 1076 if (scenePoint.y() > rect.top()) 1077 { 1078 rect.setBottom(scenePoint.y()); 1079 } 1080 else 1081 { 1082 d->mouseZone = DSelectionItem::Top; 1083 rect.setBottom(rect.top()); 1084 } 1085 1086 break; 1087 } 1088 1089 case DSelectionItem::BottomLeft: 1090 { 1091 if (scenePoint.x() < rect.right()) 1092 { 1093 rect.setLeft(scenePoint.x()); 1094 } 1095 else 1096 { 1097 d->mouseZone = DSelectionItem::BottomRight; 1098 setCursor(Qt::SizeFDiagCursor); 1099 rect.setLeft(rect.right()); 1100 } 1101 1102 if (scenePoint.y() > rect.top()) 1103 { 1104 rect.setBottom(scenePoint.y()); 1105 } 1106 else 1107 { 1108 if (d->mouseZone != DSelectionItem::BottomRight) 1109 { 1110 d->mouseZone = DSelectionItem::TopLeft; 1111 setCursor(Qt::SizeFDiagCursor); 1112 } 1113 else 1114 { 1115 d->mouseZone = DSelectionItem::TopRight; 1116 setCursor(Qt::SizeBDiagCursor); 1117 } 1118 1119 rect.setBottom(rect.top()); 1120 } 1121 1122 break; 1123 } 1124 1125 case DSelectionItem::Left: 1126 { 1127 if (scenePoint.x() < rect.right()) 1128 { 1129 rect.setLeft(scenePoint.x()); 1130 } 1131 else 1132 { 1133 d->mouseZone = DSelectionItem::Right; 1134 rect.setLeft(rect.right()); 1135 } 1136 1137 break; 1138 } 1139 1140 case DSelectionItem::TopLeft: 1141 { 1142 if (scenePoint.x() < rect.right()) 1143 { 1144 rect.setLeft(scenePoint.x()); 1145 } 1146 else 1147 { 1148 d->mouseZone = DSelectionItem::TopRight; 1149 setCursor(Qt::SizeBDiagCursor); 1150 rect.setLeft(rect.right()); 1151 } 1152 1153 if (scenePoint.y() < rect.bottom()) 1154 { 1155 rect.setTop(scenePoint.y()); 1156 } 1157 else 1158 { 1159 if (d->mouseZone != DSelectionItem::TopRight) 1160 { 1161 d->mouseZone = DSelectionItem::BottomLeft; 1162 setCursor(Qt::SizeBDiagCursor); 1163 } 1164 else 1165 { 1166 d->mouseZone = DSelectionItem::BottomRight; 1167 setCursor(Qt::SizeFDiagCursor); 1168 } 1169 1170 rect.setTop(rect.bottom()); 1171 } 1172 1173 break; 1174 } 1175 1176 case DSelectionItem::Move: 1177 { 1178 rect.translate(d->selection->fixTranslation(scenePoint - d->lastMousePoint)); 1179 break; 1180 } 1181 } 1182 1183 d->selection->setRect(rect); 1184 } 1185 } 1186 else if (d->selection->isVisible()) 1187 { 1188 d->mouseZone = d->selection->intersects(scenePoint); 1189 1190 switch (d->mouseZone) 1191 { 1192 case DSelectionItem::None: 1193 { 1194 setCursor(Qt::CrossCursor); 1195 break; 1196 } 1197 1198 case DSelectionItem::Top: 1199 { 1200 setCursor(Qt::SizeVerCursor); 1201 break; 1202 } 1203 1204 case DSelectionItem::TopRight: 1205 { 1206 setCursor(Qt::SizeBDiagCursor); 1207 break; 1208 } 1209 1210 case DSelectionItem::Right: 1211 { 1212 setCursor(Qt::SizeHorCursor); 1213 break; 1214 } 1215 1216 case DSelectionItem::BottomRight: 1217 { 1218 setCursor(Qt::SizeFDiagCursor); 1219 break; 1220 } 1221 1222 case DSelectionItem::Bottom: 1223 { 1224 setCursor(Qt::SizeVerCursor); 1225 break; 1226 } 1227 1228 case DSelectionItem::BottomLeft: 1229 { 1230 setCursor(Qt::SizeBDiagCursor); 1231 break; 1232 } 1233 1234 case DSelectionItem::Left: 1235 { 1236 setCursor(Qt::SizeHorCursor); 1237 break; 1238 } 1239 1240 case DSelectionItem::TopLeft: 1241 { 1242 setCursor(Qt::SizeFDiagCursor); 1243 break; 1244 } 1245 1246 case DSelectionItem::Move: 1247 { 1248 setCursor(Qt::SizeAllCursor); 1249 break; 1250 } 1251 } 1252 } 1253 else 1254 { 1255 setCursor(Qt::CrossCursor); 1256 } 1257 1258 d->lastMousePoint = scenePoint; 1259 updateHighlight(); 1260 QGraphicsView::mouseMoveEvent(e); 1261 } 1262 1263 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) 1264 1265 void DPreviewImage::enterEvent(QEnterEvent* /*event*/) 1266 1267 #else 1268 1269 void DPreviewImage::enterEvent(QEvent* /*event*/) 1270 1271 #endif 1272 1273 { 1274 d->toolBar->show(); 1275 } 1276 1277 void DPreviewImage::leaveEvent(QEvent*) 1278 { 1279 d->toolBar->hide(); 1280 } 1281 1282 bool DPreviewImage::eventFilter(QObject* obj, QEvent* ev) 1283 { 1284 if (obj == d->toolBar) 1285 { 1286 if (ev->type() == QEvent::Enter) 1287 { 1288 setCursor(Qt::ArrowCursor); 1289 } 1290 else if (ev->type() == QEvent::Leave) 1291 { 1292 unsetCursor(); 1293 } 1294 1295 return false; 1296 } 1297 else if (obj == verticalScrollBar() && verticalScrollBar()->isVisible()) 1298 { 1299 if (ev->type() == QEvent::Enter) 1300 { 1301 setCursor(Qt::ArrowCursor); 1302 } 1303 else if (ev->type() == QEvent::Leave) 1304 { 1305 unsetCursor(); 1306 } 1307 1308 return false; 1309 } 1310 else if (obj == horizontalScrollBar() && horizontalScrollBar()->isVisible()) 1311 { 1312 if (ev->type() == QEvent::Enter) 1313 { 1314 setCursor(Qt::ArrowCursor); 1315 } 1316 else if (ev->type() == QEvent::Leave) 1317 { 1318 unsetCursor(); 1319 } 1320 1321 return false; 1322 } 1323 1324 return QGraphicsView::eventFilter(obj, ev); 1325 } 1326 1327 void DPreviewImage::resizeEvent(QResizeEvent* e) 1328 { 1329 if (!d->zoom2FitAction->isEnabled()) 1330 { 1331 // Fit the image to the new size... 1332 1333 fitInView(d->pixmapItem->boundingRect(), Qt::KeepAspectRatio); 1334 d->selection->saveZoom(transform().m11()); 1335 } 1336 1337 QGraphicsView::resizeEvent(e); 1338 } 1339 1340 void DPreviewImage::updateSelVisibility() 1341 { 1342 if ((d->selection->rect().width() > 0.001) && 1343 (d->selection->rect().height() > 0.001) && 1344 ((d->scene->width() - d->selection->rect().width() > 0.1) || 1345 (d->scene->height() - d->selection->rect().height() > 0.1))) 1346 { 1347 d->selection->setVisible(true); 1348 } 1349 else 1350 { 1351 d->selection->setVisible(false); 1352 } 1353 1354 updateHighlight(); 1355 } 1356 1357 void DPreviewImage::updateHighlight() 1358 { 1359 if (d->selection->isVisible()) 1360 { 1361 QRectF rect; 1362 1363 // Left 1364 1365 rect.setCoords(0, 1366 0, 1367 d->selection->rect().left(), 1368 d->scene->height()); 1369 d->highLightLeft->setRect(rect); 1370 1371 // Right 1372 1373 rect.setCoords(d->selection->rect().right(), 1374 0, 1375 d->scene->width(), 1376 d->scene->height()); 1377 d->highLightRight->setRect(rect); 1378 1379 // Top 1380 1381 rect.setCoords(d->selection->rect().left(), 1382 0, 1383 d->selection->rect().right(), 1384 d->selection->rect().top()); 1385 d->highLightTop->setRect(rect); 1386 1387 // Bottom 1388 1389 rect.setCoords(d->selection->rect().left(), 1390 d->selection->rect().bottom(), 1391 d->selection->rect().right(), 1392 d->scene->height()); 1393 d->highLightBottom->setRect(rect); 1394 1395 d->highLightLeft->show(); 1396 d->highLightRight->show(); 1397 d->highLightTop->show(); 1398 d->highLightBottom->show(); 1399 d->highLightArea->hide(); 1400 } 1401 else 1402 { 1403 d->highLightLeft->hide(); 1404 d->highLightRight->hide(); 1405 d->highLightTop->hide(); 1406 d->highLightBottom->hide(); 1407 d->highLightArea->hide(); 1408 } 1409 } 1410 1411 } // namespace Digikam 1412 1413 #include "moc_dpreviewimage.cpp"