[FEATURE][layouts] Expose choice of arrangement of legends (i.e.
symbols to the left OR symbols to the right of legend text), and alignment for group/subgroup/item text Allows creation of right-to-left locale friendly legends. Additionally, we default to this right-to-left style alignment when creating new legends under a RTL based locale.
@ -765,6 +765,8 @@
|
||||
<file>themes/default/mIconAlignJustify.svg</file>
|
||||
<file>themes/default/mIconAlignLeft.svg</file>
|
||||
<file>themes/default/mIconAlignRight.svg</file>
|
||||
<file>themes/default/mIconArrangeSymbolsLeft.svg</file>
|
||||
<file>themes/default/mIconArrangeSymbolsRight.svg</file>
|
||||
</qresource>
|
||||
<qresource prefix="/images/tips">
|
||||
<file alias="symbol_levels.png">qgis_tips/symbol_levels.png</file>
|
||||
|
||||
1
images/themes/default/mIconArrangeSymbolsLeft.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 6.35 6.35"><path style="marker:none" d="M2.646 2.646H5.82v.529H2.646zm0 1.852H4.55v.529H2.646zm0-3.44h2.54v.53h-2.54z" color="#555753" overflow="visible" fill="#555753" filter="url(#filter8750)"/><path fill="#848484" stroke="#5c5c5c" stroke-width=".224" d="M.641.641h1.364V1.74H.641zm0 1.852h1.364v1.099H.641zm0 1.852h1.364v1.099H.641z"/></svg>
|
||||
|
After Width: | Height: | Size: 420 B |
1
images/themes/default/mIconArrangeSymbolsRight.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 6.35 6.35"><path style="marker:none" d="M.53 2.646h3.174v.529H.53zm0 1.852h1.904v.529H.53zm0-3.44h2.539v.53H.529z" color="#555753" overflow="visible" fill="#555753" filter="url(#filter8750)"/><path d="M4.345.641H5.71v1.1H4.345zm0 1.852H5.71v1.1H4.345zm0 1.852H5.71v1.1H4.345z" fill="#848484" stroke="#5c5c5c" stroke-width=".224"/></svg>
|
||||
|
After Width: | Height: | Size: 412 B |
@ -76,10 +76,23 @@ Default implementation does nothing. *
|
||||
|
||||
struct ItemContext
|
||||
{
|
||||
ItemContext();
|
||||
|
||||
QgsRenderContext *context;
|
||||
QPainter *painter;
|
||||
QPointF point;
|
||||
double labelXOffset;
|
||||
|
||||
QPointF point;
|
||||
|
||||
double labelXOffset;
|
||||
|
||||
double top;
|
||||
|
||||
double columnLeft;
|
||||
|
||||
double columnRight;
|
||||
|
||||
double maxSiblingSymbolWidth;
|
||||
|
||||
};
|
||||
|
||||
struct ItemMetrics
|
||||
|
||||
@ -279,6 +279,28 @@ Returns the legend symbol width.
|
||||
Sets the legend symbol ``width``.
|
||||
|
||||
.. seealso:: :py:func:`symbolWidth`
|
||||
%End
|
||||
|
||||
void setSymbolAlignment( Qt::AlignmentFlag alignment );
|
||||
%Docstring
|
||||
Sets the ``alignment`` for placement of legend symbols.
|
||||
|
||||
Only Qt.AlignLeft or Qt.AlignRight are supported values.
|
||||
|
||||
.. seealso:: :py:func:`symbolAlignment`
|
||||
|
||||
.. versionadded:: 3.10.0
|
||||
%End
|
||||
|
||||
Qt::AlignmentFlag symbolAlignment() const;
|
||||
%Docstring
|
||||
Returns the alignment for placement of legend symbols.
|
||||
|
||||
Only Qt.AlignLeft or Qt.AlignRight are supported values.
|
||||
|
||||
.. seealso:: :py:func:`setSymbolAlignment`
|
||||
|
||||
.. versionadded:: 3.10.0
|
||||
%End
|
||||
|
||||
double symbolHeight() const;
|
||||
|
||||
@ -32,18 +32,14 @@ in QgsLegendModel class.
|
||||
|
||||
Qt::AlignmentFlag titleAlignment() const;
|
||||
%Docstring
|
||||
Returns the alignment of the legend title
|
||||
|
||||
:return: Qt.AlignmentFlag for the legend title
|
||||
Returns the alignment of the legend title.
|
||||
|
||||
.. seealso:: :py:func:`setTitleAlignment`
|
||||
%End
|
||||
|
||||
void setTitleAlignment( Qt::AlignmentFlag alignment );
|
||||
%Docstring
|
||||
Sets the alignment of the legend title
|
||||
|
||||
:param alignment: Text alignment for drawing the legend title
|
||||
Sets the ``alignment`` of the legend title.
|
||||
|
||||
.. seealso:: :py:func:`titleAlignment`
|
||||
%End
|
||||
@ -102,6 +98,28 @@ Overrides fontColor()
|
||||
QSizeF symbolSize() const;
|
||||
void setSymbolSize( QSizeF s );
|
||||
|
||||
void setSymbolAlignment( Qt::AlignmentFlag alignment );
|
||||
%Docstring
|
||||
Sets the ``alignment`` for placement of legend symbols.
|
||||
|
||||
Only Qt.AlignLeft or Qt.AlignRight are supported values.
|
||||
|
||||
.. seealso:: :py:func:`symbolAlignment`
|
||||
|
||||
.. versionadded:: 3.10.0
|
||||
%End
|
||||
|
||||
Qt::AlignmentFlag symbolAlignment() const;
|
||||
%Docstring
|
||||
Returns the alignment for placement of legend symbols.
|
||||
|
||||
Only Qt.AlignLeft or Qt.AlignRight are supported values.
|
||||
|
||||
.. seealso:: :py:func:`setSymbolAlignment`
|
||||
|
||||
.. versionadded:: 3.10.0
|
||||
%End
|
||||
|
||||
bool drawRasterStroke() const;
|
||||
%Docstring
|
||||
Returns whether a stroke will be drawn around raster symbol items.
|
||||
|
||||
@ -58,6 +58,24 @@ The font for this style.
|
||||
void setMargin( double margin );
|
||||
%Docstring
|
||||
Sets all margins
|
||||
%End
|
||||
|
||||
Qt::Alignment alignment() const;
|
||||
%Docstring
|
||||
Returns the alignment for the legend component.
|
||||
|
||||
.. seealso:: :py:func:`setAlignment`
|
||||
|
||||
.. versionadded:: 3.10
|
||||
%End
|
||||
|
||||
void setAlignment( Qt::Alignment alignment );
|
||||
%Docstring
|
||||
Sets the alignment for the legend component.
|
||||
|
||||
.. seealso:: :py:func:`alignment`
|
||||
|
||||
.. versionadded:: 3.10
|
||||
%End
|
||||
|
||||
void writeXml( const QString &name, QDomElement &elem, QDomDocument &doc ) const;
|
||||
|
||||
@ -49,6 +49,18 @@ Sets the current ``alignment`` choice.
|
||||
.. seealso:: :py:func:`currentAlignment`
|
||||
%End
|
||||
|
||||
void customiseAlignmentDisplay( Qt::Alignment alignment, const QString &text = QString(), const QIcon &icon = QIcon() );
|
||||
%Docstring
|
||||
Sets the ``text`` and ``icon`` to use for a particular ``alignment`` option,
|
||||
replacing the default text or icon.
|
||||
|
||||
If ``text`` or ``icon`` is not specified, they will not be changed from the default.
|
||||
|
||||
.. note::
|
||||
|
||||
This must be called after first filtering the available alignment options via setAvailableAlignments().
|
||||
%End
|
||||
|
||||
signals:
|
||||
|
||||
void changed();
|
||||
|
||||
@ -195,6 +195,16 @@ void QgsLayoutAppUtils::registerGuiForKnownItemTypes()
|
||||
// try to find a good map to link the legend with by default
|
||||
legend->setLinkedMap( findSensibleDefaultLinkedMapItem( legend ) );
|
||||
|
||||
if ( QApplication::isRightToLeft() )
|
||||
{
|
||||
// for right-to-left locales, use an appropriate default layout
|
||||
legend->setSymbolAlignment( Qt::AlignRight );
|
||||
legend->rstyle( QgsLegendStyle::Group ).setAlignment( Qt::AlignRight );
|
||||
legend->rstyle( QgsLegendStyle::Subgroup ).setAlignment( Qt::AlignRight );
|
||||
legend->rstyle( QgsLegendStyle::SymbolLabel ).setAlignment( Qt::AlignRight );
|
||||
legend->setTitleAlignment( Qt::AlignRight );
|
||||
}
|
||||
|
||||
legend->updateLegend();
|
||||
} );
|
||||
|
||||
|
||||
@ -70,7 +70,10 @@ QgsLayoutLegendWidget::QgsLayoutLegendWidget( QgsLayoutItemLegend *legend )
|
||||
setupUi( this );
|
||||
connect( mWrapCharLineEdit, &QLineEdit::textChanged, this, &QgsLayoutLegendWidget::mWrapCharLineEdit_textChanged );
|
||||
connect( mTitleLineEdit, &QLineEdit::textChanged, this, &QgsLayoutLegendWidget::mTitleLineEdit_textChanged );
|
||||
connect( mTitleAlignCombo, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLayoutLegendWidget::mTitleAlignCombo_currentIndexChanged );
|
||||
connect( mTitleAlignCombo, &QgsAlignmentComboBox::changed, this, &QgsLayoutLegendWidget::titleAlignmentChanged );
|
||||
connect( mGroupAlignCombo, &QgsAlignmentComboBox::changed, this, &QgsLayoutLegendWidget::groupAlignmentChanged );
|
||||
connect( mSubgroupAlignCombo, &QgsAlignmentComboBox::changed, this, &QgsLayoutLegendWidget::subgroupAlignmentChanged );
|
||||
connect( mItemAlignCombo, &QgsAlignmentComboBox::changed, this, &QgsLayoutLegendWidget::itemAlignmentChanged );
|
||||
connect( mColumnCountSpinBox, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), this, &QgsLayoutLegendWidget::mColumnCountSpinBox_valueChanged );
|
||||
connect( mSplitLayerCheckBox, &QCheckBox::toggled, this, &QgsLayoutLegendWidget::mSplitLayerCheckBox_toggled );
|
||||
connect( mEqualColumnWidthCheckBox, &QCheckBox::toggled, this, &QgsLayoutLegendWidget::mEqualColumnWidthCheckBox_toggled );
|
||||
@ -111,6 +114,16 @@ QgsLayoutLegendWidget::QgsLayoutLegendWidget( QgsLayoutItemLegend *legend )
|
||||
mLayerFontButton->setMode( QgsFontButton::ModeQFont );
|
||||
mItemFontButton->setMode( QgsFontButton::ModeQFont );
|
||||
|
||||
mTitleAlignCombo->setAvailableAlignments( Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight );
|
||||
mGroupAlignCombo->setAvailableAlignments( Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight );
|
||||
mSubgroupAlignCombo->setAvailableAlignments( Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight );
|
||||
mItemAlignCombo->setAvailableAlignments( Qt::AlignLeft | Qt::AlignHCenter | Qt::AlignRight );
|
||||
|
||||
mArrangementCombo->setAvailableAlignments( Qt::AlignLeft | Qt::AlignRight );
|
||||
connect( mArrangementCombo, &QgsAlignmentComboBox::changed, this, &QgsLayoutLegendWidget::arrangementChanged );
|
||||
mArrangementCombo->customiseAlignmentDisplay( Qt::AlignLeft, tr( "Symbols on Left" ), QgsApplication::getThemeIcon( QStringLiteral( "/mIconArrangeSymbolsLeft.svg" ) ) );
|
||||
mArrangementCombo->customiseAlignmentDisplay( Qt::AlignRight, tr( "Symbols on Right" ), QgsApplication::getThemeIcon( QStringLiteral( "/mIconArrangeSymbolsRight.svg" ) ) );
|
||||
|
||||
// setup icons
|
||||
mAddToolButton->setIcon( QIcon( QgsApplication::iconPath( "symbologyAdd.svg" ) ) );
|
||||
mEditPushButton->setIcon( QIcon( QgsApplication::iconPath( "symbologyEdit.svg" ) ) );
|
||||
@ -168,11 +181,13 @@ void QgsLayoutLegendWidget::setGuiElements()
|
||||
return;
|
||||
}
|
||||
|
||||
int alignment = mLegend->titleAlignment() == Qt::AlignLeft ? 0 : mLegend->titleAlignment() == Qt::AlignHCenter ? 1 : 2;
|
||||
|
||||
blockAllSignals( true );
|
||||
mTitleLineEdit->setText( mLegend->title() );
|
||||
mTitleAlignCombo->setCurrentIndex( alignment );
|
||||
whileBlocking( mTitleAlignCombo )->setCurrentAlignment( mLegend->titleAlignment() );
|
||||
whileBlocking( mGroupAlignCombo )->setCurrentAlignment( mLegend->style( QgsLegendStyle::Group ).alignment() );
|
||||
whileBlocking( mSubgroupAlignCombo )->setCurrentAlignment( mLegend->style( QgsLegendStyle::Subgroup ).alignment() );
|
||||
whileBlocking( mItemAlignCombo )->setCurrentAlignment( mLegend->style( QgsLegendStyle::SymbolLabel ).alignment() );
|
||||
whileBlocking( mArrangementCombo )->setCurrentAlignment( mLegend->symbolAlignment() );
|
||||
mFilterByMapToolButton->setChecked( mLegend->legendFilterByMapEnabled() );
|
||||
mColumnCountSpinBox->setValue( mLegend->columnCount() );
|
||||
mSplitLayerCheckBox->setChecked( mLegend->splitLayer() );
|
||||
@ -240,11 +255,11 @@ void QgsLayoutLegendWidget::mTitleLineEdit_textChanged( const QString &text )
|
||||
}
|
||||
}
|
||||
|
||||
void QgsLayoutLegendWidget::mTitleAlignCombo_currentIndexChanged( int index )
|
||||
void QgsLayoutLegendWidget::titleAlignmentChanged()
|
||||
{
|
||||
if ( mLegend )
|
||||
{
|
||||
Qt::AlignmentFlag alignment = index == 0 ? Qt::AlignLeft : index == 1 ? Qt::AlignHCenter : Qt::AlignRight;
|
||||
Qt::AlignmentFlag alignment = static_cast< Qt::AlignmentFlag >( static_cast< int >( mTitleAlignCombo->currentAlignment() & Qt::AlignHorizontal_Mask ) );
|
||||
mLegend->beginCommand( tr( "Change Title Alignment" ) );
|
||||
mLegend->setTitleAlignment( alignment );
|
||||
mLegend->update();
|
||||
@ -252,6 +267,51 @@ void QgsLayoutLegendWidget::mTitleAlignCombo_currentIndexChanged( int index )
|
||||
}
|
||||
}
|
||||
|
||||
void QgsLayoutLegendWidget::groupAlignmentChanged()
|
||||
{
|
||||
if ( mLegend )
|
||||
{
|
||||
mLegend->beginCommand( tr( "Change Group Alignment" ) );
|
||||
mLegend->rstyle( QgsLegendStyle::Group ).setAlignment( mGroupAlignCombo->currentAlignment() );
|
||||
mLegend->update();
|
||||
mLegend->endCommand();
|
||||
}
|
||||
}
|
||||
|
||||
void QgsLayoutLegendWidget::subgroupAlignmentChanged()
|
||||
{
|
||||
if ( mLegend )
|
||||
{
|
||||
mLegend->beginCommand( tr( "Change Subgroup Alignment" ) );
|
||||
mLegend->rstyle( QgsLegendStyle::Subgroup ).setAlignment( mSubgroupAlignCombo->currentAlignment() );
|
||||
mLegend->update();
|
||||
mLegend->endCommand();
|
||||
}
|
||||
}
|
||||
|
||||
void QgsLayoutLegendWidget::itemAlignmentChanged()
|
||||
{
|
||||
if ( mLegend )
|
||||
{
|
||||
mLegend->beginCommand( tr( "Change Item Alignment" ) );
|
||||
mLegend->rstyle( QgsLegendStyle::SymbolLabel ).setAlignment( mItemAlignCombo->currentAlignment() );
|
||||
mLegend->update();
|
||||
mLegend->endCommand();
|
||||
}
|
||||
}
|
||||
|
||||
void QgsLayoutLegendWidget::arrangementChanged()
|
||||
{
|
||||
if ( mLegend )
|
||||
{
|
||||
Qt::AlignmentFlag alignment = static_cast< Qt::AlignmentFlag >( static_cast< int >( mArrangementCombo->currentAlignment() & Qt::AlignHorizontal_Mask ) );
|
||||
mLegend->beginCommand( tr( "Change Legend Arrangement" ) );
|
||||
mLegend->setSymbolAlignment( alignment );
|
||||
mLegend->update();
|
||||
mLegend->endCommand();
|
||||
}
|
||||
}
|
||||
|
||||
void QgsLayoutLegendWidget::mColumnCountSpinBox_valueChanged( int c )
|
||||
{
|
||||
if ( mLegend )
|
||||
@ -1053,7 +1113,7 @@ void QgsLayoutLegendWidget::setCurrentNodeStyleFromAction()
|
||||
if ( !a || !mItemTreeView->currentNode() )
|
||||
return;
|
||||
|
||||
QgsLegendRenderer::setNodeLegendStyle( mItemTreeView->currentNode(), ( QgsLegendStyle::Style ) a->data().toInt() );
|
||||
QgsLegendRenderer::setNodeLegendStyle( mItemTreeView->currentNode(), static_cast< QgsLegendStyle::Style >( a->data().toInt() ) );
|
||||
mLegend->updateFilterByMap();
|
||||
}
|
||||
|
||||
@ -1175,7 +1235,7 @@ QMenu *QgsLayoutLegendMenuProvider::createContextMenu()
|
||||
QAction *action = menu->addAction( QgsLegendStyle::styleLabel( style ), mWidget, &QgsLayoutLegendWidget::setCurrentNodeStyleFromAction );
|
||||
action->setCheckable( true );
|
||||
action->setChecked( currentStyle == style );
|
||||
action->setData( ( int ) style );
|
||||
action->setData( static_cast< int >( style ) );
|
||||
}
|
||||
|
||||
return menu;
|
||||
|
||||
@ -49,7 +49,6 @@ class QgsLayoutLegendWidget: public QgsLayoutItemBaseWidget, private Ui::QgsLayo
|
||||
|
||||
void mWrapCharLineEdit_textChanged( const QString &text );
|
||||
void mTitleLineEdit_textChanged( const QString &text );
|
||||
void mTitleAlignCombo_currentIndexChanged( int index );
|
||||
void mColumnCountSpinBox_valueChanged( int c );
|
||||
void mSplitLayerCheckBox_toggled( bool checked );
|
||||
void mEqualColumnWidthCheckBox_toggled( bool checked );
|
||||
@ -108,6 +107,12 @@ class QgsLayoutLegendWidget: public QgsLayoutItemBaseWidget, private Ui::QgsLayo
|
||||
void layerFontChanged();
|
||||
void itemFontChanged();
|
||||
|
||||
void titleAlignmentChanged();
|
||||
void groupAlignmentChanged();
|
||||
void subgroupAlignmentChanged();
|
||||
void itemAlignmentChanged();
|
||||
void arrangementChanged();
|
||||
|
||||
private:
|
||||
QgsLayoutLegendWidget() = delete;
|
||||
void blockAllSignals( bool b );
|
||||
|
||||
@ -84,8 +84,27 @@ QSizeF QgsLayerTreeModelLegendNode::drawSymbol( const QgsLegendSettings &setting
|
||||
return QSizeF();
|
||||
|
||||
if ( ctx && ctx->painter )
|
||||
symbolIcon.paint( ctx->painter, ctx->point.x(), ctx->point.y() + ( itemHeight - settings.symbolSize().height() ) / 2,
|
||||
settings.symbolSize().width(), settings.symbolSize().height() );
|
||||
{
|
||||
switch ( settings.symbolAlignment() )
|
||||
{
|
||||
case Qt::AlignLeft:
|
||||
default:
|
||||
symbolIcon.paint( ctx->painter,
|
||||
static_cast< int >( ctx->columnLeft ),
|
||||
static_cast< int >( ctx->top + ( itemHeight - settings.symbolSize().height() ) / 2 ),
|
||||
static_cast< int >( settings.symbolSize().width() ),
|
||||
static_cast< int >( settings.symbolSize().height() ) );
|
||||
break;
|
||||
|
||||
case Qt::AlignRight:
|
||||
symbolIcon.paint( ctx->painter,
|
||||
static_cast< int >( ctx->columnRight - settings.symbolSize().width() ),
|
||||
static_cast< int >( ctx->top + ( itemHeight - settings.symbolSize().height() ) / 2 ),
|
||||
static_cast< int >( settings.symbolSize().width() ),
|
||||
static_cast< int >( settings.symbolSize().height() ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
return settings.symbolSize();
|
||||
}
|
||||
|
||||
@ -117,13 +136,34 @@ QSizeF QgsLayerTreeModelLegendNode::drawSymbolText( const QgsLegendSettings &set
|
||||
|
||||
labelSize.rheight() = lines.count() * textHeight + ( lines.count() - 1 ) * ( settings.lineSpacing() + textDescent );
|
||||
|
||||
double labelX = 0.0, labelY = 0.0;
|
||||
double labelXMin = 0.0;
|
||||
double labelXMax = 0.0;
|
||||
double labelY = 0.0;
|
||||
if ( ctx && ctx->painter )
|
||||
{
|
||||
ctx->painter->setPen( settings.fontColor() );
|
||||
switch ( settings.symbolAlignment() )
|
||||
{
|
||||
case Qt::AlignLeft:
|
||||
default:
|
||||
labelXMin = ctx->columnLeft + std::max( static_cast< double >( symbolSize.width() ), ctx->maxSiblingSymbolWidth )
|
||||
+ settings.style( QgsLegendStyle::Symbol ).margin( QgsLegendStyle::Right )
|
||||
+ settings.style( QgsLegendStyle::SymbolLabel ).margin( QgsLegendStyle::Left );
|
||||
labelXMax = ctx->columnRight;
|
||||
break;
|
||||
|
||||
labelX = ctx->point.x() + std::max( static_cast< double >( symbolSize.width() ), ctx->labelXOffset );
|
||||
labelY = ctx->point.y();
|
||||
case Qt::AlignRight:
|
||||
labelXMin = ctx->columnLeft;
|
||||
// NOTE -- while the below calculations use the flipped margins from the style, that's only done because
|
||||
// those are the only margins we expose and use for now! (and we expose them as generic margins, not side-specific
|
||||
// ones) TODO when/if we expose other margin settings, these should be reversed...
|
||||
labelXMax = ctx->columnRight - std::max( static_cast< double >( symbolSize.width() ), ctx->maxSiblingSymbolWidth )
|
||||
- settings.style( QgsLegendStyle::Symbol ).margin( QgsLegendStyle::Right )
|
||||
- settings.style( QgsLegendStyle::SymbolLabel ).margin( QgsLegendStyle::Left );
|
||||
break;
|
||||
}
|
||||
|
||||
labelY = ctx->top;
|
||||
|
||||
// Vertical alignment of label with symbol
|
||||
if ( labelSize.height() < symbolSize.height() )
|
||||
@ -134,11 +174,27 @@ QSizeF QgsLayerTreeModelLegendNode::drawSymbolText( const QgsLegendSettings &set
|
||||
|
||||
for ( QStringList::ConstIterator itemPart = lines.constBegin(); itemPart != lines.constEnd(); ++itemPart )
|
||||
{
|
||||
labelSize.rwidth() = std::max( settings.textWidthMillimeters( symbolLabelFont, *itemPart ), double( labelSize.width() ) );
|
||||
const double lineWidth = settings.textWidthMillimeters( symbolLabelFont, *itemPart );
|
||||
labelSize.rwidth() = std::max( lineWidth, double( labelSize.width() ) );
|
||||
|
||||
if ( ctx && ctx->painter )
|
||||
{
|
||||
settings.drawText( ctx->painter, labelX, labelY, *itemPart, symbolLabelFont );
|
||||
switch ( settings.style( QgsLegendStyle::SymbolLabel ).alignment() )
|
||||
{
|
||||
case Qt::AlignLeft:
|
||||
default:
|
||||
settings.drawText( ctx->painter, labelXMin, labelY, *itemPart, symbolLabelFont );
|
||||
break;
|
||||
|
||||
case Qt::AlignRight:
|
||||
settings.drawText( ctx->painter, labelXMax - lineWidth, labelY, *itemPart, symbolLabelFont );
|
||||
break;
|
||||
|
||||
case Qt::AlignHCenter:
|
||||
settings.drawText( ctx->painter, labelXMin + ( labelXMax - labelXMin - lineWidth ) / 2.0, labelY, *itemPart, symbolLabelFont );
|
||||
break;
|
||||
}
|
||||
|
||||
if ( itemPart != ( lines.end() - 1 ) )
|
||||
labelY += textDescent + settings.lineSpacing() + textHeight;
|
||||
}
|
||||
@ -462,8 +518,7 @@ QSizeF QgsSymbolLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemC
|
||||
|
||||
if ( ctx && ctx->painter )
|
||||
{
|
||||
double currentXPosition = ctx->point.x();
|
||||
double currentYCoord = ctx->point.y() + ( itemHeight - settings.symbolSize().height() ) / 2;
|
||||
double currentYCoord = ctx->top + ( itemHeight - settings.symbolSize().height() ) / 2;
|
||||
QPainter *p = ctx->painter;
|
||||
|
||||
//setup painter scaling to dots so that raster symbology is drawn to scale
|
||||
@ -475,7 +530,18 @@ QSizeF QgsSymbolLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemC
|
||||
|
||||
p->save();
|
||||
p->setRenderHint( QPainter::Antialiasing );
|
||||
p->translate( currentXPosition + widthOffset, currentYCoord + heightOffset );
|
||||
|
||||
switch ( settings.symbolAlignment() )
|
||||
{
|
||||
case Qt::AlignLeft:
|
||||
default:
|
||||
p->translate( ctx->columnLeft + widthOffset, currentYCoord + heightOffset );
|
||||
break;
|
||||
case Qt::AlignRight:
|
||||
p->translate( ctx->columnRight - widthOffset - width, currentYCoord + heightOffset );
|
||||
break;
|
||||
}
|
||||
|
||||
p->scale( 1.0 / dotsPerMM, 1.0 / dotsPerMM );
|
||||
if ( opacity != 255 && settings.useAdvancedEffects() )
|
||||
{
|
||||
@ -659,8 +725,19 @@ QSizeF QgsImageLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemCo
|
||||
|
||||
if ( ctx && ctx->painter )
|
||||
{
|
||||
ctx->painter->drawImage( QRectF( ctx->point.x(), ctx->point.y(), settings.wmsLegendSize().width(), settings.wmsLegendSize().height() ),
|
||||
mImage, QRectF( 0, 0, mImage.width(), mImage.height() ) );
|
||||
switch ( settings.symbolAlignment() )
|
||||
{
|
||||
case Qt::AlignLeft:
|
||||
default:
|
||||
ctx->painter->drawImage( QRectF( ctx->columnLeft, ctx->top, settings.wmsLegendSize().width(), settings.wmsLegendSize().height() ),
|
||||
mImage, QRectF( 0, 0, mImage.width(), mImage.height() ) );
|
||||
break;
|
||||
|
||||
case Qt::AlignRight:
|
||||
ctx->painter->drawImage( QRectF( ctx->columnRight - settings.wmsLegendSize().width(), ctx->top, settings.wmsLegendSize().width(), settings.wmsLegendSize().height() ),
|
||||
mImage, QRectF( 0, 0, mImage.width(), mImage.height() ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
return settings.wmsLegendSize();
|
||||
}
|
||||
@ -724,8 +801,19 @@ QSizeF QgsRasterSymbolLegendNode::drawSymbol( const QgsLegendSettings &settings,
|
||||
ctx->painter->setPen( Qt::NoPen );
|
||||
}
|
||||
|
||||
ctx->painter->drawRect( QRectF( ctx->point.x(), ctx->point.y() + ( itemHeight - settings.symbolSize().height() ) / 2,
|
||||
settings.symbolSize().width(), settings.symbolSize().height() ) );
|
||||
switch ( settings.symbolAlignment() )
|
||||
{
|
||||
case Qt::AlignLeft:
|
||||
default:
|
||||
ctx->painter->drawRect( QRectF( ctx->columnLeft, ctx->top + ( itemHeight - settings.symbolSize().height() ) / 2,
|
||||
settings.symbolSize().width(), settings.symbolSize().height() ) );
|
||||
break;
|
||||
|
||||
case Qt::AlignRight:
|
||||
ctx->painter->drawRect( QRectF( ctx->columnRight - settings.symbolSize().width(), ctx->top + ( itemHeight - settings.symbolSize().height() ) / 2,
|
||||
settings.symbolSize().width(), settings.symbolSize().height() ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
return settings.symbolSize();
|
||||
}
|
||||
@ -829,9 +917,27 @@ QSizeF QgsWmsLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemCont
|
||||
|
||||
if ( ctx && ctx->painter )
|
||||
{
|
||||
ctx->painter->drawImage( QRectF( ctx->point, settings.wmsLegendSize() ),
|
||||
mImage,
|
||||
QRectF( QPointF( 0, 0 ), mImage.size() ) );
|
||||
switch ( settings.symbolAlignment() )
|
||||
{
|
||||
case Qt::AlignLeft:
|
||||
default:
|
||||
ctx->painter->drawImage( QRectF( ctx->columnLeft,
|
||||
ctx->top,
|
||||
settings.wmsLegendSize().width(),
|
||||
settings.wmsLegendSize().height() ),
|
||||
mImage,
|
||||
QRectF( QPointF( 0, 0 ), mImage.size() ) );
|
||||
break;
|
||||
|
||||
case Qt::AlignRight:
|
||||
ctx->painter->drawImage( QRectF( ctx->columnRight - settings.wmsLegendSize().width(),
|
||||
ctx->top,
|
||||
settings.wmsLegendSize().width(),
|
||||
settings.wmsLegendSize().height() ),
|
||||
mImage,
|
||||
QRectF( QPointF( 0, 0 ), mImage.size() ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
return settings.wmsLegendSize();
|
||||
}
|
||||
@ -958,7 +1064,7 @@ QgsLayerTreeModelLegendNode::ItemMetrics QgsDataDefinedSizeLegendNode::draw( con
|
||||
context.setPainter( ctx->painter );
|
||||
ctx->painter->save();
|
||||
ctx->painter->setRenderHint( QPainter::Antialiasing );
|
||||
ctx->painter->translate( ctx->point );
|
||||
ctx->painter->translate( ctx->columnLeft, ctx->top );
|
||||
ctx->painter->scale( 1 / context.scaleFactor(), 1 / context.scaleFactor() );
|
||||
}
|
||||
|
||||
|
||||
@ -86,14 +86,56 @@ class CORE_EXPORT QgsLayerTreeModelLegendNode : public QObject
|
||||
|
||||
struct ItemContext
|
||||
{
|
||||
Q_NOWARN_DEPRECATED_PUSH //because of deprecated members
|
||||
ItemContext() = default;
|
||||
Q_NOWARN_DEPRECATED_POP
|
||||
|
||||
//! Render context, if available
|
||||
QgsRenderContext *context = nullptr;
|
||||
//! Painter
|
||||
QPainter *painter = nullptr;
|
||||
//! Top-left corner of the legend item
|
||||
QPointF point;
|
||||
//! offset from the left side where label should start
|
||||
double labelXOffset;
|
||||
|
||||
/**
|
||||
* Top-left corner of the legend item.
|
||||
* \deprecated Use top, columnLeft, columnRight instead.
|
||||
*/
|
||||
Q_DECL_DEPRECATED QPointF point;
|
||||
|
||||
/**
|
||||
* Offset from the left side where label should start.
|
||||
* \deprecated use columnLeft, columnRight instead.
|
||||
*/
|
||||
Q_DECL_DEPRECATED double labelXOffset = 0.0;
|
||||
|
||||
/**
|
||||
* Top y-position of legend item.
|
||||
* \since QGIS 3.10
|
||||
*/
|
||||
double top = 0.0;
|
||||
|
||||
/**
|
||||
* Left side of current legend column. This should be used when determining
|
||||
* where to render legend item content, correctly respecting the symbol and text
|
||||
* alignment from the legend settings.
|
||||
* \since QGIS 3.10
|
||||
*/
|
||||
double columnLeft = 0.0;
|
||||
|
||||
/**
|
||||
* Right side of current legend column. This should be used when determining
|
||||
* where to render legend item content, correctly respecting the symbol and text
|
||||
* alignment from the legend settings.
|
||||
* \since QGIS 3.10
|
||||
*/
|
||||
double columnRight = 0.0;
|
||||
|
||||
/**
|
||||
* Largest symbol width, considering all other sibling legend components associated with
|
||||
* the current component.
|
||||
* \since QGIS 3.10
|
||||
*/
|
||||
double maxSiblingSymbolWidth = 0.0;
|
||||
|
||||
};
|
||||
|
||||
struct ItemMetrics
|
||||
|
||||
@ -139,6 +139,7 @@ void QgsLayoutItemLegend::paint( QPainter *painter, const QStyleOptionGraphicsIt
|
||||
attemptResize( newSize );
|
||||
}
|
||||
}
|
||||
|
||||
QgsLayoutItem::paint( painter, itemStyle, pWidget );
|
||||
}
|
||||
|
||||
@ -366,6 +367,16 @@ void QgsLayoutItemLegend::setSymbolWidth( double w )
|
||||
mSettings.setSymbolSize( QSizeF( w, mSettings.symbolSize().height() ) );
|
||||
}
|
||||
|
||||
void QgsLayoutItemLegend::setSymbolAlignment( Qt::AlignmentFlag alignment )
|
||||
{
|
||||
mSettings.setSymbolAlignment( alignment );
|
||||
}
|
||||
|
||||
Qt::AlignmentFlag QgsLayoutItemLegend::symbolAlignment() const
|
||||
{
|
||||
return mSettings.symbolAlignment();
|
||||
}
|
||||
|
||||
double QgsLayoutItemLegend::symbolHeight() const
|
||||
{
|
||||
return mSettings.symbolSize().height();
|
||||
@ -488,6 +499,10 @@ bool QgsLayoutItemLegend::writePropertiesToElement( QDomElement &legendElem, QDo
|
||||
|
||||
legendElem.setAttribute( QStringLiteral( "symbolWidth" ), QString::number( mSettings.symbolSize().width() ) );
|
||||
legendElem.setAttribute( QStringLiteral( "symbolHeight" ), QString::number( mSettings.symbolSize().height() ) );
|
||||
|
||||
legendElem.setAttribute( QStringLiteral( "symbolAlignment" ), mSettings.symbolAlignment() );
|
||||
|
||||
legendElem.setAttribute( QStringLiteral( "symbolAlignment" ), mSettings.symbolAlignment() );
|
||||
legendElem.setAttribute( QStringLiteral( "lineSpacing" ), QString::number( mSettings.lineSpacing() ) );
|
||||
|
||||
legendElem.setAttribute( QStringLiteral( "rasterBorder" ), mSettings.drawRasterStroke() );
|
||||
@ -577,6 +592,8 @@ bool QgsLayoutItemLegend::readPropertiesFromElement( const QDomElement &itemElem
|
||||
mSettings.setColumnSpace( itemElem.attribute( QStringLiteral( "columnSpace" ), QStringLiteral( "2.0" ) ).toDouble() );
|
||||
|
||||
mSettings.setSymbolSize( QSizeF( itemElem.attribute( QStringLiteral( "symbolWidth" ), QStringLiteral( "7.0" ) ).toDouble(), itemElem.attribute( QStringLiteral( "symbolHeight" ), QStringLiteral( "14.0" ) ).toDouble() ) );
|
||||
mSettings.setSymbolAlignment( static_cast< Qt::AlignmentFlag >( itemElem.attribute( QStringLiteral( "symbolAlignment" ), QString::number( Qt::AlignLeft ) ).toInt() ) );
|
||||
|
||||
mSettings.setWmsLegendSize( QSizeF( itemElem.attribute( QStringLiteral( "wmsLegendWidth" ), QStringLiteral( "50" ) ).toDouble(), itemElem.attribute( QStringLiteral( "wmsLegendHeight" ), QStringLiteral( "25" ) ).toDouble() ) );
|
||||
mSettings.setLineSpacing( itemElem.attribute( QStringLiteral( "lineSpacing" ), QStringLiteral( "1.0" ) ).toDouble() );
|
||||
|
||||
@ -776,7 +793,7 @@ void QgsLayoutItemLegend::doUpdateFilterByMap()
|
||||
|
||||
if ( mMap && ( mLegendFilterByMap || filterByExpression || mInAtlas ) )
|
||||
{
|
||||
int dpi = mLayout->renderContext().dpi();
|
||||
double dpi = mLayout->renderContext().dpi();
|
||||
|
||||
QgsRectangle requestRectangle = mMap->requestedExtent();
|
||||
|
||||
|
||||
@ -266,6 +266,26 @@ class CORE_EXPORT QgsLayoutItemLegend : public QgsLayoutItem
|
||||
*/
|
||||
void setSymbolWidth( double width );
|
||||
|
||||
/**
|
||||
* Sets the \a alignment for placement of legend symbols.
|
||||
*
|
||||
* Only Qt::AlignLeft or Qt::AlignRight are supported values.
|
||||
*
|
||||
* \see symbolAlignment()
|
||||
* \since QGIS 3.10.0
|
||||
*/
|
||||
void setSymbolAlignment( Qt::AlignmentFlag alignment );
|
||||
|
||||
/**
|
||||
* Returns the alignment for placement of legend symbols.
|
||||
*
|
||||
* Only Qt::AlignLeft or Qt::AlignRight are supported values.
|
||||
*
|
||||
* \see setSymbolAlignment()
|
||||
* \since QGIS 3.10.0
|
||||
*/
|
||||
Qt::AlignmentFlag symbolAlignment() const;
|
||||
|
||||
/**
|
||||
* Returns the legend symbol height.
|
||||
* \see setSymbolHeight()
|
||||
|
||||
@ -129,19 +129,38 @@ QSizeF QgsLegendRenderer::paintAndDetermineSizeInternal( QgsRenderContext *conte
|
||||
if ( !rootGroup )
|
||||
return size;
|
||||
|
||||
QList<Atom> atomList = createAtomList( rootGroup, mSettings.splitLayer() );
|
||||
QList<LegendComponentGroup> atomList = createComponentGroupList( rootGroup, mSettings.splitLayer() );
|
||||
|
||||
setColumns( atomList );
|
||||
|
||||
qreal maxColumnWidth = 0;
|
||||
if ( mSettings.equalColumnWidth() )
|
||||
// another iteration -- this one is required to calculate the maximum item width for each
|
||||
// column. Unfortunately, we can't trust the atom widths at this stage, as they are minimal widths
|
||||
// only. When actually rendering a symbol node, the text is aligned according to the WIDEST
|
||||
// symbol in a column. So that means we can't possibly determine the exact size of legend components
|
||||
// until now. BUUUUUUUUUUUUT. Because everything sucks, we can't even start the actual render of items
|
||||
// at the same time we calculate this -- legend items REQUIRE the REAL width of the columns in order to
|
||||
// correctly align right or center-aligned symbols/text. Bah -- A triple iteration it is!
|
||||
QMap< int, double > maxColumnWidths;
|
||||
qreal maxEqualColumnWidth = 0;
|
||||
// temporarily remove painter from context -- we don't need to actually draw anything yet. But we DO need
|
||||
// to send the full render context so that an expression context is available during the size calculation
|
||||
QPainter *prevPainter = context ? context->painter() : nullptr;
|
||||
if ( context )
|
||||
context->setPainter( nullptr );
|
||||
for ( const LegendComponentGroup &atom : qgis::as_const( atomList ) )
|
||||
{
|
||||
const auto constAtomList = atomList;
|
||||
for ( const Atom &atom : constAtomList )
|
||||
const QSizeF actualSize = drawGroup( atom, context, ColumnContext() );
|
||||
if ( mSettings.equalColumnWidth() )
|
||||
{
|
||||
maxColumnWidth = std::max( atom.size.width(), maxColumnWidth );
|
||||
maxEqualColumnWidth = std::max( actualSize.width(), maxEqualColumnWidth );
|
||||
}
|
||||
else
|
||||
{
|
||||
maxColumnWidths[ atom.column ] = std::max( actualSize.width(), maxColumnWidths.value( atom.column, 0 ) );
|
||||
}
|
||||
}
|
||||
if ( context )
|
||||
context->setPainter( prevPainter );
|
||||
|
||||
//calculate size of title
|
||||
QSizeF titleSize = drawTitle();
|
||||
@ -149,48 +168,46 @@ QSizeF QgsLegendRenderer::paintAndDetermineSizeInternal( QgsRenderContext *conte
|
||||
titleSize.rwidth() += mSettings.boxSpace() * 2.0;
|
||||
double columnTop = mSettings.boxSpace() + titleSize.height() + mSettings.style( QgsLegendStyle::Title ).margin( QgsLegendStyle::Bottom );
|
||||
|
||||
QPointF point( mSettings.boxSpace(), columnTop );
|
||||
bool firstInColumn = true;
|
||||
double columnMaxHeight = 0;
|
||||
qreal columnWidth = 0;
|
||||
int column = 0;
|
||||
const auto constAtomList = atomList;
|
||||
for ( const Atom &atom : constAtomList )
|
||||
int column = -1;
|
||||
ColumnContext columnContext;
|
||||
columnContext.left = mSettings.boxSpace();
|
||||
columnContext.right = mLegendSize.width() - mSettings.boxSpace();
|
||||
double currentY = columnTop;
|
||||
|
||||
for ( const LegendComponentGroup &atom : qgis::as_const( atomList ) )
|
||||
{
|
||||
if ( atom.column > column )
|
||||
{
|
||||
// Switch to next column
|
||||
if ( mSettings.equalColumnWidth() )
|
||||
{
|
||||
point.rx() += mSettings.columnSpace() + maxColumnWidth;
|
||||
}
|
||||
else
|
||||
{
|
||||
point.rx() += mSettings.columnSpace() + columnWidth;
|
||||
}
|
||||
point.ry() = columnTop;
|
||||
columnWidth = 0;
|
||||
columnContext.left = atom.column > 0 ? columnContext.right + mSettings.columnSpace() : mSettings.boxSpace();
|
||||
columnWidth = mSettings.equalColumnWidth() ? maxEqualColumnWidth : maxColumnWidths.value( atom.column );
|
||||
columnContext.right = columnContext.left + columnWidth;
|
||||
currentY = columnTop;
|
||||
column++;
|
||||
firstInColumn = true;
|
||||
}
|
||||
if ( !firstInColumn )
|
||||
{
|
||||
point.ry() += spaceAboveAtom( atom );
|
||||
currentY += spaceAboveGroup( atom );
|
||||
}
|
||||
|
||||
QSizeF atomSize = context ? drawAtom( atom, context, point )
|
||||
: drawAtom( atom, painter, point );
|
||||
columnWidth = std::max( atomSize.width(), columnWidth );
|
||||
if ( context )
|
||||
drawGroup( atom, context, columnContext, currentY );
|
||||
else if ( painter )
|
||||
drawGroup( atom, columnContext, painter, currentY );
|
||||
|
||||
point.ry() += atom.size.height();
|
||||
columnMaxHeight = std::max( point.y() - columnTop, columnMaxHeight );
|
||||
currentY += atom.size.height();
|
||||
columnMaxHeight = std::max( currentY - columnTop, columnMaxHeight );
|
||||
|
||||
firstInColumn = false;
|
||||
}
|
||||
point.rx() += columnWidth + mSettings.boxSpace();
|
||||
const double totalWidth = columnContext.right + mSettings.boxSpace();
|
||||
|
||||
size.rheight() = columnTop + columnMaxHeight + mSettings.boxSpace();
|
||||
size.rwidth() = point.x();
|
||||
size.rwidth() = totalWidth;
|
||||
if ( !mSettings.title().isEmpty() )
|
||||
{
|
||||
size.rwidth() = std::max( titleSize.width(), size.width() );
|
||||
@ -207,32 +224,38 @@ QSizeF QgsLegendRenderer::paintAndDetermineSizeInternal( QgsRenderContext *conte
|
||||
// Now we have set the correct total item width and can draw the title centered
|
||||
if ( !mSettings.title().isEmpty() )
|
||||
{
|
||||
if ( mSettings.titleAlignment() == Qt::AlignLeft )
|
||||
{
|
||||
point.rx() = mSettings.boxSpace();
|
||||
}
|
||||
else if ( mSettings.titleAlignment() == Qt::AlignHCenter )
|
||||
{
|
||||
point.rx() = size.width() / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
point.rx() = size.width() - mSettings.boxSpace();
|
||||
}
|
||||
point.ry() = mSettings.boxSpace();
|
||||
if ( context )
|
||||
drawTitle( context, point, mSettings.titleAlignment(), size.width() );
|
||||
drawTitle( context, mSettings.boxSpace(), mSettings.titleAlignment(), size.width() );
|
||||
else
|
||||
drawTitle( painter, point, mSettings.titleAlignment(), size.width() );
|
||||
drawTitle( painter, mSettings.boxSpace(), mSettings.titleAlignment(), size.width() );
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
QList<QgsLegendRenderer::Atom> QgsLegendRenderer::createAtomList( QgsLayerTreeGroup *parentGroup, bool splitLayer )
|
||||
void QgsLegendRenderer::widthAndOffsetForTitleText( const Qt::AlignmentFlag halignment, const double legendWidth, double &textBoxWidth, double &textBoxLeft )
|
||||
{
|
||||
QList<Atom> atoms;
|
||||
switch ( halignment )
|
||||
{
|
||||
default:
|
||||
textBoxLeft = mSettings.boxSpace();
|
||||
textBoxWidth = legendWidth - 2 * mSettings.boxSpace();
|
||||
break;
|
||||
|
||||
case Qt::AlignHCenter:
|
||||
{
|
||||
// not sure on this logic, I just moved it -- don't blame me for it being totally obscure!
|
||||
const double centerX = legendWidth / 2;
|
||||
textBoxWidth = ( std::min( static_cast< double >( centerX ), legendWidth - centerX ) - mSettings.boxSpace() ) * 2.0;
|
||||
textBoxLeft = centerX - textBoxWidth / 2.;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QList<QgsLegendRenderer::LegendComponentGroup> QgsLegendRenderer::createComponentGroupList( QgsLayerTreeGroup *parentGroup, bool splitLayer )
|
||||
{
|
||||
QList<LegendComponentGroup> atoms;
|
||||
|
||||
if ( !parentGroup ) return atoms;
|
||||
|
||||
@ -244,29 +267,29 @@ QList<QgsLegendRenderer::Atom> QgsLegendRenderer::createAtomList( QgsLayerTreeGr
|
||||
QgsLayerTreeGroup *nodeGroup = QgsLayerTree::toGroup( node );
|
||||
|
||||
// Group subitems
|
||||
QList<Atom> groupAtoms = createAtomList( nodeGroup, splitLayer );
|
||||
QList<LegendComponentGroup> groupAtoms = createComponentGroupList( nodeGroup, splitLayer );
|
||||
bool hasSubItems = !groupAtoms.empty();
|
||||
|
||||
if ( nodeLegendStyle( nodeGroup ) != QgsLegendStyle::Hidden )
|
||||
{
|
||||
Nucleon nucleon;
|
||||
LegendComponent nucleon;
|
||||
nucleon.item = node;
|
||||
nucleon.size = drawGroupTitle( nodeGroup );
|
||||
|
||||
if ( !groupAtoms.isEmpty() )
|
||||
{
|
||||
// Add internal space between this group title and the next nucleon
|
||||
groupAtoms[0].size.rheight() += spaceAboveAtom( groupAtoms[0] );
|
||||
groupAtoms[0].size.rheight() += spaceAboveGroup( groupAtoms[0] );
|
||||
// Prepend this group title to the first atom
|
||||
groupAtoms[0].nucleons.prepend( nucleon );
|
||||
groupAtoms[0].components.prepend( nucleon );
|
||||
groupAtoms[0].size.rheight() += nucleon.size.height();
|
||||
groupAtoms[0].size.rwidth() = std::max( nucleon.size.width(), groupAtoms[0].size.width() );
|
||||
}
|
||||
else
|
||||
{
|
||||
// no subitems, append new atom
|
||||
Atom atom;
|
||||
atom.nucleons.append( nucleon );
|
||||
LegendComponentGroup atom;
|
||||
atom.components.append( nucleon );
|
||||
atom.size.rwidth() += nucleon.size.width();
|
||||
atom.size.rheight() += nucleon.size.height();
|
||||
atom.size.rwidth() = std::max( nucleon.size.width(), atom.size.width() );
|
||||
@ -284,14 +307,14 @@ QList<QgsLegendRenderer::Atom> QgsLegendRenderer::createAtomList( QgsLayerTreeGr
|
||||
{
|
||||
QgsLayerTreeLayer *nodeLayer = QgsLayerTree::toLayer( node );
|
||||
|
||||
Atom atom;
|
||||
LegendComponentGroup atom;
|
||||
|
||||
if ( nodeLegendStyle( nodeLayer ) != QgsLegendStyle::Hidden )
|
||||
{
|
||||
Nucleon nucleon;
|
||||
LegendComponent nucleon;
|
||||
nucleon.item = node;
|
||||
nucleon.size = drawLayerTitle( nodeLayer );
|
||||
atom.nucleons.append( nucleon );
|
||||
atom.components.append( nucleon );
|
||||
atom.size.rwidth() = nucleon.size.width();
|
||||
atom.size.rheight() = nucleon.size.height();
|
||||
}
|
||||
@ -304,13 +327,13 @@ QList<QgsLegendRenderer::Atom> QgsLegendRenderer::createAtomList( QgsLayerTreeGr
|
||||
if ( legendNodes.isEmpty() && mLegendModel->legendFilterMapSettings() )
|
||||
continue;
|
||||
|
||||
QList<Atom> layerAtoms;
|
||||
QList<LegendComponentGroup> layerAtoms;
|
||||
|
||||
for ( int j = 0; j < legendNodes.count(); j++ )
|
||||
{
|
||||
QgsLayerTreeModelLegendNode *legendNode = legendNodes.at( j );
|
||||
|
||||
Nucleon symbolNucleon = drawSymbolItem( legendNode );
|
||||
LegendComponent symbolNucleon = drawSymbolItem( legendNode );
|
||||
|
||||
if ( !mSettings.splitLayer() || j == 0 )
|
||||
{
|
||||
@ -318,18 +341,18 @@ QList<QgsLegendRenderer::Atom> QgsLegendRenderer::createAtomList( QgsLayerTreeGr
|
||||
// the width is not correct at this moment, we must align all symbol labels
|
||||
atom.size.rwidth() = std::max( symbolNucleon.size.width(), atom.size.width() );
|
||||
// Add symbol space only if there is already title or another item above
|
||||
if ( !atom.nucleons.isEmpty() )
|
||||
if ( !atom.components.isEmpty() )
|
||||
{
|
||||
// TODO: for now we keep Symbol and SymbolLabel Top margin in sync
|
||||
atom.size.rheight() += mSettings.style( QgsLegendStyle::Symbol ).margin( QgsLegendStyle::Top );
|
||||
}
|
||||
atom.size.rheight() += symbolNucleon.size.height();
|
||||
atom.nucleons.append( symbolNucleon );
|
||||
atom.components.append( symbolNucleon );
|
||||
}
|
||||
else
|
||||
{
|
||||
Atom symbolAtom;
|
||||
symbolAtom.nucleons.append( symbolNucleon );
|
||||
LegendComponentGroup symbolAtom;
|
||||
symbolAtom.components.append( symbolNucleon );
|
||||
symbolAtom.size.rwidth() = symbolNucleon.size.width();
|
||||
symbolAtom.size.rheight() = symbolNucleon.size.height();
|
||||
layerAtoms.append( symbolAtom );
|
||||
@ -344,7 +367,7 @@ QList<QgsLegendRenderer::Atom> QgsLegendRenderer::createAtomList( QgsLayerTreeGr
|
||||
}
|
||||
|
||||
|
||||
void QgsLegendRenderer::setColumns( QList<Atom> &atomList )
|
||||
void QgsLegendRenderer::setColumns( QList<LegendComponentGroup> &atomList )
|
||||
{
|
||||
if ( mSettings.columnCount() == 0 ) return;
|
||||
|
||||
@ -352,9 +375,9 @@ void QgsLegendRenderer::setColumns( QList<Atom> &atomList )
|
||||
double totalHeight = 0;
|
||||
qreal maxAtomHeight = 0;
|
||||
const auto constAtomList = atomList;
|
||||
for ( const Atom &atom : constAtomList )
|
||||
for ( const LegendComponentGroup &atom : constAtomList )
|
||||
{
|
||||
totalHeight += spaceAboveAtom( atom );
|
||||
totalHeight += spaceAboveGroup( atom );
|
||||
totalHeight += atom.size.height();
|
||||
maxAtomHeight = std::max( atom.size.height(), maxAtomHeight );
|
||||
}
|
||||
@ -375,10 +398,10 @@ void QgsLegendRenderer::setColumns( QList<Atom> &atomList )
|
||||
// Recalc average height for remaining columns including current
|
||||
double avgColumnHeight = ( totalHeight - closedColumnsHeight ) / ( mSettings.columnCount() - currentColumn );
|
||||
|
||||
Atom atom = atomList.at( i );
|
||||
LegendComponentGroup atom = atomList.at( i );
|
||||
double currentHeight = currentColumnHeight;
|
||||
if ( currentColumnAtomCount > 0 )
|
||||
currentHeight += spaceAboveAtom( atom );
|
||||
currentHeight += spaceAboveGroup( atom );
|
||||
currentHeight += atom.size.height();
|
||||
|
||||
bool canCreateNewColumn = ( currentColumnAtomCount > 0 ) // do not leave empty column
|
||||
@ -414,39 +437,40 @@ void QgsLegendRenderer::setColumns( QList<Atom> &atomList )
|
||||
QMap<QString, qreal> maxSymbolWidth;
|
||||
for ( int i = 0; i < atomList.size(); i++ )
|
||||
{
|
||||
Atom &atom = atomList[i];
|
||||
for ( int j = 0; j < atom.nucleons.size(); j++ )
|
||||
LegendComponentGroup &atom = atomList[i];
|
||||
for ( int j = 0; j < atom.components.size(); j++ )
|
||||
{
|
||||
if ( QgsLayerTreeModelLegendNode *legendNode = qobject_cast<QgsLayerTreeModelLegendNode *>( atom.nucleons.at( j ).item ) )
|
||||
if ( QgsLayerTreeModelLegendNode *legendNode = qobject_cast<QgsLayerTreeModelLegendNode *>( atom.components.at( j ).item ) )
|
||||
{
|
||||
QString key = QStringLiteral( "%1-%2" ).arg( reinterpret_cast< qulonglong >( legendNode->layerNode() ) ).arg( atom.column );
|
||||
maxSymbolWidth[key] = std::max( atom.nucleons.at( j ).symbolSize.width(), maxSymbolWidth[key] );
|
||||
maxSymbolWidth[key] = std::max( atom.components.at( j ).symbolSize.width(), maxSymbolWidth[key] );
|
||||
}
|
||||
}
|
||||
}
|
||||
for ( int i = 0; i < atomList.size(); i++ )
|
||||
{
|
||||
Atom &atom = atomList[i];
|
||||
for ( int j = 0; j < atom.nucleons.size(); j++ )
|
||||
LegendComponentGroup &atom = atomList[i];
|
||||
for ( int j = 0; j < atom.components.size(); j++ )
|
||||
{
|
||||
if ( QgsLayerTreeModelLegendNode *legendNode = qobject_cast<QgsLayerTreeModelLegendNode *>( atom.nucleons.at( j ).item ) )
|
||||
if ( QgsLayerTreeModelLegendNode *legendNode = qobject_cast<QgsLayerTreeModelLegendNode *>( atom.components.at( j ).item ) )
|
||||
{
|
||||
QString key = QStringLiteral( "%1-%2" ).arg( reinterpret_cast< qulonglong >( legendNode->layerNode() ) ).arg( atom.column );
|
||||
double space = mSettings.style( QgsLegendStyle::Symbol ).margin( QgsLegendStyle::Right ) +
|
||||
mSettings.style( QgsLegendStyle::SymbolLabel ).margin( QgsLegendStyle::Left );
|
||||
atom.nucleons[j].labelXOffset = maxSymbolWidth[key] + space;
|
||||
atom.nucleons[j].size.rwidth() = maxSymbolWidth[key] + space + atom.nucleons.at( j ).labelSize.width();
|
||||
atom.components[j].labelXOffset = maxSymbolWidth[key] + space;
|
||||
atom.components[j].maxSiblingSymbolWidth = maxSymbolWidth[key];
|
||||
atom.components[j].size.rwidth() = maxSymbolWidth[key] + space + atom.components.at( j ).labelSize.width();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QSizeF QgsLegendRenderer::drawTitle( QPainter *painter, QPointF point, Qt::AlignmentFlag halignment, double legendWidth )
|
||||
QSizeF QgsLegendRenderer::drawTitle( QPainter *painter, double top, Qt::AlignmentFlag halignment, double legendWidth )
|
||||
{
|
||||
return drawTitleInternal( nullptr, painter, point, halignment, legendWidth );
|
||||
return drawTitleInternal( nullptr, painter, top, halignment, legendWidth );
|
||||
}
|
||||
|
||||
QSizeF QgsLegendRenderer::drawTitleInternal( QgsRenderContext *context, QPainter *painter, QPointF point, Qt::AlignmentFlag halignment, double legendWidth )
|
||||
QSizeF QgsLegendRenderer::drawTitleInternal( QgsRenderContext *context, QPainter *painter, const double top, Qt::AlignmentFlag halignment, double legendWidth )
|
||||
{
|
||||
QSizeF size( 0, 0 );
|
||||
if ( mSettings.title().isEmpty() )
|
||||
@ -455,7 +479,7 @@ QSizeF QgsLegendRenderer::drawTitleInternal( QgsRenderContext *context, QPainter
|
||||
}
|
||||
|
||||
QStringList lines = mSettings.splitStringForWrapping( mSettings.title() );
|
||||
double y = point.y();
|
||||
double y = top;
|
||||
|
||||
if ( context && context->painter() )
|
||||
{
|
||||
@ -469,22 +493,7 @@ QSizeF QgsLegendRenderer::drawTitleInternal( QgsRenderContext *context, QPainter
|
||||
//calculate width and left pos of rectangle to draw text into
|
||||
double textBoxWidth;
|
||||
double textBoxLeft;
|
||||
switch ( halignment )
|
||||
{
|
||||
case Qt::AlignHCenter:
|
||||
textBoxWidth = ( std::min( static_cast< double >( point.x() ), legendWidth - point.x() ) - mSettings.boxSpace() ) * 2.0;
|
||||
textBoxLeft = point.x() - textBoxWidth / 2.;
|
||||
break;
|
||||
case Qt::AlignRight:
|
||||
textBoxLeft = mSettings.boxSpace();
|
||||
textBoxWidth = point.x() - mSettings.boxSpace();
|
||||
break;
|
||||
case Qt::AlignLeft:
|
||||
default:
|
||||
textBoxLeft = point.x();
|
||||
textBoxWidth = legendWidth - point.x() - mSettings.boxSpace();
|
||||
break;
|
||||
}
|
||||
widthAndOffsetForTitleText( halignment, legendWidth, textBoxWidth, textBoxLeft );
|
||||
|
||||
QFont titleFont = mSettings.style( QgsLegendStyle::Title ).font();
|
||||
|
||||
@ -515,17 +524,17 @@ QSizeF QgsLegendRenderer::drawTitleInternal( QgsRenderContext *context, QPainter
|
||||
y += mSettings.lineSpacing();
|
||||
}
|
||||
}
|
||||
size.rheight() = y - point.y();
|
||||
size.rheight() = y - top;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
double QgsLegendRenderer::spaceAboveAtom( const Atom &atom )
|
||||
double QgsLegendRenderer::spaceAboveGroup( const LegendComponentGroup &atom )
|
||||
{
|
||||
if ( atom.nucleons.isEmpty() ) return 0;
|
||||
if ( atom.components.isEmpty() ) return 0;
|
||||
|
||||
Nucleon nucleon = atom.nucleons.first();
|
||||
LegendComponent nucleon = atom.components.first();
|
||||
|
||||
if ( QgsLayerTreeGroup *nodeGroup = qobject_cast<QgsLayerTreeGroup *>( nucleon.item ) )
|
||||
{
|
||||
@ -546,16 +555,17 @@ double QgsLegendRenderer::spaceAboveAtom( const Atom &atom )
|
||||
|
||||
|
||||
// Draw atom and expand its size (using actual nucleons labelXOffset)
|
||||
QSizeF QgsLegendRenderer::drawAtom( const Atom &atom, QPainter *painter, QPointF point )
|
||||
QSizeF QgsLegendRenderer::drawGroup( const LegendComponentGroup &atom, const ColumnContext &columnContext, QPainter *painter, double top )
|
||||
{
|
||||
return drawAtomInternal( atom, nullptr, painter, point );
|
||||
return drawGroupInternal( atom, nullptr, columnContext, painter, top );
|
||||
}
|
||||
|
||||
QSizeF QgsLegendRenderer::drawAtomInternal( const Atom &atom, QgsRenderContext *context, QPainter *painter, QPointF point )
|
||||
QSizeF QgsLegendRenderer::drawGroupInternal( const LegendComponentGroup &atom, QgsRenderContext *context, const ColumnContext &columnContext, QPainter *painter, const double top )
|
||||
{
|
||||
bool first = true;
|
||||
QSizeF size = QSizeF( atom.size );
|
||||
for ( const Nucleon &nucleon : qgis::as_const( atom.nucleons ) )
|
||||
double currentY = top;
|
||||
for ( const LegendComponent &nucleon : qgis::as_const( atom.components ) )
|
||||
{
|
||||
if ( QgsLayerTreeGroup *groupItem = qobject_cast<QgsLayerTreeGroup *>( nucleon.item ) )
|
||||
{
|
||||
@ -564,12 +574,12 @@ QSizeF QgsLegendRenderer::drawAtomInternal( const Atom &atom, QgsRenderContext *
|
||||
{
|
||||
if ( !first )
|
||||
{
|
||||
point.ry() += mSettings.style( s ).margin( QgsLegendStyle::Top );
|
||||
currentY += mSettings.style( s ).margin( QgsLegendStyle::Top );
|
||||
}
|
||||
if ( context )
|
||||
drawGroupTitle( groupItem, context, point );
|
||||
drawGroupTitle( groupItem, context, columnContext, currentY );
|
||||
else
|
||||
drawGroupTitle( groupItem, painter, point );
|
||||
drawGroupTitle( groupItem, columnContext, painter, currentY );
|
||||
}
|
||||
}
|
||||
else if ( QgsLayerTreeLayer *layerItem = qobject_cast<QgsLayerTreeLayer *>( nucleon.item ) )
|
||||
@ -579,38 +589,38 @@ QSizeF QgsLegendRenderer::drawAtomInternal( const Atom &atom, QgsRenderContext *
|
||||
{
|
||||
if ( !first )
|
||||
{
|
||||
point.ry() += mSettings.style( s ).margin( QgsLegendStyle::Top );
|
||||
currentY += mSettings.style( s ).margin( QgsLegendStyle::Top );
|
||||
}
|
||||
if ( context )
|
||||
drawLayerTitle( layerItem, context, point );
|
||||
drawLayerTitle( layerItem, context, columnContext, currentY );
|
||||
else
|
||||
drawLayerTitle( layerItem, painter, point );
|
||||
drawLayerTitle( layerItem, columnContext, painter, currentY );
|
||||
}
|
||||
}
|
||||
else if ( QgsLayerTreeModelLegendNode *legendNode = qobject_cast<QgsLayerTreeModelLegendNode *>( nucleon.item ) )
|
||||
{
|
||||
if ( !first )
|
||||
{
|
||||
point.ry() += mSettings.style( QgsLegendStyle::Symbol ).margin( QgsLegendStyle::Top );
|
||||
currentY += mSettings.style( QgsLegendStyle::Symbol ).margin( QgsLegendStyle::Top );
|
||||
}
|
||||
|
||||
Nucleon symbolNucleon = context ? drawSymbolItem( legendNode, context, point, nucleon.labelXOffset )
|
||||
: drawSymbolItem( legendNode, painter, point, nucleon.labelXOffset );
|
||||
LegendComponent symbolNucleon = context ? drawSymbolItem( legendNode, context, columnContext, currentY, nucleon.maxSiblingSymbolWidth )
|
||||
: drawSymbolItem( legendNode, columnContext, painter, currentY, nucleon.maxSiblingSymbolWidth );
|
||||
// expand width, it may be wider because of labelXOffset
|
||||
size.rwidth() = std::max( symbolNucleon.size.width(), size.width() );
|
||||
}
|
||||
point.ry() += nucleon.size.height();
|
||||
currentY += nucleon.size.height();
|
||||
first = false;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
QgsLegendRenderer::Nucleon QgsLegendRenderer::drawSymbolItem( QgsLayerTreeModelLegendNode *symbolItem, QPainter *painter, QPointF point, double labelXOffset )
|
||||
QgsLegendRenderer::LegendComponent QgsLegendRenderer::drawSymbolItem( QgsLayerTreeModelLegendNode *symbolItem, const ColumnContext &columnContext, QPainter *painter, double top, double maxSiblingSymbolWidth )
|
||||
{
|
||||
return drawSymbolItemInternal( symbolItem, nullptr, painter, point, labelXOffset );
|
||||
return drawSymbolItemInternal( symbolItem, columnContext, nullptr, painter, top, maxSiblingSymbolWidth );
|
||||
}
|
||||
|
||||
QgsLegendRenderer::Nucleon QgsLegendRenderer::drawSymbolItemInternal( QgsLayerTreeModelLegendNode *symbolItem, QgsRenderContext *context, QPainter *painter, QPointF point, double labelXOffset )
|
||||
QgsLegendRenderer::LegendComponent QgsLegendRenderer::drawSymbolItemInternal( QgsLayerTreeModelLegendNode *symbolItem, const ColumnContext &columnContext, QgsRenderContext *context, QPainter *painter, double top, double maxSiblingSymbolWidth )
|
||||
{
|
||||
QgsLayerTreeModelLegendNode::ItemContext ctx;
|
||||
ctx.context = context;
|
||||
@ -624,8 +634,15 @@ QgsLegendRenderer::Nucleon QgsLegendRenderer::drawSymbolItemInternal( QgsLayerTr
|
||||
}
|
||||
|
||||
ctx.painter = context ? context->painter() : painter;
|
||||
ctx.point = point;
|
||||
ctx.labelXOffset = labelXOffset;
|
||||
Q_NOWARN_DEPRECATED_PUSH
|
||||
ctx.point = QPointF( columnContext.left, top );
|
||||
ctx.labelXOffset = maxSiblingSymbolWidth;
|
||||
Q_NOWARN_DEPRECATED_POP
|
||||
|
||||
ctx.top = top;
|
||||
ctx.columnLeft = columnContext.left;
|
||||
ctx.columnRight = columnContext.right;
|
||||
ctx.maxSiblingSymbolWidth = maxSiblingSymbolWidth;
|
||||
|
||||
QgsLayerTreeModelLegendNode::ItemMetrics im = symbolItem->draw( mSettings, context ? &ctx
|
||||
: ( painter ? &ctx : nullptr ) );
|
||||
@ -633,23 +650,30 @@ QgsLegendRenderer::Nucleon QgsLegendRenderer::drawSymbolItemInternal( QgsLayerTr
|
||||
if ( layerScope )
|
||||
delete context->expressionContext().popScope();
|
||||
|
||||
Nucleon nucleon;
|
||||
LegendComponent nucleon;
|
||||
nucleon.item = symbolItem;
|
||||
nucleon.symbolSize = im.symbolSize;
|
||||
nucleon.labelSize = im.labelSize;
|
||||
//QgsDebugMsg( QStringLiteral( "symbol height = %1 label height = %2").arg( symbolSize.height()).arg( labelSize.height() ));
|
||||
double width = std::max( static_cast< double >( im.symbolSize.width() ), labelXOffset ) + im.labelSize.width();
|
||||
// NOTE -- we hard code left/right margins below, because those are the only ones exposed for use currently.
|
||||
// ideally we could (should?) expose all these margins as settings, and then adapt the below to respect the current symbol/text alignment
|
||||
// and consider the correct margin sides...
|
||||
double width = std::max( static_cast< double >( im.symbolSize.width() ), maxSiblingSymbolWidth )
|
||||
+ mSettings.style( QgsLegendStyle::Symbol ).margin( QgsLegendStyle::Right )
|
||||
+ mSettings.style( QgsLegendStyle::SymbolLabel ).margin( QgsLegendStyle::Left )
|
||||
+ im.labelSize.width();
|
||||
|
||||
double height = std::max( im.symbolSize.height(), im.labelSize.height() );
|
||||
nucleon.size = QSizeF( width, height );
|
||||
return nucleon;
|
||||
}
|
||||
|
||||
QSizeF QgsLegendRenderer::drawLayerTitle( QgsLayerTreeLayer *nodeLayer, QPainter *painter, QPointF point )
|
||||
QSizeF QgsLegendRenderer::drawLayerTitle( QgsLayerTreeLayer *nodeLayer, const ColumnContext &columnContext, QPainter *painter, double top )
|
||||
{
|
||||
return drawLayerTitleInternal( nodeLayer, nullptr, painter, point );
|
||||
return drawLayerTitleInternal( nodeLayer, columnContext, nullptr, painter, top );
|
||||
}
|
||||
|
||||
QSizeF QgsLegendRenderer::drawLayerTitleInternal( QgsLayerTreeLayer *nodeLayer, QgsRenderContext *context, QPainter *painter, QPointF point )
|
||||
QSizeF QgsLegendRenderer::drawLayerTitleInternal( QgsLayerTreeLayer *nodeLayer, const ColumnContext &columnContext, QgsRenderContext *context, QPainter *painter, const double top )
|
||||
{
|
||||
QSizeF size( 0, 0 );
|
||||
QModelIndex idx = mLegendModel->node2index( nodeLayer );
|
||||
@ -658,7 +682,7 @@ QSizeF QgsLegendRenderer::drawLayerTitleInternal( QgsLayerTreeLayer *nodeLayer,
|
||||
if ( mLegendModel->data( idx, Qt::DisplayRole ).toString().isEmpty() )
|
||||
return size;
|
||||
|
||||
double y = point.y();
|
||||
double y = top;
|
||||
|
||||
if ( context && context->painter() )
|
||||
context->painter()->setPen( mSettings.layerFontColor() );
|
||||
@ -678,21 +702,32 @@ QSizeF QgsLegendRenderer::drawLayerTitleInternal( QgsLayerTreeLayer *nodeLayer,
|
||||
|
||||
const QStringList lines = mSettings.evaluateItemText( mLegendModel->data( idx, Qt::DisplayRole ).toString(),
|
||||
context ? context->expressionContext() : tempContext );
|
||||
int i = 0;
|
||||
for ( QStringList::ConstIterator layerItemPart = lines.constBegin(); layerItemPart != lines.constEnd(); ++layerItemPart )
|
||||
{
|
||||
y += mSettings.fontAscentMillimeters( layerFont );
|
||||
if ( context && context->painter() )
|
||||
mSettings.drawText( context->painter(), point.x(), y, *layerItemPart, layerFont );
|
||||
if ( painter )
|
||||
mSettings.drawText( painter, point.x(), y, *layerItemPart, layerFont );
|
||||
if ( QPainter *destPainter = context && context->painter() ? context->painter() : painter )
|
||||
{
|
||||
double x = columnContext.left;
|
||||
if ( mSettings.style( nodeLegendStyle( nodeLayer ) ).alignment() != Qt::AlignLeft )
|
||||
{
|
||||
const double labelWidth = mSettings.textWidthMillimeters( layerFont, *layerItemPart );
|
||||
if ( mSettings.style( nodeLegendStyle( nodeLayer ) ).alignment() == Qt::AlignRight )
|
||||
x = columnContext.right - labelWidth;
|
||||
else if ( mSettings.style( nodeLegendStyle( nodeLayer ) ).alignment() == Qt::AlignHCenter )
|
||||
x = columnContext.left + ( columnContext.right - columnContext.left - labelWidth ) / 2;
|
||||
}
|
||||
mSettings.drawText( destPainter, x, y, *layerItemPart, layerFont );
|
||||
}
|
||||
qreal width = mSettings.textWidthMillimeters( layerFont, *layerItemPart );
|
||||
size.rwidth() = std::max( width, size.width() );
|
||||
if ( layerItemPart != ( lines.end() - 1 ) )
|
||||
{
|
||||
y += mSettings.lineSpacing();
|
||||
}
|
||||
i++;
|
||||
}
|
||||
size.rheight() = y - point.y();
|
||||
size.rheight() = y - top;
|
||||
size.rheight() += mSettings.style( nodeLegendStyle( nodeLayer ) ).margin( QgsLegendStyle::Side::Bottom );
|
||||
|
||||
if ( layerScope )
|
||||
@ -701,17 +736,17 @@ QSizeF QgsLegendRenderer::drawLayerTitleInternal( QgsLayerTreeLayer *nodeLayer,
|
||||
return size;
|
||||
}
|
||||
|
||||
QSizeF QgsLegendRenderer::drawGroupTitle( QgsLayerTreeGroup *nodeGroup, QPainter *painter, QPointF point )
|
||||
QSizeF QgsLegendRenderer::drawGroupTitle( QgsLayerTreeGroup *nodeGroup, const ColumnContext &columnContext, QPainter *painter, double top )
|
||||
{
|
||||
return drawGroupTitleInternal( nodeGroup, nullptr, painter, point );
|
||||
return drawGroupTitleInternal( nodeGroup, columnContext, nullptr, painter, top );
|
||||
}
|
||||
|
||||
QSizeF QgsLegendRenderer::drawGroupTitleInternal( QgsLayerTreeGroup *nodeGroup, QgsRenderContext *context, QPainter *painter, QPointF point )
|
||||
QSizeF QgsLegendRenderer::drawGroupTitleInternal( QgsLayerTreeGroup *nodeGroup, const ColumnContext &columnContext, QgsRenderContext *context, QPainter *painter, const double top )
|
||||
{
|
||||
QSizeF size( 0, 0 );
|
||||
QModelIndex idx = mLegendModel->node2index( nodeGroup );
|
||||
|
||||
double y = point.y();
|
||||
double y = top;
|
||||
|
||||
if ( context && context->painter() )
|
||||
context->painter()->setPen( mSettings.fontColor() );
|
||||
@ -727,10 +762,20 @@ QSizeF QgsLegendRenderer::drawGroupTitleInternal( QgsLayerTreeGroup *nodeGroup,
|
||||
for ( QStringList::ConstIterator groupPart = lines.constBegin(); groupPart != lines.constEnd(); ++groupPart )
|
||||
{
|
||||
y += mSettings.fontAscentMillimeters( groupFont );
|
||||
if ( context && context->painter() )
|
||||
mSettings.drawText( context->painter(), point.x(), y, *groupPart, groupFont );
|
||||
else if ( painter )
|
||||
mSettings.drawText( painter, point.x(), y, *groupPart, groupFont );
|
||||
|
||||
if ( QPainter *destPainter = context && context->painter() ? context->painter() : painter )
|
||||
{
|
||||
double x = columnContext.left;
|
||||
if ( mSettings.style( nodeLegendStyle( nodeGroup ) ).alignment() != Qt::AlignLeft )
|
||||
{
|
||||
const double labelWidth = mSettings.textWidthMillimeters( groupFont, *groupPart );
|
||||
if ( mSettings.style( nodeLegendStyle( nodeGroup ) ).alignment() == Qt::AlignRight )
|
||||
x = columnContext.right - labelWidth;
|
||||
else if ( mSettings.style( nodeLegendStyle( nodeGroup ) ).alignment() == Qt::AlignHCenter )
|
||||
x = columnContext.left + ( columnContext.right - columnContext.left - labelWidth ) / 2;
|
||||
}
|
||||
mSettings.drawText( destPainter, x, y, *groupPart, groupFont );
|
||||
}
|
||||
qreal width = mSettings.textWidthMillimeters( groupFont, *groupPart );
|
||||
size.rwidth() = std::max( width, size.width() );
|
||||
if ( groupPart != ( lines.end() - 1 ) )
|
||||
@ -738,7 +783,7 @@ QSizeF QgsLegendRenderer::drawGroupTitleInternal( QgsLayerTreeGroup *nodeGroup,
|
||||
y += mSettings.lineSpacing();
|
||||
}
|
||||
}
|
||||
size.rheight() = y - point.y();
|
||||
size.rheight() = y - top;
|
||||
return size;
|
||||
}
|
||||
|
||||
@ -794,29 +839,29 @@ void QgsLegendRenderer::setNodeLegendStyle( QgsLayerTreeNode *node, QgsLegendSty
|
||||
node->removeCustomProperty( QStringLiteral( "legend/title-style" ) );
|
||||
}
|
||||
|
||||
QSizeF QgsLegendRenderer::drawTitle( QgsRenderContext *rendercontext, QPointF point, Qt::AlignmentFlag halignment, double legendWidth )
|
||||
QSizeF QgsLegendRenderer::drawTitle( QgsRenderContext *rendercontext, double top, Qt::AlignmentFlag halignment, double legendWidth )
|
||||
{
|
||||
return drawTitleInternal( rendercontext, nullptr, point, halignment, legendWidth );
|
||||
return drawTitleInternal( rendercontext, nullptr, top, halignment, legendWidth );
|
||||
}
|
||||
|
||||
QSizeF QgsLegendRenderer::drawAtom( const Atom &atom, QgsRenderContext *rendercontext, QPointF point )
|
||||
QSizeF QgsLegendRenderer::drawGroup( const LegendComponentGroup &atom, QgsRenderContext *rendercontext, const ColumnContext &columnContext, double top )
|
||||
{
|
||||
return drawAtomInternal( atom, rendercontext, nullptr, point );
|
||||
return drawGroupInternal( atom, rendercontext, columnContext, nullptr, top );
|
||||
}
|
||||
|
||||
QgsLegendRenderer::Nucleon QgsLegendRenderer::drawSymbolItem( QgsLayerTreeModelLegendNode *symbolItem, QgsRenderContext *rendercontext, QPointF point, double labelXOffset )
|
||||
QgsLegendRenderer::LegendComponent QgsLegendRenderer::drawSymbolItem( QgsLayerTreeModelLegendNode *symbolItem, QgsRenderContext *rendercontext, const ColumnContext &columnContext, double top, double maxSiblingSymbolWidth )
|
||||
{
|
||||
return drawSymbolItemInternal( symbolItem, rendercontext, nullptr, point, labelXOffset );
|
||||
return drawSymbolItemInternal( symbolItem, columnContext, rendercontext, nullptr, top, maxSiblingSymbolWidth );
|
||||
}
|
||||
|
||||
QSizeF QgsLegendRenderer::drawLayerTitle( QgsLayerTreeLayer *nodeLayer, QgsRenderContext *rendercontext, QPointF point )
|
||||
QSizeF QgsLegendRenderer::drawLayerTitle( QgsLayerTreeLayer *nodeLayer, QgsRenderContext *rendercontext, const ColumnContext &columnContext, double top )
|
||||
{
|
||||
return drawLayerTitleInternal( nodeLayer, rendercontext, nullptr, point );
|
||||
return drawLayerTitleInternal( nodeLayer, columnContext, rendercontext, nullptr, top );
|
||||
}
|
||||
|
||||
QSizeF QgsLegendRenderer::drawGroupTitle( QgsLayerTreeGroup *nodeGroup, QgsRenderContext *rendercontext, QPointF point )
|
||||
QSizeF QgsLegendRenderer::drawGroupTitle( QgsLayerTreeGroup *nodeGroup, QgsRenderContext *rendercontext, const ColumnContext &columnContext, double top )
|
||||
{
|
||||
return drawGroupTitleInternal( nodeGroup, rendercontext, nullptr, point );
|
||||
return drawGroupTitleInternal( nodeGroup, columnContext, rendercontext, nullptr, top );
|
||||
}
|
||||
|
||||
void QgsLegendRenderer::drawLegend( QgsRenderContext &context )
|
||||
|
||||
@ -119,17 +119,17 @@ class CORE_EXPORT QgsLegendRenderer
|
||||
#ifndef SIP_RUN
|
||||
|
||||
/**
|
||||
* A legend Nucleon is either a group title, a layer title or a layer child item.
|
||||
* A legend component is either a group title, a layer title or a layer child item.
|
||||
*
|
||||
* E.g. a layer title nucleon is just the layer's title, it does not
|
||||
* include all of that layer's subitems. Similarly, a group's title nucleon is just
|
||||
* E.g. a layer title component is just the layer's title, it does not
|
||||
* include all of that layer's subitems. Similarly, a group's title component is just
|
||||
* the group title, and does not include the actual content of that group.
|
||||
*/
|
||||
class Nucleon
|
||||
class LegendComponent
|
||||
{
|
||||
public:
|
||||
//! Constructor for Nuclean
|
||||
Nucleon() = default;
|
||||
|
||||
LegendComponent() = default;
|
||||
|
||||
QObject *item = nullptr;
|
||||
|
||||
@ -139,7 +139,7 @@ class CORE_EXPORT QgsLegendRenderer
|
||||
//! Label size, not including any preset padding space around the label
|
||||
QSizeF labelSize;
|
||||
|
||||
//! Nucleon size
|
||||
//! Component size
|
||||
QSizeF size;
|
||||
|
||||
/**
|
||||
@ -149,12 +149,18 @@ class CORE_EXPORT QgsLegendRenderer
|
||||
* within the same legend column.
|
||||
*/
|
||||
double labelXOffset = 0.0;
|
||||
|
||||
/**
|
||||
* Largest symbol width, considering all other sibling components associated with
|
||||
* this component.
|
||||
*/
|
||||
double maxSiblingSymbolWidth = 0.0;
|
||||
};
|
||||
|
||||
/**
|
||||
* An Atom is indivisible set of legend Nucleons (i.e. it is indivisible into more columns).
|
||||
* An component group is an indivisible set of legend components (i.e. it is indivisible into more columns).
|
||||
*
|
||||
* An Atom may consist of one or more Nucleon(s), depending on the layer splitting mode:
|
||||
* A group may consist of one or more component(s), depending on the layer splitting mode:
|
||||
*
|
||||
* 1) no layer split: [group_title ...] layer_title layer_item [layer_item ...]
|
||||
* 2) layer split: [group_title ...] layer_title layer_item
|
||||
@ -165,20 +171,38 @@ class CORE_EXPORT QgsLegendRenderer
|
||||
* and it would not be logical to leave a group or layer title at the bottom of a column,
|
||||
* separated from the actual content of that group or layer.
|
||||
*/
|
||||
class Atom
|
||||
class LegendComponentGroup
|
||||
{
|
||||
public:
|
||||
|
||||
//! List of child Nucleons belonging to this Atom.
|
||||
QList<Nucleon> nucleons;
|
||||
//! List of child components belonging to this group.
|
||||
QList<LegendComponent> components;
|
||||
|
||||
//! Atom size, including internal spacing between Nucleons, but excluding any padding space around the Atom itself.
|
||||
//! Group size, including internal spacing between components, but excluding any padding space around the group itself.
|
||||
QSizeF size = QSizeF( 0, 0 );
|
||||
|
||||
//! Corresponding column index
|
||||
int column = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Contains contextual information about the current column being rendered
|
||||
*/
|
||||
class ColumnContext
|
||||
{
|
||||
public:
|
||||
|
||||
ColumnContext()
|
||||
: left( 0 )
|
||||
, right( 0 )
|
||||
{}
|
||||
|
||||
//! Left edge of column
|
||||
double left = 0;
|
||||
//! Right edge of column
|
||||
double right = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Draws the legend and returns the actual size of the legend.
|
||||
*
|
||||
@ -188,15 +212,15 @@ class CORE_EXPORT QgsLegendRenderer
|
||||
QSizeF paintAndDetermineSize( QPainter *painter = nullptr );
|
||||
|
||||
/**
|
||||
* Returns a list of Atoms for the specified \a parentGroup, respecting the current layer's
|
||||
* Returns a list of component groups for the specified \a parentGroup, respecting the current layer's
|
||||
* splitting settings.
|
||||
*/
|
||||
QList<Atom> createAtomList( QgsLayerTreeGroup *parentGroup, bool splitLayer );
|
||||
QList<LegendComponentGroup> createComponentGroupList( QgsLayerTreeGroup *parentGroup, bool splitLayer );
|
||||
|
||||
/**
|
||||
* Divides a list of Atoms into columns, and sets the column index for each atom in the list.
|
||||
* Divides a list of component groups into columns, and sets the column index for each group in the list.
|
||||
*/
|
||||
void setColumns( QList<Atom> &atomList );
|
||||
void setColumns( QList<LegendComponentGroup> &groupList );
|
||||
|
||||
/**
|
||||
* Draws a title in the legend using the title font and the specified alignment settings.
|
||||
@ -205,25 +229,25 @@ class CORE_EXPORT QgsLegendRenderer
|
||||
*
|
||||
* If \a painter is NULLPTR, no painting will be attempted, but the required size will still be calculated and returned.
|
||||
*/
|
||||
QSizeF drawTitle( QPainter *painter = nullptr, QPointF point = QPointF(), Qt::AlignmentFlag halignment = Qt::AlignLeft, double legendWidth = 0 );
|
||||
QSizeF drawTitle( QPainter *painter = nullptr, double top = 0, Qt::AlignmentFlag halignment = Qt::AlignLeft, double legendWidth = 0 );
|
||||
|
||||
/**
|
||||
* Returns the calculated padding space required above the given \a atom.
|
||||
* Returns the calculated padding space required above the given component \a group.
|
||||
*/
|
||||
double spaceAboveAtom( const Atom &atom );
|
||||
double spaceAboveGroup( const LegendComponentGroup &group );
|
||||
|
||||
/**
|
||||
* Draws an \a atom and return its actual size.
|
||||
* Draws a component \a group and return its actual size.
|
||||
*
|
||||
* The \a atom is drawn with the space above it, so that the first atoms in column are all
|
||||
* The \a group is drawn with the space above it, so that the first groups in a column are all
|
||||
* aligned to the same line regardless of their style top spacing.
|
||||
*/
|
||||
QSizeF drawAtom( const Atom &atom, QPainter *painter = nullptr, QPointF point = QPointF() );
|
||||
QSizeF drawGroup( const LegendComponentGroup &group, const ColumnContext &columnContext, QPainter *painter = nullptr, double top = 0 );
|
||||
|
||||
/**
|
||||
* Draws the symbol of a given symbol QgsLayerTreeModelLegendNode.
|
||||
*/
|
||||
Nucleon drawSymbolItem( QgsLayerTreeModelLegendNode *symbolItem, QPainter *painter = nullptr, QPointF point = QPointF(), double labelXOffset = 0 );
|
||||
LegendComponent drawSymbolItem( QgsLayerTreeModelLegendNode *symbolItem, const ColumnContext &columnContext = ColumnContext(), QPainter *painter = nullptr, double top = 0, double maxSiblingSymbolWidth = 0 );
|
||||
|
||||
/**
|
||||
* Draws the title of a layer, given a QgsLayerTreeLayer, and a destination \a painter.
|
||||
@ -232,13 +256,13 @@ class CORE_EXPORT QgsLegendRenderer
|
||||
*
|
||||
* The \a painter may be NULLPTR, in which case on the size is calculated and no painting is attempted.
|
||||
*/
|
||||
QSizeF drawLayerTitle( QgsLayerTreeLayer *nodeLayer, QPainter *painter = nullptr, QPointF point = QPointF() );
|
||||
QSizeF drawLayerTitle( QgsLayerTreeLayer *nodeLayer, const ColumnContext &columnContext = ColumnContext(), QPainter *painter = nullptr, double top = 0 );
|
||||
|
||||
/**
|
||||
* Draws a group item.
|
||||
* Returns the size of the title.
|
||||
*/
|
||||
QSizeF drawGroupTitle( QgsLayerTreeGroup *nodeGroup, QPainter *painter = nullptr, QPointF point = QPointF() );
|
||||
QSizeF drawGroupTitle( QgsLayerTreeGroup *nodeGroup, const ColumnContext &columnContext = ColumnContext(), QPainter *painter = nullptr, double top = 0 );
|
||||
|
||||
/**
|
||||
* Renders a group item in a \a json object.
|
||||
@ -262,22 +286,22 @@ class CORE_EXPORT QgsLegendRenderer
|
||||
*
|
||||
* If \a context is NULLPTR, no painting will be attempted, but the required size will still be calculated and returned.
|
||||
*/
|
||||
QSizeF drawTitle( QgsRenderContext *context, QPointF point = QPointF(), Qt::AlignmentFlag halignment = Qt::AlignLeft, double legendWidth = 0 );
|
||||
QSizeF drawTitle( QgsRenderContext *context, double top, Qt::AlignmentFlag halignment = Qt::AlignLeft, double legendWidth = 0 );
|
||||
|
||||
/**
|
||||
* Draws an \a atom and return its actual size, using the specified render \a context.
|
||||
* Draws an \a group and return its actual size, using the specified render \a context.
|
||||
*
|
||||
* The \a atom is drawn with the space above it, so that the first atoms in column are all
|
||||
* The \a group is drawn with the space above it, so that the first groups in a column are all
|
||||
* aligned to the same line regardless of their style top spacing.
|
||||
*
|
||||
* If \a context is NULLPTR, no painting will be attempted, but the required size will still be calculated and returned.
|
||||
*/
|
||||
QSizeF drawAtom( const Atom &atom, QgsRenderContext *rendercontext, QPointF point = QPointF() );
|
||||
QSizeF drawGroup( const LegendComponentGroup &group, QgsRenderContext *rendercontext, const ColumnContext &columnContext, double top = 0 );
|
||||
|
||||
/**
|
||||
* Draws the symbol of a given symbol QgsLayerTreeModelLegendNode, using the specified render \a context.
|
||||
*/
|
||||
Nucleon drawSymbolItem( QgsLayerTreeModelLegendNode *symbolItem, QgsRenderContext *context, QPointF point = QPointF(), double labelXOffset = 0 );
|
||||
LegendComponent drawSymbolItem( QgsLayerTreeModelLegendNode *symbolItem, QgsRenderContext *context, const ColumnContext &columnContext, double top, double maxSiblingSymbolWidth = 0 );
|
||||
|
||||
/**
|
||||
* Draws the title of a layer, given a QgsLayerTreeLayer, and a destination render \a context.
|
||||
@ -286,21 +310,20 @@ class CORE_EXPORT QgsLegendRenderer
|
||||
*
|
||||
* The \a context may be NULLPTR, in which case on the size is calculated and no painting is attempted.
|
||||
*/
|
||||
QSizeF drawLayerTitle( QgsLayerTreeLayer *nodeLayer, QgsRenderContext *context, QPointF point = QPointF() );
|
||||
QSizeF drawLayerTitle( QgsLayerTreeLayer *nodeLayer, QgsRenderContext *context, const ColumnContext &columnContext, double top = 0 );
|
||||
|
||||
/**
|
||||
* Draws a group's title, using the specified render \a context.
|
||||
*
|
||||
* Returns the size of the title.
|
||||
*/
|
||||
QSizeF drawGroupTitle( QgsLayerTreeGroup *nodeGroup, QgsRenderContext *context, QPointF point = QPointF() );
|
||||
QSizeF drawGroupTitle( QgsLayerTreeGroup *nodeGroup, QgsRenderContext *context, const ColumnContext &columnContext = ColumnContext(), double top = 0 );
|
||||
|
||||
/**
|
||||
* Returns the style of the given \a node.
|
||||
*/
|
||||
QgsLegendStyle::Style nodeLegendStyle( QgsLayerTreeNode *node );
|
||||
|
||||
private:
|
||||
QgsLayerTreeModel *mLegendModel = nullptr;
|
||||
|
||||
QgsLegendSettings mSettings;
|
||||
@ -308,12 +331,14 @@ class CORE_EXPORT QgsLegendRenderer
|
||||
QSizeF mLegendSize;
|
||||
|
||||
#endif
|
||||
QSizeF drawTitleInternal( QgsRenderContext *context, QPainter *painter, QPointF point, Qt::AlignmentFlag halignment, double legendWidth );
|
||||
QSizeF drawAtomInternal( const Atom &atom, QgsRenderContext *context, QPainter *painter, QPointF point );
|
||||
QgsLegendRenderer::Nucleon drawSymbolItemInternal( QgsLayerTreeModelLegendNode *symbolItem, QgsRenderContext *context, QPainter *painter, QPointF point, double labelXOffset );
|
||||
QSizeF drawLayerTitleInternal( QgsLayerTreeLayer *nodeLayer, QgsRenderContext *context, QPainter *painter, QPointF point );
|
||||
QSizeF drawGroupTitleInternal( QgsLayerTreeGroup *nodeGroup, QgsRenderContext *context, QPainter *painter, QPointF point );
|
||||
QSizeF drawTitleInternal( QgsRenderContext *context, QPainter *painter, double top, Qt::AlignmentFlag halignment, double legendWidth );
|
||||
QSizeF drawGroupInternal( const LegendComponentGroup &group, QgsRenderContext *context, const ColumnContext &columnContext, QPainter *painter, double top );
|
||||
QgsLegendRenderer::LegendComponent drawSymbolItemInternal( QgsLayerTreeModelLegendNode *symbolItem, const ColumnContext &columnContext, QgsRenderContext *context, QPainter *painter, double top, double maxSiblingSymbolWidth );
|
||||
QSizeF drawLayerTitleInternal( QgsLayerTreeLayer *nodeLayer, const ColumnContext &columnContext, QgsRenderContext *context, QPainter *painter, double top );
|
||||
QSizeF drawGroupTitleInternal( QgsLayerTreeGroup *nodeGroup, const ColumnContext &columnContext, QgsRenderContext *context, QPainter *painter, double top );
|
||||
QSizeF paintAndDetermineSizeInternal( QgsRenderContext *context, QPainter *painter );
|
||||
|
||||
void widthAndOffsetForTitleText( const Qt::AlignmentFlag halignment, double legendWidth, double &width, double &offset );
|
||||
};
|
||||
|
||||
#endif // QGSLEGENDRENDERER_H
|
||||
|
||||
@ -44,16 +44,14 @@ class CORE_EXPORT QgsLegendSettings
|
||||
QString title() const { return mTitle; }
|
||||
|
||||
/**
|
||||
* Returns the alignment of the legend title
|
||||
* \returns Qt::AlignmentFlag for the legend title
|
||||
* \see setTitleAlignment
|
||||
* Returns the alignment of the legend title.
|
||||
* \see setTitleAlignment()
|
||||
*/
|
||||
Qt::AlignmentFlag titleAlignment() const { return mTitleAlignment; }
|
||||
|
||||
/**
|
||||
* Sets the alignment of the legend title
|
||||
* \param alignment Text alignment for drawing the legend title
|
||||
* \see titleAlignment
|
||||
* Sets the \a alignment of the legend title.
|
||||
* \see titleAlignment()
|
||||
*/
|
||||
void setTitleAlignment( Qt::AlignmentFlag alignment ) { mTitleAlignment = alignment; }
|
||||
|
||||
@ -109,6 +107,26 @@ class CORE_EXPORT QgsLegendSettings
|
||||
QSizeF symbolSize() const {return mSymbolSize;}
|
||||
void setSymbolSize( QSizeF s ) {mSymbolSize = s;}
|
||||
|
||||
/**
|
||||
* Sets the \a alignment for placement of legend symbols.
|
||||
*
|
||||
* Only Qt::AlignLeft or Qt::AlignRight are supported values.
|
||||
*
|
||||
* \see symbolAlignment()
|
||||
* \since QGIS 3.10.0
|
||||
*/
|
||||
void setSymbolAlignment( Qt::AlignmentFlag alignment ) { mSymbolAlignment = alignment; }
|
||||
|
||||
/**
|
||||
* Returns the alignment for placement of legend symbols.
|
||||
*
|
||||
* Only Qt::AlignLeft or Qt::AlignRight are supported values.
|
||||
*
|
||||
* \see setSymbolAlignment()
|
||||
* \since QGIS 3.10.0
|
||||
*/
|
||||
Qt::AlignmentFlag symbolAlignment() const { return mSymbolAlignment; }
|
||||
|
||||
/**
|
||||
* Returns whether a stroke will be drawn around raster symbol items.
|
||||
* \see setDrawRasterStroke()
|
||||
@ -327,6 +345,9 @@ class CORE_EXPORT QgsLegendSettings
|
||||
|
||||
//! Font color for layers, overrides font color
|
||||
QColor mLayerFontColor;
|
||||
|
||||
//! Symbol alignment
|
||||
Qt::AlignmentFlag mSymbolAlignment = Qt::AlignLeft;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -48,16 +48,22 @@ void QgsLegendStyle::setMargin( double margin )
|
||||
|
||||
void QgsLegendStyle::writeXml( const QString &name, QDomElement &elem, QDomDocument &doc ) const
|
||||
{
|
||||
if ( elem.isNull() ) return;
|
||||
if ( elem.isNull() )
|
||||
return;
|
||||
|
||||
QDomElement styleElem = doc.createElement( QStringLiteral( "style" ) );
|
||||
|
||||
styleElem.setAttribute( QStringLiteral( "name" ), name );
|
||||
styleElem.setAttribute( QStringLiteral( "alignment" ), QString::number( mAlignment ) );
|
||||
|
||||
if ( !qgsDoubleNear( mMarginMap[Top], 0.0 ) ) styleElem.setAttribute( QStringLiteral( "marginTop" ), QString::number( mMarginMap[Top] ) );
|
||||
if ( !qgsDoubleNear( mMarginMap[Bottom], 0.0 ) ) styleElem.setAttribute( QStringLiteral( "marginBottom" ), QString::number( mMarginMap[Bottom] ) );
|
||||
if ( !qgsDoubleNear( mMarginMap[Left], 0.0 ) ) styleElem.setAttribute( QStringLiteral( "marginLeft" ), QString::number( mMarginMap[Left] ) );
|
||||
if ( !qgsDoubleNear( mMarginMap[Right], 0.0 ) ) styleElem.setAttribute( QStringLiteral( "marginRight" ), QString::number( mMarginMap[Right] ) );
|
||||
if ( !qgsDoubleNear( mMarginMap[Top], 0.0 ) )
|
||||
styleElem.setAttribute( QStringLiteral( "marginTop" ), QString::number( mMarginMap[Top] ) );
|
||||
if ( !qgsDoubleNear( mMarginMap[Bottom], 0.0 ) )
|
||||
styleElem.setAttribute( QStringLiteral( "marginBottom" ), QString::number( mMarginMap[Bottom] ) );
|
||||
if ( !qgsDoubleNear( mMarginMap[Left], 0.0 ) )
|
||||
styleElem.setAttribute( QStringLiteral( "marginLeft" ), QString::number( mMarginMap[Left] ) );
|
||||
if ( !qgsDoubleNear( mMarginMap[Right], 0.0 ) )
|
||||
styleElem.setAttribute( QStringLiteral( "marginRight" ), QString::number( mMarginMap[Right] ) );
|
||||
|
||||
styleElem.appendChild( QgsFontUtils::toXmlElement( mFont, doc, QStringLiteral( "styleFont" ) ) );
|
||||
|
||||
@ -78,6 +84,8 @@ void QgsLegendStyle::readXml( const QDomElement &elem, const QDomDocument &doc )
|
||||
mMarginMap[Bottom] = elem.attribute( QStringLiteral( "marginBottom" ), QStringLiteral( "0" ) ).toDouble();
|
||||
mMarginMap[Left] = elem.attribute( QStringLiteral( "marginLeft" ), QStringLiteral( "0" ) ).toDouble();
|
||||
mMarginMap[Right] = elem.attribute( QStringLiteral( "marginRight" ), QStringLiteral( "0" ) ).toDouble();
|
||||
|
||||
mAlignment = static_cast< Qt::Alignment >( elem.attribute( QStringLiteral( "alignment" ), QString::number( Qt::AlignLeft ) ).toInt() );
|
||||
}
|
||||
|
||||
QString QgsLegendStyle::styleName( Style s )
|
||||
|
||||
@ -80,6 +80,22 @@ class CORE_EXPORT QgsLegendStyle
|
||||
//! Sets all margins
|
||||
void setMargin( double margin );
|
||||
|
||||
/**
|
||||
* Returns the alignment for the legend component.
|
||||
*
|
||||
* \see setAlignment()
|
||||
* \since QGIS 3.10
|
||||
*/
|
||||
Qt::Alignment alignment() const { return mAlignment; }
|
||||
|
||||
/**
|
||||
* Sets the alignment for the legend component.
|
||||
*
|
||||
* \see alignment()
|
||||
* \since QGIS 3.10
|
||||
*/
|
||||
void setAlignment( Qt::Alignment alignment ) { mAlignment = alignment; }
|
||||
|
||||
void writeXml( const QString &name, QDomElement &elem, QDomDocument &doc ) const;
|
||||
|
||||
void readXml( const QDomElement &elem, const QDomDocument &doc );
|
||||
@ -97,6 +113,8 @@ class CORE_EXPORT QgsLegendStyle
|
||||
QFont mFont;
|
||||
//! Space around element
|
||||
QMap<Side, double> mMarginMap;
|
||||
|
||||
Qt::Alignment mAlignment = Qt::AlignLeft;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -48,6 +48,18 @@ void QgsAlignmentComboBox::setCurrentAlignment( Qt::Alignment alignment )
|
||||
setCurrentIndex( index );
|
||||
}
|
||||
|
||||
void QgsAlignmentComboBox::customiseAlignmentDisplay( Qt::Alignment alignment, const QString &text, const QIcon &icon )
|
||||
{
|
||||
const int index = findData( QVariant( alignment ) );
|
||||
if ( index >= 0 )
|
||||
{
|
||||
if ( !text.isEmpty() )
|
||||
setItemText( index, text );
|
||||
if ( !icon.isNull() )
|
||||
setItemIcon( index, icon );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsAlignmentComboBox::populate()
|
||||
{
|
||||
Qt::Alignment prevAlign = currentAlignment();
|
||||
|
||||
@ -61,6 +61,16 @@ class GUI_EXPORT QgsAlignmentComboBox : public QComboBox
|
||||
*/
|
||||
void setCurrentAlignment( Qt::Alignment alignment );
|
||||
|
||||
/**
|
||||
* Sets the \a text and \a icon to use for a particular \a alignment option,
|
||||
* replacing the default text or icon.
|
||||
*
|
||||
* If \a text or \a icon is not specified, they will not be changed from the default.
|
||||
*
|
||||
* \note This must be called after first filtering the available alignment options via setAvailableAlignments().
|
||||
*/
|
||||
void customiseAlignmentDisplay( Qt::Alignment alignment, const QString &text = QString(), const QIcon &icon = QIcon() );
|
||||
|
||||
signals:
|
||||
|
||||
/**
|
||||
|
||||
@ -167,8 +167,6 @@ namespace QgsWms
|
||||
QgsLegendSettings settings = legendSettings();
|
||||
QgsLayerTreeModelLegendNode::ItemContext ctx;
|
||||
ctx.painter = painter.get();
|
||||
ctx.labelXOffset = 0;
|
||||
ctx.point = QPointF();
|
||||
nodeModel.drawSymbol( settings, &ctx, size.height() / dpmm );
|
||||
painter->end();
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>393</width>
|
||||
<width>323</width>
|
||||
<height>995</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -64,8 +64,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>377</width>
|
||||
<height>1662</height>
|
||||
<width>312</width>
|
||||
<height>1459</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="mainLayout">
|
||||
@ -84,6 +84,44 @@
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="mTitleLineEdit"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Wrap text on</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" colspan="2">
|
||||
<widget class="QLineEdit" name="mWrapCharLineEdit">
|
||||
<property name="frame">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QgsPropertyOverrideButton" name="mLegendTitleDDBtn">
|
||||
<property name="text">
|
||||
<string>…</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="mCheckboxResizeContents">
|
||||
<property name="text">
|
||||
<string>Resize to fit contents</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="mMapLabel">
|
||||
<property name="text">
|
||||
<string>Map</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="mTitleLabel">
|
||||
<property name="text">
|
||||
@ -94,70 +132,16 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_15">
|
||||
<property name="text">
|
||||
<string>Title alignment</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="mMapLabel">
|
||||
<property name="text">
|
||||
<string>Map</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="mCheckboxResizeContents">
|
||||
<property name="text">
|
||||
<string>Resize to fit contents</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Wrap text on</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="mTitleLineEdit"/>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QgsPropertyOverrideButton" name="mLegendTitleDDBtn">
|
||||
<property name="text">
|
||||
<string>…</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="2">
|
||||
<widget class="QComboBox" name="mTitleAlignCombo">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Left</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Center</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Right</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" colspan="2">
|
||||
<widget class="QgsLayoutItemComboBox" name="mMapComboBox"/>
|
||||
</item>
|
||||
<item row="3" column="1" colspan="2">
|
||||
<widget class="QLineEdit" name="mWrapCharLineEdit">
|
||||
<property name="frame">
|
||||
<bool>true</bool>
|
||||
<widget class="QgsAlignmentComboBox" name="mArrangementCombo"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_15">
|
||||
<property name="text">
|
||||
<string>Arrangement</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -255,7 +239,7 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../images/images.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/images/themes/default/mActionArrowDown.svg</normaloff>:/images/themes/default/mActionArrowDown.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
@ -272,7 +256,7 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../images/images.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/images/themes/default/mActionArrowUp.svg</normaloff>:/images/themes/default/mActionArrowUp.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
@ -292,7 +276,7 @@
|
||||
<string>…</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../images/images.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/images/themes/default/mActionAddGroup.svg</normaloff>:/images/themes/default/mActionAddGroup.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
@ -309,7 +293,7 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../images/images.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/images/themes/default/symbologyAdd.svg</normaloff>:/images/themes/default/symbologyAdd.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
@ -326,7 +310,7 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../images/images.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/images/themes/default/symbologyRemove.svg</normaloff>:/images/themes/default/symbologyRemove.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
@ -343,7 +327,7 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../images/images.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/images/themes/default/symbologyEdit.svg</normaloff>:/images/themes/default/symbologyEdit.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
@ -366,7 +350,7 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../images/images.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/images/themes/default/mActionSum.svg</normaloff>:/images/themes/default/mActionSum.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
@ -386,7 +370,7 @@
|
||||
<string>Filter Legend by Map Content</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../images/images.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/images/themes/default/mActionFilter2.svg</normaloff>:/images/themes/default/mActionFilter2.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
@ -406,7 +390,7 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../images/images.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/images/themes/default/mIconExpressionFilter.svg</normaloff>:/images/themes/default/mIconExpressionFilter.svg</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
@ -451,7 +435,7 @@
|
||||
<enum>Qt::StrongFocus</enum>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Fonts</string>
|
||||
<string>Fonts and Text Formatting</string>
|
||||
</property>
|
||||
<property name="syncGroup" stdset="0">
|
||||
<string notr="true">composeritem</string>
|
||||
@ -459,34 +443,32 @@
|
||||
<property name="collapsed" stdset="0">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QgsFontButton" name="mTitleFontButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_4" columnstretch="0,0,0">
|
||||
<item row="3" column="0" colspan="3">
|
||||
<widget class="QLabel" name="label_21">
|
||||
<property name="text">
|
||||
<string>Title font</string>
|
||||
<string><b>Group Headings</b></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QgsFontButton" name="mGroupFontButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_28">
|
||||
<property name="text">
|
||||
<string>Group font</string>
|
||||
<string>Font</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<item row="11" column="1" colspan="2">
|
||||
<widget class="QgsAlignmentComboBox" name="mItemAlignCombo"/>
|
||||
</item>
|
||||
<item row="6" column="0" colspan="3">
|
||||
<widget class="QLabel" name="label_23">
|
||||
<property name="text">
|
||||
<string><b>Subgroup Headings</b></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1" colspan="2">
|
||||
<widget class="QgsFontButton" name="mLayerFontButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
@ -499,7 +481,10 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<item row="5" column="1" colspan="2">
|
||||
<widget class="QgsAlignmentComboBox" name="mGroupAlignCombo"/>
|
||||
</item>
|
||||
<item row="10" column="1" colspan="2">
|
||||
<widget class="QgsFontButton" name="mItemFontButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
@ -512,7 +497,41 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<item row="9" column="0" colspan="3">
|
||||
<widget class="QLabel" name="label_25">
|
||||
<property name="text">
|
||||
<string><b>Item Labels</b></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="11" column="0">
|
||||
<widget class="QLabel" name="label_20">
|
||||
<property name="text">
|
||||
<string>Alignment</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="2">
|
||||
<widget class="QgsFontButton" name="mTitleFontButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Title font</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_18">
|
||||
<property name="text">
|
||||
<string>Alignment</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="12" column="0" colspan="3">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_16">
|
||||
@ -555,6 +574,67 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_22">
|
||||
<property name="text">
|
||||
<string>Font</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<widget class="QLabel" name="label_19">
|
||||
<property name="text">
|
||||
<string>Alignment</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="0">
|
||||
<widget class="QLabel" name="label_26">
|
||||
<property name="text">
|
||||
<string>Font</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_24">
|
||||
<property name="text">
|
||||
<string>Font</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="3">
|
||||
<widget class="QLabel" name="label_27">
|
||||
<property name="text">
|
||||
<string><b>Legend Title</b></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1" colspan="2">
|
||||
<widget class="QgsAlignmentComboBox" name="mSubgroupAlignCombo"/>
|
||||
</item>
|
||||
<item row="4" column="1" colspan="2">
|
||||
<widget class="QgsFontButton" name="mGroupFontButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Group font</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" colspan="2">
|
||||
<widget class="QgsAlignmentComboBox" name="mTitleAlignCombo"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_29">
|
||||
<property name="text">
|
||||
<string>Alignment</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@ -1102,15 +1182,20 @@
|
||||
<extends>QToolButton</extends>
|
||||
<header location="global">qgslegendfilterbutton.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>QgsAlignmentComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>qgsalignmentcombobox.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>scrollArea</tabstop>
|
||||
<tabstop>mMainPropertiesColGroupBox</tabstop>
|
||||
<tabstop>mTitleLineEdit</tabstop>
|
||||
<tabstop>mLegendTitleDDBtn</tabstop>
|
||||
<tabstop>mTitleAlignCombo</tabstop>
|
||||
<tabstop>mMapComboBox</tabstop>
|
||||
<tabstop>mWrapCharLineEdit</tabstop>
|
||||
<tabstop>mArrangementCombo</tabstop>
|
||||
<tabstop>mCheckboxResizeContents</tabstop>
|
||||
<tabstop>mLegendItemColGroupBox</tabstop>
|
||||
<tabstop>mCheckBoxAutoUpdate</tabstop>
|
||||
@ -1128,13 +1213,17 @@
|
||||
<tabstop>mFilterLegendByAtlasCheckBox</tabstop>
|
||||
<tabstop>mFontsColGroupBox</tabstop>
|
||||
<tabstop>mTitleFontButton</tabstop>
|
||||
<tabstop>mTitleAlignCombo</tabstop>
|
||||
<tabstop>mGroupFontButton</tabstop>
|
||||
<tabstop>mGroupAlignCombo</tabstop>
|
||||
<tabstop>mLayerFontButton</tabstop>
|
||||
<tabstop>mSubgroupAlignCombo</tabstop>
|
||||
<tabstop>mItemFontButton</tabstop>
|
||||
<tabstop>mItemAlignCombo</tabstop>
|
||||
<tabstop>mFontColorButton</tabstop>
|
||||
<tabstop>mColumnsColGroupBox</tabstop>
|
||||
<tabstop>mColumnsDDBtn</tabstop>
|
||||
<tabstop>mColumnCountSpinBox</tabstop>
|
||||
<tabstop>mColumnsDDBtn</tabstop>
|
||||
<tabstop>mEqualColumnWidthCheckBox</tabstop>
|
||||
<tabstop>mSplitLayerCheckBox</tabstop>
|
||||
<tabstop>mSymbolsColGroupBox</tabstop>
|
||||
@ -1156,35 +1245,6 @@
|
||||
<tabstop>mColumnSpaceSpinBox</tabstop>
|
||||
<tabstop>mLineSpacingSpinBox</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="../../../images/images.qrc"/>
|
||||
<include location="../../../images/images.qrc"/>
|
||||
<include location="../../../images/images.qrc"/>
|
||||
<include location="../../../images/images.qrc"/>
|
||||
<include location="../../../images/images.qrc"/>
|
||||
<include location="../../../images/images.qrc"/>
|
||||
<include location="../../../images/images.qrc"/>
|
||||
<include location="../../../images/images.qrc"/>
|
||||
<include location="../../../images/images.qrc"/>
|
||||
<include location="../../../images/images.qrc"/>
|
||||
<include location="../../../images/images.qrc"/>
|
||||
<include location="../../../images/images.qrc"/>
|
||||
<include location="../../../images/images.qrc"/>
|
||||
<include location="../../../images/images.qrc"/>
|
||||
<include location="../../../images/images.qrc"/>
|
||||
<include location="../../../images/images.qrc"/>
|
||||
<include location="../../../images/images.qrc"/>
|
||||
<include location="../../../images/images.qrc"/>
|
||||
<include location="../../../images/images.qrc"/>
|
||||
<include location="../../../images/images.qrc"/>
|
||||
<include location="../../../images/images.qrc"/>
|
||||
<include location="../../../images/images.qrc"/>
|
||||
<include location="../../../images/images.qrc"/>
|
||||
<include location="../../../images/images.qrc"/>
|
||||
<include location="../../../images/images.qrc"/>
|
||||
<include location="../../../images/images.qrc"/>
|
||||
<include location="../../../images/images.qrc"/>
|
||||
<include location="../../../images/images.qrc"/>
|
||||
</resources>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
||||
@ -124,6 +124,13 @@ class TestQgsLegendRenderer : public QObject
|
||||
|
||||
void testBasic();
|
||||
void testBigMarker();
|
||||
|
||||
void testRightAlignText();
|
||||
void testCenterAlignText();
|
||||
void testLeftAlignTextRightAlignSymbol();
|
||||
void testCenterAlignTextRightAlignSymbol();
|
||||
void testRightAlignTextRightAlignSymbol();
|
||||
|
||||
void testMapUnits();
|
||||
void testTallSymbol();
|
||||
void testLineSpacing();
|
||||
@ -321,6 +328,124 @@ void TestQgsLegendRenderer::testBigMarker()
|
||||
QVERIFY( _verifyImage( testName, mReport ) );
|
||||
}
|
||||
|
||||
void TestQgsLegendRenderer::testCenterAlignText()
|
||||
{
|
||||
QgsMarkerSymbol *sym = new QgsMarkerSymbol();
|
||||
sym->setColor( Qt::red );
|
||||
sym->setSize( sym->size() * 6 );
|
||||
QgsCategorizedSymbolRenderer *catRenderer = dynamic_cast<QgsCategorizedSymbolRenderer *>( mVL3->renderer() );
|
||||
QVERIFY( catRenderer );
|
||||
catRenderer->updateCategorySymbol( 0, sym );
|
||||
|
||||
QgsLayerTreeModel legendModel( mRoot );
|
||||
QgsLegendSettings settings;
|
||||
settings.rstyle( QgsLegendStyle::Group ).setAlignment( Qt::AlignHCenter );
|
||||
settings.rstyle( QgsLegendStyle::Subgroup ).setAlignment( Qt::AlignHCenter );
|
||||
settings.rstyle( QgsLegendStyle::SymbolLabel ).setAlignment( Qt::AlignHCenter );
|
||||
_setStandardTestFont( settings );
|
||||
_renderLegend( QStringLiteral( "legend_center_align_text" ), &legendModel, settings );
|
||||
QVERIFY( _verifyImage( QStringLiteral( "legend_center_align_text" ), mReport ) );
|
||||
|
||||
settings.setColumnCount( 2 );
|
||||
_renderLegend( QStringLiteral( "legend_two_cols_center_align_text" ), &legendModel, settings );
|
||||
QVERIFY( _verifyImage( QStringLiteral( "legend_two_cols_center_align_text" ), mReport ) );
|
||||
}
|
||||
|
||||
void TestQgsLegendRenderer::testLeftAlignTextRightAlignSymbol()
|
||||
{
|
||||
QgsMarkerSymbol *sym = new QgsMarkerSymbol();
|
||||
sym->setColor( Qt::red );
|
||||
sym->setSize( sym->size() * 6 );
|
||||
QgsCategorizedSymbolRenderer *catRenderer = dynamic_cast<QgsCategorizedSymbolRenderer *>( mVL3->renderer() );
|
||||
QVERIFY( catRenderer );
|
||||
catRenderer->updateCategorySymbol( 0, sym );
|
||||
|
||||
QgsLayerTreeModel legendModel( mRoot );
|
||||
QgsLegendSettings settings;
|
||||
settings.rstyle( QgsLegendStyle::Group ).setAlignment( Qt::AlignLeft );
|
||||
settings.rstyle( QgsLegendStyle::Subgroup ).setAlignment( Qt::AlignLeft );
|
||||
settings.rstyle( QgsLegendStyle::SymbolLabel ).setAlignment( Qt::AlignLeft );
|
||||
settings.setSymbolAlignment( Qt::AlignRight );
|
||||
_setStandardTestFont( settings );
|
||||
_renderLegend( QStringLiteral( "legend_right_symbol_left_align_text" ), &legendModel, settings );
|
||||
QVERIFY( _verifyImage( QStringLiteral( "legend_right_symbol_left_align_text" ), mReport ) );
|
||||
|
||||
settings.setColumnCount( 2 );
|
||||
_renderLegend( QStringLiteral( "legend_two_cols_right_align_symbol_left_align_text" ), &legendModel, settings );
|
||||
QVERIFY( _verifyImage( QStringLiteral( "legend_two_cols_right_align_symbol_left_align_text" ), mReport ) );
|
||||
}
|
||||
|
||||
void TestQgsLegendRenderer::testCenterAlignTextRightAlignSymbol()
|
||||
{
|
||||
QgsMarkerSymbol *sym = new QgsMarkerSymbol();
|
||||
sym->setColor( Qt::red );
|
||||
sym->setSize( sym->size() * 6 );
|
||||
QgsCategorizedSymbolRenderer *catRenderer = dynamic_cast<QgsCategorizedSymbolRenderer *>( mVL3->renderer() );
|
||||
QVERIFY( catRenderer );
|
||||
catRenderer->updateCategorySymbol( 0, sym );
|
||||
|
||||
QgsLayerTreeModel legendModel( mRoot );
|
||||
QgsLegendSettings settings;
|
||||
settings.rstyle( QgsLegendStyle::Group ).setAlignment( Qt::AlignHCenter );
|
||||
settings.rstyle( QgsLegendStyle::Subgroup ).setAlignment( Qt::AlignHCenter );
|
||||
settings.rstyle( QgsLegendStyle::SymbolLabel ).setAlignment( Qt::AlignHCenter );
|
||||
settings.setSymbolAlignment( Qt::AlignRight );
|
||||
_setStandardTestFont( settings );
|
||||
_renderLegend( QStringLiteral( "legend_right_symbol_center_align_text" ), &legendModel, settings );
|
||||
QVERIFY( _verifyImage( QStringLiteral( "legend_right_symbol_center_align_text" ), mReport ) );
|
||||
|
||||
settings.setColumnCount( 2 );
|
||||
_renderLegend( QStringLiteral( "legend_two_cols_right_align_symbol_center_align_text" ), &legendModel, settings );
|
||||
QVERIFY( _verifyImage( QStringLiteral( "legend_two_cols_right_align_symbol_center_align_text" ), mReport ) );
|
||||
}
|
||||
|
||||
void TestQgsLegendRenderer::testRightAlignTextRightAlignSymbol()
|
||||
{
|
||||
QgsMarkerSymbol *sym = new QgsMarkerSymbol();
|
||||
sym->setColor( Qt::red );
|
||||
sym->setSize( sym->size() * 6 );
|
||||
QgsCategorizedSymbolRenderer *catRenderer = dynamic_cast<QgsCategorizedSymbolRenderer *>( mVL3->renderer() );
|
||||
QVERIFY( catRenderer );
|
||||
catRenderer->updateCategorySymbol( 0, sym );
|
||||
|
||||
QgsLayerTreeModel legendModel( mRoot );
|
||||
QgsLegendSettings settings;
|
||||
settings.rstyle( QgsLegendStyle::Group ).setAlignment( Qt::AlignRight );
|
||||
settings.rstyle( QgsLegendStyle::Subgroup ).setAlignment( Qt::AlignRight );
|
||||
settings.rstyle( QgsLegendStyle::SymbolLabel ).setAlignment( Qt::AlignRight );
|
||||
settings.setSymbolAlignment( Qt::AlignRight );
|
||||
_setStandardTestFont( settings );
|
||||
_renderLegend( QStringLiteral( "legend_right_symbol_right_align_text" ), &legendModel, settings );
|
||||
QVERIFY( _verifyImage( QStringLiteral( "legend_right_symbol_right_align_text" ), mReport ) );
|
||||
|
||||
settings.setColumnCount( 2 );
|
||||
_renderLegend( QStringLiteral( "legend_two_cols_right_align_symbol_right_align_text" ), &legendModel, settings );
|
||||
QVERIFY( _verifyImage( QStringLiteral( "legend_two_cols_right_align_symbol_right_align_text" ), mReport ) );
|
||||
}
|
||||
|
||||
void TestQgsLegendRenderer::testRightAlignText()
|
||||
{
|
||||
QgsMarkerSymbol *sym = new QgsMarkerSymbol();
|
||||
sym->setColor( Qt::red );
|
||||
sym->setSize( sym->size() * 6 );
|
||||
QgsCategorizedSymbolRenderer *catRenderer = dynamic_cast<QgsCategorizedSymbolRenderer *>( mVL3->renderer() );
|
||||
QVERIFY( catRenderer );
|
||||
catRenderer->updateCategorySymbol( 0, sym );
|
||||
|
||||
QgsLayerTreeModel legendModel( mRoot );
|
||||
QgsLegendSettings settings;
|
||||
settings.rstyle( QgsLegendStyle::Group ).setAlignment( Qt::AlignRight );
|
||||
settings.rstyle( QgsLegendStyle::Subgroup ).setAlignment( Qt::AlignRight );
|
||||
settings.rstyle( QgsLegendStyle::SymbolLabel ).setAlignment( Qt::AlignRight );
|
||||
_setStandardTestFont( settings );
|
||||
_renderLegend( QStringLiteral( "legend_right_align_text" ), &legendModel, settings );
|
||||
QVERIFY( _verifyImage( QStringLiteral( "legend_right_align_text" ), mReport ) );
|
||||
|
||||
settings.setColumnCount( 2 );
|
||||
_renderLegend( QStringLiteral( "legend_two_cols_right_align_text" ), &legendModel, settings );
|
||||
QVERIFY( _verifyImage( QStringLiteral( "legend_two_cols_right_align_text" ), mReport ) );
|
||||
}
|
||||
|
||||
void TestQgsLegendRenderer::testMapUnits()
|
||||
{
|
||||
QString testName = QStringLiteral( "legend_mapunits" );
|
||||
|
||||
@ -10,7 +10,7 @@ __author__ = '(C) 2017 by Nyall Dawson'
|
||||
__date__ = '24/10/2017'
|
||||
__copyright__ = 'Copyright 2017, The QGIS Project'
|
||||
|
||||
from qgis.PyQt.QtCore import QRectF
|
||||
from qgis.PyQt.QtCore import QRectF, QDir
|
||||
from qgis.PyQt.QtGui import QColor
|
||||
|
||||
from qgis.core import (QgsPrintLayout,
|
||||
@ -52,8 +52,17 @@ class TestQgsLayoutItemLegend(unittest.TestCase, LayoutItemTestCase):
|
||||
def setUpClass(cls):
|
||||
cls.item_class = QgsLayoutItemLegend
|
||||
|
||||
def setUp(self):
|
||||
self.report = "<h1>Python QgsLayoutItemLegend Tests</h1>\n"
|
||||
|
||||
def tearDown(self):
|
||||
report_file_path = "%s/qgistest.html" % QDir.tempPath()
|
||||
with open(report_file_path, 'a') as report_file:
|
||||
report_file.write(self.report)
|
||||
|
||||
def testInitialSizeSymbolMapUnits(self):
|
||||
"""Test initial size of legend with a symbol size in map units"""
|
||||
QgsProject.instance().removeAllMapLayers()
|
||||
|
||||
point_path = os.path.join(TEST_DATA_DIR, 'points.shp')
|
||||
point_layer = QgsVectorLayer(point_path, 'points', 'ogr')
|
||||
@ -89,6 +98,7 @@ class TestQgsLayoutItemLegend(unittest.TestCase, LayoutItemTestCase):
|
||||
'composer_legend_mapunits', layout)
|
||||
checker.setControlPathPrefix("composer_legend")
|
||||
result, message = checker.testLayout()
|
||||
self.report += checker.report()
|
||||
self.assertTrue(result, message)
|
||||
|
||||
# resize with non-top-left reference point
|
||||
@ -147,6 +157,7 @@ class TestQgsLayoutItemLegend(unittest.TestCase, LayoutItemTestCase):
|
||||
'composer_legend_size_content', layout)
|
||||
checker.setControlPathPrefix("composer_legend")
|
||||
result, message = checker.testLayout()
|
||||
self.report += checker.report()
|
||||
self.assertTrue(result, message)
|
||||
|
||||
QgsProject.instance().removeMapLayers([point_layer.id()])
|
||||
@ -191,6 +202,7 @@ class TestQgsLayoutItemLegend(unittest.TestCase, LayoutItemTestCase):
|
||||
'composer_legend_noresize', layout)
|
||||
checker.setControlPathPrefix("composer_legend")
|
||||
result, message = checker.testLayout()
|
||||
self.report += checker.report()
|
||||
self.assertTrue(result, message)
|
||||
|
||||
QgsProject.instance().removeMapLayers([point_layer.id()])
|
||||
@ -235,6 +247,7 @@ class TestQgsLayoutItemLegend(unittest.TestCase, LayoutItemTestCase):
|
||||
'composer_legend_noresize_crop', layout)
|
||||
checker.setControlPathPrefix("composer_legend")
|
||||
result, message = checker.testLayout()
|
||||
self.report += checker.report()
|
||||
self.assertTrue(result, message)
|
||||
|
||||
QgsProject.instance().removeMapLayers([point_layer.id()])
|
||||
@ -360,6 +373,7 @@ class TestQgsLayoutItemLegend(unittest.TestCase, LayoutItemTestCase):
|
||||
'composer_legend_expressions', layout)
|
||||
checker.setControlPathPrefix("composer_legend")
|
||||
result, message = checker.testLayout()
|
||||
self.report += checker.report()
|
||||
self.assertTrue(result, message)
|
||||
|
||||
QgsProject.instance().removeMapLayers([point_layer.id()])
|
||||
|
||||
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 15 KiB |