Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
|
|
|
/***************************************************************************
|
|
|
|
* Copyright (C) 2017 by Tobias Deiminger <haxtibal@t-online.de> *
|
|
|
|
* Copyright (C) 2004-2005 by Enrico Ros <eros.kde@email.it> *
|
|
|
|
* Copyright (C) 2004-2006 by Albert Astals Cid <aacid@kde.org> *
|
|
|
|
* *
|
|
|
|
* With portions of code from kpdf/kpdf_pagewidget.cc by: *
|
|
|
|
* Copyright (C) 2002 by Wilco Greven <greven@kde.org> *
|
|
|
|
* Copyright (C) 2003 by Christophe Devriese *
|
|
|
|
* <Christophe.Devriese@student.kuleuven.ac.be> *
|
|
|
|
* Copyright (C) 2003 by Laurent Montel <montel@kde.org> *
|
|
|
|
* Copyright (C) 2003 by Dirk Mueller <mueller@kde.org> *
|
|
|
|
* Copyright (C) 2004 by James Ots <kde@jamesots.com> *
|
|
|
|
* Copyright (C) 2011 by Jiri Baum - NICTA <jiri@baum.com.au> *
|
|
|
|
* *
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
|
|
* (at your option) any later version. *
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#ifndef _OKULAR_PAGEVIEWMOUSEANNOTATION_H_
|
|
|
|
#define _OKULAR_PAGEVIEWMOUSEANNOTATION_H_
|
|
|
|
|
|
|
|
#include <qobject.h>
|
|
|
|
|
|
|
|
#include "pageviewutils.h"
|
|
|
|
#include "core/annotations.h"
|
|
|
|
|
|
|
|
class QHelpEvent;
|
|
|
|
class QPainter;
|
|
|
|
class QPoint;
|
|
|
|
class PageView;
|
|
|
|
class PageViewItem;
|
|
|
|
class AnnotationDescription;
|
|
|
|
|
|
|
|
namespace Okular
|
|
|
|
{
|
|
|
|
class Document;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This class shall help to keep data for one annotation consistent. */
|
|
|
|
class AnnotationDescription
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
AnnotationDescription()
|
|
|
|
: annotation( 0 ), pageViewItem( 0 ), pageNumber( 0 ) {}
|
|
|
|
AnnotationDescription( PageViewItem * newPageViewItem, const QPoint& eventPos );
|
|
|
|
bool isValid() const;
|
|
|
|
void invalidate();
|
|
|
|
bool operator==( const AnnotationDescription & rhs ) const
|
|
|
|
{
|
|
|
|
return ( annotation == rhs.annotation );
|
|
|
|
}
|
|
|
|
Okular::Annotation * annotation;
|
|
|
|
PageViewItem * pageViewItem;
|
|
|
|
int pageNumber;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @short Handle UI for annotation interactions, like moving, resizing and triggering actions.
|
|
|
|
*
|
|
|
|
* An object of this class tracks which annotation is currently under the mouse cursor.
|
|
|
|
* Some annotation types can be focused in order to move or resize them.
|
|
|
|
* State is determined from mouse and keyboard events, which are forwarded from the parent PageView object.
|
|
|
|
* Move and resize actions are dispatched to the Document object.
|
|
|
|
*/
|
|
|
|
class MouseAnnotation : public QObject
|
|
|
|
{
|
|
|
|
Q_OBJECT
|
|
|
|
|
|
|
|
public:
|
|
|
|
MouseAnnotation( PageView * parent, Okular::Document * document );
|
|
|
|
~MouseAnnotation();
|
|
|
|
|
|
|
|
/* Process a mouse press event. eventPos: Mouse position in content area coordinates. */
|
|
|
|
void routeMousePressEvent( PageViewItem * pageViewItem, const QPoint & eventPos );
|
|
|
|
|
|
|
|
/* Process a mouse release event. */
|
|
|
|
void routeMouseReleaseEvent();
|
|
|
|
|
|
|
|
/* Process a mouse move event. eventPos: Mouse position in content area coordinates. */
|
|
|
|
void routeMouseMoveEvent( PageViewItem * pageViewItem, const QPoint & eventPos, bool leftButtonPressed );
|
|
|
|
|
|
|
|
/* Process a key event. */
|
|
|
|
void routeKeyPressEvent( const QKeyEvent * e );
|
|
|
|
|
|
|
|
/* Process a tooltip event. eventPos: Mouse position in content area coordinates. */
|
|
|
|
void routeTooltipEvent( const QHelpEvent * helpEvent );
|
|
|
|
|
|
|
|
/* Process a paint event. */
|
|
|
|
void routePaint( QPainter * painter, const QRect & paintRect );
|
|
|
|
|
|
|
|
/* Cancel the current selection or action, if any. */
|
|
|
|
void cancel();
|
|
|
|
|
2017-04-13 17:17:56 +00:00
|
|
|
/* Reset to initial state. Cancel current action and relinquish references to PageViewItem widgets. */
|
|
|
|
void reset();
|
|
|
|
|
Add annotation resize functionality
Usage:
If you left-click an annotation, it gets selected. Resize handles appear on the selection rectangle. When cursor is moved over one of the 8 resize handles on the corners/edges, the cursor shape changes to indicate resize mode. Everywhere else on the annotation means "move", just as it was before resize feature was added. Pressing ESC or clicking an area outside the annotation cancels a selection. Pressing Del deletes a selected annotation.
Feature is only applicable for annotation types AText, AStamp and AGeom.
Implementation:
It works by eventually changing AnnotationPrivate::m_boundary and notifying generator (i.e. poppler) about that change. Annotation state handling is shifted out of PageView into a new class MouseAnnotation (ui/pageviewmouseannotation.cpp). Some functionality not related to resizing but to annotation interaction in general is also shifted to class MouseAnnotation, to build a single place of responsiblity.
Other changes:
Add method Document::adjustPageAnnotation, backed by a QUndoCommand.
class Okular::AdjustAnnotationCommand.
Add Annotation::adjust and Annotation::canBeResized methods.
Draw resize handles in PagePainter::paintCroppedPageOnPainter.
Resize and move work
-for types AText, AStamp and AGeom
-on all pages of document
-when viewport position changes
-when zoom level changes
-for all page rotations (0°, 90°, 180°, 270°)
Selection is canceled
-when currently selected annotation is deleted
-on mouse click outside of currently selected annotation
-ESC is pressed
Viewport is shifted when mouse cursor during move/resize comes close to viewport border.
Resize to negative is prevented.
Tiny annotations are still selectable.
If mouse is moved over an annotation type that we can focus, and the annotation is not yet focused, mouse cursor shape changes to arrow.
If mouse cursor rests over an annotation A, while annotation B is focused, a tooltip for annotation A is shown.
Selected Annotation is deleted when Del is pressed.
Test for regressions:
-Annotation interaction (focus, move, resize, start playback, ...) are only done in mode EnumMouseMode::Browse.
-If mouse is moved over an annotation type where we can start an action, mouse cursor shape changes to pointing hand.
-If mouse is moved over an annotation type that we can't interact with, mouse cursor shape stays a open hand.
-If mouse cursor rests over an annotation of any type, a tooltip for that annotation is shown.
-Grab/move scroll area (on left click + mouse move) is prevented, if mouse is over focused annotation, or over AMovie/AScreen/AFileAttachment annotation.
-A double click on a annotation starts the "annotator".
REVIEW: 127366
BUG: 177778
BUG: 314843
BUG: 358060
2017-03-19 22:16:06 +00:00
|
|
|
Okular::Annotation * annotation() const;
|
|
|
|
|
|
|
|
/* Return true, if MouseAnnotation demands control for a mouse click on the current cursor position. */
|
|
|
|
bool isMouseOver() const;
|
|
|
|
|
|
|
|
bool isActive() const;
|
|
|
|
|
|
|
|
bool isFocused() const;
|
|
|
|
|
|
|
|
bool isMoved() const;
|
|
|
|
|
|
|
|
bool isResized() const;
|
|
|
|
|
|
|
|
bool isModified() const;
|
|
|
|
|
|
|
|
Qt::CursorShape cursor() const;
|
|
|
|
|
|
|
|
enum MouseAnnotationState {
|
|
|
|
StateInactive,
|
|
|
|
StateFocused,
|
|
|
|
StateMoving,
|
|
|
|
StateResizing
|
|
|
|
};
|
|
|
|
|
|
|
|
enum ResizeHandleFlag {
|
|
|
|
RH_None = 0,
|
|
|
|
RH_Top = 1,
|
|
|
|
RH_Right = 2,
|
|
|
|
RH_Bottom = 4,
|
|
|
|
RH_Left = 8,
|
|
|
|
RH_TopLeft = RH_Top | RH_Left,
|
|
|
|
RH_BottomLeft = RH_Bottom | RH_Left,
|
|
|
|
RH_TopRight = RH_Top | RH_Right,
|
|
|
|
RH_BottomRight = RH_Bottom | RH_Right,
|
|
|
|
RH_Content = 16,
|
|
|
|
RH_AllHandles = RH_Top | RH_Right | RH_Bottom | RH_Left
|
|
|
|
};
|
|
|
|
Q_DECLARE_FLAGS( ResizeHandle, ResizeHandleFlag )
|
|
|
|
|
|
|
|
private:
|
|
|
|
void setState( MouseAnnotationState state, const AnnotationDescription & ad );
|
|
|
|
QRect getFullBoundingRect( const AnnotationDescription & ad ) const;
|
|
|
|
void performCommand( const QPoint & newPos );
|
|
|
|
void finishCommand();
|
|
|
|
void updateViewport( const AnnotationDescription & ad ) const;
|
|
|
|
ResizeHandle getHandleAt( const QPoint & eventPos, const AnnotationDescription & ad ) const;
|
|
|
|
QRect getHandleRect( ResizeHandle handle, const AnnotationDescription & ad ) const;
|
|
|
|
static void handleToAdjust( const QPointF & dIn, QPointF & dOut1, QPointF & dOut2, MouseAnnotation::ResizeHandle handle, Okular::Rotation rotation );
|
|
|
|
static QPointF rotateInRect( const QPointF & rotated, Okular::Rotation rotation );
|
|
|
|
static ResizeHandle rotateHandle( ResizeHandle handle, Okular::Rotation rotation );
|
|
|
|
void processAction( const AnnotationDescription& ad );
|
|
|
|
|
|
|
|
/* We often have to delegate to the document model and our parent widget. */
|
|
|
|
Okular::Document * m_document;
|
|
|
|
PageView * m_pageView;
|
|
|
|
|
|
|
|
/* Remember which annotation is currently focused/modified. */
|
|
|
|
MouseAnnotationState m_state;
|
|
|
|
MouseAnnotation::ResizeHandle m_handle;
|
|
|
|
AnnotationDescription m_focusedAnnotation;
|
|
|
|
|
|
|
|
/* Mouse tracking, always kept up to date with the latest mouse position and annotation under mouse cursor. */
|
|
|
|
AnnotationDescription m_mouseOverAnnotation;
|
|
|
|
QPoint m_mousePosition; // in page view item coordinates
|
|
|
|
|
|
|
|
QList<ResizeHandle> m_resizeHandleList;
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|