QGIS API Documentation 4.1.0-Master (60fea48833c)
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 <QKeySequence>
35#include <QScreen>
36#include <QTransform>
37#include <QWindow>
38
39#include "moc_qgsmaptoolselectannotation.cpp"
40
42 : QgsRubberBand( canvas, Qgis::GeometryType::Line )
43 , mLayerId( layerId )
44 , mItemId( itemId )
45{
46 setFlags( flags() | QGraphicsItem::ItemIsSelectable );
47
48 setWidth( canvas->fontMetrics().xHeight() * .2 );
49 setSecondaryStrokeColor( QColor( 255, 255, 255, 100 ) );
50 setColor( QColor( 50, 50, 50, 200 ) );
51 setZValue( 10 );
52 setSelected( false );
53}
54
56{
57 QgsAnnotationLayer *lyr = qobject_cast<QgsAnnotationLayer *>( QgsProject::instance()->mapLayer( mLayerId ) );
58 if ( !lyr && mLayerId == QgsProject::instance()->mainAnnotationLayer()->id() )
59 {
61 }
62 return lyr;
63}
64
66{
68 return lyr ? lyr->item( mItemId ) : nullptr;
69}
70
72{
73 mBoundingBox = boundingBox;
74 QgsAnnotationItem *annotationItem = item();
75 mNeedsUpdatedBoundingBox = annotationItem && ( annotationItem->flags() & Qgis::AnnotationItemFlag::ScaleDependentBoundingBox );
76
78 addPoint( QgsPointXY( boundingBox.xMinimum(), boundingBox.yMinimum() ) );
79 addPoint( QgsPointXY( boundingBox.xMaximum(), boundingBox.yMinimum() ) );
80 addPoint( QgsPointXY( boundingBox.xMaximum(), boundingBox.yMaximum() ) );
81 addPoint( QgsPointXY( boundingBox.xMinimum(), boundingBox.yMaximum() ) );
82 addPoint( QgsPointXY( boundingBox.xMinimum(), boundingBox.yMinimum() ) );
83
84 show();
85 setSelected( true );
86}
87
92
93
101
103{
104 mSelectionRubberBand.reset();
105 mMouseHandles.reset();
106}
107
109{
110 mMouseHandles.reset( new QgsMapToolSelectAnnotationMouseHandles( this, mCanvas ) );
111
113}
114
116{
117 mSelectionRubberBand.reset();
118 mMouseHandles.reset();
119
120 mSelectedItems.clear();
121
122 mCopiedItems.clear();
123 mCopiedItemsTopLeft = QPointF();
124
126}
127
129{
130 const QPointF scenePos = mCanvas->mapToScene( event->pos() );
131
132 if ( event->buttons() == Qt::NoButton )
133 {
134 if ( mMouseHandles->isDragging() )
135 {
136 QGraphicsSceneMouseEvent forwardedEvent( QEvent::GraphicsSceneMouseMove );
137 forwardedEvent.setPos( mMouseHandles->mapFromScene( scenePos ) );
138 forwardedEvent.setScenePos( scenePos );
139 forwardedEvent.setLastScenePos( mLastScenePos );
140 forwardedEvent.setButton( Qt::LeftButton );
141 mMouseHandles->mouseMoveEvent( &forwardedEvent );
142 }
143 else
144 {
145 if ( mMouseHandles->sceneBoundingRect().contains( scenePos ) )
146 {
147 QGraphicsSceneHoverEvent forwardedEvent( QEvent::GraphicsSceneHoverMove );
148 forwardedEvent.setPos( mMouseHandles->mapFromScene( scenePos ) );
149 forwardedEvent.setScenePos( scenePos );
150 mMouseHandles->hoverMoveEvent( &forwardedEvent );
151 mHoveringMouseHandles = true;
152 }
153 else if ( mHoveringMouseHandles )
154 {
155 QGraphicsSceneHoverEvent forwardedEvent( QEvent::GraphicsSceneHoverLeave );
156 forwardedEvent.setPos( mMouseHandles->mapFromScene( scenePos ) );
157 forwardedEvent.setScenePos( scenePos );
158 mMouseHandles->hoverMoveEvent( &forwardedEvent );
159 mHoveringMouseHandles = false;
160 }
161 }
162 }
163 else if ( event->buttons() == Qt::LeftButton )
164 {
165 if ( mMouseHandles->shouldBlockEvent( event ) )
166 {
167 QGraphicsSceneMouseEvent forwardedEvent( QEvent::GraphicsSceneMouseMove );
168 forwardedEvent.setPos( mMouseHandles->mapFromScene( scenePos ) );
169 forwardedEvent.setScenePos( scenePos );
170 forwardedEvent.setLastScenePos( mLastScenePos );
171 forwardedEvent.setButton( Qt::LeftButton );
172 mMouseHandles->mouseMoveEvent( &forwardedEvent );
173 }
174 else
175 {
176 if ( !mDragging )
177 {
178 mDragging = true;
179 mSelectionRubberBand.reset( new QgsRubberBand( mCanvas, Qgis::GeometryType::Polygon ) );
180 QColor color( Qt::blue );
181 color.setAlpha( 63 );
182 mSelectionRubberBand->setColor( color );
183 mSelectionRect.setTopLeft( event->pos() );
184 }
185
186 mSelectionRect.setBottomRight( event->pos() );
187 if ( mSelectionRubberBand )
188 {
189 mSelectionRubberBand->setToCanvasRectangle( mSelectionRect );
190 mSelectionRubberBand->show();
191 }
192 }
193 }
194
195 mLastScenePos = scenePos;
196}
197
199{
200 if ( event->button() != Qt::LeftButton )
201 {
202 return;
203 }
204
205 QPointF scenePos = mCanvas->mapToScene( event->pos() );
206 const bool toggleSelection = event->modifiers() & Qt::ShiftModifier;
207
208 if ( !toggleSelection && !mSelectedItems.empty() && mMouseHandles->sceneBoundingRect().contains( scenePos ) )
209 {
210 QGraphicsSceneMouseEvent forwardedEvent( QEvent::GraphicsSceneMousePress );
211 forwardedEvent.setPos( mMouseHandles->mapFromScene( scenePos ) );
212 forwardedEvent.setScenePos( scenePos );
213 forwardedEvent.setLastScenePos( mLastScenePos );
214 forwardedEvent.setButton( Qt::LeftButton );
215 mMouseHandles->mousePressEvent( &forwardedEvent );
216 }
217 else
218 {
219 mSelectionRect.setTopLeft( event->pos() );
220 mSelectionRect.setBottomRight( event->pos() );
221 }
222
223 mLastScenePos = scenePos;
224}
225
227{
228 if ( event->button() != Qt::LeftButton )
229 {
230 return;
231 }
232
233 QPointF scenePos = mCanvas->mapToScene( event->pos() );
234
235 if ( mMouseHandles->shouldBlockEvent( event ) )
236 {
237 QGraphicsSceneMouseEvent forwardedEvent( QEvent::GraphicsSceneMouseRelease );
238 forwardedEvent.setPos( mMouseHandles->mapFromScene( scenePos ) );
239 forwardedEvent.setScenePos( scenePos );
240 forwardedEvent.setLastScenePos( mLastScenePos );
241 forwardedEvent.setButton( Qt::LeftButton );
242 mMouseHandles->mouseReleaseEvent( &forwardedEvent );
243 }
244 else
245 {
246 if ( mCanceled )
247 {
248 mCanceled = false;
249 mDragging = false;
250 return;
251 }
252
253 if ( mDragging )
254 {
255 mDragging = false;
256 mSelectionRubberBand.reset();
257
258 const QgsPointXY topLeft = toMapCoordinates( mSelectionRect.topLeft() );
259 const QgsPointXY bottomRight = toMapCoordinates( mSelectionRect.bottomRight() );
260 const QgsRectangle searchRect( topLeft, bottomRight );
261
262 setSelectedItemsFromRect( searchRect, ( event->modifiers() & Qt::ShiftModifier ) );
263 }
264 else
265 {
266 setSelectedItemFromPoint( event->mapPoint(), ( event->modifiers() & Qt::ShiftModifier ) );
267 }
268
269 mMouseHandles->setSelected( !mSelectedItems.empty() );
270 }
271}
272
274{
275 if ( mMouseHandles->isDragging() || mMouseHandles->isResizing() || mMouseHandles->isRotating() )
276 {
277 return;
278 }
279
280 if ( mSelectedItems.empty() )
281 {
282 return;
283 }
284
285 if ( event->key() == Qt::Key_Backspace || event->key() == Qt::Key_Delete )
286 {
287 while ( !mSelectedItems.empty() )
288 {
289 if ( QgsAnnotationLayer *annotationLayer = mSelectedItems.back()->layer() )
290 {
291 annotationLayer->removeItem( mSelectedItems.back()->itemId() );
292 }
293 mSelectedItems.pop_back();
294 }
296 updateSelectedItem();
297 event->ignore();
298 }
299 else if ( event->key() == Qt::Key_Left || event->key() == Qt::Key_Right || event->key() == Qt::Key_Up || event->key() == Qt::Key_Down )
300 {
301 const int pixels = ( event->modifiers() & Qt::ShiftModifier ) ? 1 : 50;
302 int deltaX = 0;
303 int deltaY = 0;
304 if ( event->key() == Qt::Key_Up )
305 {
306 deltaY = -pixels;
307 }
308 else if ( event->key() == Qt::Key_Down )
309 {
310 deltaY = pixels;
311 }
312 else if ( event->key() == Qt::Key_Left )
313 {
314 deltaX = -pixels;
315 }
316 else if ( event->key() == Qt::Key_Right )
317 {
318 deltaX = pixels;
319 }
320
321 for ( std::unique_ptr<QgsAnnotationItemRubberBand> &selectedItem : mSelectedItems )
322 {
323 attemptMoveBy( selectedItem.get(), deltaX, deltaY );
324 }
325 event->ignore();
326 }
327}
328
330{
331 if ( mMouseHandles->isDragging() || mMouseHandles->isResizing() || mMouseHandles->isRotating() )
332 {
333 return true;
334 }
335 // NOLINTBEGIN(bugprone-narrowing-conversions)
336 QKeySequence keySequence( event->key() | event->modifiers() );
337 // NOLINTEND(bugprone-narrowing-conversions)
338 if ( keySequence == QKeySequence::Copy || keySequence == QKeySequence::Cut )
339 {
340 mCopiedItems.clear();
341 mCopiedItemsTopLeft = toMapCoordinates( QPoint( mMouseHandles->sceneBoundingRect().topLeft().x(), mMouseHandles->sceneBoundingRect().topLeft().y() ) );
342 for ( std::unique_ptr<QgsAnnotationItemRubberBand> &selectedItem : mSelectedItems )
343 {
344 if ( QgsAnnotationItem *annotationItem = selectedItem->item() )
345 {
346 std::unique_ptr<QgsAnnotationItem> copiedItem;
347 copiedItem.reset( annotationItem->clone() );
348 mCopiedItems.push_back( std::move( copiedItem ) );
349 }
350 }
351
352 if ( keySequence == QKeySequence::Cut )
353 {
354 while ( !mSelectedItems.empty() )
355 {
356 if ( QgsAnnotationLayer *annotationLayer = mSelectedItems.back()->layer() )
357 {
358 annotationLayer->removeItem( mSelectedItems.back()->itemId() );
359 }
360 mSelectedItems.pop_back();
361 }
363 }
364
365 return true;
366 }
367 else if ( keySequence == QKeySequence::Paste )
368 {
369 const QgsPointXY copiedItemsSceneTopLeft = mCanvas->mapSettings().mapToPixel().transform( mCopiedItemsTopLeft );
370 const double deltaX = mLastScenePos.x() - copiedItemsSceneTopLeft.x();
371 const double deltaY = mLastScenePos.y() - copiedItemsSceneTopLeft.y();
372 if ( !mSelectedItems.empty() )
373 {
374 mSelectedItems.clear();
375 }
376
377 for ( std::unique_ptr<QgsAnnotationItem> &copiedItem : mCopiedItems )
378 {
379 QgsAnnotationLayer *annotationLayer = dynamic_cast<QgsAnnotationLayer *>( layer() );
380 if ( !annotationLayer )
381 {
382 annotationLayer = QgsProject::instance()->mainAnnotationLayer();
383 }
384 QString pastedItemId = annotationLayer->addItem( copiedItem->clone() );
385 mSelectedItems.push_back( std::make_unique<QgsAnnotationItemRubberBand>( annotationLayer->id(), pastedItemId, mCanvas ) );
386 attemptMoveBy( mSelectedItems.back().get(), deltaX, deltaY );
387 mSelectedItems.back().get()->setNeedsUpdatedBoundingBox( true );
388 }
390
391 return true;
392 }
393
394 return false;
395}
396
397QList<QgsAnnotationItemRubberBand *> QgsMapToolSelectAnnotation::selectedItems() const
398{
399 QList<QgsAnnotationItemRubberBand *> items;
400 for ( const std::unique_ptr<QgsAnnotationItemRubberBand> &selectedItem : mSelectedItems )
401 {
402 if ( !selectedItem.get()->boundingBox().isEmpty() )
403 {
404 items << selectedItem.get();
405 }
406 }
407 return items;
408}
409
410void QgsMapToolSelectAnnotation::onCanvasRefreshed()
411{
412 const QgsRenderedItemResults *renderedItemResults = canvas()->renderedItemResults( false );
413 if ( !renderedItemResults )
414 {
415 return;
416 }
417
418 const QList<QgsRenderedItemDetails *> items = renderedItemResults->renderedItems();
419 bool needsSelectedItemsUpdate = false;
420 for ( std::unique_ptr<QgsAnnotationItemRubberBand> &selectedItem : mSelectedItems )
421 {
422 if ( selectedItem->needsUpdatedBoundingBox() )
423 {
424 needsSelectedItemsUpdate = true;
425
426 auto it = std::find_if( items.begin(), items.end(), [&selectedItem]( const QgsRenderedItemDetails *item ) {
427 if ( const QgsRenderedAnnotationItemDetails *annotationItem = dynamic_cast<const QgsRenderedAnnotationItemDetails *>( item ) )
428 {
429 if ( annotationItem->itemId() == selectedItem->itemId() && annotationItem->layerId() == selectedItem->layerId() )
430 {
431 return true;
432 }
433 }
434 return false;
435 } );
436
437 if ( it != items.end() )
438 {
439 selectedItem->updateBoundingBox( ( *it )->boundingBox() );
440 }
441 }
442 }
443
444 if ( needsSelectedItemsUpdate )
445 {
446 emit selectedItemsChanged();
447 }
448}
449
450long long QgsMapToolSelectAnnotation::annotationItemRubberBandIndexFromId( const QString &layerId, const QString &itemId )
451{
452 if ( mSelectedItems.empty() )
453 {
454 return -1;
455 }
456
457 auto it = std::find_if( mSelectedItems.begin(), mSelectedItems.end(), [&layerId, &itemId]( auto &item ) { return item->layerId() == layerId && item->itemId() == itemId; } );
458 return it != mSelectedItems.end() ? std::distance( mSelectedItems.begin(), it ) : -1;
459}
460
461void QgsMapToolSelectAnnotation::setSelectedItemsFromRect( const QgsRectangle &mapRect, bool toggleSelection )
462{
463 const QgsRenderedItemResults *renderedItemResults = canvas()->renderedItemResults( false );
464 if ( !renderedItemResults )
465 {
466 if ( !toggleSelection )
467 {
468 clearSelectedItems();
469 }
470 return;
471 }
472
473 const QList<const QgsRenderedAnnotationItemDetails *> items = renderedItemResults->renderedAnnotationItemsInBounds( mapRect );
474 if ( items.empty() )
475 {
476 if ( !toggleSelection )
477 {
478 clearSelectedItems();
479 }
480 return;
481 }
482
483 if ( !toggleSelection )
484 {
485 mSelectedItems.clear();
486 }
487 for ( const QgsRenderedAnnotationItemDetails *item : items )
488 {
489 QgsAnnotationItem *annotationItem = annotationItemFromId( item->layerId(), item->itemId() );
490 if ( annotationItem )
491 {
492 if ( toggleSelection )
493 {
494 long long index = annotationItemRubberBandIndexFromId( item->layerId(), item->itemId() );
495 if ( index >= 0 )
496 {
497 mSelectedItems.erase( mSelectedItems.begin() + index );
498 continue;
499 }
500 }
501 mSelectedItems.push_back( std::make_unique<QgsAnnotationItemRubberBand>( item->layerId(), item->itemId(), mCanvas ) );
502 mSelectedItems.back()->updateBoundingBox( item->boundingBox() );
503 }
504 }
506 updateSelectedItem();
507}
508
509void QgsMapToolSelectAnnotation::setSelectedItemFromPoint( const QgsPointXY &mapPoint, bool toggleSelection )
510{
511 QgsRectangle searchRect = QgsRectangle( mapPoint.x(), mapPoint.y(), mapPoint.x(), mapPoint.y() );
512 searchRect.grow( searchRadiusMU( canvas() ) );
513
514 const QgsRenderedItemResults *renderedItemResults = canvas()->renderedItemResults( false );
515 if ( !renderedItemResults )
516 {
517 clearSelectedItems();
518 return;
519 }
520
521 const QList<const QgsRenderedAnnotationItemDetails *> items = renderedItemResults->renderedAnnotationItemsInBounds( searchRect );
522 if ( items.empty() )
523 {
524 if ( !toggleSelection )
525 {
526 clearSelectedItems();
527 }
528 return;
529 }
530
531 QgsRectangle itemBounds;
532 const QgsRenderedAnnotationItemDetails *closestItem = findClosestItemToPoint( mapPoint, items, itemBounds );
533 if ( !closestItem )
534 {
535 if ( !toggleSelection )
536 {
537 clearSelectedItems();
538 }
539 return;
540 }
541
542 long long index = annotationItemRubberBandIndexFromId( closestItem->layerId(), closestItem->itemId() );
543 if ( index >= 0 )
544 {
545 if ( toggleSelection )
546 {
547 mSelectedItems.erase( mSelectedItems.begin() + index );
548 }
549 }
550 else
551 {
552 if ( !toggleSelection )
553 {
554 mSelectedItems.clear();
555 }
556
557 mSelectedItems.push_back( std::make_unique<QgsAnnotationItemRubberBand>( closestItem->layerId(), closestItem->itemId(), mCanvas ) );
558 mSelectedItems.back()->updateBoundingBox( closestItem->boundingBox() );
559 }
561 updateSelectedItem();
562}
563
564void QgsMapToolSelectAnnotation::updateSelectedItem()
565{
566 if ( mSelectedItems.size() > 1 )
567 {
569 }
570 else if ( mSelectedItems.size() == 1 )
571 {
572 emit singleItemSelected( mSelectedItems[0]->layer(), mSelectedItems[0]->itemId() );
573 }
574 else
575 {
576 emit selectionCleared();
577 }
578}
579
580void QgsMapToolSelectAnnotation::clearSelectedItems()
581{
582 const bool hadSelection = !mSelectedItems.empty();
583 mSelectedItems.clear();
584
585 if ( hadSelection )
586 {
588 updateSelectedItem();
589 }
590}
591
592void QgsMapToolSelectAnnotation::attemptMoveBy( QgsAnnotationItemRubberBand *annotationItemRubberBand, double deltaX, double deltaY )
593{
594 if ( QgsAnnotationItem *annotationItem = annotationItemRubberBand->item() )
595 {
596 QgsRectangle boundingBox = annotationItemRubberBand->boundingBox();
597 const double mupp = mCanvas->mapSettings().mapUnitsPerPixel();
598 QgsVector translation( deltaX * mupp, -deltaY * mupp );
599 QgsAnnotationLayer *annotationLayer = annotationItemRubberBand->layer();
600
602 context.setCurrentItemBounds( boundingBox );
604
605 const QList<QgsAnnotationItemNode> itemNodes = annotationItem->nodesV2( context );
606 for ( const QgsAnnotationItemNode &node : itemNodes )
607 {
608 QgsPointXY mapPoint = mCanvas->mapSettings().layerToMapCoordinates( annotationLayer, node.point() );
609 mapPoint += translation;
610 QgsPointXY modifiedPoint = mCanvas->mapSettings().mapToLayerCoordinates( annotationLayer, mapPoint );
611
612 QgsAnnotationItemEditOperationMoveNode operation( annotationItemRubberBand->itemId(), node.id(), QgsPoint( node.point() ), QgsPoint( modifiedPoint ) );
613 switch ( annotationLayer->applyEditV2( &operation, context ) )
614 {
617 annotationItemRubberBand->setNeedsUpdatedBoundingBox( true );
618 break;
619
622 break;
623 }
624 }
625 boundingBox += translation;
626 annotationItemRubberBand->updateBoundingBox( boundingBox );
627 }
628}
629
630void QgsMapToolSelectAnnotation::attemptRotateBy( QgsAnnotationItemRubberBand *annotationItemRubberBand, double deltaDegree )
631{
632 if ( QgsAnnotationLayer *annotationLayer = annotationItemRubberBand->layer() )
633 {
634 const QgsRectangle boundingBox = mCanvas->mapSettings().mapToLayerCoordinates( annotationLayer, annotationItemRubberBand->boundingBox() );
636 context.setCurrentItemBounds( boundingBox );
638
639 QgsAnnotationItemEditOperationRotateItem operation( annotationItemRubberBand->itemId(), deltaDegree );
640 switch ( annotationLayer->applyEditV2( &operation, context ) )
641 {
644 annotationItemRubberBand->setNeedsUpdatedBoundingBox( true );
645 break;
646
649 break;
650 }
651 }
652}
653
654void QgsMapToolSelectAnnotation::attemptSetSceneRect( QgsAnnotationItemRubberBand *annotationItemRubberBand, const QRectF &rect )
655{
656 if ( QgsAnnotationItem *annotationItem = annotationItemRubberBand->item() )
657 {
658 const double widthRatio = rect.width() / annotationItemRubberBand->boundingRect().width();
659 const double heightRatio = rect.height() / annotationItemRubberBand->boundingRect().height();
660 const double deltaX = rect.x() - annotationItemRubberBand->x() + 1;
661 const double deltaY = rect.y() - annotationItemRubberBand->y() + 1;
662 attemptMoveBy( annotationItemRubberBand, deltaX, deltaY );
663
664 QgsAnnotationLayer *annotationLayer = annotationItemRubberBand->layer();
665 const QgsRectangle boundingBox = mCanvas->mapSettings().mapToLayerCoordinates( annotationLayer, annotationItemRubberBand->boundingBox() );
666 const QgsRectangle
667 modifiedBoundingBox( boundingBox.xMinimum(), boundingBox.yMaximum() - boundingBox.height() * heightRatio, boundingBox.xMinimum() + boundingBox.width() * widthRatio, boundingBox.yMaximum() );
668
670 context.setCurrentItemBounds( boundingBox );
672
673 const QList<QgsAnnotationItemNode> itemNodes = annotationItem->nodesV2( context );
674 for ( const QgsAnnotationItemNode &node : itemNodes )
675 {
676 const double modifiedX = modifiedBoundingBox.xMinimum() + modifiedBoundingBox.width() * ( ( node.point().x() - boundingBox.xMinimum() ) / boundingBox.width() );
677 const double modifiedY = modifiedBoundingBox.yMaximum() - modifiedBoundingBox.height() * ( ( boundingBox.yMaximum() - node.point().y() ) / boundingBox.height() );
678 QgsPointXY modifiedPoint( modifiedX, modifiedY );
679 QgsAnnotationItemEditOperationMoveNode operation( annotationItemRubberBand->itemId(), node.id(), QgsPoint( node.point() ), QgsPoint( modifiedPoint ) );
680 switch ( annotationLayer->applyEditV2( &operation, context ) )
681 {
684 annotationItemRubberBand->setNeedsUpdatedBoundingBox( true );
685 break;
686
689 break;
690 }
691 }
692 }
693}
Provides global constants and enumerations for use throughout the application.
Definition qgis.h:62
@ ScaleDependentBoundingBox
Item's bounding box will vary depending on map scale.
Definition qgis.h:2554
@ Invalid
Operation has invalid parameters for the item, no change occurred.
Definition qgis.h:2610
@ Success
Item was modified successfully.
Definition qgis.h:2609
@ ItemCleared
The operation results in the item being cleared, and the item should be removed from the layer as a r...
Definition qgis.h:2611
@ Line
Lines.
Definition qgis.h:381
@ Polygon
Polygons.
Definition qgis.h:382
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.
bool shortcutEvent(QKeyEvent *event) override
Shortcut events coming from the application for overriding.
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:369
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