File indexing completed on 2024-04-28 15:51:51

0001 /*
0002     SPDX-FileCopyrightText: 2017 Tobias Deiminger <haxtibal@t-online.de>
0003     SPDX-FileCopyrightText: 2004-2005 Enrico Ros <eros.kde@email.it>
0004     SPDX-FileCopyrightText: 2004-2006 Albert Astals Cid <aacid@kde.org>
0005 
0006     Work sponsored by the LiMux project of the city of Munich:
0007     SPDX-FileCopyrightText: 2017 Klarälvdalens Datakonsult AB a KDAB Group company <info@kdab.com>
0008 
0009     With portions of code from kpdf/kpdf_pagewidget.cc by:
0010     SPDX-FileCopyrightText: 2002 Wilco Greven <greven@kde.org>
0011     SPDX-FileCopyrightText: 2003 Christophe Devriese <Christophe.Devriese@student.kuleuven.ac.be>
0012     SPDX-FileCopyrightText: 2003 Laurent Montel <montel@kde.org>
0013     SPDX-FileCopyrightText: 2003 Dirk Mueller <mueller@kde.org>
0014     SPDX-FileCopyrightText: 2004 James Ots <kde@jamesots.com>
0015     SPDX-FileCopyrightText: 2011 Jiri Baum - NICTA <jiri@baum.com.au>
0016 
0017     SPDX-License-Identifier: GPL-2.0-or-later
0018 */
0019 
0020 #ifndef _OKULAR_PAGEVIEWMOUSEANNOTATION_H_
0021 #define _OKULAR_PAGEVIEWMOUSEANNOTATION_H_
0022 
0023 #include <QObject>
0024 
0025 #include "core/annotations.h"
0026 #include "pageviewutils.h"
0027 
0028 class QHelpEvent;
0029 class QPainter;
0030 class QPoint;
0031 class PageView;
0032 class PageViewItem;
0033 class AnnotationDescription;
0034 
0035 namespace Okular
0036 {
0037 class Document;
0038 }
0039 
0040 /* This class shall help to keep data for one annotation consistent. */
0041 class AnnotationDescription
0042 {
0043 public:
0044     AnnotationDescription()
0045         : annotation(nullptr)
0046         , pageViewItem(nullptr)
0047         , pageNumber(-1)
0048     {
0049     }
0050     AnnotationDescription(PageViewItem *newPageViewItem, const QPoint eventPos);
0051     bool isValid() const;
0052     bool isContainedInPage(const Okular::Document *document, int pageNumber) const;
0053     void invalidate();
0054     bool operator==(const AnnotationDescription &rhs) const
0055     {
0056         return (annotation == rhs.annotation);
0057     }
0058     Okular::Annotation *annotation;
0059     PageViewItem *pageViewItem;
0060     int pageNumber;
0061 };
0062 
0063 /**
0064  * @short Handle UI for annotation interactions, like moving, resizing and triggering actions.
0065  *
0066  * An object of this class tracks which annotation is currently under the mouse cursor.
0067  * Some annotation types can be focused in order to move or resize them.
0068  * State is determined from mouse and keyboard events, which are forwarded from the parent PageView object.
0069  * Move and resize actions are dispatched to the Document object.
0070  */
0071 class MouseAnnotation : public QObject
0072 {
0073     Q_OBJECT
0074 
0075 public:
0076     MouseAnnotation(PageView *parent, Okular::Document *document);
0077     ~MouseAnnotation() override;
0078 
0079     /* Process a mouse press event. eventPos: Mouse position in content area coordinates. */
0080     void routeMousePressEvent(PageViewItem *pageViewItem, const QPoint eventPos);
0081 
0082     /* Process a mouse release event. */
0083     void routeMouseReleaseEvent();
0084 
0085     /* Process a mouse move event. eventPos: Mouse position in content area coordinates. */
0086     void routeMouseMoveEvent(PageViewItem *pageViewItem, const QPoint eventPos, bool leftButtonPressed);
0087 
0088     /* Process a key event. */
0089     void routeKeyPressEvent(const QKeyEvent *e);
0090 
0091     /* Process a tooltip event. eventPos: Mouse position in content area coordinates. */
0092     void routeTooltipEvent(const QHelpEvent *helpEvent);
0093 
0094     /* Process a paint event. */
0095     void routePaint(QPainter *painter, const QRect paintRect);
0096 
0097     /* Cancel the current selection or action, if any. */
0098     void cancel();
0099 
0100     /* Reset to initial state. Cancel current action and relinquish references to PageViewItem widgets. */
0101     void reset();
0102 
0103     Okular::Annotation *annotation() const;
0104 
0105     /* Return true, if MouseAnnotation demands control for a mouse click on the current cursor position. */
0106     bool isMouseOver() const;
0107 
0108     bool isActive() const;
0109 
0110     bool isFocused() const;
0111 
0112     bool isMoved() const;
0113 
0114     bool isResized() const;
0115 
0116     bool isModified() const;
0117 
0118     Qt::CursorShape cursor() const;
0119 
0120     /* Forward DocumentObserver::notifyPageChanged to this method. */
0121     void notifyAnnotationChanged(int pageNumber);
0122 
0123     /* Forward DocumentObserver::notifySetup to this method. */
0124     void updateAnnotationPointers();
0125 
0126     enum MouseAnnotationState { StateInactive, StateFocused, StateMoving, StateResizing };
0127 
0128     enum ResizeHandleFlag {
0129         RH_None = 0,
0130         RH_Top = 1,
0131         RH_Right = 2,
0132         RH_Bottom = 4,
0133         RH_Left = 8,
0134         RH_TopLeft = RH_Top | RH_Left,
0135         RH_BottomLeft = RH_Bottom | RH_Left,
0136         RH_TopRight = RH_Top | RH_Right,
0137         RH_BottomRight = RH_Bottom | RH_Right,
0138         RH_Content = 16,
0139         RH_AllHandles = RH_Top | RH_Right | RH_Bottom | RH_Left
0140     };
0141     Q_DECLARE_FLAGS(ResizeHandle, ResizeHandleFlag)
0142 
0143 private:
0144     void setState(MouseAnnotationState state, const AnnotationDescription &ad);
0145     QRect getFullBoundingRect(const AnnotationDescription &ad) const;
0146     void performCommand(const QPoint newPos);
0147     void finishCommand();
0148     void updateViewport(const AnnotationDescription &ad) const;
0149     ResizeHandle getHandleAt(const QPoint eventPos, const AnnotationDescription &ad) const;
0150     QRect getHandleRect(ResizeHandle handle, const AnnotationDescription &ad) const;
0151     static void handleToAdjust(const QPointF dIn, QPointF &dOut1, QPointF &dOut2, MouseAnnotation::ResizeHandle handle, Okular::Rotation rotation);
0152     static QPointF rotateInRect(const QPointF rotated, Okular::Rotation rotation);
0153     static ResizeHandle rotateHandle(ResizeHandle handle, Okular::Rotation rotation);
0154     void processAction(const AnnotationDescription &ad);
0155 
0156     /* We often have to delegate to the document model and our parent widget. */
0157     Okular::Document *m_document;
0158     PageView *m_pageView;
0159 
0160     /* Remember which annotation is currently focused/modified. */
0161     MouseAnnotationState m_state;
0162     MouseAnnotation::ResizeHandle m_handle;
0163     AnnotationDescription m_focusedAnnotation;
0164 
0165     /* Mouse tracking, always kept up to date with the latest mouse position and annotation under mouse cursor. */
0166     AnnotationDescription m_mouseOverAnnotation;
0167     QPoint m_mousePosition; // in page view item coordinates
0168 
0169     QList<ResizeHandle> m_resizeHandleList;
0170 };
0171 
0172 #endif