Skip to content

Commit

Permalink
Merge pull request #9454 from nastasi-oq/distribute-equispaced2
Browse files Browse the repository at this point in the history
[layout] add new vertical and horizontal equispaced distributions
  • Loading branch information
nyalldawson committed Mar 11, 2019
2 parents 8e39f0f + ae0e12b commit 0b270f9
Show file tree
Hide file tree
Showing 9 changed files with 250 additions and 3 deletions.
2 changes: 2 additions & 0 deletions images/images.qrc
Expand Up @@ -167,10 +167,12 @@
<file>themes/default/mActionDataSourceManager.svg</file>
<file>themes/default/mActionDistributeBottom.svg</file>
<file>themes/default/mActionDistributeHCenter.svg</file>
<file>themes/default/mActionDistributeHSpace.svg</file>
<file>themes/default/mActionDistributeLeft.svg</file>
<file>themes/default/mActionDistributeRight.svg</file>
<file>themes/default/mActionDistributeTop.svg</file>
<file>themes/default/mActionDistributeVCenter.svg</file>
<file>themes/default/mActionDistributeVSpace.svg</file>
<file>themes/default/mActionAddLayer.svg</file>
<file>themes/default/mActionAddMeshLayer.svg</file>
<file>themes/default/mActionAddAllToOverview.svg</file>
Expand Down
49 changes: 49 additions & 0 deletions images/themes/default/mActionDistributeHSpace.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
49 changes: 49 additions & 0 deletions images/themes/default/mActionDistributeVSpace.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions python/core/auto_generated/layout/qgslayoutaligner.sip.in
Expand Up @@ -38,9 +38,11 @@ sets of layout items, e.g. aligning a group of items to top or left sides.
{
DistributeLeft,
DistributeHCenter,
DistributeHSpace,
DistributeRight,
DistributeTop,
DistributeVCenter,
DistributeVSpace,
DistributeBottom,
};

Expand Down
12 changes: 12 additions & 0 deletions src/app/layout/qgslayoutdesignerdialog.cpp
Expand Up @@ -411,9 +411,11 @@ QgsLayoutDesignerDialog::QgsLayoutDesignerDialog( QWidget *parent, Qt::WindowFla
distributeToolButton->setToolButtonStyle( Qt::ToolButtonIconOnly );
distributeToolButton->addAction( mActionDistributeLeft );
distributeToolButton->addAction( mActionDistributeHCenter );
distributeToolButton->addAction( mActionDistributeHSpace );
distributeToolButton->addAction( mActionDistributeRight );
distributeToolButton->addAction( mActionDistributeTop );
distributeToolButton->addAction( mActionDistributeVCenter );
distributeToolButton->addAction( mActionDistributeVSpace );
distributeToolButton->addAction( mActionDistributeBottom );
distributeToolButton->setDefaultAction( mActionDistributeLeft );
mActionsToolbar->addWidget( distributeToolButton );
Expand Down Expand Up @@ -582,6 +584,10 @@ QgsLayoutDesignerDialog::QgsLayoutDesignerDialog( QWidget *parent, Qt::WindowFla
{
mView->distributeSelectedItems( QgsLayoutAligner::DistributeHCenter );
} );
connect( mActionDistributeHSpace, &QAction::triggered, this, [ = ]
{
mView->distributeSelectedItems( QgsLayoutAligner::DistributeHSpace );
} );
connect( mActionDistributeRight, &QAction::triggered, this, [ = ]
{
mView->distributeSelectedItems( QgsLayoutAligner::DistributeRight );
Expand All @@ -594,6 +600,10 @@ QgsLayoutDesignerDialog::QgsLayoutDesignerDialog( QWidget *parent, Qt::WindowFla
{
mView->distributeSelectedItems( QgsLayoutAligner::DistributeVCenter );
} );
connect( mActionDistributeVSpace, &QAction::triggered, this, [ = ]
{
mView->distributeSelectedItems( QgsLayoutAligner::DistributeVSpace );
} );
connect( mActionDistributeBottom, &QAction::triggered, this, [ = ]
{
mView->distributeSelectedItems( QgsLayoutAligner::DistributeBottom );
Expand Down Expand Up @@ -4330,9 +4340,11 @@ void QgsLayoutDesignerDialog::toggleActions( bool layoutAvailable )
mActionAlignBottom->setEnabled( layoutAvailable );
mActionDistributeLeft->setEnabled( layoutAvailable );
mActionDistributeHCenter->setEnabled( layoutAvailable );
mActionDistributeHSpace->setEnabled( layoutAvailable );
mActionDistributeRight->setEnabled( layoutAvailable );
mActionDistributeTop->setEnabled( layoutAvailable );
mActionDistributeVCenter->setEnabled( layoutAvailable );
mActionDistributeVSpace->setEnabled( layoutAvailable );
mActionDistributeBottom->setEnabled( layoutAvailable );
mActionResizeNarrowest->setEnabled( layoutAvailable );
mActionResizeWidest->setEnabled( layoutAvailable );
Expand Down
76 changes: 74 additions & 2 deletions src/core/layout/qgslayoutaligner.cpp
Expand Up @@ -97,6 +97,13 @@ void QgsLayoutAligner::distributeItems( QgsLayout *layout, const QList<QgsLayout
if ( items.size() < 2 )
return;

// equispaced distribution doesn't follow the same approach of the other distribution types
if ( distribution == DistributeHSpace || distribution == DistributeVSpace )
{
distributeEquispacedItems( layout, items, distribution );
return;
}

auto collectReferenceCoord = [distribution]( QgsLayoutItem * item )->double
{
QRectF itemBBox = item->sceneBoundingRect();
Expand All @@ -114,6 +121,10 @@ void QgsLayoutAligner::distributeItems( QgsLayout *layout, const QList<QgsLayout
return itemBBox.center().y();
case DistributeBottom:
return itemBBox.bottom();
case DistributeHSpace:
case DistributeVSpace:
// not reachable branch, just to avoid compilation warning
return std::numeric_limits<double>::quiet_NaN();
}
// no warnings
return itemBBox.left();
Expand All @@ -131,7 +142,7 @@ void QgsLayoutAligner::distributeItems( QgsLayout *layout, const QList<QgsLayout
itemCoords.insert( refCoord, item );
}

double step = ( maxCoord - minCoord ) / ( items.size() - 1 );
const double step = ( maxCoord - minCoord ) / ( items.size() - 1 );

auto distributeItemToCoord = [layout, distribution]( QgsLayoutItem * item, double refCoord )
{
Expand All @@ -156,6 +167,10 @@ void QgsLayoutAligner::distributeItems( QgsLayout *layout, const QList<QgsLayout
case DistributeBottom:
shifted.setY( refCoord - item->rect().height() );
break;
case DistributeHSpace:
case DistributeVSpace:
// not reachable branch, just to avoid compilation warning
break;
}

// need to keep item units
Expand Down Expand Up @@ -302,13 +317,17 @@ QString QgsLayoutAligner::undoText( Distribution distribution )
case DistributeLeft:
return QObject::tr( "Distribute Items by Left" );
case DistributeHCenter:
return QObject::tr( "Distribute Items by Center" );
return QObject::tr( "Distribute Items by Horizontal Center" );
case DistributeHSpace:
return QObject::tr( "Distribute Horizontal Spacing Equally" );
case DistributeRight:
return QObject::tr( "Distribute Items by Right" );
case DistributeTop:
return QObject::tr( "Distribute Items by Top" );
case DistributeVCenter:
return QObject::tr( "Distribute Items by Vertical Center" );
case DistributeVSpace:
return QObject::tr( "Distribute Vertical Spacing Equally" );
case DistributeBottom:
return QObject::tr( "Distribute Items by Bottom" );
}
Expand Down Expand Up @@ -352,3 +371,56 @@ QString QgsLayoutAligner::undoText( Alignment alignment )
}
return QString(); //no warnings
}

void QgsLayoutAligner::distributeEquispacedItems( QgsLayout *layout, const QList<QgsLayoutItem *> &items, QgsLayoutAligner::Distribution distribution )
{
double length = 0.0;
double minCoord = std::numeric_limits<double>::max();
double maxCoord = std::numeric_limits<double>::lowest();
QMap< double, QgsLayoutItem * > itemCoords;

for ( QgsLayoutItem *item : items )
{
QRectF itemBBox = item->sceneBoundingRect();

double item_min = ( distribution == DistributeHSpace ? itemBBox.left() :
itemBBox.top() );
double item_max = ( distribution == DistributeHSpace ? itemBBox.right() :
itemBBox.bottom() );

minCoord = std::min( minCoord, item_min );
maxCoord = std::max( maxCoord, item_max );
length += ( item_max - item_min );
itemCoords.insert( item_min, item );
}
const double step = ( maxCoord - minCoord - length ) / ( items.size() - 1 );

double currentVal = minCoord;
layout->undoStack()->beginMacro( undoText( distribution ) );
for ( auto itemIt = itemCoords.constBegin(); itemIt != itemCoords.constEnd(); ++itemIt )
{
QgsLayoutItem *item = itemIt.value();
QPointF shifted = item->pos();

layout->undoStack()->beginCommand( itemIt.value(), QString() );

if ( distribution == DistributeHSpace )
{
shifted.setX( currentVal );
}
else
{
shifted.setY( currentVal );
}

QgsLayoutPoint newPos = layout->convertFromLayoutUnits( shifted, item->positionWithUnits().units() );
item->attemptMove( newPos );

layout->undoStack()->endCommand();

currentVal += ( distribution == DistributeHSpace ? item->rect().width() :
item->rect().height() ) + step;
}
layout->undoStack()->endMacro();
return;
}
9 changes: 9 additions & 0 deletions src/core/layout/qgslayoutaligner.h
Expand Up @@ -54,9 +54,11 @@ class CORE_EXPORT QgsLayoutAligner
{
DistributeLeft, //!< Distribute left edges
DistributeHCenter, //!< Distribute horizontal centers
DistributeHSpace, //!< Distribute horizontal equispaced
DistributeRight, //!< Distribute right edges
DistributeTop, //!< Distribute top edges
DistributeVCenter, //!< Distribute vertical centers
DistributeVSpace, //!< Distribute vertical equispaced
DistributeBottom, //!< Distribute bottom edges
};

Expand Down Expand Up @@ -103,6 +105,13 @@ class CORE_EXPORT QgsLayoutAligner
static QString undoText( Distribution distribution );
static QString undoText( Resize resize );

/**
* Distributes a set of \a items from a \a layout in place for \a DistributeHSpace
* and \a DistributeVSpace distribution type special cases.
*
* The \a distribution argument specifies the method to use when distributing the items.
*/
static void distributeEquispacedItems( QgsLayout *layout, const QList<QgsLayoutItem *> &items, QgsLayoutAligner::Distribution distribution );


};
Expand Down
28 changes: 27 additions & 1 deletion src/ui/layout/qgslayoutdesignerbase.ui
Expand Up @@ -317,10 +317,12 @@
</property>
<addaction name="mActionDistributeLeft"/>
<addaction name="mActionDistributeHCenter"/>
<addaction name="mActionDistributeHSpace"/>
<addaction name="mActionDistributeRight"/>
<addaction name="separator"/>
<addaction name="mActionDistributeTop"/>
<addaction name="mActionDistributeVCenter"/>
<addaction name="mActionDistributeVSpace"/>
<addaction name="mActionDistributeBottom"/>
</widget>
<widget class="QMenu" name="menuResize">
Expand Down Expand Up @@ -918,12 +920,24 @@
<normaloff>:/images/themes/default/mActionDistributeHCenter.svg</normaloff>:/images/themes/default/mActionDistributeHCenter.svg</iconset>
</property>
<property name="text">
<string>Distribute &amp;Centers</string>
<string>Distribute horizontal &amp;Centers</string>
</property>
<property name="toolTip">
<string>Distributes horizontal centers of items equidistantly</string>
</property>
</action>
<action name="mActionDistributeHSpace">
<property name="icon">
<iconset resource="../../../images/images.qrc">
<normaloff>:/images/themes/default/mActionDistributeHSpace.svg</normaloff>:/images/themes/default/mActionDistributeHSpace.svg</iconset>
</property>
<property name="text">
<string>Distribute &amp;Horizontally Equispaced</string>
</property>
<property name="toolTip">
<string>Distributes the horizontal spacing equally between all items</string>
</property>
</action>
<action name="mActionDistributeRight">
<property name="icon">
<iconset resource="../../../images/images.qrc">
Expand Down Expand Up @@ -960,6 +974,18 @@
<string>Distributes vertical centers of items equidistantly</string>
</property>
</action>
<action name="mActionDistributeVSpace">
<property name="icon">
<iconset resource="../../../images/images.qrc">
<normaloff>:/images/themes/default/mActionDistributeVSpace.svg</normaloff>:/images/themes/default/mActionDistributeVSpace.svg</iconset>
</property>
<property name="text">
<string>Distribute Vertically &amp;Equispaced</string>
</property>
<property name="toolTip">
<string>Distributes items equidistantly with respect to their vertical edges</string>
</property>
</action>
<action name="mActionDistributeBottom">
<property name="icon">
<iconset resource="../../../images/images.qrc">
Expand Down

0 comments on commit 0b270f9

Please sign in to comment.