QGIS API Documentation 3.99.0-Master (a8882ad4560)
Loading...
Searching...
No Matches
qgsmaptoolselectannotation.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsmaptoolselectannotation.cpp
3 ----------------
4 copyright : (C) 2025 by Mathieu Pellerin
5 email : mathieu at opengis dot ch
6 ***************************************************************************/
7
8/***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 ***************************************************************************/
16
18
19#include "qgsannotationitem.h"
22#include "qgsannotationlayer.h"
23#include "qgsapplication.h"
24#include "qgsmapcanvas.h"
26#include "qgsproject.h"
30#include "qgsrubberband.h"
31#include "qgssnapindicator.h"
32
33#include <QGraphicsSceneHoverEvent>
34#include <QScreen>
35#include <QTransform>
36#include <QWindow>
37
38#include "moc_qgsmaptoolselectannotation.cpp"
39
41 : QgsRubberBand( canvas, Qgis::GeometryType::Line )
42 , mLayerId( layerId )
43 , mItemId( itemId )
44{
45 setFlags( flags() | QGraphicsItem::ItemIsSelectable );
46
47 setWidth( canvas->fontMetrics().xHeight() * .2 );
48 setSecondaryStrokeColor( QColor( 255, 255, 255, 100 ) );
49 setColor( QColor( 50, 50, 50, 200 ) );
50 setZValue( 10 );
51}
52
54{
55 QgsAnnotationLayer *lyr = qobject_cast<QgsAnnotationLayer *>( QgsProject::instance()->mapLayer( mLayerId ) );
56 if ( !lyr && mLayerId == QgsProject::instance()->mainAnnotationLayer()->id() )
57 {
59 }
60 return lyr;
61}
62
64{
66 return lyr ? lyr->item( mItemId ) : nullptr;
67}
68
70{
71 mBoundingBox = boundingBox;
72 QgsAnnotationItem *annotationItem = item();
73 mNeedsUpdatedBoundingBox = annotationItem && ( annotationItem->flags() & Qgis::AnnotationItemFlag::ScaleDependentBoundingBox );
74
76 addPoint( QgsPointXY( boundingBox.xMinimum(), boundingBox.yMinimum() ) );
77 addPoint( QgsPointXY( boundingBox.xMaximum(), boundingBox.yMinimum() ) );
78 addPoint( QgsPointXY( boundingBox.xMaximum(), boundingBox.yMaximum() ) );
79 addPoint( QgsPointXY( boundingBox.xMinimum(), boundingBox.yMaximum() ) );
80 addPoint( QgsPointXY( boundingBox.xMinimum(), boundingBox.yMinimum() ) );
81
82 show();
83 setSelected( true );
84}
85
90
91
99
101{
102 mSelectionRubberBand.reset();
103 mMouseHandles.reset();
104}
105
107{
108 mMouseHandles.reset( new QgsMapToolSelectAnnotationMouseHandles( this, mCanvas ) );
109
111}
112
114{
115 mSelectionRubberBand.reset();
116 mMouseHandles.reset();
117
118 mSelectedItems.clear();
119
120 mCopiedItems.clear();
121 mCopiedItemsTopLeft = QPointF();
122
124}
125
127{
128 const QPointF scenePos = mCanvas->mapToScene( event->pos() );
129
130 if ( event->buttons() == Qt::NoButton )
131 {
132 if ( mMouseHandles->sceneBoundingRect().contains( scenePos ) )
133 {
134 QGraphicsSceneHoverEvent forwardedEvent( QEvent::GraphicsSceneHoverMove );
135 forwardedEvent.setPos( mMouseHandles->mapFromScene( scenePos ) );
136 forwardedEvent.setScenePos( scenePos );
137 mMouseHandles->hoverMoveEvent( &forwardedEvent );
138 mHoveringMouseHandles = true;
139 }
140 else if ( mHoveringMouseHandles )
141 {
142 QGraphicsSceneHoverEvent forwardedEvent( QEvent::GraphicsSceneHoverLeave );
143 forwardedEvent.setPos( mMouseHandles->mapFromScene( scenePos ) );
144 forwardedEvent.setScenePos( scenePos );
145 mMouseHandles->hoverMoveEvent( &forwardedEvent );
146 mHoveringMouseHandles = false;
147 }
148 }
149 else if ( event->buttons() == Qt::LeftButton )
150 {
151 if ( mMouseHandles->shouldBlockEvent( event ) )
152 {
153 QGraphicsSceneMouseEvent forwardedEvent( QEvent::GraphicsSceneMouseMove );
154 forwardedEvent.setPos( mMouseHandles->mapFromScene( scenePos ) );
155 forwardedEvent.setScenePos( scenePos );
156 forwardedEvent.setLastScenePos( mLastScenePos );
157 forwardedEvent.setButton( Qt::LeftButton );
158 mMouseHandles->mouseMoveEvent( &forwardedEvent );
159 }
160 else
161 {
162 if ( !mDragging )
163 {
164 mDragging = true;
165 mSelectionRubberBand.reset( new QgsRubberBand( mCanvas, Qgis::GeometryType::Polygon ) );
166 QColor color( Qt::blue );
167 color.setAlpha( 63 );
168 mSelectionRubberBand->setColor( color );
169 mSelectionRect.setTopLeft( event->pos() );
170 }
171
172 mSelectionRect.setBottomRight( event->pos() );
173 if ( mSelectionRubberBand )
174 {
175 mSelectionRubberBand->setToCanvasRectangle( mSelectionRect );
176 mSelectionRubberBand->show();
177 }
178 }
179 }
180
181 mLastScenePos = scenePos;
182}
183
185{
186 if ( event->button() != Qt::LeftButton )
187 {
188 return;
189 }
190
191 QPointF scenePos = mCanvas->mapToScene( event->pos() );
192 const bool toggleSelection = event->modifiers() & Qt::ShiftModifier;
193
194 if ( !toggleSelection && !mSelectedItems.empty() && mMouseHandles->sceneBoundingRect().contains( scenePos ) )
195 {
196 QGraphicsSceneMouseEvent forwardedEvent( QEvent::GraphicsSceneMousePress );
197 forwardedEvent.setPos( mMouseHandles->mapFromScene( scenePos ) );
198 forwardedEvent.setScenePos( scenePos );
199 forwardedEvent.setLastScenePos( mLastScenePos );
200 forwardedEvent.setButton( Qt::LeftButton );
201 mMouseHandles->mousePressEvent( &forwardedEvent );
202 }
203 else
204 {
205 mSelectionRect.setTopLeft( event->pos() );
206 mSelectionRect.setBottomRight( event->pos() );
207 }
208
209 mLastScenePos = scenePos;
210}
211
213{
214 if ( event->button() != Qt::LeftButton )
215 {
216 return;
217 }
218
219 QPointF scenePos = mCanvas->mapToScene( event->pos() );
220
221 if ( mMouseHandles->shouldBlockEvent( event ) )
222 {
223 QGraphicsSceneMouseEvent forwardedEvent( QEvent::GraphicsSceneMouseRelease );
224 forwardedEvent.setPos( mMouseHandles->mapFromScene( scenePos ) );
225 forwardedEvent.setScenePos( scenePos );
226 forwardedEvent.setLastScenePos( mLastScenePos );
227 forwardedEvent.setButton( Qt::LeftButton );
228 mMouseHandles->mouseReleaseEvent( &forwardedEvent );
229 }
230 else
231 {
232 if ( mCanceled )
233 {
234 mCanceled = false;
235 mDragging = false;
236 return;
237 }
238
239 if ( mDragging )
240 {
241 mDragging = false;
242 mSelectionRubberBand.reset();
243
244 const QgsPointXY topLeft = toMapCoordinates( mSelectionRect.topLeft() );
245 const QgsPointXY bottomRight = toMapCoordinates( mSelectionRect.bottomRight() );
246 const QgsRectangle searchRect( topLeft, bottomRight );
247
248 setSelectedItemsFromRect( searchRect, ( event->modifiers() & Qt::ShiftModifier ) );
249 }
250 else
251 {
252 setSelectedItemFromPoint( event->mapPoint(), ( event->modifiers() & Qt::ShiftModifier ) );
253 }
254
255 mMouseHandles->setSelected( !mSelectedItems.empty() );
256 }
257}
258
260{
261 if ( mMouseHandles->isDragging() || mMouseHandles->isResizing() || mMouseHandles->isRotating() )
262 {
263 return;
264 }
265
266 if ( mSelectedItems.empty() )
267 {
268 return;
269 }
270
271 if ( event->key() == Qt::Key_C || event->key() == Qt::Key_X )
272 {
273 mCopiedItems.clear();
274 mCopiedItemsTopLeft = toMapCoordinates( QPoint( mMouseHandles->sceneBoundingRect().topLeft().x(), mMouseHandles->sceneBoundingRect().topLeft().y() ) );
275 for ( std::unique_ptr<QgsAnnotationItemRubberBand> &selectedItem : mSelectedItems )
276 {
277 mCopiedItems << qMakePair( selectedItem->layerId(), selectedItem->itemId() );
278 }
279 if ( event->key() == Qt::Key_C )
280 {
281 event->ignore();
282 return;
283 }
284 }
285 else if ( event->key() == Qt::Key_V )
286 {
287 const QgsPointXY copiedItemsSceneTopLeft = mCanvas->mapSettings().mapToPixel().transform( mCopiedItemsTopLeft );
288 const double deltaX = mLastScenePos.x() - copiedItemsSceneTopLeft.x();
289 const double deltaY = mLastScenePos.y() - copiedItemsSceneTopLeft.y();
290 if ( !mSelectedItems.empty() )
291 {
292 mSelectedItems.clear();
293 }
294
295 for ( const QPair<QString, QString> &copiedItem : mCopiedItems )
296 {
297 if ( QgsAnnotationItem *annotationItem = annotationItemFromId( copiedItem.first, copiedItem.second ) )
298 {
299 QgsAnnotationLayer *annotationLayer = dynamic_cast<QgsAnnotationLayer *>( layer() );
300 if ( !annotationLayer )
301 {
302 annotationLayer = QgsProject::instance()->mainAnnotationLayer();
303 }
304 QString pastedItemId = annotationLayer->addItem( annotationItem->clone() );
305
306 mSelectedItems.push_back( std::make_unique<QgsAnnotationItemRubberBand>( annotationLayer->id(), pastedItemId, mCanvas ) );
307 attemptMoveBy( mSelectedItems.back().get(), deltaX, deltaY );
308 }
309 }
311 updateSelectedItem();
312 event->ignore();
313 return;
314 }
315
316 if ( event->key() == Qt::Key_Backspace || event->key() == Qt::Key_Delete || event->key() == Qt::Key_X )
317 {
318 while ( !mSelectedItems.empty() )
319 {
320 if ( QgsAnnotationLayer *annotationLayer = mSelectedItems.back()->layer() )
321 {
322 annotationLayer->removeItem( mSelectedItems.back()->itemId() );
323 }
324 mSelectedItems.pop_back();
325 }
327 updateSelectedItem();
328 event->ignore();
329 }
330 else if ( event->key() == Qt::Key_Left
331 || event->key() == Qt::Key_Right
332 || event->key() == Qt::Key_Up
333 || event->key() == Qt::Key_Down )
334 {
335 const int pixels = ( event->modifiers() & Qt::ShiftModifier ) ? 1 : 50;
336 int deltaX = 0;
337 int deltaY = 0;
338 if ( event->key() == Qt::Key_Up )
339 {
340 deltaY = -pixels;
341 }
342 else if ( event->key() == Qt::Key_Down )
343 {
344 deltaY = pixels;
345 }
346 else if ( event->key() == Qt::Key_Left )
347 {
348 deltaX = -pixels;
349 }
350 else if ( event->key() == Qt::Key_Right )
351 {
352 deltaX = pixels;
353 }
354
355 for ( std::unique_ptr<QgsAnnotationItemRubberBand> &selectedItem : mSelectedItems )
356 {
357 attemptMoveBy( selectedItem.get(), deltaX, deltaY );
358 }
359 event->ignore();
360 }
361}
362
363QList<QgsAnnotationItemRubberBand *> QgsMapToolSelectAnnotation::selectedItems() const
364{
365 QList<QgsAnnotationItemRubberBand *> items;
366 for ( const std::unique_ptr<QgsAnnotationItemRubberBand> &selectedItem : mSelectedItems )
367 {
368 items << selectedItem.get();
369 }
370 return items;
371}
372
373void QgsMapToolSelectAnnotation::onCanvasRefreshed()
374{
375 const QgsRenderedItemResults *renderedItemResults = canvas()->renderedItemResults( false );
376 if ( !renderedItemResults )
377 {
378 return;
379 }
380
381 const QList<QgsRenderedItemDetails *> items = renderedItemResults->renderedItems();
382 bool needsSelectedItemsUpdate = false;
383 for ( std::unique_ptr<QgsAnnotationItemRubberBand> &selectedItem : mSelectedItems )
384 {
385 if ( selectedItem->needsUpdatedBoundingBox() )
386 {
387 needsSelectedItemsUpdate = true;
388
389 auto it = std::find_if( items.begin(), items.end(), [&selectedItem]( const QgsRenderedItemDetails *item ) {
390 if ( const QgsRenderedAnnotationItemDetails *annotationItem = dynamic_cast<const QgsRenderedAnnotationItemDetails *>( item ) )
391 {
392 if ( annotationItem->itemId() == selectedItem->itemId() && annotationItem->layerId() == selectedItem->layerId() )
393 {
394 return true;
395 }
396 }
397 return false;
398 } );
399
400 if ( it != items.end() )
401 {
402 selectedItem->updateBoundingBox( ( *it )->boundingBox() );
403 }
404 }
405 }
406
407 if ( needsSelectedItemsUpdate )
408 {
409 emit selectedItemsChanged();
410 }
411}
412
413long long QgsMapToolSelectAnnotation::annotationItemRubberBandIndexFromId( const QString &layerId, const QString &itemId )
414{
415 if ( mSelectedItems.empty() )
416 {
417 return -1;
418 }
419
420 auto it = std::find_if( mSelectedItems.begin(), mSelectedItems.end(), [&layerId, &itemId]( auto &item ) { return item->layerId() == layerId && item->itemId() == itemId; } );
421 return it != mSelectedItems.end() ? std::distance( mSelectedItems.begin(), it ) : -1;
422}
423
424void QgsMapToolSelectAnnotation::setSelectedItemsFromRect( const QgsRectangle &mapRect, bool toggleSelection )
425{
426 const QgsRenderedItemResults *renderedItemResults = canvas()->renderedItemResults( false );
427 if ( !renderedItemResults )
428 {
429 if ( !toggleSelection )
430 {
431 clearSelectedItems();
432 }
433 return;
434 }
435
436 const QList<const QgsRenderedAnnotationItemDetails *> items = renderedItemResults->renderedAnnotationItemsInBounds( mapRect );
437 if ( items.empty() )
438 {
439 if ( !toggleSelection )
440 {
441 clearSelectedItems();
442 }
443 return;
444 }
445
446 if ( !toggleSelection )
447 {
448 mSelectedItems.clear();
449 }
450 for ( const QgsRenderedAnnotationItemDetails *item : items )
451 {
452 QgsAnnotationItem *annotationItem = annotationItemFromId( item->layerId(), item->itemId() );
453 if ( annotationItem )
454 {
455 if ( toggleSelection )
456 {
457 long long index = annotationItemRubberBandIndexFromId( item->layerId(), item->itemId() );
458 if ( index >= 0 )
459 {
460 mSelectedItems.erase( mSelectedItems.begin() + index );
461 continue;
462 }
463 }
464 mSelectedItems.push_back( std::make_unique<QgsAnnotationItemRubberBand>( item->layerId(), item->itemId(), mCanvas ) );
465 mSelectedItems.back()->updateBoundingBox( item->boundingBox() );
466 }
467 }
469 updateSelectedItem();
470}
471
472void QgsMapToolSelectAnnotation::setSelectedItemFromPoint( const QgsPointXY &mapPoint, bool toggleSelection )
473{
474 QgsRectangle searchRect = QgsRectangle( mapPoint.x(), mapPoint.y(), mapPoint.x(), mapPoint.y() );
475 searchRect.grow( searchRadiusMU( canvas() ) );
476
477 const QgsRenderedItemResults *renderedItemResults = canvas()->renderedItemResults( false );
478 if ( !renderedItemResults )
479 {
480 clearSelectedItems();
481 return;
482 }
483
484 const QList<const QgsRenderedAnnotationItemDetails *> items = renderedItemResults->renderedAnnotationItemsInBounds( searchRect );
485 if ( items.empty() )
486 {
487 if ( !toggleSelection )
488 {
489 clearSelectedItems();
490 }
491 return;
492 }
493
494 QgsRectangle itemBounds;
495 const QgsRenderedAnnotationItemDetails *closestItem = findClosestItemToPoint( mapPoint, items, itemBounds );
496 if ( !closestItem )
497 {
498 if ( !toggleSelection )
499 {
500 clearSelectedItems();
501 }
502 return;
503 }
504
505 long long index = annotationItemRubberBandIndexFromId( closestItem->layerId(), closestItem->itemId() );
506 if ( index >= 0 )
507 {
508 if ( toggleSelection )
509 {
510 mSelectedItems.erase( mSelectedItems.begin() + index );
511 }
512 }
513 else
514 {
515 if ( !toggleSelection )
516 {
517 mSelectedItems.clear();
518 }
519
520 mSelectedItems.push_back( std::make_unique<QgsAnnotationItemRubberBand>( closestItem->layerId(), closestItem->itemId(), mCanvas ) );
521 mSelectedItems.back()->updateBoundingBox( closestItem->boundingBox() );
522 }
524 updateSelectedItem();
525}
526
527void QgsMapToolSelectAnnotation::updateSelectedItem()
528{
529 if ( mSelectedItems.size() > 1 )
530 {
532 }
533 else if ( mSelectedItems.size() == 1 )
534 {
535 emit singleItemSelected( mSelectedItems[0]->layer(), mSelectedItems[0]->itemId() );
536 }
537 else
538 {
539 emit selectionCleared();
540 }
541}
542
543void QgsMapToolSelectAnnotation::clearSelectedItems()
544{
545 const bool hadSelection = !mSelectedItems.empty();
546 mSelectedItems.clear();
547
548 if ( hadSelection )
549 {
551 updateSelectedItem();
552 }
553}
554
555void QgsMapToolSelectAnnotation::attemptMoveBy( QgsAnnotationItemRubberBand *annotationItemRubberBand, double deltaX, double deltaY )
556{
557 if ( QgsAnnotationItem *annotationItem = annotationItemRubberBand->item() )
558 {
559 QgsRectangle boundingBox = annotationItemRubberBand->boundingBox();
560 const double mupp = mCanvas->mapSettings().mapUnitsPerPixel();
561 QgsVector translation( deltaX * mupp, -deltaY * mupp );
562 QgsAnnotationLayer *annotationLayer = annotationItemRubberBand->layer();
563
565 context.setCurrentItemBounds( boundingBox );
567
568 const QList<QgsAnnotationItemNode> itemNodes = annotationItem->nodesV2( context );
569 for ( const QgsAnnotationItemNode &node : itemNodes )
570 {
571 QgsPointXY mapPoint = mCanvas->mapSettings().layerToMapCoordinates( annotationLayer, node.point() );
572 mapPoint += translation;
573 QgsPointXY modifiedPoint = mCanvas->mapSettings().mapToLayerCoordinates( annotationLayer, mapPoint );
574
575 QgsAnnotationItemEditOperationMoveNode operation( annotationItemRubberBand->itemId(), node.id(), QgsPoint( node.point() ), QgsPoint( modifiedPoint ) );
576 switch ( annotationLayer->applyEditV2( &operation, context ) )
577 {
580 annotationItemRubberBand->setNeedsUpdatedBoundingBox( true );
581 break;
582
585 break;
586 }
587 }
588 boundingBox += translation;
589 annotationItemRubberBand->updateBoundingBox( boundingBox );
590 }
591}
592
593void QgsMapToolSelectAnnotation::attemptRotateBy( QgsAnnotationItemRubberBand *annotationItemRubberBand, double deltaDegree )
594{
595 if ( QgsAnnotationLayer *annotationLayer = annotationItemRubberBand->layer() )
596 {
597 const QgsRectangle boundingBox = mCanvas->mapSettings().mapToLayerCoordinates( annotationLayer, annotationItemRubberBand->boundingBox() );
599 context.setCurrentItemBounds( boundingBox );
601
602 QgsAnnotationItemEditOperationRotateItem operation( annotationItemRubberBand->itemId(), deltaDegree );
603 switch ( annotationLayer->applyEditV2( &operation, context ) )
604 {
607 annotationItemRubberBand->setNeedsUpdatedBoundingBox( true );
608 break;
609
612 break;
613 }
614 }
615}
616
617void QgsMapToolSelectAnnotation::attemptSetSceneRect( QgsAnnotationItemRubberBand *annotationItemRubberBand, const QRectF &rect )
618{
619 if ( QgsAnnotationItem *annotationItem = annotationItemRubberBand->item() )
620 {
621 const double widthRatio = rect.width() / annotationItemRubberBand->boundingRect().width();
622 const double heightRatio = rect.height() / annotationItemRubberBand->boundingRect().height();
623 const double deltaX = rect.x() - annotationItemRubberBand->x() + 1;
624 const double deltaY = rect.y() - annotationItemRubberBand->y() + 1;
625 attemptMoveBy( annotationItemRubberBand, deltaX, deltaY );
626
627 QgsAnnotationLayer *annotationLayer = annotationItemRubberBand->layer();
628 const QgsRectangle boundingBox = mCanvas->mapSettings().mapToLayerCoordinates( annotationLayer, annotationItemRubberBand->boundingBox() );
629 const QgsRectangle modifiedBoundingBox( boundingBox.xMinimum(), boundingBox.yMaximum() - boundingBox.height() * heightRatio, boundingBox.xMinimum() + boundingBox.width() * widthRatio, boundingBox.yMaximum() );
630
632 context.setCurrentItemBounds( boundingBox );
634
635 const QList<QgsAnnotationItemNode> itemNodes = annotationItem->nodesV2( context );
636 for ( const QgsAnnotationItemNode &node : itemNodes )
637 {
638 const double modifiedX = modifiedBoundingBox.xMinimum() + modifiedBoundingBox.width() * ( ( node.point().x() - boundingBox.xMinimum() ) / boundingBox.width() );
639 const double modifiedY = modifiedBoundingBox.yMaximum() - modifiedBoundingBox.height() * ( ( boundingBox.yMaximum() - node.point().y() ) / boundingBox.height() );
640 QgsPointXY modifiedPoint( modifiedX, modifiedY );
641 QgsAnnotationItemEditOperationMoveNode operation( annotationItemRubberBand->itemId(), node.id(), QgsPoint( node.point() ), QgsPoint( modifiedPoint ) );
642 switch ( annotationLayer->applyEditV2( &operation, context ) )
643 {
646 annotationItemRubberBand->setNeedsUpdatedBoundingBox( true );
647 break;
648
651 break;
652 }
653 }
654 }
655}
Provides global constants and enumerations for use throughout the application.
Definition qgis.h:59
@ ScaleDependentBoundingBox
Item's bounding box will vary depending on map scale.
Definition qgis.h:2511
@ Invalid
Operation has invalid parameters for the item, no change occurred.
Definition qgis.h:2567
@ Success
Item was modified successfully.
Definition qgis.h:2566
@ ItemCleared
The operation results in the item being cleared, and the item should be removed from the layer as a r...
Definition qgis.h:2568
@ Line
Lines.
Definition qgis.h:367
@ Polygon
Polygons.
Definition qgis.h:368
A dockable widget used to handle the CAD tools on top of a selection of map tools.
Encapsulates the context for an annotation item edit operation.
void setCurrentItemBounds(const QgsRectangle &bounds)
Sets the current rendered bounds of the item, in the annotation layer's CRS.
void setRenderContext(const QgsRenderContext &context)
Sets the render context associated with the edit operation.
Annotation item edit operation consisting of moving a node.
Annotation item edit operation consisting of rotating an item.
Contains information about a node used for editing an annotation item.
An annotation item rubberband used by QgsMapToolSelectAnnotation to represent selected items.
bool needsUpdatedBoundingBox() const
Returns true if the bounding box requires updating on fresh annotation item rendering.
QgsRectangle boundingBox() const
Returns the item bounding box.
QString itemId() const
Returns the annotation item ID.
QgsAnnotationItemRubberBand(const QString &layerId, const QString &itemId, QgsMapCanvas *canvas)
Constructor for QgsAnnotationItemRubberBand.
QgsAnnotationItem * item() const
Returns a pointer to the annotation item.
QgsAnnotationLayer * layer() const
Returns a pointer to the annotation layer.
void updateBoundingBox(const QgsRectangle &boundingBox)
Update the rubberband using the provided annotation item bounding box.
QString layerId() const
Returns the annotation layer ID.
void setNeedsUpdatedBoundingBox(bool needsUpdatedBoundingBox)
Sets whether the bounding box requires updating on fresh annotation item rendering.
Abstract base class for annotation items which are drawn with QgsAnnotationLayers.
virtual QList< QgsAnnotationItemNode > nodesV2(const QgsAnnotationItemEditContext &context) const
Returns the nodes for the item, used for editing the item.
virtual Qgis::AnnotationItemFlags flags() const
Returns item flags.
Represents a map layer containing a set of georeferenced annotations, e.g.
Qgis::AnnotationItemEditOperationResult applyEditV2(QgsAbstractAnnotationItemEditOperation *operation, const QgsAnnotationItemEditContext &context)
Applies an edit operation to the layer.
QString addItem(QgsAnnotationItem *item)
Adds an item to the layer.
QgsAnnotationItem * item(const QString &id) const
Returns the item with the specified id, or nullptr if no matching item was found.
QgsAnnotationMapTool(QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget)
Constructor for QgsAnnotationMapTool.
const QgsRenderedAnnotationItemDetails * findClosestItemToPoint(const QgsPointXY &mapPoint, const QList< const QgsRenderedAnnotationItemDetails * > &items, QgsRectangle &bounds)
Returns the closest item from a list of annotation items to a given map point.
QgsAnnotationItem * annotationItemFromId(const QString &layerId, const QString &itemId)
Returns the annotation item matching a given pair of layer and item IDs.
QRectF boundingRect() const override
Map canvas is a class for displaying all GIS data types on a canvas.
const QgsRenderedItemResults * renderedItemResults(bool allowOutdatedResults=true) const
Gets access to the rendered item results (may be nullptr), which includes the results of rendering an...
void mapCanvasRefreshed()
Emitted when canvas finished a refresh request.
QString id
Definition qgsmaplayer.h:83
A mouse event which is the result of a user interaction with a QgsMapCanvas.
QgsPointXY mapPoint() const
mapPoint returns the point in coordinates
void deactivate() override
Unregisters this maptool from the cad dock widget.
virtual QgsMapLayer * layer() const
Returns the layer associated with the map tool.
QgsAdvancedDigitizingDockWidget * cadDockWidget() const
void setAdvancedDigitizingAllowed(bool allowed)
Sets whether functionality of advanced digitizing dock widget is currently allowed.
void activate() override
Registers this maptool with the cad dock widget.
QList< QgsAnnotationItemRubberBand * > selectedItems() const
Returns the current list of selected annotation item rubberband items.
void cadCanvasReleaseEvent(QgsMapMouseEvent *event) override
Override this method when subclassing this class.
void singleItemSelected(QgsAnnotationLayer *layer, const QString &itemId)
Emitted when the selected items list has changed and a single item is selected.
void attemptRotateBy(QgsAnnotationItemRubberBand *annotationItemRubberBand, double deltaDegree)
Attempts to rotate am annotation item.
void keyPressEvent(QKeyEvent *event) override
Key event for overriding. Default implementation does nothing.
void activate() override
Registers this maptool with the cad dock widget.
void attemptSetSceneRect(QgsAnnotationItemRubberBand *annotationItemRubberBand, const QRectF &rect)
Attempts to move and resize an annotation item.
QgsMapToolSelectAnnotation(QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget)
Constructor for QgsMapToolSelectAnnotation.
void multipleItemsSelected()
Emitted when the selected items list has changed and multiple items are selected.
void cadCanvasMoveEvent(QgsMapMouseEvent *event) override
Override this method when subclassing this class.
void attemptMoveBy(QgsAnnotationItemRubberBand *annotationItemRubberBand, double deltaX, double deltaY)
Attempts to move an annotation item.
void cadCanvasPressEvent(QgsMapMouseEvent *event) override
Override this method when subclassing this class.
void selectedItemsChanged()
Emitted when the selected items list has changed.
void selectionCleared()
Emitted when the selected items list is cleared.
void deactivate() override
Unregisters this maptool from the cad dock widget.
QgsMapCanvas * canvas() const
returns pointer to the tool's map canvas
QgsPointXY toMapCoordinates(QPoint point)
Transforms a point from screen coordinates to map coordinates.
QPointer< QgsMapCanvas > mCanvas
The pointer to the map canvas.
Definition qgsmaptool.h:360
static double searchRadiusMU(const QgsRenderContext &context)
Gets search radius in map units for given context.
Represents a 2D point.
Definition qgspointxy.h:60
double y
Definition qgspointxy.h:64
double x
Definition qgspointxy.h:63
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:49
static QgsProject * instance()
Returns the QgsProject singleton instance.
QgsAnnotationLayer * mainAnnotationLayer()
Returns the main annotation layer associated with the project.
void setDirty(bool b=true)
Flag the project as dirty (modified).
A rectangle specified with double values.
double xMinimum
void grow(double delta)
Grows the rectangle in place by the specified amount.
double yMaximum
static QgsRenderContext fromMapSettings(const QgsMapSettings &mapSettings)
create initialized QgsRenderContext instance from given QgsMapSettings
QString itemId() const
Returns the item ID of the associated annotation item.
QString layerId() const
Returns the layer ID of the associated map layer.
QgsRectangle boundingBox() const
Returns the bounding box of the item (in map units).
Stores collated details of rendered items during a map rendering operation.
QList< const QgsRenderedAnnotationItemDetails * > renderedAnnotationItemsInBounds(const QgsRectangle &bounds) const
Returns a list with details of the rendered annotation items within the specified bounds.
QList< QgsRenderedItemDetails * > renderedItems() const
Returns a list of all rendered items.
Responsible for drawing transient features (e.g.
QgsRubberBand(QgsMapCanvas *mapCanvas, Qgis::GeometryType geometryType=Qgis::GeometryType::Line)
Creates a new RubberBand.
void setWidth(double width)
Sets the width of the line.
void reset(Qgis::GeometryType geometryType=Qgis::GeometryType::Line)
Clears all the geometries in this rubberband.
void setSecondaryStrokeColor(const QColor &color)
Sets a secondary stroke color for the rubberband which will be drawn under the main stroke color.
void setColor(const QColor &color)
Sets the color for the rubberband.
void addPoint(const QgsPointXY &p, bool doUpdate=true, int geometryIndex=0, int ringIndex=0)
Adds a vertex to the rubberband and update canvas.
Represent a 2-dimensional vector.
Definition qgsvector.h:31