1 /***************************************************************************
2                              qgslayoutviewtoolmoveitemcontent.cpp
3                              ------------------------------------
4     Date                 : October 2017
5     Copyright            : (C) 2017 Nyall Dawson
6     Email                : nyall dot dawson at gmail dot com
7  ***************************************************************************
8  *                                                                         *
9  *   This program is free software; you can redistribute it and/or modify  *
10  *   it under the terms of the GNU General Public License as published by  *
11  *   the Free Software Foundation; either version 2 of the License, or     *
12  *   (at your option) any later version.                                   *
13  *                                                                         *
14  ***************************************************************************/
15 
16 #include "qgslayoutviewtoolmoveitemcontent.h"
17 #include "qgslayoutviewmouseevent.h"
18 #include "qgslayoutview.h"
19 #include "qgslayout.h"
20 #include "qgslayoutitemnodeitem.h"
21 #include "qgssettings.h"
22 #include "qgslayoutundostack.h"
23 
QgsLayoutViewToolMoveItemContent(QgsLayoutView * view)24 QgsLayoutViewToolMoveItemContent::QgsLayoutViewToolMoveItemContent( QgsLayoutView *view )
25   : QgsLayoutViewTool( view, tr( "Select" ) )
26 {
27   setCursor( Qt::ArrowCursor );
28 }
29 
layoutPressEvent(QgsLayoutViewMouseEvent * event)30 void QgsLayoutViewToolMoveItemContent::layoutPressEvent( QgsLayoutViewMouseEvent *event )
31 {
32   if ( event->button() != Qt::LeftButton )
33   {
34     event->ignore();
35     return;
36   }
37 
38   const QList<QGraphicsItem *> itemsAtCursorPos = view()->items( event->pos() );
39   if ( itemsAtCursorPos.isEmpty() )
40     return;
41 
42   //find highest non-locked QgsLayoutItem at clicked position
43   //(other graphics items may be higher, e.g., selection handles)
44   for ( QGraphicsItem *graphicsItem : itemsAtCursorPos )
45   {
46     QgsLayoutItem *item = dynamic_cast<QgsLayoutItem *>( graphicsItem );
47     if ( item && !item->isLocked() )
48     {
49       //we've found the highest QgsLayoutItem
50       mMoveContentStartPos = event->layoutPoint();
51       mMoveContentItem = item;
52       mMovingItemContent = true;
53       break;
54     }
55   }
56 }
57 
layoutMoveEvent(QgsLayoutViewMouseEvent * event)58 void QgsLayoutViewToolMoveItemContent::layoutMoveEvent( QgsLayoutViewMouseEvent *event )
59 {
60   if ( !mMovingItemContent || !mMoveContentItem )
61   {
62     event->ignore();
63     return;
64   }
65 
66   //update item preview
67   mMoveContentItem->setMoveContentPreviewOffset( event->layoutPoint().x() - mMoveContentStartPos.x(),
68       event->layoutPoint().y() - mMoveContentStartPos.y() );
69   mMoveContentItem->update();
70 }
71 
layoutReleaseEvent(QgsLayoutViewMouseEvent * event)72 void QgsLayoutViewToolMoveItemContent::layoutReleaseEvent( QgsLayoutViewMouseEvent *event )
73 {
74   if ( event->button() != Qt::LeftButton || !mMovingItemContent || !mMoveContentItem )
75   {
76     event->ignore();
77     return;
78   }
79 
80   //update item preview
81   mMoveContentItem->setMoveContentPreviewOffset( 0, 0 );
82 
83   const double moveX = event->layoutPoint().x() - mMoveContentStartPos.x();
84   const double moveY = event->layoutPoint().y() - mMoveContentStartPos.y();
85 
86   mMoveContentItem->layout()->undoStack()->beginCommand( mMoveContentItem, tr( "Move Item Content" ) );
87   mMoveContentItem->moveContent( -moveX, -moveY );
88   mMoveContentItem->layout()->undoStack()->endCommand();
89   mMoveContentItem = nullptr;
90   mMovingItemContent = false;
91 }
92 
wheelEvent(QWheelEvent * event)93 void QgsLayoutViewToolMoveItemContent::wheelEvent( QWheelEvent *event )
94 {
95   event->accept();
96 
97 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 2)
98   QPointF scenePoint = view()->mapToScene( event->pos().x(), event->pos().y() );
99 #else
100   const QPointF scenePoint = view()->mapToScene( event->position().x(), event->position().y() );
101 #endif
102 
103   //select topmost item at position of event
104   QgsLayoutItem *item = layout()->layoutItemAt( scenePoint, true );
105   if ( !item || !item->isSelected() )
106     return;
107 
108   const QgsSettings settings;
109   double zoomFactor = settings.value( QStringLiteral( "qgis/zoom_factor" ), 2.0 ).toDouble();
110 
111   // "Normal" mouse have an angle delta of 120, precision mouses provide data faster, in smaller steps
112   zoomFactor = 1.0 + ( zoomFactor - 1.0 ) / 120.0 * std::fabs( event->angleDelta().y() );
113 
114   if ( event->modifiers() & Qt::ControlModifier )
115   {
116     //holding ctrl while wheel zooming results in a finer zoom
117     zoomFactor = 1.0 + ( zoomFactor - 1.0 ) / 20.0;
118   }
119 
120   //calculate zoom scale factor
121   const bool zoomIn = event->angleDelta().y() > 0;
122   const double scaleFactor = ( zoomIn ? zoomFactor : 1 / zoomFactor );
123 
124   const QPointF itemPoint = item->mapFromScene( scenePoint );
125   item->layout()->undoStack()->beginCommand( item, tr( "Zoom Item Content" ), QgsLayoutItem::UndoZoomContent );
126   item->zoomContent( scaleFactor, itemPoint );
127   item->layout()->undoStack()->endCommand();
128 }
129