QGIS API Documentation  3.20.0-Odense (decaadbb31)
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 constrained 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 QgsLayoutItemGuiRegistry * layoutItemGuiRegistry()
Returns the global layout item GUI registry, used for registering the GUI behavior of layout items.
Definition: qgsgui.cpp:116
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.
An abstract layout item that provides generic methods for node based shapes such as polygon or polyli...
static double snappedAngle(double angle)
Snaps an angle (in degrees) to its closest 45 degree angle.
A QgsLayoutViewMouseEvent is the result of a user interaction with the mouse on a QgsLayoutView.
QPointF snappedPoint() const
Returns the snapped event point location in layout coordinates.
void layoutMoveEvent(QgsLayoutViewMouseEvent *event) override
Mouse move event for overriding.
int itemMetadataId() const
Returns the item metadata id for items created by the tool.
void createdItem()
Emitted when an item has been created using the tool.
void layoutReleaseEvent(QgsLayoutViewMouseEvent *event) override
Mouse release event for overriding.
QgsLayoutViewToolAddNodeItem(QgsLayoutView *view)
Constructs a QgsLayoutViewToolAddNodeItem for the given layout view.
void setItemMetadataId(int metadataId)
Sets the item metadata metadataId for items created by the tool.
void keyPressEvent(QKeyEvent *event) override
Key press event for overriding.
void layoutPressEvent(QgsLayoutViewMouseEvent *event) override
Mouse press event for overriding.
void deactivate() override
Called when tool is deactivated.
Abstract base class for all layout view tools.
void setCursor(const QCursor &cursor)
Sets a user defined cursor for use when the tool is active.
QgsLayoutView * view() const
Returns the view associated with the tool.
virtual void deactivate()
Called when tool is deactivated.
void setFlags(QgsLayoutViewTool::Flags flags)
Sets the combination of flags that will be used for the tool.
@ FlagSnaps
Tool utilizes snapped coordinates.
QgsLayout * layout() const
Returns the layout associated with the tool.
A graphical widget to display and interact with QgsLayouts.
Definition: qgslayoutview.h:50
void setSelectedItem(QgsLayoutItem *item)
Clears any selected items and sets item as the current selection.
Definition: qgslayout.cpp:159
void addLayoutItem(QgsLayoutItem *item)
Adds an item to the layout.
Definition: qgslayout.cpp:540
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