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 ) );