Skip to content

Commit

Permalink
Fix deprecated api use in QgsDataDefinedSizeLegend, port away from in…
Browse files Browse the repository at this point in the history
…ts to

make more layout export friendly
  • Loading branch information
nyalldawson committed Feb 7, 2020
1 parent f3c4234 commit 5566c53
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 34 deletions.
2 changes: 1 addition & 1 deletion python/core/auto_generated/qgsdatadefinedsizelegend.sip.in
Expand Up @@ -150,7 +150,7 @@ Updates the list of classes, source symbol and title label from given symbol and
Generates legend symbol items according to the configuration
%End

void drawCollapsedLegend( QgsRenderContext &context, QSize *outputSize /Out/ = 0, int *labelXOffset /Out/ = 0 ) const;
void drawCollapsedLegend( QgsRenderContext &context, QSizeF *outputSize /Out/ = 0, double *labelXOffset /Out/ = 0 ) const;
%Docstring
Draw the legend if using LegendOneNodeForAll and optionally output size of the legend and x offset of labels (in painter units).
If the painter in context is ``None``, it only does size calculation without actual rendering.
Expand Down
4 changes: 2 additions & 2 deletions src/core/layertree/qgslayertreemodellegendnode.cpp
Expand Up @@ -1134,8 +1134,8 @@ QgsLayerTreeModelLegendNode::ItemMetrics QgsDataDefinedSizeLegendNode::draw( con
ddsLegend.setFont( settings.style( QgsLegendStyle::SymbolLabel ).font() );
ddsLegend.setTextColor( settings.fontColor() );

QSize contentSize;
int labelXOffset;
QSizeF contentSize;
double labelXOffset;
ddsLegend.drawCollapsedLegend( context, &contentSize, &labelXOffset );

if ( ctx && ctx->painter )
Expand Down
58 changes: 28 additions & 30 deletions src/core/qgsdatadefinedsizelegend.cpp
Expand Up @@ -141,12 +141,12 @@ QgsLegendSymbolList QgsDataDefinedSizeLegend::legendSymbolList() const
}


void QgsDataDefinedSizeLegend::drawCollapsedLegend( QgsRenderContext &context, QSize *outputSize, int *labelXOffset ) const
void QgsDataDefinedSizeLegend::drawCollapsedLegend( QgsRenderContext &context, QSizeF *outputSize, double *labelXOffset ) const
{
if ( mType != LegendCollapsed || mSizeClasses.isEmpty() || !mSymbol )
{
if ( outputSize )
*outputSize = QSize();
*outputSize = QSizeF();
if ( labelXOffset )
*labelXOffset = 0;
return;
Expand All @@ -170,78 +170,76 @@ void QgsDataDefinedSizeLegend::drawCollapsedLegend( QgsRenderContext &context, Q
// make sure we draw bigger symbols first
std::sort( classes.begin(), classes.end(), []( const SizeClass & a, const SizeClass & b ) { return a.size > b.size; } );

int hLengthLine = std::round( context.convertToPainterUnits( hLengthLineMM, QgsUnitTypes::RenderMillimeters ) );
int hSpaceLineText = std::round( context.convertToPainterUnits( hSpaceLineTextMM, QgsUnitTypes::RenderMillimeters ) );
double hLengthLine = context.convertToPainterUnits( hLengthLineMM, QgsUnitTypes::RenderMillimeters );
double hSpaceLineText = context.convertToPainterUnits( hSpaceLineTextMM, QgsUnitTypes::RenderMillimeters );
int dpm = std::round( context.scaleFactor() * 1000 ); // scale factor = dots per millimeter

// get font metrics - we need a temporary image just to get the metrics right for the given DPI
QImage tmpImg( QSize( 1, 1 ), QImage::Format_ARGB32_Premultiplied );
tmpImg.setDotsPerMeterX( dpm );
tmpImg.setDotsPerMeterY( dpm );
QFontMetrics fm( mFont, &tmpImg );
int textHeight = fm.height();
int leading = fm.leading();
int minTextDistY = textHeight + leading;
QFontMetricsF fm( mFont, &tmpImg );
double textHeight = fm.height();
double leading = fm.leading();
double minTextDistY = textHeight + leading;

//
// determine layout of the rendered elements
//

// find out how wide the text will be
int maxTextWidth = 0;
double maxTextWidth = 0;
for ( const SizeClass &c : qgis::as_const( classes ) )
{
int w = fm.width( c.label );
if ( w > maxTextWidth )
maxTextWidth = w;
maxTextWidth = std::max( maxTextWidth, fm.boundingRect( c.label ).width() );
}
// add extra width needed to handle varying rendering of font weight
maxTextWidth += 1;

// find out size of the largest symbol
double largestSize = classes.at( 0 ).size;
int outputLargestSize = std::round( context.convertToPainterUnits( largestSize, s->sizeUnit(), s->sizeMapUnitScale() ) );
double outputLargestSize = context.convertToPainterUnits( largestSize, s->sizeUnit(), s->sizeMapUnitScale() );

// find out top Y coordinate for individual symbol sizes
QList<int> symbolTopY;
QList<double> symbolTopY;
for ( const SizeClass &c : qgis::as_const( classes ) )
{
int outputSymbolSize = std::round( context.convertToPainterUnits( c.size, s->sizeUnit(), s->sizeMapUnitScale() ) );
double outputSymbolSize = context.convertToPainterUnits( c.size, s->sizeUnit(), s->sizeMapUnitScale() );
switch ( mVAlign )
{
case AlignCenter:
symbolTopY << std::round( outputLargestSize / 2 - outputSymbolSize / 2 );
symbolTopY << outputLargestSize / 2 - outputSymbolSize / 2;
break;
case AlignBottom:
symbolTopY << std::round( outputLargestSize - outputSymbolSize );
symbolTopY << outputLargestSize - outputSymbolSize;
break;
}
}

// determine Y coordinate of texts: ideally they should be at the same level as symbolTopY
// but we need to avoid overlapping texts, so adjust the vertical positions
int middleIndex = 0; // classes.count() / 2; // will get the ideal position
QList<int> textCenterY;
int lastY = symbolTopY[middleIndex];
double middleIndex = 0; // classes.count() / 2; // will get the ideal position
QList<double> textCenterY;
double lastY = symbolTopY[middleIndex];
textCenterY << lastY;
for ( int i = middleIndex + 1; i < classes.count(); ++i )
{
int symbolY = symbolTopY[i];
double symbolY = symbolTopY[i];
if ( symbolY - lastY < minTextDistY )
symbolY = lastY + minTextDistY;
textCenterY << symbolY;
lastY = symbolY;
}

int textTopY = textCenterY.first() - textHeight / 2;
int textBottomY = textCenterY.last() + textHeight / 2;
int totalTextHeight = textBottomY - textTopY;
double textTopY = textCenterY.first() - textHeight / 2;
double textBottomY = textCenterY.last() + textHeight / 2;
double totalTextHeight = textBottomY - textTopY;

int fullWidth = outputLargestSize + hLengthLine + hSpaceLineText + maxTextWidth;
int fullHeight = std::max( static_cast< int >( std::round( outputLargestSize ) ) - textTopY, totalTextHeight );
double fullWidth = outputLargestSize + hLengthLine + hSpaceLineText + maxTextWidth;
double fullHeight = std::max( outputLargestSize - textTopY, totalTextHeight );

if ( outputSize )
*outputSize = QSize( fullWidth, fullHeight );
*outputSize = QSizeF( fullWidth, fullHeight );
if ( labelXOffset )
*labelXOffset = outputLargestSize + hLengthLine + hSpaceLineText;

Expand All @@ -262,7 +260,7 @@ void QgsDataDefinedSizeLegend::drawCollapsedLegend( QgsRenderContext &context, Q
{
s->setSize( c.size );

int outputSymbolSize = std::round( context.convertToPainterUnits( c.size, s->sizeUnit(), s->sizeMapUnitScale() ) );
double outputSymbolSize = context.convertToPainterUnits( c.size, s->sizeUnit(), s->sizeMapUnitScale() );
double tx = ( outputLargestSize - outputSymbolSize ) / 2;

p->save();
Expand Down Expand Up @@ -305,10 +303,10 @@ QImage QgsDataDefinedSizeLegend::collapsedLegendImage( QgsRenderContext &context
return QImage();

// find out the size first
QSize contentSize;
QSizeF contentSize;
drawCollapsedLegend( context, &contentSize );

int padding = std::round( context.convertToPainterUnits( paddingMM, QgsUnitTypes::RenderMillimeters ) );
double padding = context.convertToPainterUnits( paddingMM, QgsUnitTypes::RenderMillimeters );
int dpm = std::round( context.scaleFactor() * 1000 ); // scale factor = dots per millimeter

QImage img( contentSize.width() + padding * 2, contentSize.height() + padding * 2, QImage::Format_ARGB32_Premultiplied );
Expand Down
2 changes: 1 addition & 1 deletion src/core/qgsdatadefinedsizelegend.h
Expand Up @@ -133,7 +133,7 @@ class CORE_EXPORT QgsDataDefinedSizeLegend
* If the painter in context is NULLPTR, it only does size calculation without actual rendering.
* Does nothing if legend is not configured as collapsed.
*/
void drawCollapsedLegend( QgsRenderContext &context, QSize *outputSize SIP_OUT = nullptr, int *labelXOffset SIP_OUT = nullptr ) const;
void drawCollapsedLegend( QgsRenderContext &context, QSizeF *outputSize SIP_OUT = nullptr, double *labelXOffset SIP_OUT = nullptr ) const;

//! Returns output image that would be shown in the legend. Returns invalid image if legend is not configured as collapsed.
QImage collapsedLegendImage( QgsRenderContext &context, const QColor &backgroundColor = Qt::transparent, double paddingMM = 1 ) const;
Expand Down

0 comments on commit 5566c53

Please sign in to comment.