Skip to content
Permalink
Browse files

Work on resizing layouts to item bounds

  • Loading branch information
nyalldawson committed Dec 17, 2017
1 parent f4f5f75 commit fe5bd47eb06f38676ff4481dfbbc0acc06d42d0c
@@ -282,6 +282,16 @@ Returns the space between pages, in layout units.
Returns the size of the page shadow, in layout units.
%End

void resizeToContents( const QgsMargins &margins, QgsUnitTypes::LayoutUnit marginUnits );
%Docstring
Resizes the layout to a single page which fits the current contents of the layout.

Calling this method resets the number of pages to 1, with the size set to the
minimum size required to fit all existing layout items. Items will also be
repositioned so that the new top-left bounds of the layout is at the point
(marginLeft, marginTop). An optional margin can be specified.
%End

virtual bool writeXml( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context ) const;

%Docstring
@@ -18,11 +18,14 @@
#include "qgslayout.h"
#include "qgslayoutsnapper.h"
#include "qgslayoutpagecollection.h"
#include "qgslayoutundostack.h"

QgsLayoutPropertiesWidget::QgsLayoutPropertiesWidget( QWidget *parent, QgsLayout *layout )
: QgsPanelWidget( parent )
, mLayout( layout )
{
Q_ASSERT( mLayout );

setupUi( this );
setPanelTitle( tr( "Layout properties" ) );
blockSignals( true );
@@ -42,6 +45,30 @@ QgsLayoutPropertiesWidget::QgsLayoutPropertiesWidget( QWidget *parent, QgsLayout
connect( mGridResolutionSpinBox, static_cast < void ( QgsDoubleSpinBox::* )( double ) > ( &QgsDoubleSpinBox::valueChanged ), this, &QgsLayoutPropertiesWidget::gridResolutionChanged );
connect( mOffsetXSpinBox, static_cast < void ( QgsDoubleSpinBox::* )( double ) > ( &QgsDoubleSpinBox::valueChanged ), this, &QgsLayoutPropertiesWidget::gridOffsetXChanged );
connect( mOffsetYSpinBox, static_cast < void ( QgsDoubleSpinBox::* )( double ) > ( &QgsDoubleSpinBox::valueChanged ), this, &QgsLayoutPropertiesWidget::gridOffsetYChanged );

double leftMargin = mLayout->customProperty( QStringLiteral( "resizeToContentsLeftMargin" ) ).toDouble();
double topMargin = mLayout->customProperty( QStringLiteral( "resizeToContentsTopMargin" ) ).toDouble();
double bottomMargin = mLayout->customProperty( QStringLiteral( "resizeToContentsBottomMargin" ) ).toDouble();
double rightMargin = mLayout->customProperty( QStringLiteral( "resizeToContentsRightMargin" ) ).toDouble();
QgsUnitTypes::LayoutUnit marginUnit = static_cast< QgsUnitTypes::LayoutUnit >(
mLayout->customProperty( QStringLiteral( "imageCropMarginUnit" ), QgsUnitTypes::LayoutMillimeters ).toInt() );

mTopMarginSpinBox->setValue( topMargin );
mMarginUnitsComboBox->linkToWidget( mTopMarginSpinBox );
mRightMarginSpinBox->setValue( rightMargin );
mMarginUnitsComboBox->linkToWidget( mRightMarginSpinBox );
mBottomMarginSpinBox->setValue( bottomMargin );
mMarginUnitsComboBox->linkToWidget( mBottomMarginSpinBox );
mLeftMarginSpinBox->setValue( leftMargin );
mMarginUnitsComboBox->linkToWidget( mLeftMarginSpinBox );
mMarginUnitsComboBox->setUnit( marginUnit );
mMarginUnitsComboBox->setConverter( &mLayout->context().measurementConverter() );

connect( mTopMarginSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutPropertiesWidget::resizeMarginsChanged );
connect( mRightMarginSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutPropertiesWidget::resizeMarginsChanged );
connect( mBottomMarginSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutPropertiesWidget::resizeMarginsChanged );
connect( mLeftMarginSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutPropertiesWidget::resizeMarginsChanged );
connect( mResizePageButton, &QPushButton::clicked, this, &QgsLayoutPropertiesWidget::resizeToContents );
}

void QgsLayoutPropertiesWidget::updateSnappingElements()
@@ -101,6 +128,28 @@ void QgsLayoutPropertiesWidget::snapToleranceChanged( int tolerance )
mLayout->snapper().setSnapTolerance( tolerance );
}

void QgsLayoutPropertiesWidget::resizeMarginsChanged()
{
mLayout->setCustomProperty( QStringLiteral( "resizeToContentsLeftMargin" ), mLeftMarginSpinBox->value() );
mLayout->setCustomProperty( QStringLiteral( "resizeToContentsTopMargin" ), mTopMarginSpinBox->value() );
mLayout->setCustomProperty( QStringLiteral( "resizeToContentsBottomMargin" ), mBottomMarginSpinBox->value() );
mLayout->setCustomProperty( QStringLiteral( "resizeToContentsRightMargin" ), mRightMarginSpinBox->value() );
mLayout->setCustomProperty( QStringLiteral( "imageCropMarginUnit" ), mMarginUnitsComboBox->unit() );
}

void QgsLayoutPropertiesWidget::resizeToContents()
{
mLayout->undoStack()->beginMacro( tr( "Resize to Contents" ) );

mLayout->pageCollection()->resizeToContents( QgsMargins( mLeftMarginSpinBox->value(),
mTopMarginSpinBox->value(),
mRightMarginSpinBox->value(),
mBottomMarginSpinBox->value() ),
mMarginUnitsComboBox->unit() );

mLayout->undoStack()->endMacro();
}

void QgsLayoutPropertiesWidget::blockSignals( bool block )
{
mGridResolutionSpinBox->blockSignals( block );
@@ -36,6 +36,8 @@ class QgsLayoutPropertiesWidget: public QgsPanelWidget, private Ui::QgsLayoutWid
void gridOffsetYChanged( double d );
void gridOffsetUnitsChanged( QgsUnitTypes::LayoutUnit unit );
void snapToleranceChanged( int tolerance );
void resizeMarginsChanged();
void resizeToContents();

private:

@@ -199,6 +199,77 @@ double QgsLayoutPageCollection::pageShadowWidth() const
return spaceBetweenPages() / 2;
}

void QgsLayoutPageCollection::resizeToContents( const QgsMargins &margins, QgsUnitTypes::LayoutUnit marginUnits )
{
if ( !mBlockUndoCommands )
mLayout->undoStack()->beginCommand( this, tr( "Resize to Contents" ) );

//calculate current bounds
QRectF bounds = mLayout->layoutBounds( true, 0.0 );

for ( int page = mPages.count() - 1; page > 0; page-- )
{
deletePage( page );
}

if ( mPages.empty() )
{
std::unique_ptr< QgsLayoutItemPage > page = qgis::make_unique< QgsLayoutItemPage >( mLayout );
addPage( page.release() );
}

QgsLayoutItemPage *page = mPages.at( 0 );

double marginLeft = mLayout->convertToLayoutUnits( QgsLayoutMeasurement( margins.left(), marginUnits ) );
double marginTop = mLayout->convertToLayoutUnits( QgsLayoutMeasurement( margins.top(), marginUnits ) );
double marginBottom = mLayout->convertToLayoutUnits( QgsLayoutMeasurement( margins.bottom(), marginUnits ) );
double marginRight = mLayout->convertToLayoutUnits( QgsLayoutMeasurement( margins.right(), marginUnits ) );

bounds.setWidth( bounds.width() + marginLeft + marginRight );
bounds.setHeight( bounds.height() + marginTop + marginBottom );

QgsLayoutSize newPageSize = mLayout->convertFromLayoutUnits( bounds.size(), mLayout->units() );
page->setPageSize( newPageSize );

reflow();

//also move all items so that top-left of bounds is at marginLeft, marginTop
double diffX = marginLeft - bounds.left();
double diffY = marginTop - bounds.top();

const QList<QGraphicsItem *> itemList = mLayout->items();
for ( QGraphicsItem *item : itemList )
{
if ( QgsLayoutItem *layoutItem = dynamic_cast<QgsLayoutItem *>( item ) )
{
QgsLayoutItemPage *pageItem = dynamic_cast<QgsLayoutItemPage *>( layoutItem );
if ( !pageItem )
{
layoutItem->beginCommand( tr( "Move Item" ) );
layoutItem->attemptMoveBy( diffX, diffY );
layoutItem->endCommand();
}
}
}

//also move guides
mLayout->undoStack()->beginCommand( &mLayout->guides(), tr( "Move Guides" ) );
const QList< QgsLayoutGuide * > verticalGuides = mLayout->guides().guides( Qt::Vertical );
for ( QgsLayoutGuide *guide : verticalGuides )
{
guide->setLayoutPosition( guide->layoutPosition() + diffX );
}
const QList< QgsLayoutGuide * > horizontalGuides = mLayout->guides().guides( Qt::Horizontal );
for ( QgsLayoutGuide *guide : horizontalGuides )
{
guide->setLayoutPosition( guide->layoutPosition() + diffY );
}
mLayout->undoStack()->endCommand();

if ( !mBlockUndoCommands )
mLayout->undoStack()->endCommand();
}

bool QgsLayoutPageCollection::writeXml( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context ) const
{
QDomElement element = document.createElement( QStringLiteral( "PageCollection" ) );
@@ -306,6 +306,16 @@ class CORE_EXPORT QgsLayoutPageCollection : public QObject, public QgsLayoutSeri
*/
double pageShadowWidth() const;

/**
* Resizes the layout to a single page which fits the current contents of the layout.
*
* Calling this method resets the number of pages to 1, with the size set to the
* minimum size required to fit all existing layout items. Items will also be
* repositioned so that the new top-left bounds of the layout is at the point
* (marginLeft, marginTop). An optional margin can be specified.
*/
void resizeToContents( const QgsMargins &margins, QgsUnitTypes::LayoutUnit marginUnits );

/**
* Stores the collection's state in a DOM element. The \a parentElement should refer to the parent layout's DOM element.
* \see readXml()
@@ -175,6 +175,126 @@
</layout>
</widget>
</item>
<item>
<widget class="QgsCollapsibleGroupBoxBasic" name="groupBox_5">
<property name="title">
<string>Resize layout to content</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,1">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Margin units</string>
</property>
</widget>
</item>
<item>
<widget class="QgsLayoutUnitsComboBox" name="mMarginUnitsComboBox"/>
</item>
</layout>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="1">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Top margin</string>
</property>
</widget>
</item>
<item row="0" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="3">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="2">
<widget class="QgsDoubleSpinBox" name="mTopMarginSpinBox">
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="1" column="0" colspan="4">
<layout class="QHBoxLayout" name="horizontalLayout_7">
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>Left</string>
</property>
</widget>
</item>
<item>
<widget class="QgsDoubleSpinBox" name="mLeftMarginSpinBox">
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_11">
<property name="text">
<string>Right</string>
</property>
</widget>
</item>
<item>
<widget class="QgsDoubleSpinBox" name="mRightMarginSpinBox">
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="1">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Bottom</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QgsDoubleSpinBox" name="mBottomMarginSpinBox">
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
<item row="3" column="1" colspan="2">
<widget class="QPushButton" name="mResizePageButton">
<property name="text">
<string>Resize layout</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
@@ -196,16 +316,6 @@
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>QgsDoubleSpinBox</class>
<extends>QDoubleSpinBox</extends>
<header>qgsdoublespinbox.h</header>
</customwidget>
<customwidget>
<class>QgsLayoutUnitsComboBox</class>
<extends>QComboBox</extends>
<header>qgslayoutunitscombobox.h</header>
</customwidget>
<customwidget>
<class>QgsScrollArea</class>
<extends>QScrollArea</extends>
@@ -218,6 +328,16 @@
<header>qgscollapsiblegroupbox.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>QgsDoubleSpinBox</class>
<extends>QDoubleSpinBox</extends>
<header>qgsdoublespinbox.h</header>
</customwidget>
<customwidget>
<class>QgsLayoutUnitsComboBox</class>
<extends>QComboBox</extends>
<header>qgslayoutunitscombobox.h</header>
</customwidget>
<customwidget>
<class>QgsSpinBox</class>
<extends>QSpinBox</extends>
@@ -233,6 +353,12 @@
<tabstop>mOffsetYSpinBox</tabstop>
<tabstop>mGridOffsetUnitsComboBox</tabstop>
<tabstop>mSnapToleranceSpinBox</tabstop>
<tabstop>mMarginUnitsComboBox</tabstop>
<tabstop>mTopMarginSpinBox</tabstop>
<tabstop>mLeftMarginSpinBox</tabstop>
<tabstop>mRightMarginSpinBox</tabstop>
<tabstop>mBottomMarginSpinBox</tabstop>
<tabstop>mResizePageButton</tabstop>
</tabstops>
<resources/>
<connections/>

0 comments on commit fe5bd47

Please sign in to comment.
You can’t perform that action at this time.