Skip to content

Commit

Permalink
[feature][layouts] Expose option to clip maps to a shape or polygon item
Browse files Browse the repository at this point in the history
in UI

Allows users to clip a map item to a shape or polygon item from their layout,
allowing for non-rectangular maps in the layout
  • Loading branch information
nyalldawson committed Jul 30, 2020
1 parent 6d647aa commit ed2cca4
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 5 deletions.
23 changes: 19 additions & 4 deletions src/core/layout/qgslayoutitemmap.cpp
Expand Up @@ -2874,6 +2874,12 @@ void QgsLayoutItemMapItemClipPathSettings::setEnabled( bool enabled )
return;

mEnabled = enabled;

if ( mClipPathSource )
{
// may need to refresh the clip source in order to get it to render/not render depending on enabled state
mClipPathSource->refresh();
}
emit changed();
}

Expand Down Expand Up @@ -2913,22 +2919,31 @@ void QgsLayoutItemMapItemClipPathSettings::setSourceItem( QgsLayoutItem *item )

if ( mClipPathSource )
{
disconnect( mClipPathSource, &QgsLayoutItem::sizePositionChanged, mMap, &QgsLayoutItemMap::refresh );
disconnect( mClipPathSource, &QgsLayoutItem::clipPathChanged, mMap, &QgsLayoutItemMap::refresh );
disconnect( mClipPathSource, &QgsLayoutItem::rotationChanged, mMap, &QgsLayoutItemMap::refresh );
disconnect( mClipPathSource, &QgsLayoutItem::sizePositionChanged, mMap, &QgsLayoutItemMap::extentChanged );
disconnect( mClipPathSource, &QgsLayoutItem::clipPathChanged, mMap, &QgsLayoutItemMap::extentChanged );
disconnect( mClipPathSource, &QgsLayoutItem::rotationChanged, mMap, &QgsLayoutItemMap::extentChanged );
}

QgsLayoutItem *oldItem = mClipPathSource;
mClipPathSource = item;

if ( mClipPathSource )
{
// if item size or rotation changes, we need to redraw this map
connect( mClipPathSource, &QgsLayoutItem::sizePositionChanged, mMap, &QgsLayoutItemMap::refresh );
connect( mClipPathSource, &QgsLayoutItem::clipPathChanged, mMap, &QgsLayoutItemMap::refresh );
connect( mClipPathSource, &QgsLayoutItem::rotationChanged, mMap, &QgsLayoutItemMap::refresh );
// and if clip item size or rotation changes, then effectively we've changed the visible extent of the map
connect( mClipPathSource, &QgsLayoutItem::sizePositionChanged, mMap, &QgsLayoutItemMap::extentChanged );
connect( mClipPathSource, &QgsLayoutItem::clipPathChanged, mMap, &QgsLayoutItemMap::extentChanged );
connect( mClipPathSource, &QgsLayoutItem::rotationChanged, mMap, &QgsLayoutItemMap::extentChanged );
// trigger a redraw of the clip source, so that it becomes invisible
mClipPathSource->refresh();
}

if ( oldItem )
{
// may need to refresh the previous item in order to get it to render
oldItem->refresh();
}

emit changed();
Expand Down
52 changes: 52 additions & 0 deletions src/gui/layout/qgslayoutmapwidget.cpp
Expand Up @@ -1970,6 +1970,14 @@ QgsLayoutMapClippingWidget::QgsLayoutMapClippingWidget( QgsLayoutItemMap *map )
mAtlasClippingTypeComboBox->addItem( tr( "Clip Feature Before Render" ), static_cast< int >( QgsMapClippingRegion::FeatureClippingType::ClipToIntersection ) );
mAtlasClippingTypeComboBox->addItem( tr( "Render Intersecting Features Unchanged" ), static_cast< int >( QgsMapClippingRegion::FeatureClippingType::NoClipping ) );

for ( int i = 0; i < mAtlasClippingTypeComboBox->count(); ++i )
{
mItemClippingTypeComboBox->addItem( mAtlasClippingTypeComboBox->itemText( i ), mAtlasClippingTypeComboBox->itemData( i ) );
}

mClipItemComboBox->setCurrentLayout( map->layout() );
mClipItemComboBox->setItemFlags( QgsLayoutItem::FlagProvidesClipPath );

connect( mRadioClipSelectedLayers, &QRadioButton::toggled, mLayersTreeView, &QWidget::setEnabled );
mLayersTreeView->setEnabled( false );
mRadioClipAllLayers->setChecked( true );
Expand Down Expand Up @@ -2039,6 +2047,45 @@ QgsLayoutMapClippingWidget::QgsLayoutMapClippingWidget( QgsLayoutItemMap *map )
}
} );

// item clipping widgets

connect( mClipToItemCheckBox, &QGroupBox::toggled, this, [ = ]( bool active )
{
if ( !mBlockUpdates )
{
mMapItem->beginCommand( tr( "Toggle Map Clipping" ) );
mMapItem->itemClippingSettings()->setEnabled( active );
mMapItem->endCommand();
}
} );
connect( mItemClippingTypeComboBox, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, [ = ]
{
if ( !mBlockUpdates )
{
mMapItem->beginCommand( tr( "Change Map Clipping Behavior" ) );
mMapItem->itemClippingSettings()->setFeatureClippingType( static_cast< QgsMapClippingRegion::FeatureClippingType >( mItemClippingTypeComboBox->currentData().toInt() ) );
mMapItem->endCommand();
}
} );
connect( mForceLabelsInsideItemCheckBox, &QCheckBox::toggled, this, [ = ]( bool active )
{
if ( !mBlockUpdates )
{
mMapItem->beginCommand( tr( "Change Map Clipping Label Behavior" ) );
mMapItem->itemClippingSettings()->setForceLabelsInsideClipPath( active );
mMapItem->endCommand();
}
} );
connect( mClipItemComboBox, &QgsLayoutItemComboBox::itemChanged, this, [ = ]( QgsLayoutItem * item )
{
if ( !mBlockUpdates )
{
mMapItem->beginCommand( tr( "Change Map Clipping Item" ) );
mMapItem->itemClippingSettings()->setSourceItem( item );
mMapItem->endCommand();
}
} );

setNewItem( map );

connect( &map->layout()->reportContext(), &QgsLayoutReportContext::layerChanged,
Expand Down Expand Up @@ -2093,6 +2140,11 @@ void QgsLayoutMapClippingWidget::updateGuiElements()
mRadioClipSelectedLayers->setChecked( !mMapItem->atlasClippingSettings()->layersToClip().isEmpty() );
mLayerModel->setLayersChecked( mMapItem->atlasClippingSettings()->layersToClip() );

mClipToItemCheckBox->setChecked( mMapItem->itemClippingSettings()->enabled() );
mItemClippingTypeComboBox->setCurrentIndex( mItemClippingTypeComboBox->findData( static_cast< int >( mMapItem->itemClippingSettings()->featureClippingType() ) ) );
mForceLabelsInsideItemCheckBox->setChecked( mMapItem->itemClippingSettings()->forceLabelsInsideClipPath() );
mClipItemComboBox->setItem( mMapItem->itemClippingSettings()->sourceItem() );

mBlockUpdates = false;
}

Expand Down
52 changes: 51 additions & 1 deletion src/ui/layout/qgslayoutmapclippingwidgetbase.ui
Expand Up @@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>318</width>
<height>408</height>
<height>619</height>
</rect>
</property>
<property name="sizePolicy">
Expand Down Expand Up @@ -98,6 +98,51 @@
</layout>
</widget>
</item>
<item>
<widget class="QgsCollapsibleGroupBox" name="mClipToItemCheckBox">
<property name="title">
<string>Clip to item</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>The clipping mode determines how features from vector layers will be clipped.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="mClipToAtlasLabel_2">
<property name="text">
<string>&lt;b&gt;When enabled, the map will be automatically clipped to the selected shape.&lt;/b&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QComboBox" name="mItemClippingTypeComboBox"/>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="mForceLabelsInsideItemCheckBox">
<property name="text">
<string>Force labels inside clipping shape</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QgsLayoutItemComboBox" name="mClipItemComboBox"/>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
Expand All @@ -121,6 +166,11 @@
<header>qgscollapsiblegroupbox.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>QgsLayoutItemComboBox</class>
<extends>QComboBox</extends>
<header>qgslayoutitemcombobox.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
Expand Down

0 comments on commit ed2cca4

Please sign in to comment.