Skip to content
Permalink
Browse files

Prefix/suffix support, ensure correct size determination of legend text

  • Loading branch information
nyalldawson committed Dec 18, 2020
1 parent c5dd120 commit 8eb9448746eef05e6749238db3cec81a38bc19bc
@@ -52,6 +52,9 @@ Constructor for QgsColorRampLegendNode.

virtual QSizeF drawSymbol( const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight ) const;

virtual QSizeF drawSymbolText( const QgsLegendSettings &settings, ItemContext *ctx, QSizeF symbolSize ) const;



void setIconSize( QSize size );
%Docstring
@@ -125,6 +125,42 @@ Writes settings to an XML ``element``.
void readXml( const QDomElement &element, const QgsReadWriteContext &context );
%Docstring
Reads settings from an XML ``element``.
%End

QString prefix() const;
%Docstring
Returns the prefix to show before legend text.

.. seealso:: :py:func:`setPrefix`

.. seealso:: :py:func:`suffix`
%End

void setPrefix( const QString &prefix );
%Docstring
Sets the ``prefix`` to show before legend text.

.. seealso:: :py:func:`prefix`

.. seealso:: :py:func:`setSuffix`
%End

QString suffix() const;
%Docstring
Returns the suffix to show after legend text.

.. seealso:: :py:func:`setSuffix`

.. seealso:: :py:func:`prefix`
%End

void setSuffix( const QString &suffix );
%Docstring
Sets the ``suffix`` to show after legend text.

.. seealso:: :py:func:`suffix`

.. seealso:: :py:func:`setPrefix`
%End

};
@@ -86,8 +86,11 @@ QVariant QgsColorRampLegendNode::data( int role ) const

const QFont font = data( Qt::FontRole ).value< QFont >();

const QString minLabel = mSettings.prefix() + mSettings.minimumLabel() + mSettings.suffix();
const QString maxLabel = mSettings.prefix() + mSettings.maximumLabel() + mSettings.suffix();

const QFontMetrics fm( font );
const int maxTextWidth = std::max( fm.boundingRect( mSettings.minimumLabel() ).width(), fm.boundingRect( mSettings.maximumLabel() ).width() );
const int maxTextWidth = std::max( fm.boundingRect( minLabel ).width(), fm.boundingRect( maxLabel ).width() );
const int labelGapFromRamp = fm.boundingRect( QStringLiteral( "x" ) ).width();
const int extraAllowance = labelGapFromRamp * 0.4; // extra allowance to avoid text clipping on right
const QRect labelRect( mIconSize.width() + labelGapFromRamp, 0, maxTextWidth + extraAllowance, mIconSize.height() );
@@ -99,8 +102,8 @@ QVariant QgsColorRampLegendNode::data( int role ) const
p.drawPixmap( 0, 0, pix );
p.setFont( font );

p.drawText( labelRect, Qt::AlignBottom | Qt::AlignLeft, mSettings.direction() == QgsColorRampLegendNodeSettings::MinimumToMaximum ? mSettings.minimumLabel() : mSettings.maximumLabel() );
p.drawText( labelRect, Qt::AlignTop | Qt::AlignLeft, mSettings.direction() == QgsColorRampLegendNodeSettings::MinimumToMaximum ? mSettings.maximumLabel() : mSettings.minimumLabel() );
p.drawText( labelRect, Qt::AlignBottom | Qt::AlignLeft, mSettings.direction() == QgsColorRampLegendNodeSettings::MinimumToMaximum ? minLabel : maxLabel );
p.drawText( labelRect, Qt::AlignTop | Qt::AlignLeft, mSettings.direction() == QgsColorRampLegendNodeSettings::MinimumToMaximum ? maxLabel : minLabel );
p.end();
}
return mPixmap;
@@ -149,7 +152,10 @@ QSizeF QgsColorRampLegendNode::drawSymbol( const QgsLegendSettings &settings, It
QgsTextFormat format = QgsTextFormat::fromQFont( symbolLabelFont );
format.setColor( settings.fontColor() );

double minHeightMm = QgsTextRenderer::textHeight( *context, format, QStringList() << mSettings.minimumLabel() << mSettings.maximumLabel(), QgsTextRenderer::Rect ) / context->scaleFactor();
const QString minLabel = mSettings.prefix() + mSettings.minimumLabel() + mSettings.suffix();
const QString maxLabel = mSettings.prefix() + mSettings.maximumLabel() + mSettings.suffix();

double minHeightMm = QgsTextRenderer::textHeight( *context, format, QStringList() << minLabel << maxLabel, QgsTextRenderer::Rect ) / context->scaleFactor();

const double height = ctx && ctx->patchSize.height() > 0 ? std::max( minHeightMm / 2, ctx->patchSize.height() ) : std::max( minHeightMm, settings.symbolSize().height() );
const double width = ctx && ctx->patchSize.width() > 0 ? ctx->patchSize.width() : settings.symbolSize().width();
@@ -212,6 +218,66 @@ QSizeF QgsColorRampLegendNode::drawSymbol( const QgsLegendSettings &settings, It

p->setBrush( QBrush( gradient ) );
p->drawRect( rampLeftMm * dotsPerMM, rampTopMm * dotsPerMM, width * dotsPerMM, height * dotsPerMM );
}

return QSizeF( width, height );
}

QSizeF QgsColorRampLegendNode::drawSymbolText( const QgsLegendSettings &settings, QgsLayerTreeModelLegendNode::ItemContext *ctx, QSizeF symbolSize ) const
{
if ( !mRamp )
{
return QSizeF();
}

// setup temporary render context
QgsRenderContext *context = nullptr;
std::unique_ptr< QgsRenderContext > tempRenderContext;
if ( ctx && ctx->context )
context = ctx->context;
else
{
tempRenderContext = qgis::make_unique< QgsRenderContext >();
// QGIS 4.0 - make ItemContext compulsory, so we don't have to construct temporary render contexts here
Q_NOWARN_DEPRECATED_PUSH
tempRenderContext->setScaleFactor( settings.dpi() / 25.4 );
tempRenderContext->setRendererScale( settings.mapScale() );
tempRenderContext->setFlag( QgsRenderContext::Antialiasing, true );
tempRenderContext->setMapToPixel( QgsMapToPixel( 1 / ( settings.mmPerMapUnit() * tempRenderContext->scaleFactor() ) ) );
Q_NOWARN_DEPRECATED_POP
tempRenderContext->setForceVectorOutput( true );
tempRenderContext->setPainter( ctx ? ctx->painter : nullptr );

// setup a minimal expression context
QgsExpressionContext expContext;
expContext.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( nullptr ) );
tempRenderContext->setExpressionContext( expContext );
context = tempRenderContext.get();
}

QFont symbolLabelFont = settings.style( QgsLegendStyle::SymbolLabel ).font();
QgsTextFormat format = QgsTextFormat::fromQFont( symbolLabelFont );
format.setColor( settings.fontColor() );

const QString minLabel = mSettings.prefix() + mSettings.minimumLabel() + mSettings.suffix();
const QString maxLabel = mSettings.prefix() + mSettings.maximumLabel() + mSettings.suffix();

const double height = symbolSize.height();
const double width = symbolSize.width();
double textWidth = 0;

if ( ctx && ctx->painter )
{
double currentYCoord = ctx->top;
QPainter *p = ctx->painter;

//setup painter scaling to dots so that raster symbology is drawn to scale
double dotsPerMM = context->scaleFactor();

QgsScopedQPainterState painterState( p );
context->setPainterFlagsUsingContext( p );

p->scale( 1.0 / dotsPerMM, 1.0 / dotsPerMM );

double labelXMin = 0;
double labelXMax = 0;
@@ -238,16 +304,17 @@ QSizeF QgsColorRampLegendNode::drawSymbol( const QgsLegendSettings &settings, It

const QRectF textRect( labelXMin * dotsPerMM, currentYCoord * dotsPerMM, ( labelXMax - labelXMin ) * dotsPerMM, height * dotsPerMM );
QgsTextRenderer::drawText( textRect, 0, QgsTextRenderer::convertQtHAlignment( settings.style( QgsLegendStyle::SymbolLabel ).alignment() ),
QStringList() << ( mSettings.direction() == QgsColorRampLegendNodeSettings::MinimumToMaximum ? mSettings.maximumLabel() : mSettings.minimumLabel() ),
QStringList() << ( mSettings.direction() == QgsColorRampLegendNodeSettings::MinimumToMaximum ? maxLabel : minLabel ),
*context, format, true, QgsTextRenderer::AlignTop );
QgsTextRenderer::drawText( textRect, 0, QgsTextRenderer::convertQtHAlignment( settings.style( QgsLegendStyle::SymbolLabel ).alignment() ),
QStringList() << ( mSettings.direction() == QgsColorRampLegendNodeSettings::MinimumToMaximum ? mSettings.minimumLabel() : mSettings.maximumLabel() ),
QStringList() << ( mSettings.direction() == QgsColorRampLegendNodeSettings::MinimumToMaximum ? minLabel : maxLabel ),
*context, format, true, QgsTextRenderer::AlignBottom );
}
else
{
// we only need this when we are calculating the size of the node, not at render time
textWidth = QgsTextRenderer::textWidth( *context, format, QStringList() << minLabel << maxLabel ) / context->scaleFactor();
}

return QSizeF( width, height );
return QSizeF( textWidth, height );
}




@@ -63,6 +63,8 @@ class CORE_EXPORT QgsColorRampLegendNode : public QgsLayerTreeModelLegendNode

QVariant data( int role ) const override;
QSizeF drawSymbol( const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight ) const override;
QSizeF drawSymbolText( const QgsLegendSettings &settings, ItemContext *ctx, QSizeF symbolSize ) const override;


/**
* Set the icon \a size, which controls how large the ramp will render in a layer tree widget.
@@ -28,6 +28,8 @@ QgsColorRampLegendNodeSettings::QgsColorRampLegendNodeSettings()
QgsColorRampLegendNodeSettings::QgsColorRampLegendNodeSettings( const QgsColorRampLegendNodeSettings &other )
: mMinimumLabel( other.mMinimumLabel )
, mMaximumLabel( other.mMaximumLabel )
, mPrefix( other.mPrefix )
, mSuffix( other.mSuffix )
, mDirection( other.mDirection )
, mNumericFormat( other.numericFormat()->clone() )
{
@@ -38,6 +40,8 @@ QgsColorRampLegendNodeSettings &QgsColorRampLegendNodeSettings::operator=( const
{
mMinimumLabel = other.mMinimumLabel;
mMaximumLabel = other.mMaximumLabel;
mPrefix = other.mPrefix;
mSuffix = other.mSuffix;
mDirection = other.mDirection;
mNumericFormat.reset( other.numericFormat()->clone() );
return *this;
@@ -91,6 +95,8 @@ void QgsColorRampLegendNodeSettings::writeXml( QDomDocument &doc, QDomElement &e

settingsElement.setAttribute( QStringLiteral( "minimumLabel" ), mMinimumLabel );
settingsElement.setAttribute( QStringLiteral( "maximumLabel" ), mMaximumLabel );
settingsElement.setAttribute( QStringLiteral( "prefix" ), mPrefix );
settingsElement.setAttribute( QStringLiteral( "suffix" ), mSuffix );
settingsElement.setAttribute( QStringLiteral( "direction" ), static_cast< int >( mDirection ) );

QDomElement numericFormatElem = doc.createElement( QStringLiteral( "numericFormat" ) );
@@ -107,6 +113,8 @@ void QgsColorRampLegendNodeSettings::readXml( const QDomElement &element, const
{
mMinimumLabel = settingsElement.attribute( QStringLiteral( "minimumLabel" ) );
mMaximumLabel = settingsElement.attribute( QStringLiteral( "maximumLabel" ) );
mPrefix = settingsElement.attribute( QStringLiteral( "prefix" ) );
mSuffix = settingsElement.attribute( QStringLiteral( "suffix" ) );
mDirection = static_cast< QgsColorRampLegendNodeSettings::Direction >( settingsElement.attribute( QStringLiteral( "direction" ) ).toInt() );

QDomNodeList numericFormatNodeList = settingsElement.elementsByTagName( QStringLiteral( "numericFormat" ) );
@@ -117,3 +125,23 @@ void QgsColorRampLegendNodeSettings::readXml( const QDomElement &element, const
}
}
}

QString QgsColorRampLegendNodeSettings::prefix() const
{
return mPrefix;
}

void QgsColorRampLegendNodeSettings::setPrefix( const QString &prefix )
{
mPrefix = prefix;
}

QString QgsColorRampLegendNodeSettings::suffix() const
{
return mSuffix;
}

void QgsColorRampLegendNodeSettings::setSuffix( const QString &suffix )
{
mSuffix = suffix;
}
@@ -137,9 +137,43 @@ class CORE_EXPORT QgsColorRampLegendNodeSettings
*/
void readXml( const QDomElement &element, const QgsReadWriteContext &context );

/**
* Returns the prefix to show before legend text.
*
* \see setPrefix()
* \see suffix()
*/
QString prefix() const;

/**
* Sets the \a prefix to show before legend text.
*
* \see prefix()
* \see setSuffix()
*/
void setPrefix( const QString &prefix );

/**
* Returns the suffix to show after legend text.
*
* \see setSuffix()
* \see prefix()
*/
QString suffix() const;

/**
* Sets the \a suffix to show after legend text.
*
* \see suffix()
* \see setPrefix()
*/
void setSuffix( const QString &suffix );

private:
QString mMinimumLabel;
QString mMaximumLabel;
QString mPrefix;
QString mSuffix;
Direction mDirection = MinimumToMaximum;
std::unique_ptr< QgsNumericFormat > mNumericFormat;
};
@@ -34,6 +34,8 @@ QgsColorRampLegendNodeWidget::QgsColorRampLegendNodeWidget( QWidget *parent )

connect( mMinLabelLineEdit, &QLineEdit::textChanged, this, &QgsColorRampLegendNodeWidget::onChanged );
connect( mMaxLabelLineEdit, &QLineEdit::textChanged, this, &QgsColorRampLegendNodeWidget::onChanged );
connect( mPrefixLineEdit, &QLineEdit::textChanged, this, &QgsColorRampLegendNodeWidget::onChanged );
connect( mSuffixLineEdit, &QLineEdit::textChanged, this, &QgsColorRampLegendNodeWidget::onChanged );
connect( mDirectionComboBox, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, &QgsColorRampLegendNodeWidget::onChanged );
connect( mNumberFormatPushButton, &QPushButton::clicked, this, &QgsColorRampLegendNodeWidget::changeNumberFormat );
}
@@ -44,6 +46,8 @@ QgsColorRampLegendNodeSettings QgsColorRampLegendNodeWidget::settings() const
settings.setDirection( static_cast< QgsColorRampLegendNodeSettings::Direction >( mDirectionComboBox->currentData().toInt() ) );
settings.setMinimumLabel( mMinLabelLineEdit->text() );
settings.setMaximumLabel( mMaxLabelLineEdit->text() );
settings.setPrefix( mPrefixLineEdit->text() );
settings.setSuffix( mSuffixLineEdit->text() );
settings.setNumericFormat( mSettings.numericFormat()->clone() );
return settings;
}
@@ -55,6 +59,8 @@ void QgsColorRampLegendNodeWidget::setSettings( const QgsColorRampLegendNodeSett
mSettings = settings;
mMinLabelLineEdit->setText( settings.minimumLabel() );
mMaxLabelLineEdit->setText( settings.maximumLabel() );
mPrefixLineEdit->setText( settings.prefix() );
mSuffixLineEdit->setText( settings.suffix() );
mDirectionComboBox->setCurrentIndex( mDirectionComboBox->findData( settings.direction() ) );

mBlockSignals = false;

0 comments on commit 8eb9448

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