Skip to content
Permalink
Browse files

Merge pull request #9454 from nastasi-oq/distribute-equispaced2

[layout] add new vertical and horizontal equispaced distributions
  • Loading branch information
nyalldawson committed Mar 11, 2019
2 parents 8e39f0f + ae0e12b commit 0b270f98fb43d81afc60bc2fa2fb3c1ab1a4e027
@@ -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>
@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.1"
id="svg2"
width="24"
height="24">
<metadata
id="metadata16">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs14" />
<path
id="path4"
stroke-linecap="round"
stroke="#8dbf8d"
fill="#c8fac8"
d="M5.5 7.5v10h-4v-10z" />
<path
id="path6"
stroke-opacity=".984"
stroke-linecap="round"
stroke="#81a1b4"
fill="#c8e6fa"
d="M15.5 7.5v14h-6v-14z" />
<path
id="path8"
stroke-linecap="round"
stroke="#8dbf8d"
fill="#c8fac8"
d="M23.5 7.5v8h-4v-8z" />
<path
d="m 19.498347,9.9989656 0.0028,-7.4936232 -4.000671,-0.00534 L 15.504356,10 M 9.498347,9.9989651 9.501127,2.5053419 5.500456,2.5 5.504356,10"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#424242;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="path10-3-7" />
</svg>
@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.1"
id="svg3581"
width="24"
height="24">
<metadata
id="metadata3597">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs3595" />
<path
id="path3583"
stroke-linecap="round"
stroke="#8dbf8d"
fill="#c8fac8"
d="M7.5 18.5h10v4h-10z" />
<path
id="path3585"
stroke-opacity=".984"
stroke-linecap="round"
stroke="#81a1b4"
fill="#c8e6fa"
d="M7.5 8.5h14v6h-14z" />
<path
id="path3589"
stroke-linecap="round"
stroke="#8dbf8d"
fill="#c8fac8"
d="M7.5.5h8v4h-8z" />
<path
d="m 9.9986182,4.5013959 -7.493624,-0.0028 -0.0053,4.0006709 7.499998,-0.0039 m -10e-4,6.0060081 -7.493623,-0.0028 -0.0053,4.000671 7.5,-0.0039"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:#424242;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="path10-3-7" />
</svg>
@@ -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,
};

@@ -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 );
@@ -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 );
@@ -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 );
@@ -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 );
@@ -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();
@@ -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();
@@ -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 )
{
@@ -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
@@ -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" );
}
@@ -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;
}
@@ -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
};

@@ -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 );


};
@@ -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">
@@ -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">
@@ -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">

0 comments on commit 0b270f9

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