36 class QgsAnnotationItemNodesSpatialIndex : 
public RTree<int, float, 2, float>
 
   42       std::array< float, 4 > scaledBounds = scaleBounds( bounds );
 
   45         scaledBounds[0], scaledBounds[ 1]
 
   48         scaledBounds[2], scaledBounds[3]
 
   61       std::array< float, 4 > scaledBounds = scaleBounds( bounds );
 
   64         scaledBounds[0], scaledBounds[ 1]
 
   67         scaledBounds[2], scaledBounds[3]
 
   77     bool intersects( 
const QgsRectangle &bounds, 
const std::function< 
bool( 
int index )> &callback )
 const 
   79       std::array< float, 4 > scaledBounds = scaleBounds( bounds );
 
   82         scaledBounds[0], scaledBounds[ 1]
 
   85         scaledBounds[2], scaledBounds[3]
 
   92     std::array<float, 4> scaleBounds( 
const QgsRectangle &bounds )
 const 
   96         static_cast< float >( bounds.
xMinimum() ),
 
   97         static_cast< float >( bounds.
yMinimum() ),
 
   98         static_cast< float >( bounds.
xMaximum() ),
 
   99         static_cast< float >( bounds.
yMaximum() )
 
  129   const QgsPointXY mapPoint = 
event->mapPoint();
 
  131   switch ( mCurrentAction )
 
  133     case Action::NoAction:
 
  139       if ( !renderedItemResults )
 
  161       if ( closestItem->
itemId() != mHoveredItemId || closestItem->
layerId() != mHoveredItemLayerId )
 
  163         setHoveredItem( closestItem, itemBounds );
 
  168       if ( closestItem->
itemId() == mSelectedItemId && closestItem->
layerId() == mSelectedItemLayerId )
 
  170         double currentNodeDistance = std::numeric_limits< double >::max();
 
  171         mHoveredItemNodesSpatialIndex->intersects( searchRect, [&hoveredNode, ¤tNodeDistance, &mapPoint, 
this]( 
int index )-> 
bool 
  174           const double nodeDistance = thisNode.
point().sqrDist( mapPoint );
 
  175           if ( nodeDistance < currentNodeDistance )
 
  177             hoveredNode = thisNode;
 
  178             currentNodeDistance = nodeDistance;
 
  187         if ( mHoveredNodeRubberBand )
 
  188           mHoveredNodeRubberBand->hide();
 
  189         setCursor( mHoveredItemId == mSelectedItemId && mHoveredItemLayerId == mSelectedItemLayerId ? Qt::OpenHandCursor : Qt::ArrowCursor );
 
  193         if ( !mHoveredNodeRubberBand )
 
  194           createHoveredNodeBand();
 
  198         mHoveredNodeRubberBand->show();
 
  205     case Action::MoveItem:
 
  207       if ( 
QgsAnnotationItem *item = annotationItemFromId( mSelectedItemLayerId, mSelectedItemId ) )
 
  213         std::unique_ptr< QgsAnnotationItemEditOperationTransientResults > operationResults( item->transientEditResults( &operation ) );
 
  214         if ( operationResults )
 
  217           const double scaleFactor = 
canvas()->fontMetrics().xHeight() * .2;
 
  218           mTemporaryRubberBand->
setWidth( scaleFactor );
 
  223           mTemporaryRubberBand.
reset();
 
  229     case Action::MoveNode:
 
  231       if ( 
QgsAnnotationItem *item = annotationItemFromId( mSelectedItemLayerId, mSelectedItemId ) )
 
  236         std::unique_ptr< QgsAnnotationItemEditOperationTransientResults > operationResults( item->transientEditResults( &operation ) );
 
  237         if ( operationResults )
 
  240           const double scaleFactor = 
canvas()->fontMetrics().xHeight() * .2;
 
  241           mTemporaryRubberBand->
setWidth( scaleFactor );
 
  246           mTemporaryRubberBand.
reset();
 
  257   switch ( mCurrentAction )
 
  259     case Action::NoAction:
 
  261       if ( event->button() != Qt::LeftButton )
 
  264       if ( mHoveredItemId.isEmpty() || !mHoverRubberBand )
 
  268       if ( mHoveredItemId == mSelectedItemId && mHoveredItemLayerId == mSelectedItemLayerId )
 
  273           const QgsPointXY mapPoint = 
event->mapPoint();
 
  278           double currentNodeDistance = std::numeric_limits< double >::max();
 
  279           mHoveredItemNodesSpatialIndex->intersects( searchRect, [&hoveredNode, ¤tNodeDistance, &mapPoint, 
this]( 
int index )-> 
bool 
  282             const double nodeDistance = thisNode.
point().sqrDist( mapPoint );
 
  283             if ( nodeDistance < currentNodeDistance )
 
  285               hoveredNode = thisNode;
 
  286               currentNodeDistance = nodeDistance;
 
  291           mMoveStartPointCanvasCrs = mapPoint;
 
  293           if ( mHoverRubberBand )
 
  294             mHoverRubberBand->hide();
 
  295           if ( mSelectedRubberBand )
 
  296             mSelectedRubberBand->hide();
 
  300             mCurrentAction = Action::MoveItem;
 
  304             mCurrentAction = Action::MoveNode;
 
  305             mTargetNode = hoveredNode;
 
  312         mSelectedItemId = mHoveredItemId;
 
  313         mSelectedItemLayerId = mHoveredItemLayerId;
 
  315         if ( !mSelectedRubberBand )
 
  316           createSelectedItemBand();
 
  319         mSelectedRubberBand->show();
 
  323         emit 
itemSelected( annotationLayerFromId( mSelectedItemLayerId ), mSelectedItemId );
 
  328     case Action::MoveItem:
 
  330       if ( event->button() == Qt::RightButton )
 
  332         mCurrentAction = Action::NoAction;
 
  333         mTemporaryRubberBand.
reset();
 
  334         if ( mSelectedRubberBand )
 
  337           mSelectedRubberBand->show();
 
  339         mHoveredItemNodeRubberBands.clear();
 
  342       else if ( event->button() == Qt::LeftButton )
 
  350           switch ( 
layer->applyEdit( &operation ) )
 
  354               mRefreshSelectedItemAfterRedraw = 
true;
 
  362         mTemporaryRubberBand.
reset();
 
  363         mCurrentAction = Action::NoAction;
 
  369     case Action::MoveNode:
 
  371       if ( event->button() == Qt::RightButton )
 
  373         mCurrentAction = Action::NoAction;
 
  374         mTemporaryRubberBand.
reset();
 
  375         mHoveredItemNodeRubberBands.clear();
 
  376         mTemporaryRubberBand.
reset();
 
  379       else if ( event->button() == Qt::LeftButton )
 
  385           switch ( 
layer->applyEdit( &operation ) )
 
  389               mRefreshSelectedItemAfterRedraw = 
true;
 
  398         mTemporaryRubberBand.
reset();
 
  399         mHoveredItemNodeRubberBands.clear();
 
  400         mHoveredItemNodes.clear();
 
  401         mTemporaryRubberBand.
reset();
 
  402         mCurrentAction = Action::NoAction;
 
  412   switch ( mCurrentAction )
 
  414     case Action::NoAction:
 
  415     case Action::MoveItem:
 
  417       if ( event->button() != Qt::LeftButton )
 
  420       mCurrentAction = Action::NoAction;
 
  421       if ( mHoveredItemId == mSelectedItemId && mHoveredItemLayerId == mSelectedItemLayerId )
 
  428           switch ( 
layer->applyEdit( &operation ) )
 
  432               mRefreshSelectedItemAfterRedraw = 
true;
 
  444         mSelectedItemId = mHoveredItemId;
 
  445         mSelectedItemLayerId = mHoveredItemLayerId;
 
  447         if ( !mSelectedRubberBand )
 
  448           createSelectedItemBand();
 
  451         mSelectedRubberBand->show();
 
  455         emit 
itemSelected( annotationLayerFromId( mSelectedItemLayerId ), mSelectedItemId );
 
  460     case Action::MoveNode:
 
  467   switch ( mCurrentAction )
 
  469     case Action::NoAction:
 
  471       if ( event->key() == Qt::Key_Backspace || event->key() == Qt::Key_Delete )
 
  474         if ( !
layer || mSelectedItemId.isEmpty() )
 
  477         layer->removeItem( mSelectedItemId );
 
  482       else if ( event->key() == Qt::Key_Left
 
  483                 || event->key() == Qt::Key_Right
 
  484                 || event->key() == Qt::Key_Up
 
  485                 || event->key() == Qt::Key_Down )
 
  494         switch ( 
layer->applyEdit( &operation ) )
 
  498             mRefreshSelectedItemAfterRedraw = 
true;
 
  509     case Action::MoveNode:
 
  511       if ( event->key() == Qt::Key_Delete || event->key() == Qt::Key_Backspace )
 
  516           switch ( 
layer->applyEdit( &operation ) )
 
  520               mRefreshSelectedItemAfterRedraw = 
true;
 
  530         mTemporaryRubberBand.
reset();
 
  531         mHoveredItemNodeRubberBands.clear();
 
  532         mHoveredItemNodes.clear();
 
  533         mTemporaryRubberBand.
reset();
 
  534         mCurrentAction = Action::NoAction;
 
  542     case Action::MoveItem:
 
  545       if ( event->key() == Qt::Key_Escape )
 
  547         mCurrentAction = Action::NoAction;
 
  548         mTemporaryRubberBand.
reset();
 
  549         if ( mSelectedRubberBand )
 
  552           mSelectedRubberBand->show();
 
  554         mHoveredItemNodeRubberBands.clear();
 
  563 void QgsMapToolModifyAnnotation::onCanvasRefreshed()
 
  565   if ( mRefreshSelectedItemAfterRedraw )
 
  568     if ( !renderedItemResults )
 
  573     const QList<QgsRenderedItemDetails *> items = renderedItemResults->
renderedItems();
 
  576       if ( const QgsRenderedAnnotationItemDetails *annotationItem = dynamic_cast< const QgsRenderedAnnotationItemDetails *>( item ) )
 
  578         if ( annotationItem->itemId() == mSelectedItemId && annotationItem->layerId() == mSelectedItemLayerId )
 
  583     if ( it != items.end() )
 
  588       if ( !mSelectedRubberBand )
 
  589         createSelectedItemBand();
 
  592       mSelectedRubberBand->show();
 
  595   mRefreshSelectedItemAfterRedraw = 
false;
 
  600   mHoveredItemNodeRubberBands.clear();
 
  601   if ( mHoveredNodeRubberBand )
 
  602     mHoveredNodeRubberBand->hide();
 
  603   mHoveredItemId = item->
itemId();
 
  604   mHoveredItemLayerId = item->
layerId();
 
  605   if ( !mHoverRubberBand )
 
  608   mHoverRubberBand->show();
 
  619   if ( !annotationItem )
 
  624   const double scaleFactor = 
canvas()->fontMetrics().xHeight() * .2;
 
  626   const QList< QgsAnnotationItemNode > itemNodes = annotationItem->
nodes();
 
  630   vertexNodeBand->
setWidth( scaleFactor );
 
  632   vertexNodeBand->
setColor( QColor( 200, 0, 120, 255 ) );
 
  635   mHoveredItemNodesSpatialIndex = std::make_unique< QgsAnnotationItemNodesSpatialIndex >();
 
  637   mHoveredItemNodes.clear();
 
  638   mHoveredItemNodes.reserve( itemNodes.size() );
 
  644       nodeMapPoint = layerToMapTransform.
transform( node.point() );
 
  651     switch ( node.type() )
 
  654         vertexNodeBand->
addPoint( nodeMapPoint );
 
  658     mHoveredItemNodesSpatialIndex->insert( index, 
QgsRectangle( nodeMapPoint.
x(), nodeMapPoint.
y(),
 
  659                                            nodeMapPoint.
x(), nodeMapPoint.
y() ) );
 
  662     transformedNode.
setPoint( nodeMapPoint );
 
  663     mHoveredItemNodes.append( transformedNode );
 
  668   mHoveredItemNodeRubberBands.emplace_back( vertexNodeBand );
 
  671 QSizeF QgsMapToolModifyAnnotation::deltaForKeyEvent( 
QgsAnnotationLayer *layer, 
const QgsPointXY &originalCanvasPoint, QKeyEvent *event )
 
  673   const double canvasDpi = 
canvas()->window()->windowHandle()->screen()->physicalDotsPerInch();
 
  676   double incrementPixels = 0.0;
 
  677   if ( event->modifiers() & Qt::ShiftModifier )
 
  680     incrementPixels = 20.0 / 25.4 * canvasDpi;
 
  682   else if ( event->modifiers() & Qt::AltModifier )
 
  690     incrementPixels = 5.0 / 25.4 * canvasDpi;
 
  693   double deltaXPixels = 0;
 
  694   double deltaYPixels = 0;
 
  695   switch ( event->key() )
 
  698       deltaXPixels = -incrementPixels;
 
  701       deltaXPixels = incrementPixels;
 
  704       deltaYPixels = -incrementPixels;
 
  707       deltaYPixels = incrementPixels;
 
  716   const QgsPointXY afterMoveCanvasPoint( originalCanvasPoint.
x() + deltaXPixels, originalCanvasPoint.
y() + deltaYPixels );
 
  720   return QSizeF( afterMoveLayerPoint.
x() - beforeMoveLayerPoint.
x(), afterMoveLayerPoint.
y() - beforeMoveLayerPoint.
y() );
 
  726   double closestItemDistance = std::numeric_limits< double >::max();
 
  727   int closestItemZ = 0;
 
  732     if ( !annotationItem )
 
  736     const double itemDistance = itemBounds.
contains( mapPoint ) ? 0 : itemBounds.
distance( mapPoint );
 
  737     if ( !closestItem || itemDistance < closestItemDistance || ( itemDistance == closestItemDistance && annotationItem->
zIndex() > closestItemZ ) )
 
  740       closestItemDistance = itemDistance;
 
  741       closestItemZ = annotationItem->
zIndex();
 
  748 QgsAnnotationLayer *QgsMapToolModifyAnnotation::annotationLayerFromId( 
const QString &layerId )
 
  756 QgsAnnotationItem *QgsMapToolModifyAnnotation::annotationItemFromId( 
const QString &layerId, 
const QString &itemId )
 
  759   return layer ? 
layer->item( itemId ) : 
nullptr;
 
  762 void QgsMapToolModifyAnnotation::clearHoveredItem()
 
  764   if ( mHoverRubberBand )
 
  765     mHoverRubberBand->hide();
 
  766   if ( mHoveredNodeRubberBand )
 
  767     mHoveredNodeRubberBand->hide();
 
  769   mHoveredItemId.clear();
 
  770   mHoveredItemLayerId.clear();
 
  771   mHoveredItemNodeRubberBands.clear();
 
  772   mHoveredItemNodesSpatialIndex.reset();
 
  777 void QgsMapToolModifyAnnotation::clearSelectedItem()
 
  779   if ( mSelectedRubberBand )
 
  780     mSelectedRubberBand->hide();
 
  782   const bool hadSelection = !mSelectedItemId.isEmpty();
 
  783   mSelectedItemId.clear();
 
  784   mSelectedItemLayerId.clear();
 
  789 void QgsMapToolModifyAnnotation::createHoverBand()
 
  791   const double scaleFactor = 
canvas()->fontMetrics().xHeight() * .2;
 
  794   mHoverRubberBand->
setWidth( scaleFactor );
 
  796   mHoverRubberBand->
setColor( QColor( 100, 100, 100, 155 ) );
 
  799 void QgsMapToolModifyAnnotation::createHoveredNodeBand()
 
  801   const double scaleFactor = 
canvas()->fontMetrics().xHeight() * .2;
 
  805   mHoveredNodeRubberBand->
setWidth( scaleFactor );
 
  806   mHoveredNodeRubberBand->
setIconSize( scaleFactor * 5 );
 
  807   mHoveredNodeRubberBand->
setColor( QColor( 200, 0, 120, 255 ) );
 
  810 void QgsMapToolModifyAnnotation::createSelectedItemBand()
 
  812   const double scaleFactor = 
canvas()->fontMetrics().xHeight() * .2;
 
  815   mSelectedRubberBand->
setWidth( scaleFactor );
 
  817   mSelectedRubberBand->
setColor( QColor( 50, 50, 50, 200 ) );