QGIS API Documentation 3.27.0-Master (f261cc1f8b)
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"
22#include "qgslogger.h"
24#include "qgsgui.h"
27#include "qgssettings.h"
28#include "qgslayoututils.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
154void QgsLayoutViewToolAddNodeItem::addNode( QPointF scenePoint )
155{
156 mPolygon.append( scenePoint );
157
158 if ( mPolygon.size() == 1 )
159 mPolygon.append( scenePoint );
160
161 setRubberBandNodes();
162}
163
164void 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 const QPointF start = mPolygon.at( mPolygon.size() - 2 );
172 QLineF newLine = QLineF( start, scenePoint );
173
174 //movement is constrained to 45 degree angles
175 const 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
184void 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:130
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