QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
qgslayoutviewtooladdnodeitem.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslayoutviewtooladdnodeitem.cpp
3  ----------------------------
4  Date : July 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 
17 #include "qgsapplication.h"
18 #include "qgslayoutview.h"
19 #include "qgslayout.h"
20 #include "qgslayoutitemregistry.h"
22 #include "qgslogger.h"
24 #include "qgsgui.h"
27 #include "qgssettings.h"
28 #include "qgslayoututils.h"
29 #include "qgslayoutitemnodeitem.h"
30 #include <QGraphicsRectItem>
31 #include <QPen>
32 #include <QBrush>
33 #include <QMouseEvent>
34 
36  : QgsLayoutViewTool( view, tr( "Add item" ) )
37 {
39  setCursor( Qt::CrossCursor );
40 }
41 
43 {
44  mItemMetadataId = metadataId;
45 }
46 
48 {
49  if ( event->button() == Qt::LeftButton )
50  {
51  if ( !mRubberBand )
52  {
53  mPolygon.clear();
54  mRubberBand.reset( QgsGui::layoutItemGuiRegistry()->createNodeItemRubberBand( mItemMetadataId, view() ) );
55  if ( mRubberBand )
56  layout()->addItem( mRubberBand.get() );
57  }
58 
59  if ( mRubberBand )
60  {
61  //add a new node
62  addNode( event->snappedPoint() );
63  }
64  }
65  else if ( event->button() == Qt::RightButton && mRubberBand )
66  {
67  // finish up
68 
69  // last (temporary) point is removed
70  mPolygon.remove( mPolygon.count() - 1 );
71 
72  QgsLayoutItem *item = QgsGui::layoutItemGuiRegistry()->createItem( mItemMetadataId, layout() );
73  if ( !item )
74  return;
75 
76  if ( QgsLayoutNodesItem *nodesItem = qobject_cast< QgsLayoutNodesItem * >( item ) )
77  nodesItem->setNodes( mPolygon );
78 
79  layout()->addLayoutItem( item );
80  layout()->setSelectedItem( item );
81  emit createdItem();
82  }
83  else
84  {
85  event->ignore();
86  mRubberBand.reset();
87  }
88 
89 }
90 
92 {
93  if ( mRubberBand )
94  {
95  moveTemporaryNode( event->snappedPoint(), event->modifiers() );
96  }
97  else
98  {
99  event->ignore();
100  }
101 }
102 
104 {
105  if ( !mRubberBand )
106  {
107  event->ignore();
108  return;
109  }
110 }
111 
113 {
114  if ( !mRubberBand || event->isAutoRepeat() )
115  {
116  event->ignore();
117  return;
118  }
119 
120  if ( event->key() == Qt::Key_Delete || event->key() == Qt::Key_Backspace )
121  {
122  if ( mPolygon.size() > 2 )
123  {
124  //remove last added vertex
125  mPolygon.pop_back();
126  setRubberBandNodes();
127  }
128  else
129  {
130  // all deleted, cancel
131  mRubberBand.reset();
132  }
133  }
134  else if ( event->key() == Qt::Key_Escape )
135  {
136  mRubberBand.reset();
137  }
138  else
139  {
140  event->ignore();
141  }
142 }
143 
145 {
146  if ( mRubberBand )
147  {
148  // canceled mid operation
149  mRubberBand.reset();
150  }
152 }
153 
154 void QgsLayoutViewToolAddNodeItem::addNode( QPointF scenePoint )
155 {
156  mPolygon.append( scenePoint );
157 
158  if ( mPolygon.size() == 1 )
159  mPolygon.append( scenePoint );
160 
161  setRubberBandNodes();
162 }
163 
164 void QgsLayoutViewToolAddNodeItem::moveTemporaryNode( QPointF scenePoint, Qt::KeyboardModifiers modifiers )
165 {
166  if ( mPolygon.isEmpty() )
167  return;
168 
169  if ( mPolygon.size() > 1 && ( modifiers & Qt::ShiftModifier ) )
170  {
171  QPointF start = mPolygon.at( mPolygon.size() - 2 );
172  QLineF newLine = QLineF( start, scenePoint );
173 
174  //movement is contrained to 45 degree angles
175  double angle = QgsLayoutUtils::snappedAngle( newLine.angle() );
176  newLine.setAngle( angle );
177  scenePoint = newLine.p2();
178  }
179 
180  mPolygon.replace( mPolygon.size() - 1, scenePoint );
181  setRubberBandNodes();
182 }
183 
184 void QgsLayoutViewToolAddNodeItem::setRubberBandNodes()
185 {
186  if ( QGraphicsPolygonItem *polygonItem = dynamic_cast< QGraphicsPolygonItem *>( mRubberBand.get() ) )
187  {
188  polygonItem->setPolygon( mPolygon );
189  }
190  else if ( QGraphicsPathItem *polylineItem = dynamic_cast< QGraphicsPathItem *>( mRubberBand.get() ) )
191  {
192  // rebuild a new qpainter path
193  QPainterPath path;
194  path.addPolygon( mPolygon );
195  polylineItem->setPath( path );
196  }
197 }
198 
200 {
201  return mItemMetadataId;
202 }
static double snappedAngle(double angle)
Snaps an angle (in degrees) to its closest 45 degree angle.
void setCursor(const QCursor &cursor)
Sets a user defined cursor for use when the tool is active.
void setFlags(QgsLayoutViewTool::Flags flags)
Sets the combination of flags that will be used for the tool.
void setSelectedItem(QgsLayoutItem *item)
Clears any selected items and sets item as the current selection.
Definition: qgslayout.cpp:158
QgsLayoutViewToolAddNodeItem(QgsLayoutView *view)
Constructs a QgsLayoutViewToolAddNodeItem for the given layout view.
void layoutMoveEvent(QgsLayoutViewMouseEvent *event) override
Mouse move event for overriding.
QgsLayoutItem * createItem(int metadataId, QgsLayout *layout) const
Creates a new instance of a layout item given the item metadata metadataId, target layout...
Base class for graphical items within a QgsLayout.
A graphical widget to display and interact with QgsLayouts.
Definition: qgslayoutview.h:49
virtual void deactivate()
Called when tool is deactivated.
void createdItem()
Emitted when an item has been created using the tool.
An abstract layout item that provides generic methods for node based shapes such as polygon or polyli...
int itemMetadataId() const
Returns the item metadata id for items created by the tool.
void deactivate() override
Called when tool is deactivated.
void setItemMetadataId(int metadataId)
Sets the item metadata metadataId for items created by the tool.
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
Definition: MathUtils.cpp:786
QgsLayoutView * view() const
Returns the view associated with the tool.
static QgsLayoutItemGuiRegistry * layoutItemGuiRegistry()
Returns the global layout item GUI registry, used for registering the GUI behavior of layout items...
Definition: qgsgui.cpp:97
QgsLayout * layout() const
Returns the layout associated with the tool.
A QgsLayoutViewMouseEvent is the result of a user interaction with the mouse on a QgsLayoutView...
void keyPressEvent(QKeyEvent *event) override
Key press event for overriding.
void addLayoutItem(QgsLayoutItem *item)
Adds an item to the layout.
Definition: qgslayout.cpp:539
Abstract base class for all layout view tools.
QPointF snappedPoint() const
Returns the snapped event point location in layout coordinates.
void layoutPressEvent(QgsLayoutViewMouseEvent *event) override
Mouse press event for overriding.
void layoutReleaseEvent(QgsLayoutViewMouseEvent *event) override
Mouse release event for overriding.
Tool utilizes snapped coordinates.