mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
[FEATURE][layouts] Add a dedicated toolbar action to create north arrows
This is a shortcut to adding a picture item, setting it to a north arrow picture, and linking it with a map. The end result is identical, but it's much easier for new users to understand if we expose it as an explicit "North Arrow" item. Even experienced users will likely appreciate the improved workflow, including automatically linking the picture rotation to a sensible default map choice (if a map is selected, it's used. If not, the topmost map item under the newly drawn north arrow is used. If there's none, the layout's 'reference map' (or biggest map) is used as a fallback) Fixes #30162
This commit is contained in:
parent
26c83dac78
commit
0ccc8f15ff
@ -756,6 +756,7 @@
|
||||
<file>themes/default/mActionNewVirtualLayer.svg</file>
|
||||
<file>themes/default/mActionDoubleArrowRight.svg</file>
|
||||
<file>themes/default/mActionDoubleArrowLeft.svg</file>
|
||||
<file>north_arrows/layout_default_north_arrow.svg</file>
|
||||
</qresource>
|
||||
<qresource prefix="/images/tips">
|
||||
<file alias="symbol_levels.png">qgis_tips/symbol_levels.png</file>
|
||||
|
@ -47,6 +47,45 @@
|
||||
#include "qgslayout3dmapwidget.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Attempts to find the best guess at a map item to link \a referenceItem to,
|
||||
* by:
|
||||
* 1. Prioritising a selected map
|
||||
* 2. If no selection, prioritising the topmost map the item was drawn over
|
||||
* 3. If still none, use the layout's reference map (or biggest map)
|
||||
*/
|
||||
QgsLayoutItemMap *findSensibleDefaultLinkedMapItem( QgsLayoutItem *referenceItem )
|
||||
{
|
||||
// start by trying to find a selected map
|
||||
QList<QgsLayoutItemMap *> mapItems;
|
||||
referenceItem->layout()->layoutItems( mapItems );
|
||||
|
||||
QgsLayoutItemMap *targetMap = nullptr;
|
||||
for ( QgsLayoutItemMap *map : qgis::as_const( mapItems ) )
|
||||
{
|
||||
if ( map->isSelected() )
|
||||
{
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
// nope, no selection... hm, was the item drawn over a map? If so, use the topmost intersecting one
|
||||
double largestZValue = std::numeric_limits< double >::lowest();
|
||||
for ( QgsLayoutItemMap *map : qgis::as_const( mapItems ) )
|
||||
{
|
||||
if ( map->collidesWithItem( referenceItem ) && map->zValue() > largestZValue )
|
||||
{
|
||||
targetMap = map;
|
||||
largestZValue = map->zValue();
|
||||
}
|
||||
}
|
||||
if ( targetMap )
|
||||
return targetMap;
|
||||
|
||||
// ah frick it, just use the reference (or biggest!) map
|
||||
return referenceItem->layout()->referenceMap();
|
||||
}
|
||||
|
||||
void QgsLayoutAppUtils::registerGuiForKnownItemTypes()
|
||||
{
|
||||
QgsLayoutItemGuiRegistry *registry = QgsGui::layoutItemGuiRegistry();
|
||||
@ -153,29 +192,8 @@ void QgsLayoutAppUtils::registerGuiForKnownItemTypes()
|
||||
QgsLayoutItemLegend *legend = qobject_cast< QgsLayoutItemLegend * >( item );
|
||||
Q_ASSERT( legend );
|
||||
|
||||
QList<QgsLayoutItemMap *> mapItems;
|
||||
legend->layout()->layoutItems( mapItems );
|
||||
|
||||
// try to find a good map to link the legend with by default
|
||||
// start by trying to find a selected map
|
||||
QgsLayoutItemMap *targetMap = nullptr;
|
||||
for ( QgsLayoutItemMap *map : qgis::as_const( mapItems ) )
|
||||
{
|
||||
if ( map->isSelected() )
|
||||
{
|
||||
targetMap = map;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// otherwise just use first map
|
||||
if ( !targetMap && !mapItems.isEmpty() )
|
||||
{
|
||||
targetMap = mapItems.at( 0 );
|
||||
}
|
||||
if ( targetMap )
|
||||
{
|
||||
legend->setLinkedMap( targetMap );
|
||||
}
|
||||
legend->setLinkedMap( findSensibleDefaultLinkedMapItem( legend ) );
|
||||
|
||||
legend->updateLegend();
|
||||
} );
|
||||
@ -194,26 +212,8 @@ void QgsLayoutAppUtils::registerGuiForKnownItemTypes()
|
||||
QgsLayoutItemScaleBar *scalebar = qobject_cast< QgsLayoutItemScaleBar * >( item );
|
||||
Q_ASSERT( scalebar );
|
||||
|
||||
QList<QgsLayoutItemMap *> mapItems;
|
||||
scalebar->layout()->layoutItems( mapItems );
|
||||
|
||||
// try to find a good map to link the scalebar with by default
|
||||
// start by trying to find a selected map
|
||||
QgsLayoutItemMap *targetMap = nullptr;
|
||||
for ( QgsLayoutItemMap *map : qgis::as_const( mapItems ) )
|
||||
{
|
||||
if ( map->isSelected() )
|
||||
{
|
||||
targetMap = map;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// otherwise just use first map
|
||||
if ( !targetMap && !mapItems.isEmpty() )
|
||||
{
|
||||
targetMap = mapItems.at( 0 );
|
||||
}
|
||||
if ( targetMap )
|
||||
if ( QgsLayoutItemMap *targetMap = findSensibleDefaultLinkedMapItem( scalebar ) )
|
||||
{
|
||||
scalebar->setLinkedMap( targetMap );
|
||||
scalebar->applyDefaultSize( scalebar->guessUnits() );
|
||||
@ -222,6 +222,34 @@ void QgsLayoutAppUtils::registerGuiForKnownItemTypes()
|
||||
|
||||
registry->addLayoutItemGuiMetadata( scalebarItemMetadata.release() );
|
||||
|
||||
|
||||
// north arrow
|
||||
std::unique_ptr< QgsLayoutItemGuiMetadata > northArrowMetadata = qgis::make_unique< QgsLayoutItemGuiMetadata>(
|
||||
QgsLayoutItemRegistry::LayoutPicture, QObject::tr( "North Arrow" ), QgsApplication::getThemeIcon( QStringLiteral( "/north_arrow.svg" ) ),
|
||||
[ = ]( QgsLayoutItem * item )->QgsLayoutItemBaseWidget *
|
||||
{
|
||||
return new QgsLayoutPictureWidget( qobject_cast< QgsLayoutItemPicture * >( item ) );
|
||||
}, createRubberBand );
|
||||
northArrowMetadata->setItemCreationFunction( []( QgsLayout * layout )->QgsLayoutItem *
|
||||
{
|
||||
std::unique_ptr< QgsLayoutItemPicture > picture = qgis::make_unique< QgsLayoutItemPicture >( layout );
|
||||
picture->setNorthMode( QgsLayoutItemPicture::GridNorth );
|
||||
picture->setPicturePath( QStringLiteral( ":/images/north_arrows/layout_default_north_arrow.svg" ) );
|
||||
return picture.release();
|
||||
} );
|
||||
northArrowMetadata->setItemAddedToLayoutFunction( [ = ]( QgsLayoutItem * item )
|
||||
{
|
||||
QgsLayoutItemPicture *picture = qobject_cast< QgsLayoutItemPicture * >( item );
|
||||
Q_ASSERT( picture );
|
||||
|
||||
QList<QgsLayoutItemMap *> mapItems;
|
||||
picture->layout()->layoutItems( mapItems );
|
||||
|
||||
// try to find a good map to link the north arrow with by default
|
||||
picture->setLinkedMap( findSensibleDefaultLinkedMapItem( picture ) );
|
||||
} );
|
||||
registry->addLayoutItemGuiMetadata( northArrowMetadata.release() );
|
||||
|
||||
// shape items
|
||||
|
||||
auto createShapeWidget =
|
||||
@ -271,7 +299,6 @@ void QgsLayoutAppUtils::registerGuiForKnownItemTypes()
|
||||
} );
|
||||
registry->addLayoutItemGuiMetadata( arrowMetadata.release() );
|
||||
|
||||
|
||||
// node items
|
||||
|
||||
std::unique_ptr< QgsLayoutItemGuiMetadata > polygonMetadata = qgis::make_unique< QgsLayoutItemGuiMetadata >(
|
||||
|
Loading…
x
Reference in New Issue
Block a user