File indexing completed on 2025-04-27 03:58:25
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2010-09-09 0007 * Description : tag region frame 0008 * 0009 * SPDX-FileCopyrightText: 2007 by Aurelien Gateau <agateau at kde dot org> 0010 * SPDX-FileCopyrightText: 2010-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> 0011 * 0012 * SPDX-License-Identifier: GPL-2.0-or-later 0013 * 0014 * ============================================================ */ 0015 0016 #include "regionframeitem.h" 0017 0018 // C++ includes 0019 0020 #include <cmath> 0021 0022 // Qt includes 0023 0024 #include <QApplication> 0025 #include <QGraphicsProxyWidget> 0026 #include <QGraphicsScene> 0027 #include <QGraphicsSceneMouseEvent> 0028 #include <QHBoxLayout> 0029 #include <QPainter> 0030 #include <QPropertyAnimation> 0031 #include <QRect> 0032 #include <QTimer> 0033 #include <QToolButton> 0034 0035 // Local includes 0036 0037 #include "graphicsdimgitem.h" 0038 #include "itemvisibilitycontroller.h" 0039 0040 namespace 0041 { 0042 static const int HANDLE_SIZE = 15; 0043 } 0044 0045 namespace Digikam 0046 { 0047 0048 enum CropHandleFlag 0049 { 0050 CH_None, 0051 CH_Top = 1, 0052 CH_Left = 2, 0053 CH_Right = 4, 0054 CH_Bottom = 8, 0055 CH_TopLeft = CH_Top | CH_Left, 0056 CH_BottomLeft = CH_Bottom | CH_Left, 0057 CH_TopRight = CH_Top | CH_Right, 0058 CH_BottomRight = CH_Bottom | CH_Right, 0059 CH_Content = 16 0060 }; 0061 0062 enum HudSide 0063 { 0064 HS_None = 0, ///< Special value used to avoid initial animation 0065 HS_Top = 1, 0066 HS_Bottom = 2, 0067 HS_Inside = 4, 0068 HS_TopInside = HS_Top | HS_Inside, 0069 HS_BottomInside = HS_Bottom | HS_Inside 0070 }; 0071 0072 typedef QPair<QPointF, HudSide> OptimalPosition; 0073 0074 Q_DECLARE_FLAGS(CropHandle, CropHandleFlag) 0075 0076 } // namespace Digikam 0077 0078 Q_DECLARE_OPERATORS_FOR_FLAGS(Digikam::CropHandle) 0079 0080 // -------------------------------------------------------------------------------- 0081 0082 namespace Digikam 0083 { 0084 0085 class Q_DECL_HIDDEN RegionFrameItem::Private 0086 { 0087 public: 0088 0089 explicit Private(RegionFrameItem* const q); 0090 0091 QRectF handleRect(CropHandle handle) const; 0092 CropHandle handleAt(const QPointF& pos) const; 0093 void updateCursor(CropHandle handle, bool buttonDown); 0094 QRectF keepRectInsideImage(const QRectF& rect, bool moving = true) const; 0095 OptimalPosition computeOptimalHudWidgetPosition() const; 0096 void updateHudWidgetPosition(); 0097 0098 public: 0099 0100 RegionFrameItem* const q; 0101 0102 HudSide hudSide; 0103 QRectF viewportRect; 0104 QList<CropHandle> cropHandleList; 0105 CropHandle movingHandle; 0106 QPointF lastMouseMovePos; 0107 double fixedRatio; 0108 QGraphicsWidget* hudWidget; 0109 0110 RegionFrameItem::Flags flags; 0111 0112 AnimatedVisibility* resizeHandleVisibility; 0113 qreal hoverAnimationOpacity; 0114 QTimer* hudTimer; 0115 QPointF hudEndPos; 0116 0117 const int HUD_TIMER_MAX_PIXELS_PER_UPDATE; 0118 const int HUD_TIMER_ANIMATION_INTERVAL; 0119 }; 0120 0121 RegionFrameItem::Private::Private(RegionFrameItem* const qq) 0122 : q (qq), 0123 hudSide (HS_None), 0124 movingHandle (CH_None), 0125 fixedRatio (0), 0126 hudWidget (nullptr), 0127 flags (NoFlags), 0128 resizeHandleVisibility (nullptr), 0129 hoverAnimationOpacity (1.0), 0130 hudTimer (nullptr), 0131 HUD_TIMER_MAX_PIXELS_PER_UPDATE (20), 0132 HUD_TIMER_ANIMATION_INTERVAL (20) 0133 { 0134 0135 cropHandleList << CH_Left << CH_Right << CH_Top << CH_Bottom 0136 << CH_TopLeft << CH_TopRight 0137 << CH_BottomLeft << CH_BottomRight; 0138 } 0139 0140 QRectF RegionFrameItem::Private::handleRect(CropHandle handle) const 0141 { 0142 QSizeF size = q->boundingRect().size(); 0143 double left, top; 0144 0145 if (handle & CH_Top) 0146 { 0147 top = 0; 0148 } 0149 else if (handle & CH_Bottom) 0150 { 0151 top = size.height() - HANDLE_SIZE; 0152 } 0153 else 0154 { 0155 top = (size.height() - HANDLE_SIZE) / 2; 0156 } 0157 0158 if (handle & CH_Left) 0159 { 0160 left = 0; 0161 } 0162 else if (handle & CH_Right) 0163 { 0164 left = size.width() - HANDLE_SIZE; 0165 } 0166 else 0167 { 0168 left = (size.width() - HANDLE_SIZE) / 2; 0169 } 0170 0171 return QRectF(left, top, HANDLE_SIZE, HANDLE_SIZE); 0172 } 0173 0174 CropHandle RegionFrameItem::Private::handleAt(const QPointF& pos) const 0175 { 0176 if (flags & ShowResizeHandles) 0177 { 0178 Q_FOREACH (const CropHandle& handle, cropHandleList) 0179 { 0180 QRectF rect = handleRect(handle); 0181 0182 if (rect.contains(pos)) 0183 { 0184 return handle; 0185 } 0186 } 0187 } 0188 0189 if (flags & MoveByDrag) 0190 { 0191 if (q->boundingRect().contains(pos)) 0192 { 0193 return CH_Content; 0194 } 0195 } 0196 0197 0198 return CH_None; 0199 } 0200 0201 void RegionFrameItem::Private::updateCursor(CropHandle handle, bool buttonDown) 0202 { 0203 Qt::CursorShape shape; 0204 0205 switch (handle) 0206 { 0207 case CH_TopLeft: 0208 case CH_BottomRight: 0209 shape = Qt::SizeFDiagCursor; 0210 break; 0211 0212 case CH_TopRight: 0213 case CH_BottomLeft: 0214 shape = Qt::SizeBDiagCursor; 0215 break; 0216 0217 case CH_Left: 0218 case CH_Right: 0219 shape = Qt::SizeHorCursor; 0220 break; 0221 0222 case CH_Top: 0223 case CH_Bottom: 0224 shape = Qt::SizeVerCursor; 0225 break; 0226 0227 case CH_Content: 0228 shape = buttonDown ? Qt::ClosedHandCursor : Qt::OpenHandCursor; 0229 break; 0230 0231 default: 0232 shape = Qt::ArrowCursor; 0233 break; 0234 } 0235 0236 q->setCursor(shape); 0237 } 0238 0239 QRectF RegionFrameItem::Private::keepRectInsideImage(const QRectF& rect, bool moving) const 0240 { 0241 QRectF r(rect); 0242 const QSizeF imageSize = q->parentDImgItem()->boundingRect().size(); 0243 0244 if ((r.width() > imageSize.width()) || (r.height() > imageSize.height())) 0245 { 0246 // This can happen when the crop ratio changes 0247 0248 QSizeF rectSize = r.size(); 0249 rectSize.scale(imageSize, Qt::KeepAspectRatio); 0250 r.setSize(rectSize); 0251 } 0252 0253 if (r.right() > imageSize.width()) 0254 { 0255 moving ? r.moveRight(imageSize.width()) : r.setRight(imageSize.width()); 0256 } 0257 else if (r.left() < 0) 0258 { 0259 moving ? r.moveLeft(0) : r.setLeft(0); 0260 } 0261 0262 if (r.bottom() > imageSize.height()) 0263 { 0264 moving ? r.moveBottom(imageSize.height()) : r.setBottom(imageSize.height()); 0265 } 0266 else if (r.top() < 0) 0267 { 0268 moving ? r.moveTop(0) : r.setTop(0); 0269 } 0270 0271 return r; 0272 } 0273 0274 OptimalPosition RegionFrameItem::Private::computeOptimalHudWidgetPosition() const 0275 { 0276 const QRectF visibleSceneRect = viewportRect.isValid() ? viewportRect : q->scene()->sceneRect(); 0277 const QRectF rect = q->sceneBoundingRect(); 0278 0279 const int margin = HANDLE_SIZE; 0280 const int hudHeight = hudWidget->boundingRect().height(); 0281 const QRectF hudMaxRect = visibleSceneRect.adjusted(0, 0, 0, -hudHeight); 0282 0283 OptimalPosition ret; 0284 0285 // Compute preferred and fallback positions. Preferred is outside rect 0286 // on the same side, fallback is outside on the other side. 0287 0288 OptimalPosition preferred = OptimalPosition(QPointF(rect.left(), rect.bottom() + margin), HS_Bottom); 0289 OptimalPosition fallback = OptimalPosition(QPointF(rect.left(), rect.top() - margin - hudHeight), HS_Top); 0290 0291 if (hudSide & HS_Top) 0292 { 0293 std::swap(preferred, fallback); 0294 } 0295 0296 // Check if a position outside rect fits 0297 0298 if (hudMaxRect.contains(preferred.first)) 0299 { 0300 ret = preferred; 0301 } 0302 else if (hudMaxRect.contains(fallback.first)) 0303 { 0304 ret= fallback; 0305 } 0306 else 0307 { 0308 // Does not fit outside, use a position inside rect 0309 0310 QPoint pos; 0311 0312 if (hudSide & HS_Top) 0313 { 0314 pos = QPoint(rect.left() + margin, rect.top() + margin); 0315 } 0316 else 0317 { 0318 pos = QPoint(rect.left() + margin, rect.bottom() - margin - hudHeight); 0319 } 0320 0321 ret = OptimalPosition(pos, HudSide(hudSide | HS_Inside)); 0322 } 0323 0324 // Ensure it's always fully visible 0325 0326 ret.first.rx() = qMin(ret.first.rx(), hudMaxRect.width() - hudWidget->boundingRect().width()); 0327 0328 // map from scene to item coordinates 0329 0330 ret.first = q->mapFromScene(ret.first); 0331 0332 return ret; 0333 } 0334 0335 void RegionFrameItem::Private::updateHudWidgetPosition() 0336 { 0337 if (!hudWidget || !q->scene()) 0338 { 0339 return; 0340 } 0341 0342 OptimalPosition result = computeOptimalHudWidgetPosition(); 0343 0344 if ((result.first == hudWidget->pos()) && (result.second == hudSide)) 0345 { 0346 return; 0347 } 0348 0349 if (hudSide == HS_None) 0350 { 0351 hudSide = result.second; 0352 } 0353 0354 if ((hudSide == result.second) && !hudTimer->isActive()) 0355 { 0356 // Not changing side and not in an animation, move directly the hud 0357 // to the final position to avoid lagging effect 0358 0359 hudWidget->setPos(result.first); 0360 } 0361 else 0362 { 0363 hudEndPos = result.first; 0364 hudSide = result.second; 0365 0366 if (!hudTimer->isActive()) 0367 { 0368 hudTimer->start(); 0369 } 0370 } 0371 } 0372 0373 // --------------------------------------------------------------------------------------- 0374 0375 RegionFrameItem::RegionFrameItem(QGraphicsItem* const item) 0376 : DImgChildItem(item), 0377 d (new Private(this)) 0378 { 0379 d->resizeHandleVisibility = new AnimatedVisibility(this); 0380 d->resizeHandleVisibility->controller()->setShallBeShown(false); 0381 0382 connect(d->resizeHandleVisibility, SIGNAL(visibleChanged()), 0383 this, SLOT(slotUpdate())); 0384 0385 connect(d->resizeHandleVisibility, SIGNAL(opacityChanged()), 0386 this, SLOT(slotUpdate())); 0387 0388 d->hudTimer = new QTimer(this); 0389 d->hudTimer->setInterval(d->HUD_TIMER_ANIMATION_INTERVAL); 0390 0391 connect(scene(), SIGNAL(sceneRectChanged(QRectF)), 0392 this, SLOT(slotSizeChanged())); 0393 0394 connect(this, SIGNAL(sizeChanged()), 0395 this, SLOT(slotSizeChanged())); 0396 0397 connect(this, SIGNAL(positionChanged()), 0398 this, SLOT(slotPosChanged())); 0399 0400 connect(d->hudTimer, SIGNAL(timeout()), 0401 this, SLOT(moveHudWidget())); 0402 0403 setFlags(GeometryEditable); 0404 0405 d->updateHudWidgetPosition(); 0406 } 0407 0408 RegionFrameItem::~RegionFrameItem() 0409 { 0410 if (d->hudWidget) 0411 { 0412 // See bug #359196: hide or close the QGraphicsWidget before delete it. Possible Qt bug? 0413 0414 d->hudWidget->hide(); 0415 delete d->hudWidget; 0416 } 0417 0418 delete d; 0419 } 0420 0421 void RegionFrameItem::setHudWidget(QWidget* const widget, Qt::WindowFlags wFlags) 0422 { 0423 QGraphicsProxyWidget* const proxy = new QGraphicsProxyWidget(nullptr, wFlags); 0424 0425 /* 0426 * This is utterly undocumented magic. If you add a normal widget directly, 0427 * with transparent parts (round corners), you will have ugly color in the corners. 0428 * If you set WA_TranslucentBackground on the widget directly, a lot of the 0429 * painting and stylesheets is broken. Like this, with an extra container, it seems to work. 0430 */ 0431 0432 QWidget* const container = new QWidget; 0433 container->setAttribute(Qt::WA_TranslucentBackground); 0434 QHBoxLayout* const layout = new QHBoxLayout; 0435 layout->setSizeConstraint(QLayout::SetFixedSize); 0436 layout->setContentsMargins(QMargins()); 0437 layout->setSpacing(0); 0438 layout->addWidget(widget); 0439 container->setLayout(layout); 0440 proxy->setWidget(container); 0441 0442 // Reset fixed sizes wrongly copied by setWidget onto the QGraphicsWidget 0443 0444 proxy->setMinimumSize(QSizeF()); 0445 proxy->setMaximumSize(QSizeF()); 0446 0447 setHudWidget(proxy); 0448 } 0449 0450 void RegionFrameItem::setHudWidget(QGraphicsWidget* const hudWidget) 0451 { 0452 if (d->hudWidget == hudWidget) 0453 { 0454 return; 0455 } 0456 0457 if (d->hudWidget) 0458 { 0459 d->hudWidget->hide(); 0460 delete d->hudWidget; 0461 } 0462 0463 d->hudWidget = hudWidget; 0464 0465 if (d->hudWidget) 0466 { 0467 d->hudWidget->setParentItem(this); 0468 d->hudWidget->installEventFilter(this); 0469 d->updateHudWidgetPosition(); 0470 } 0471 } 0472 0473 QGraphicsWidget* RegionFrameItem::hudWidget() const 0474 { 0475 return d->hudWidget; 0476 } 0477 0478 void RegionFrameItem::setFlags(Flags flags) 0479 { 0480 if (d->flags == flags) 0481 { 0482 return; 0483 } 0484 0485 d->flags = flags; 0486 update(); 0487 setAcceptHoverEvents(d->flags & GeometryEditable); 0488 d->resizeHandleVisibility->controller()->setShallBeShown(d->flags & ShowResizeHandles); 0489 0490 // ensure cursor is reset 0491 0492 CropHandle handle = d->handleAt(QCursor::pos()); 0493 d->updateCursor(handle, false/* buttonDown*/); 0494 } 0495 0496 void RegionFrameItem::changeFlags(Flags flags, bool addOrRemove) 0497 { 0498 if (addOrRemove) 0499 { 0500 setFlags(d->flags | flags); 0501 } 0502 else 0503 { 0504 setFlags(d->flags & ~flags); 0505 } 0506 } 0507 0508 void RegionFrameItem::setHudWidgetVisible(bool visible) 0509 { 0510 if (d->hudWidget) 0511 { 0512 d->hudWidget->setVisible(visible); 0513 } 0514 } 0515 0516 RegionFrameItem::Flags RegionFrameItem::flags() const 0517 { 0518 return d->flags; 0519 } 0520 0521 void RegionFrameItem::setFixedRatio(double ratio) 0522 { 0523 d->fixedRatio = ratio; 0524 } 0525 0526 void RegionFrameItem::slotSizeChanged() 0527 { 0528 d->updateHudWidgetPosition(); 0529 } 0530 0531 void RegionFrameItem::slotPosChanged() 0532 { 0533 d->updateHudWidgetPosition(); 0534 } 0535 0536 void RegionFrameItem::hudSizeChanged() 0537 { 0538 d->updateHudWidgetPosition(); 0539 } 0540 0541 void RegionFrameItem::setViewportRect(const QRectF& rect) 0542 { 0543 d->viewportRect = rect; 0544 d->updateHudWidgetPosition(); 0545 } 0546 0547 QRectF RegionFrameItem::boundingRect() const 0548 { 0549 return DImgChildItem::boundingRect(); //.adjusted(-1, -1, 1, 1); 0550 } 0551 0552 void RegionFrameItem::paint(QPainter* painter, const QStyleOptionGraphicsItem*, QWidget*) 0553 { 0554 /* 0555 QRect rect = d->viewportCropRect(); 0556 QRect imageRect = imageView()->rect(); 0557 static const QColor outerColor = QColor::fromHsvF(0, 0, 0, 0.5); 0558 QRegion outerRegion = QRegion(imageRect) - QRegion(rect); 0559 0560 Q_FOREACH (const QRect& outerRect, outerRegion.rects()) 0561 { 0562 painter->fillRect(outerRect, outerColor); 0563 } 0564 */ 0565 0566 const QColor borderColor = QColor::fromHsvF(0, 0, 1.0, 0.66 + 0.34 * d->hoverAnimationOpacity); 0567 const QColor fillColor = QColor::fromHsvF(0, 0, 0.75, 0.66); 0568 0569 // will paint to the left and bottom of logical coordinates 0570 0571 QRectF drawRect = boundingRect(); 0572 0573 painter->setPen(borderColor); 0574 painter->drawRect(drawRect); 0575 0576 if (d->resizeHandleVisibility->isVisible()) 0577 { 0578 // Only draw handles when user is not resizing 0579 0580 if (d->movingHandle == CH_None) 0581 { 0582 painter->setOpacity(d->resizeHandleVisibility->opacity()); 0583 painter->setBrush(fillColor); 0584 0585 Q_FOREACH (const CropHandle& handle, d->cropHandleList) 0586 { 0587 QRectF rect = d->handleRect(handle); 0588 painter->drawRect(rect); 0589 } 0590 } 0591 } 0592 } 0593 0594 void RegionFrameItem::slotUpdate() 0595 { 0596 update(); 0597 } 0598 0599 void RegionFrameItem::hoverEnterEvent(QGraphicsSceneHoverEvent* e) 0600 { 0601 if (boundingRect().contains(e->pos())) 0602 { 0603 d->resizeHandleVisibility->controller()->show(); 0604 } 0605 } 0606 0607 void RegionFrameItem::hoverLeaveEvent(QGraphicsSceneHoverEvent* e) 0608 { 0609 if (!boundingRect().contains(e->pos())) 0610 { 0611 d->resizeHandleVisibility->controller()->hide(); 0612 } 0613 } 0614 0615 void RegionFrameItem::hoverMoveEvent(QGraphicsSceneHoverEvent* e) 0616 { 0617 if (boundingRect().contains(e->pos())) 0618 { 0619 if (d->flags & GeometryEditable) 0620 { 0621 CropHandle handle = d->handleAt(e->pos()); 0622 d->updateCursor(handle, false/* buttonDown*/); 0623 } 0624 0625 d->resizeHandleVisibility->controller()->show(); 0626 } 0627 } 0628 0629 void RegionFrameItem::mousePressEvent(QGraphicsSceneMouseEvent* event) 0630 { 0631 // FIXME: Fade out? 0632 /* 0633 d->hudWidget->hide(); 0634 */ 0635 if (!(d->flags & GeometryEditable)) 0636 { 0637 DImgChildItem::mousePressEvent(event); 0638 return; 0639 } 0640 0641 d->movingHandle = d->handleAt(event->pos()); 0642 d->updateCursor(d->movingHandle, event->buttons() != Qt::NoButton); 0643 0644 if (d->movingHandle == CH_Content) 0645 { 0646 d->lastMouseMovePos = mapToParent(event->pos()); 0647 } 0648 0649 // Update to hide handles 0650 0651 update(); 0652 } 0653 0654 void RegionFrameItem::mouseMoveEvent(QGraphicsSceneMouseEvent* event) 0655 { 0656 const QSizeF maxSize = parentDImgItem()->boundingRect().size(); 0657 const QPointF point = mapToParent(event->pos()); 0658 qreal posX = qBound<qreal>(0., point.x(), maxSize.width()); 0659 qreal posY = qBound<qreal>(0., point.y(), maxSize.height()); 0660 QRectF r = rect(); 0661 0662 // Adjust edge 0663 0664 if (d->movingHandle & CH_Top) 0665 { 0666 r.setTop(posY); 0667 } 0668 else if (d->movingHandle & CH_Bottom) 0669 { 0670 r.setBottom(posY); 0671 } 0672 0673 if (d->movingHandle & CH_Left) 0674 { 0675 r.setLeft(posX); 0676 } 0677 else if (d->movingHandle & CH_Right) 0678 { 0679 r.setRight(posX); 0680 } 0681 0682 // Normalize rect and handles (this is useful when user drag the right side 0683 // of the crop rect to the left of the left side) 0684 0685 if (r.height() < 0) 0686 { 0687 d->movingHandle = d->movingHandle ^ (CH_Top | CH_Bottom); 0688 } 0689 0690 if (r.width() < 0) 0691 { 0692 d->movingHandle = d->movingHandle ^ (CH_Left | CH_Right); 0693 } 0694 0695 r = r.normalized(); 0696 0697 // Enforce ratio 0698 0699 if (d->fixedRatio > 0.) 0700 { 0701 if ((d->movingHandle == CH_Top) || (d->movingHandle == CH_Bottom)) 0702 { 0703 // Top or bottom 0704 0705 int width = int(r.height() / d->fixedRatio); 0706 r.setWidth(width); 0707 } 0708 else if ((d->movingHandle == CH_Left) || (d->movingHandle == CH_Right)) 0709 { 0710 // Left or right 0711 0712 int height = int(r.width() * d->fixedRatio); 0713 r.setHeight(height); 0714 } 0715 else if (d->movingHandle & CH_Top) 0716 { 0717 // Top left or top right 0718 0719 int height = int(r.width() * d->fixedRatio); 0720 r.setTop(r.bottom() - height); 0721 } 0722 else if (d->movingHandle & CH_Bottom) 0723 { 0724 // Bottom left or bottom right 0725 0726 int height = int(r.width() * d->fixedRatio); 0727 r.setHeight(height); 0728 } 0729 } 0730 0731 if (d->movingHandle == CH_Content) 0732 { 0733 QPointF delta = point - d->lastMouseMovePos; 0734 r.adjust(delta.x(), delta.y(), delta.x(), delta.y()); 0735 d->lastMouseMovePos = mapToParent(event->pos()); 0736 } 0737 0738 setRect(d->keepRectInsideImage(r)); 0739 0740 d->updateHudWidgetPosition(); 0741 } 0742 0743 void RegionFrameItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) 0744 { 0745 // FIXME: Fade in? 0746 /* 0747 d->hudWidget->show(); 0748 */ 0749 d->movingHandle = CH_None; 0750 d->updateCursor(d->handleAt(event->pos()), false); 0751 0752 // Update to show handles 0753 0754 update(); 0755 } 0756 0757 bool RegionFrameItem::eventFilter(QObject* watched, QEvent* event) 0758 { 0759 if ((watched == d->hudWidget) && (event->type() == QEvent::GraphicsSceneResize)) 0760 { 0761 d->updateHudWidgetPosition(); 0762 } 0763 0764 return DImgChildItem::eventFilter(watched, event); 0765 } 0766 0767 void RegionFrameItem::moveHudWidget() 0768 { 0769 const QPointF delta = d->hudEndPos - d->hudWidget->pos(); 0770 const double distance = sqrt(pow(delta.x(), 2) + pow(delta.y(), 2)); 0771 QPointF pos; 0772 0773 if (distance > double(d->HUD_TIMER_MAX_PIXELS_PER_UPDATE)) 0774 { 0775 pos = d->hudWidget->pos() + delta * double(d->HUD_TIMER_MAX_PIXELS_PER_UPDATE) / distance; 0776 } 0777 else 0778 { 0779 pos = d->hudEndPos; 0780 d->hudTimer->stop(); 0781 } 0782 0783 d->hudWidget->setPos(pos); 0784 } 0785 0786 void RegionFrameItem::setRectInSceneCoordinatesAdjusted(const QRectF& rect) 0787 { 0788 setRectInSceneCoordinates(d->keepRectInsideImage(rect, false)); 0789 } 0790 0791 } // namespace Digikam 0792 0793 #include "moc_regionframeitem.cpp"