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"