QGIS API Documentation 3.99.0-Master (d270888f95f)
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->isDragging() )
133 {
134 QGraphicsSceneMouseEvent forwardedEvent( QEvent::GraphicsSceneMouseMove );
135 forwardedEvent.setPos( mMouseHandles->mapFromScene( scenePos ) );
136 forwardedEvent.setScenePos( scenePos );
137 forwardedEvent.setLastScenePos( mLastScenePos );
138 forwardedEvent.setButton( Qt::LeftButton );
139 mMouseHandles->mouseMoveEvent( &forwardedEvent );
140 }
141 else
142 {
143 if ( mMouseHandles->sceneBoundingRect().contains( scenePos ) )
144 {
145 QGraphicsSceneHoverEvent forwardedEvent( QEvent::GraphicsSceneHoverMove );
146 forwardedEvent.setPos( mMouseHandles->mapFromScene( scenePos ) );
147 forwardedEvent.setScenePos( scenePos );
148 mMouseHandles->hoverMoveEvent( &forwardedEvent );
149 mHoveringMouseHandles = true;
150 }
151 else if ( mHoveringMouseHandles )
152 {
153 QGraphicsSceneHoverEvent forwardedEvent( QEvent::GraphicsSceneHoverLeave );
154 forwardedEvent.setPos( mMouseHandles->mapFromScene( scenePos ) );
155 forwardedEvent.setScenePos( scenePos );
156 mMouseHandles->hoverMoveEvent( &forwardedEvent );
157 mHoveringMouseHandles = false;
158 }
159 }
160 }
161 else if ( event->buttons() == Qt::LeftButton )
162 {
163 if ( mMouseHandles->shouldBlockEvent( event ) )
164 {
165 QGraphicsSceneMouseEvent forwardedEvent( QEvent::GraphicsSceneMouseMove );
166 forwardedEvent.setPos( mMouseHandles->mapFromScene( scenePos ) );
167 forwardedEvent.setScenePos( scenePos );
168 forwardedEvent.setLastScenePos( mLastScenePos );
169 forwardedEvent.setButton( Qt::LeftButton );
170 mMouseHandles->mouseMoveEvent( &forwardedEvent );
171 }
172 else
173 {
174 if ( !mDragging )
175 {
176 mDragging = true;
177 mSelectionRubberBand.reset( new QgsRubberBand( mCanvas, Qgis::GeometryType::Polygon ) );
178 QColor color( Qt::blue );
179 color.setAlpha( 63 );
180 mSelectionRubberBand->setColor( color );
181 mSelectionRect.setTopLeft( event->pos() );
182 }
183
184 mSelectionRect.setBottomRight( event->pos() );
185 if ( mSelectionRubberBand )
186 {
187 mSelectionRubberBand->setToCanvasRectangle( mSelectionRect );
188 mSelectionRubberBand->show();
189 }
190 }
191 }
192
193 mLastScenePos = scenePos;
194}
195
197{
198 if ( event->button() != Qt::LeftButton )
199 {
200 return;
201 }
202
203 QPointF scenePos = mCanvas->mapToScene( event->pos() );
204 const bool toggleSelection = event->modifiers() & Qt::ShiftModifier;
205
206 if ( !toggleSelection && !mSelectedItems.empty() && mMouseHandles->sceneBoundingRect().contains( scenePos ) )
207 {
208 QGraphicsSceneMouseEvent forwardedEvent( QEvent::GraphicsSceneMousePress );
209 forwardedEvent.setPos( mMouseHandles->mapFromScene( scenePos ) );
210 forwardedEvent.setScenePos( scenePos );
211 forwardedEvent.setLastScenePos( mLastScenePos );
212 forwardedEvent.setButton( Qt::LeftButton );
213 mMouseHandles->mousePressEvent( &forwardedEvent );
214 }
215 else
216 {
217 mSelectionRect.setTopLeft( event->pos() );
218 mSelectionRect.setBottomRight( event->pos() );
219 }
220
221 mLastScenePos = scenePos;
222}
223
225{
226 if ( event->button() != Qt::LeftButton )
227 {
228 return;
229 }
230
231 QPointF scenePos = mCanvas->mapToScene( event->pos() );
232
233 if ( mMouseHandles->shouldBlockEvent( event ) )
234 {
235 QGraphicsSceneMouseEvent forwardedEvent( QEvent::GraphicsSceneMouseRelease );
236 forwardedEvent.setPos( mMouseHandles->mapFromScene( scenePos ) );
237 forwardedEvent.setScenePos( scenePos );
238 forwardedEvent.setLastScenePos( mLastScenePos );
239 forwardedEvent.setButton( Qt::LeftButton );
240 mMouseHandles->mouseReleaseEvent( &forwardedEvent );
241 }
242 else
243 {
244 if ( mCanceled )
245 {
246 mCanceled = false;
247 mDragging = false;
248 return;
249 }
250
251 if ( mDragging )
252 {
253 mDragging = false;
254 mSelectionRubberBand.reset();
255
256 const QgsPointXY topLeft = toMapCoordinates( mSelectionRect.topLeft() );
257 const QgsPointXY bottomRight = toMapCoordinates( mSelectionRect.bottomRight() );
258 const QgsRectangle searchRect( topLeft, bottomRight );
259
260 setSelectedItemsFromRect( searchRect, ( event->modifiers() & Qt::ShiftModifier ) );
261 }
262 else
263 {
264 setSelectedItemFromPoint( event->mapPoint(), ( event->modifiers() & Qt::ShiftModifier ) );
265 }
266
267 mMouseHandles->setSelected( !mSelectedItems.empty() );
268 }
269}
270
272{
273 if ( mMouseHandles->isDragging() || mMouseHandles->isResizing() || mMouseHandles->isRotating() )
274 {
275 return;
276 }
277
278 if ( mSelectedItems.empty() )
279 {
280 return;
281 }
282
283 if ( event->key() == Qt::Key_C || event->key() == Qt::Key_X )
284 {
285 mCopiedItems.clear();
286 mCopiedItemsTopLeft = toMapCoordinates( QPoint( mMouseHandles->sceneBoundingRect().topLeft().x(), mMouseHandles->sceneBoundingRect().topLeft().y() ) );
287 for ( std::unique_ptr<QgsAnnotationItemRubberBand> &selectedItem : mSelectedItems )
288 {
289 mCopiedItems << qMakePair( selectedItem->layerId(), selectedItem->itemId() );
290 }
291 if ( event->key() == Qt::Key_C )
292 {
293 event->ignore();
294 return;
295 }
296 }
297 else if ( event->key() == Qt::Key_V )
298 {
299 const QgsPointXY copiedItemsSceneTopLeft = mCanvas->mapSettings().mapToPixel().transform( mCopiedItemsTopLeft );
300 const double deltaX = mLastScenePos.x() - copiedItemsSceneTopLeft.x();
301 const double deltaY = mLastScenePos.y() - copiedItemsSceneTopLeft.y();
302 if ( !mSelectedItems.empty() )
303 {
304 mSelectedItems.clear();
305 }
306
307 for ( const QPair<QString, QString> &copiedItem : mCopiedItems )
308 {
309 if ( QgsAnnotationItem *annotationItem = annotationItemFromId( copiedItem.first, copiedItem.second ) )
310 {
311 QgsAnnotationLayer *annotationLayer = dynamic_cast<QgsAnnotationLayer *>( layer() );
312 if ( !annotationLayer )
313 {
314 annotationLayer = QgsProject::instance()->mainAnnotationLayer();
315 }
316 QString pastedItemId = annotationLayer->addItem( annotationItem->clone() );
317
318 mSelectedItems.push_back( std::make_unique<QgsAnnotationItemRubberBand>( annotationLayer->id(), pastedItemId, mCanvas ) );
319 attemptMoveBy( mSelectedItems.back().get(), deltaX, deltaY );
320 }
321 }
323 updateSelectedItem();
324 event->ignore();
325 return;
326 }
327
328 if ( event->key() == Qt::Key_Backspace || event->key() == Qt::Key_Delete || event->key() == Qt::Key_X )
329 {
330 while ( !mSelectedItems.empty() )
331 {
332 if ( QgsAnnotationLayer *annotationLayer = mSelectedItems.back()->layer() )
333 {
334 annotationLayer->removeItem( mSelectedItems.back()->itemId() );
335 }
336 mSelectedItems.pop_back();
337 }
339 updateSelectedItem();
340 event->ignore();
341 }
342 else if ( event->key() == Qt::Key_Left
343 || event->key() == Qt::Key_Right
344 || event->key() == Qt::Key_Up
345 || event->key() == Qt::Key_Down )
346 {
347 const int pixels = ( event->modifiers() & Qt::ShiftModifier ) ? 1 : 50;
348 int deltaX = 0;
349 int deltaY = 0;
350 if ( event->key() == Qt::Key_Up )
351 {
352 deltaY = -pixels;
353 }
354 else if ( event->key() == Qt::Key_Down )
355 {
356 deltaY = pixels;
357 }
358 else if ( event->key() == Qt::Key_Left )
359 {
360 deltaX = -pixels;
361 }
362 else if ( event->key() == Qt::Key_Right )
363 {
364 deltaX = pixels;
365 }
366
367 for ( std::unique_ptr<QgsAnnotationItemRubberBand> &selectedItem : mSelectedItems )
368 {
369 attemptMoveBy( selectedItem.get(), deltaX, deltaY );
370 }
371 event->ignore();
372 }
373}
374
375QList<QgsAnnotationItemRubberBand *> QgsMapToolSelectAnnotation::selectedItems() const
376{
377 QList<QgsAnnotationItemRubberBand *> items;
378 for ( const std::unique_ptr<QgsAnnotationItemRubberBand> &selectedItem : mSelectedItems )
379 {
380 items << selectedItem.get();
381 }
382 return items;
383}
384
385void QgsMapToolSelectAnnotation::onCanvasRefreshed()
386{
387 const QgsRenderedItemResults *renderedItemResults = canvas()->renderedItemResults( false );
388 if ( !renderedItemResults )
389 {
390 return;
391 }
392
393 const QList<QgsRenderedItemDetails *> items = renderedItemResults->renderedItems();
394 bool needsSelectedItemsUpdate = false;
395 for ( std::unique_ptr<QgsAnnotationItemRubberBand> &selectedItem : mSelectedItems )
396 {
397 if ( selectedItem->needsUpdatedBoundingBox() )
398 {
399 needsSelectedItemsUpdate = true;
400
401 auto it = std::find_if( items.begin(), items.end(), [&selectedItem]( const QgsRenderedItemDetails *item ) {
402 if ( const QgsRenderedAnnotationItemDetails *annotationItem = dynamic_cast<const QgsRenderedAnnotationItemDetails *>( item ) )
403 {
404 if ( annotationItem->itemId() == selectedItem->itemId() && annotationItem->layerId() == selectedItem->layerId() )
405 {
406 return true;
407 }
408 }
409 return false;
410 } );
411
412 if ( it != items.end() )
413 {
414 selectedItem->updateBoundingBox( ( *it )->boundingBox() );
415 }
416 }
417 }
418
419 if ( needsSelectedItemsUpdate )
420 {
421 emit selectedItemsChanged();
422 }
423}
424
425long long QgsMapToolSelectAnnotation::annotationItemRubberBandIndexFromId( const QString &layerId, const QString &itemId )
426{
427 if ( mSelectedItems.empty() )
428 {
429 return -1;
430 }
431
432 auto it = std::find_if( mSelectedItems.begin(), mSelectedItems.end(), [&layerId, &itemId]( auto &item ) { return item->layerId() == layerId && item->itemId() == itemId; } );
433 return it != mSelectedItems.end() ? std::distance( mSelectedItems.begin(), it ) : -1;
434}
435
436void QgsMapToolSelectAnnotation::setSelectedItemsFromRect( const QgsRectangle &mapRect, bool toggleSelection )
437{
438 const QgsRenderedItemResults *renderedItemResults = canvas()->renderedItemResults( false );
439 if ( !renderedItemResults )
440 {
441 if ( !toggleSelection )
442 {
443 clearSelectedItems();
444 }
445 return;
446 }
447
448 const QList<const QgsRenderedAnnotationItemDetails *> items = renderedItemResults->renderedAnnotationItemsInBounds( mapRect );
449 if ( items.empty() )
450 {
451 if ( !toggleSelection )
452 {
453 clearSelectedItems();
454 }
455 return;
456 }
457
458 if ( !toggleSelection )
459 {
460 mSelectedItems.clear();
461 }
462 for ( const QgsRenderedAnnotationItemDetails *item : items )
463 {
464 QgsAnnotationItem *annotationItem = annotationItemFromId( item->layerId(), item->itemId() );
465 if ( annotationItem )
466 {
467 if ( toggleSelection )
468 {
469 long long index = annotationItemRubberBandIndexFromId( item->layerId(), item->itemId() );
470 if ( index >= 0 )
471 {
472 mSelectedItems.erase( mSelectedItems.begin() + index );
473 continue;
474 }
475 }
476 mSelectedItems.push_back( std::make_unique<QgsAnnotationItemRubberBand>( item->layerId(), item->itemId(), mCanvas ) );
477 mSelectedItems.back()->updateBoundingBox( item->boundingBox() );
478 }
479 }
481 updateSelectedItem();
482}
483
484void QgsMapToolSelectAnnotation::setSelectedItemFromPoint( const QgsPointXY &mapPoint, bool toggleSelection )
485{
486 QgsRectangle searchRect = QgsRectangle( mapPoint.x(), mapPoint.y(), mapPoint.x(), mapPoint.y() );
487 searchRect.grow( searchRadiusMU( canvas() ) );
488
489 const QgsRenderedItemResults *renderedItemResults = canvas()->renderedItemResults( false );
490 if ( !renderedItemResults )
491 {
492 clearSelectedItems();
493 return;
494 }
495
496 const QList<const QgsRenderedAnnotationItemDetails *> items = renderedItemResults->renderedAnnotationItemsInBounds( searchRect );
497 if ( items.empty() )
498 {
499 if ( !toggleSelection )
500 {
501 clearSelectedItems();
502 }
503 return;
504 }
505
506 QgsRectangle itemBounds;
507 const QgsRenderedAnnotationItemDetails *closestItem = findClosestItemToPoint( mapPoint, items, itemBounds );
508 if ( !closestItem )
509 {
510 if ( !toggleSelection )
511 {
512 clearSelectedItems();
513 }
514 return;
515 }
516
517 long long index = annotationItemRubberBandIndexFromId( closestItem->layerId(), closestItem->itemId() );
518 if ( index >= 0 )
519 {
520 if ( toggleSelection )
521 {
522 mSelectedItems.erase( mSelectedItems.begin() + index );
523 }
524 }
525 else
526 {
527 if ( !toggleSelection )
528 {
529 mSelectedItems.clear();
530 }
531
532 mSelectedItems.push_back( std::make_unique<QgsAnnotationItemRubberBand>( closestItem->layerId(), closestItem->itemId(), mCanvas ) );
533 mSelectedItems.back()->updateBoundingBox( closestItem->boundingBox() );
534 }
536 updateSelectedItem();
537}
538
539void QgsMapToolSelectAnnotation::updateSelectedItem()
540{
541 if ( mSelectedItems.size() > 1 )
542 {
544 }
545 else if ( mSelectedItems.size() == 1 )
546 {
547 emit singleItemSelected( mSelectedItems[0]->layer(), mSelectedItems[0]->itemId() );
548 }
549 else
550 {
551 emit selectionCleared();
552 }
553}
554
555void QgsMapToolSelectAnnotation::clearSelectedItems()
556{
557 const bool hadSelection = !mSelectedItems.empty();
558 mSelectedItems.clear();
559
560 if ( hadSelection )
561 {
563 updateSelectedItem();
564 }
565}
566
567void QgsMapToolSelectAnnotation::attemptMoveBy( QgsAnnotationItemRubberBand *annotationItemRubberBand, double deltaX, double deltaY )
568{
569 if ( QgsAnnotationItem *annotationItem = annotationItemRubberBand->item() )
570 {
571 QgsRectangle boundingBox = annotationItemRubberBand->boundingBox();
572 const double mupp = mCanvas->mapSettings().mapUnitsPerPixel();
573 QgsVector translation( deltaX * mupp, -deltaY * mupp );
574 QgsAnnotationLayer *annotationLayer = annotationItemRubberBand->layer();
575
577 context.setCurrentItemBounds( boundingBox );
579
580 const QList<QgsAnnotationItemNode> itemNodes = annotationItem->nodesV2( context );
581 for ( const QgsAnnotationItemNode &node : itemNodes )
582 {
583 QgsPointXY mapPoint = mCanvas->mapSettings().layerToMapCoordinates( annotationLayer, node.point() );
584 mapPoint += translation;
585 QgsPointXY modifiedPoint = mCanvas->mapSettings().mapToLayerCoordinates( annotationLayer, mapPoint );
586
587 QgsAnnotationItemEditOperationMoveNode operation( annotationItemRubberBand->itemId(), node.id(), QgsPoint( node.point() ), QgsPoint( modifiedPoint ) );
588 switch ( annotationLayer->applyEditV2( &operation, context ) )
589 {
592 annotationItemRubberBand->setNeedsUpdatedBoundingBox( true );
593 break;
594
597 break;
598 }
599 }
600 boundingBox += translation;
601 annotationItemRubberBand->updateBoundingBox( boundingBox );
602 }
603}
604
605void QgsMapToolSelectAnnotation::attemptRotateBy( QgsAnnotationItemRubberBand *annotationItemRubberBand, double deltaDegree )
606{
607 if ( QgsAnnotationLayer *annotationLayer = annotationItemRubberBand->layer() )
608 {
609 const QgsRectangle boundingBox = mCanvas->mapSettings().mapToLayerCoordinates( annotationLayer, annotationItemRubberBand->boundingBox() );
611 context.setCurrentItemBounds( boundingBox );
613
614 QgsAnnotationItemEditOperationRotateItem operation( annotationItemRubberBand->itemId(), deltaDegree );
615 switch ( annotationLayer->applyEditV2( &operation, context ) )
616 {
619 annotationItemRubberBand->setNeedsUpdatedBoundingBox( true );
620 break;
621
624 break;
625 }
626 }
627}
628
629void QgsMapToolSelectAnnotation::attemptSetSceneRect( QgsAnnotationItemRubberBand *annotationItemRubberBand, const QRectF &rect )
630{
631 if ( QgsAnnotationItem *annotationItem = annotationItemRubberBand->item() )
632 {
633 const double widthRatio = rect.width() / annotationItemRubberBand->boundingRect().width();
634 const double heightRatio = rect.height() / annotationItemRubberBand->boundingRect().height();
635 const double deltaX = rect.x() - annotationItemRubberBand->x() + 1;
636 const double deltaY = rect.y() - annotationItemRubberBand->y() + 1;
637 attemptMoveBy( annotationItemRubberBand, deltaX, deltaY );
638
639 QgsAnnotationLayer *annotationLayer = annotationItemRubberBand->layer();
640 const QgsRectangle boundingBox = mCanvas->mapSettings().mapToLayerCoordinates( annotationLayer, annotationItemRubberBand->boundingBox() );
641 const QgsRectangle modifiedBoundingBox( boundingBox.xMinimum(), boundingBox.yMaximum() - boundingBox.height() * heightRatio, boundingBox.xMinimum() + boundingBox.width() * widthRatio, boundingBox.yMaximum() );
642
644 context.setCurrentItemBounds( boundingBox );
646
647 const QList<QgsAnnotationItemNode> itemNodes = annotationItem->nodesV2( context );
648 for ( const QgsAnnotationItemNode &node : itemNodes )
649 {
650 const double modifiedX = modifiedBoundingBox.xMinimum() + modifiedBoundingBox.width() * ( ( node.point().x() - boundingBox.xMinimum() ) / boundingBox.width() );
651 const double modifiedY = modifiedBoundingBox.yMaximum() - modifiedBoundingBox.height() * ( ( boundingBox.yMaximum() - node.point().y() ) / boundingBox.height() );
652 QgsPointXY modifiedPoint( modifiedX, modifiedY );
653 QgsAnnotationItemEditOperationMoveNode operation( annotationItemRubberBand->itemId(), node.id(), QgsPoint( node.point() ), QgsPoint( modifiedPoint ) );
654 switch ( annotationLayer->applyEditV2( &operation, context ) )
655 {
658 annotationItemRubberBand->setNeedsUpdatedBoundingBox( true );
659 break;
660
663 break;
664 }
665 }
666 }
667}
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:2523
@ Invalid
Operation has invalid parameters for the item, no change occurred.
Definition qgis.h:2579
@ Success
Item was modified successfully.
Definition qgis.h:2578
@ ItemCleared
The operation results in the item being cleared, and the item should be removed from the layer as a r...
Definition qgis.h:2580
@ 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:86
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:62
double y
Definition qgspointxy.h:66
double x
Definition qgspointxy.h:65
Point geometry type, with support for z-dimension and m-values.
Definition qgspoint.h:53
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:34