File indexing completed on 2025-04-27 03:58:23

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2011-03-04
0007  * Description : A simple item to click, drag and release
0008  *
0009  * SPDX-FileCopyrightText: 2010-2011 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
0010  *
0011  * SPDX-License-Identifier: GPL-2.0-or-later
0012  *
0013  * ============================================================ */
0014 
0015 #include "clickdragreleaseitem.h"
0016 
0017 // Qt includes
0018 
0019 #include <QApplication>
0020 #include <QGraphicsSceneMouseEvent>
0021 #include <QKeyEvent>
0022 #include <QObject>
0023 #include <QPointF>
0024 
0025 // Local includes
0026 
0027 #include "digikam_debug.h"
0028 #include "itemvisibilitycontroller.h"
0029 
0030 namespace Digikam
0031 {
0032 
0033 enum ClickDragState
0034 {
0035     HoverState,
0036     PressedState,
0037     PressDragState,
0038     ClickedMoveState
0039 };
0040 
0041 class Q_DECL_HIDDEN ClickDragReleaseItem::Private
0042 {
0043 public:
0044 
0045     explicit Private()
0046         : state(HoverState)
0047     {
0048     }
0049 
0050     template <class Event> bool isDrag(Event* e)
0051     {
0052         return ((pressPos - e->scenePos()).manhattanLength() > QApplication::startDragDistance());
0053     }
0054 
0055     template <class Event> QRectF rect(Event* e)
0056     {
0057         return QRectF(pressPos, e->scenePos()).normalized();
0058     }
0059 
0060 public:
0061 
0062     ClickDragState state;
0063     QPointF        pressPos;
0064 };
0065 
0066 // ----------------------------------------------------------------------------
0067 
0068 ClickDragReleaseItem::ClickDragReleaseItem(QGraphicsItem* const parent)
0069     : QGraphicsObject(parent),
0070       d              (new Private)
0071 {
0072     setCursor(Qt::CrossCursor);
0073     setFlags(ItemIsFocusable | ItemHasNoContents);
0074 }
0075 
0076 ClickDragReleaseItem::~ClickDragReleaseItem()
0077 {
0078     delete d;
0079 }
0080 
0081 QRectF ClickDragReleaseItem::boundingRect() const
0082 {
0083     if (parentItem())
0084     {
0085         return QRectF(QPointF(0, 0), parentItem()->boundingRect().size());
0086     }
0087 
0088     return QRectF();
0089 }
0090 
0091 void ClickDragReleaseItem::paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*)
0092 {
0093 }
0094 
0095 /**
0096  * 1) Press - Drag - Release:
0097  *    mousePress, PressedState -> mouseMoveEvent over threshold, PressDragState -> mouseReleaseEvent, finished
0098  * 2) Click - Move - Click:
0099  *    mousePressEvent, PressedState -> mouseReleaseEvent, ClickedMoveState ->
0100  *    hoverMoveEvent -> mouseReleaseEvent, finished
0101  */
0102 
0103 void ClickDragReleaseItem::mousePressEvent(QGraphicsSceneMouseEvent* e)
0104 {
0105     if (e->button() != Qt::LeftButton)
0106     {
0107         Q_EMIT cancelled();
0108         return;
0109     }
0110 
0111     if (d->state == HoverState)
0112     {
0113         d->pressPos = e->scenePos();
0114         d->state    = PressedState;
0115         Q_EMIT started(e->scenePos());
0116     }
0117 }
0118 
0119 void ClickDragReleaseItem::mouseMoveEvent(QGraphicsSceneMouseEvent* e)
0120 {
0121     if (d->state == PressedState && d->isDrag(e))
0122     {
0123         d->state = PressDragState;
0124         setCursor(Qt::SizeFDiagCursor);
0125     }
0126 
0127     if (d->state == PressDragState)
0128     {
0129         Q_EMIT moving(d->rect(e));
0130     }
0131 }
0132 
0133 void ClickDragReleaseItem::hoverMoveEvent(QGraphicsSceneHoverEvent* e)
0134 {
0135     if (d->state == ClickedMoveState)
0136     {
0137         Q_EMIT moving(d->rect(e));
0138     }
0139 }
0140 
0141 void ClickDragReleaseItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* e)
0142 {
0143     if      (d->state == PressedState)
0144     {
0145         // click-move-click mode first click.
0146         // It cannot be over the drag threshold in this state, would be caught in moveEvent.
0147 
0148         d->state = ClickedMoveState;
0149         setCursor(Qt::SizeFDiagCursor);
0150         setAcceptHoverEvents(true);
0151     }
0152     else if (d->state == ClickedMoveState)
0153     {
0154         // click-move-click mode second click
0155 
0156         d->state = HoverState;
0157         setCursor(Qt::CrossCursor);
0158         setAcceptHoverEvents(false);
0159         Q_EMIT finished(d->rect(e));
0160     }
0161     else if (d->state == PressDragState)
0162     {
0163         if (d->isDrag(e))
0164         {
0165             Q_EMIT finished(d->rect(e));
0166         }
0167         else
0168         {
0169             Q_EMIT cancelled();
0170         }
0171 
0172         d->state = HoverState;
0173         setCursor(Qt::CrossCursor);
0174         setAcceptHoverEvents(false);
0175     }
0176 }
0177 
0178 void ClickDragReleaseItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* e)
0179 {
0180     e->ignore();
0181 }
0182 
0183 void ClickDragReleaseItem::keyPressEvent(QKeyEvent* e)
0184 {
0185     qCDebug(DIGIKAM_WIDGETS_LOG) << e;
0186 
0187     switch (e->key())
0188     {
0189         case Qt::Key_Backspace:
0190         case Qt::Key_Escape:
0191             Q_EMIT cancelled();
0192             break;
0193 
0194         default:
0195             e->ignore();
0196             break;
0197     }
0198 }
0199 
0200 } // namespace Digikam
0201 
0202 #include "moc_clickdragreleaseitem.cpp"