Skip to content

Commit 0b270f9

Browse files
authored
Merge pull request #9454 from nastasi-oq/distribute-equispaced2
[layout] add new vertical and horizontal equispaced distributions
2 parents 8e39f0f + ae0e12b commit 0b270f9

File tree

9 files changed

+250
-3
lines changed

9 files changed

+250
-3
lines changed

images/images.qrc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,12 @@
167167
<file>themes/default/mActionDataSourceManager.svg</file>
168168
<file>themes/default/mActionDistributeBottom.svg</file>
169169
<file>themes/default/mActionDistributeHCenter.svg</file>
170+
<file>themes/default/mActionDistributeHSpace.svg</file>
170171
<file>themes/default/mActionDistributeLeft.svg</file>
171172
<file>themes/default/mActionDistributeRight.svg</file>
172173
<file>themes/default/mActionDistributeTop.svg</file>
173174
<file>themes/default/mActionDistributeVCenter.svg</file>
175+
<file>themes/default/mActionDistributeVSpace.svg</file>
174176
<file>themes/default/mActionAddLayer.svg</file>
175177
<file>themes/default/mActionAddMeshLayer.svg</file>
176178
<file>themes/default/mActionAddAllToOverview.svg</file>
Lines changed: 49 additions & 0 deletions
Loading
Lines changed: 49 additions & 0 deletions
Loading

python/core/auto_generated/layout/qgslayoutaligner.sip.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,11 @@ sets of layout items, e.g. aligning a group of items to top or left sides.
3838
{
3939
DistributeLeft,
4040
DistributeHCenter,
41+
DistributeHSpace,
4142
DistributeRight,
4243
DistributeTop,
4344
DistributeVCenter,
45+
DistributeVSpace,
4446
DistributeBottom,
4547
};
4648

src/app/layout/qgslayoutdesignerdialog.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -411,9 +411,11 @@ QgsLayoutDesignerDialog::QgsLayoutDesignerDialog( QWidget *parent, Qt::WindowFla
411411
distributeToolButton->setToolButtonStyle( Qt::ToolButtonIconOnly );
412412
distributeToolButton->addAction( mActionDistributeLeft );
413413
distributeToolButton->addAction( mActionDistributeHCenter );
414+
distributeToolButton->addAction( mActionDistributeHSpace );
414415
distributeToolButton->addAction( mActionDistributeRight );
415416
distributeToolButton->addAction( mActionDistributeTop );
416417
distributeToolButton->addAction( mActionDistributeVCenter );
418+
distributeToolButton->addAction( mActionDistributeVSpace );
417419
distributeToolButton->addAction( mActionDistributeBottom );
418420
distributeToolButton->setDefaultAction( mActionDistributeLeft );
419421
mActionsToolbar->addWidget( distributeToolButton );
@@ -582,6 +584,10 @@ QgsLayoutDesignerDialog::QgsLayoutDesignerDialog( QWidget *parent, Qt::WindowFla
582584
{
583585
mView->distributeSelectedItems( QgsLayoutAligner::DistributeHCenter );
584586
} );
587+
connect( mActionDistributeHSpace, &QAction::triggered, this, [ = ]
588+
{
589+
mView->distributeSelectedItems( QgsLayoutAligner::DistributeHSpace );
590+
} );
585591
connect( mActionDistributeRight, &QAction::triggered, this, [ = ]
586592
{
587593
mView->distributeSelectedItems( QgsLayoutAligner::DistributeRight );
@@ -594,6 +600,10 @@ QgsLayoutDesignerDialog::QgsLayoutDesignerDialog( QWidget *parent, Qt::WindowFla
594600
{
595601
mView->distributeSelectedItems( QgsLayoutAligner::DistributeVCenter );
596602
} );
603+
connect( mActionDistributeVSpace, &QAction::triggered, this, [ = ]
604+
{
605+
mView->distributeSelectedItems( QgsLayoutAligner::DistributeVSpace );
606+
} );
597607
connect( mActionDistributeBottom, &QAction::triggered, this, [ = ]
598608
{
599609
mView->distributeSelectedItems( QgsLayoutAligner::DistributeBottom );
@@ -4330,9 +4340,11 @@ void QgsLayoutDesignerDialog::toggleActions( bool layoutAvailable )
43304340
mActionAlignBottom->setEnabled( layoutAvailable );
43314341
mActionDistributeLeft->setEnabled( layoutAvailable );
43324342
mActionDistributeHCenter->setEnabled( layoutAvailable );
4343+
mActionDistributeHSpace->setEnabled( layoutAvailable );
43334344
mActionDistributeRight->setEnabled( layoutAvailable );
43344345
mActionDistributeTop->setEnabled( layoutAvailable );
43354346
mActionDistributeVCenter->setEnabled( layoutAvailable );
4347+
mActionDistributeVSpace->setEnabled( layoutAvailable );
43364348
mActionDistributeBottom->setEnabled( layoutAvailable );
43374349
mActionResizeNarrowest->setEnabled( layoutAvailable );
43384350
mActionResizeWidest->setEnabled( layoutAvailable );

src/core/layout/qgslayoutaligner.cpp

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,13 @@ void QgsLayoutAligner::distributeItems( QgsLayout *layout, const QList<QgsLayout
9797
if ( items.size() < 2 )
9898
return;
9999

100+
// equispaced distribution doesn't follow the same approach of the other distribution types
101+
if ( distribution == DistributeHSpace || distribution == DistributeVSpace )
102+
{
103+
distributeEquispacedItems( layout, items, distribution );
104+
return;
105+
}
106+
100107
auto collectReferenceCoord = [distribution]( QgsLayoutItem * item )->double
101108
{
102109
QRectF itemBBox = item->sceneBoundingRect();
@@ -114,6 +121,10 @@ void QgsLayoutAligner::distributeItems( QgsLayout *layout, const QList<QgsLayout
114121
return itemBBox.center().y();
115122
case DistributeBottom:
116123
return itemBBox.bottom();
124+
case DistributeHSpace:
125+
case DistributeVSpace:
126+
// not reachable branch, just to avoid compilation warning
127+
return std::numeric_limits<double>::quiet_NaN();
117128
}
118129
// no warnings
119130
return itemBBox.left();
@@ -131,7 +142,7 @@ void QgsLayoutAligner::distributeItems( QgsLayout *layout, const QList<QgsLayout
131142
itemCoords.insert( refCoord, item );
132143
}
133144

134-
double step = ( maxCoord - minCoord ) / ( items.size() - 1 );
145+
const double step = ( maxCoord - minCoord ) / ( items.size() - 1 );
135146

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

161176
// need to keep item units
@@ -302,13 +317,17 @@ QString QgsLayoutAligner::undoText( Distribution distribution )
302317
case DistributeLeft:
303318
return QObject::tr( "Distribute Items by Left" );
304319
case DistributeHCenter:
305-
return QObject::tr( "Distribute Items by Center" );
320+
return QObject::tr( "Distribute Items by Horizontal Center" );
321+
case DistributeHSpace:
322+
return QObject::tr( "Distribute Horizontal Spacing Equally" );
306323
case DistributeRight:
307324
return QObject::tr( "Distribute Items by Right" );
308325
case DistributeTop:
309326
return QObject::tr( "Distribute Items by Top" );
310327
case DistributeVCenter:
311328
return QObject::tr( "Distribute Items by Vertical Center" );
329+
case DistributeVSpace:
330+
return QObject::tr( "Distribute Vertical Spacing Equally" );
312331
case DistributeBottom:
313332
return QObject::tr( "Distribute Items by Bottom" );
314333
}
@@ -352,3 +371,56 @@ QString QgsLayoutAligner::undoText( Alignment alignment )
352371
}
353372
return QString(); //no warnings
354373
}
374+
375+
void QgsLayoutAligner::distributeEquispacedItems( QgsLayout *layout, const QList<QgsLayoutItem *> &items, QgsLayoutAligner::Distribution distribution )
376+
{
377+
double length = 0.0;
378+
double minCoord = std::numeric_limits<double>::max();
379+
double maxCoord = std::numeric_limits<double>::lowest();
380+
QMap< double, QgsLayoutItem * > itemCoords;
381+
382+
for ( QgsLayoutItem *item : items )
383+
{
384+
QRectF itemBBox = item->sceneBoundingRect();
385+
386+
double item_min = ( distribution == DistributeHSpace ? itemBBox.left() :
387+
itemBBox.top() );
388+
double item_max = ( distribution == DistributeHSpace ? itemBBox.right() :
389+
itemBBox.bottom() );
390+
391+
minCoord = std::min( minCoord, item_min );
392+
maxCoord = std::max( maxCoord, item_max );
393+
length += ( item_max - item_min );
394+
itemCoords.insert( item_min, item );
395+
}
396+
const double step = ( maxCoord - minCoord - length ) / ( items.size() - 1 );
397+
398+
double currentVal = minCoord;
399+
layout->undoStack()->beginMacro( undoText( distribution ) );
400+
for ( auto itemIt = itemCoords.constBegin(); itemIt != itemCoords.constEnd(); ++itemIt )
401+
{
402+
QgsLayoutItem *item = itemIt.value();
403+
QPointF shifted = item->pos();
404+
405+
layout->undoStack()->beginCommand( itemIt.value(), QString() );
406+
407+
if ( distribution == DistributeHSpace )
408+
{
409+
shifted.setX( currentVal );
410+
}
411+
else
412+
{
413+
shifted.setY( currentVal );
414+
}
415+
416+
QgsLayoutPoint newPos = layout->convertFromLayoutUnits( shifted, item->positionWithUnits().units() );
417+
item->attemptMove( newPos );
418+
419+
layout->undoStack()->endCommand();
420+
421+
currentVal += ( distribution == DistributeHSpace ? item->rect().width() :
422+
item->rect().height() ) + step;
423+
}
424+
layout->undoStack()->endMacro();
425+
return;
426+
}

src/core/layout/qgslayoutaligner.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,11 @@ class CORE_EXPORT QgsLayoutAligner
5454
{
5555
DistributeLeft, //!< Distribute left edges
5656
DistributeHCenter, //!< Distribute horizontal centers
57+
DistributeHSpace, //!< Distribute horizontal equispaced
5758
DistributeRight, //!< Distribute right edges
5859
DistributeTop, //!< Distribute top edges
5960
DistributeVCenter, //!< Distribute vertical centers
61+
DistributeVSpace, //!< Distribute vertical equispaced
6062
DistributeBottom, //!< Distribute bottom edges
6163
};
6264

@@ -103,6 +105,13 @@ class CORE_EXPORT QgsLayoutAligner
103105
static QString undoText( Distribution distribution );
104106
static QString undoText( Resize resize );
105107

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

107116

108117
};

src/ui/layout/qgslayoutdesignerbase.ui

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,10 +317,12 @@
317317
</property>
318318
<addaction name="mActionDistributeLeft"/>
319319
<addaction name="mActionDistributeHCenter"/>
320+
<addaction name="mActionDistributeHSpace"/>
320321
<addaction name="mActionDistributeRight"/>
321322
<addaction name="separator"/>
322323
<addaction name="mActionDistributeTop"/>
323324
<addaction name="mActionDistributeVCenter"/>
325+
<addaction name="mActionDistributeVSpace"/>
324326
<addaction name="mActionDistributeBottom"/>
325327
</widget>
326328
<widget class="QMenu" name="menuResize">
@@ -918,12 +920,24 @@
918920
<normaloff>:/images/themes/default/mActionDistributeHCenter.svg</normaloff>:/images/themes/default/mActionDistributeHCenter.svg</iconset>
919921
</property>
920922
<property name="text">
921-
<string>Distribute &amp;Centers</string>
923+
<string>Distribute horizontal &amp;Centers</string>
922924
</property>
923925
<property name="toolTip">
924926
<string>Distributes horizontal centers of items equidistantly</string>
925927
</property>
926928
</action>
929+
<action name="mActionDistributeHSpace">
930+
<property name="icon">
931+
<iconset resource="../../../images/images.qrc">
932+
<normaloff>:/images/themes/default/mActionDistributeHSpace.svg</normaloff>:/images/themes/default/mActionDistributeHSpace.svg</iconset>
933+
</property>
934+
<property name="text">
935+
<string>Distribute &amp;Horizontally Equispaced</string>
936+
</property>
937+
<property name="toolTip">
938+
<string>Distributes the horizontal spacing equally between all items</string>
939+
</property>
940+
</action>
927941
<action name="mActionDistributeRight">
928942
<property name="icon">
929943
<iconset resource="../../../images/images.qrc">
@@ -960,6 +974,18 @@
960974
<string>Distributes vertical centers of items equidistantly</string>
961975
</property>
962976
</action>
977+
<action name="mActionDistributeVSpace">
978+
<property name="icon">
979+
<iconset resource="../../../images/images.qrc">
980+
<normaloff>:/images/themes/default/mActionDistributeVSpace.svg</normaloff>:/images/themes/default/mActionDistributeVSpace.svg</iconset>
981+
</property>
982+
<property name="text">
983+
<string>Distribute Vertically &amp;Equispaced</string>
984+
</property>
985+
<property name="toolTip">
986+
<string>Distributes items equidistantly with respect to their vertical edges</string>
987+
</property>
988+
</action>
963989
<action name="mActionDistributeBottom">
964990
<property name="icon">
965991
<iconset resource="../../../images/images.qrc">

0 commit comments

Comments
 (0)