QgsLayerTreeModelLegendNode::ItemMetrics QgsDataDefinedSizeLegendNode::draw( const QgsLegendSettings &settings, QgsLayerTreeModelLegendNode::ItemContext *ctx )
{
  // setup temporary render context
  QgsRenderContext context;
  context.setScaleFactor( settings.dpi() / 25.4 );
  context.setRendererScale( settings.mapScale() );
  context.setMapToPixel( QgsMapToPixel( 1 / ( settings.mmPerMapUnit() * context.scaleFactor() ) ) );
  context.setForceVectorOutput( true );

  if ( ctx && ctx->painter )
  {
    context.setPainter( ctx->painter );
    ctx->painter->save();
    ctx->painter->setRenderHint( QPainter::Antialiasing );
    ctx->painter->translate( ctx->point );
    ctx->painter->scale( 1 / context.scaleFactor(), 1 / context.scaleFactor() );
  }

  QgsDataDefinedSizeLegend ddsLegend( *mSettings );
  ddsLegend.setFont( settings.style( QgsLegendStyle::SymbolLabel ).font() );
  ddsLegend.setTextColor( settings.fontColor() );

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

  if ( ctx && ctx->painter )
    ctx->painter->restore();

  ItemMetrics im;
  im.symbolSize = QSizeF( ( contentSize.width() - labelXOffset ) / context.scaleFactor(), contentSize.height() / context.scaleFactor() );
  im.labelSize = QSizeF( labelXOffset / context.scaleFactor(), contentSize.height() / context.scaleFactor() );
  return im;
}
QSizeF QgsLayerTreeModelLegendNode::drawSymbol( const QgsLegendSettings& settings, ItemContext* ctx, double itemHeight ) const
{
    QIcon symbolIcon = data( Qt::DecorationRole ).value<QIcon>();
    if ( symbolIcon.isNull() )
        return QSizeF();

    if ( ctx )
        symbolIcon.paint( ctx->painter, ctx->point.x(), ctx->point.y() + ( itemHeight - settings.symbolSize().height() ) / 2,
                          settings.symbolSize().width(), settings.symbolSize().height() );
    return settings.symbolSize();
}
QSizeF QgsImageLegendNode::drawSymbol( const QgsLegendSettings& settings, ItemContext* ctx, double itemHeight ) const
{
    Q_UNUSED( itemHeight );

    if ( ctx )
    {
        ctx->painter->drawImage( QRectF( ctx->point.x(), ctx->point.y(), settings.wmsLegendSize().width(), settings.wmsLegendSize().height() ),
                                 mImage, QRectF( 0, 0, mImage.width(), mImage.height() ) );
    }
    return settings.wmsLegendSize();
}
QSizeF QgsWmsLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight ) const
{
  Q_UNUSED( itemHeight );

  if ( ctx && ctx->painter )
  {
    ctx->painter->drawImage( QRectF( ctx->point, settings.wmsLegendSize() ),
                             mImage,
                             QRectF( QPointF( 0, 0 ), mImage.size() ) );
  }
  return settings.wmsLegendSize();
}
Example #5
0
static void _setStandardTestFont( QgsLegendSettings& settings, const QString& style = "Roman" )
{
  QList< QgsComposerLegendStyle::Style> styles;
  styles << QgsComposerLegendStyle::Title
  << QgsComposerLegendStyle::Group
  << QgsComposerLegendStyle::Subgroup
  << QgsComposerLegendStyle::SymbolLabel;
  Q_FOREACH ( QgsComposerLegendStyle::Style st, styles )
  {
    QFont font( QgsFontUtils::getStandardTestFont( style ) );
    font.setPointSizeF( settings.style( st ).font().pointSizeF() );
    settings.rstyle( st ).setFont( font );
  }
Example #6
0
static void _setStandardTestFont( QgsLegendSettings& settings )
{
  QList< QgsComposerLegendStyle::Style> styles;
  styles << QgsComposerLegendStyle::Title
  << QgsComposerLegendStyle::Group
  << QgsComposerLegendStyle::Subgroup
  << QgsComposerLegendStyle::SymbolLabel;
  foreach ( QgsComposerLegendStyle::Style st, styles )
  {
    QFont font( QgsFontUtils::getStandardTestFont() );
    font.setPointSizeF( settings.style( st ).font().pointSizeF() );
    settings.rstyle( st ).setFont( font );
  }
void QgsLayerTreeModelLegendNode::exportSymbolToJson( const QgsLegendSettings &settings, const QgsRenderContext &, QJsonObject &json ) const
{
  const QIcon icon = data( Qt::DecorationRole ).value<QIcon>();
  if ( icon.isNull() )
    return;

  const QImage image( icon.pixmap( settings.symbolSize().width(), settings.symbolSize().height() ).toImage() );
  QByteArray byteArray;
  QBuffer buffer( &byteArray );
  image.save( &buffer, "PNG" );
  const QString base64 = QString::fromLatin1( byteArray.toBase64().data() );
  json[ "icon" ] = base64;
}
QgsLayerTreeModelLegendNode::ItemMetrics QgsLayerTreeModelLegendNode::draw( const QgsLegendSettings& settings, ItemContext* ctx )
{
    QFont symbolLabelFont = settings.style( QgsComposerLegendStyle::SymbolLabel ).font();

    double textHeight = settings.fontHeightCharacterMM( symbolLabelFont, QChar( '0' ) );
    // itemHeight here is not realy item height, it is only for symbol
    // vertical alignment purpose, i.e. ok take single line height
    // if there are more lines, thos run under the symbol
    double itemHeight = qMax(( double ) settings.symbolSize().height(), textHeight );

    ItemMetrics im;
    im.symbolSize = drawSymbol( settings, ctx, itemHeight );
    im.labelSize = drawSymbolText( settings, ctx, im.symbolSize );
    return im;
}
QSizeF QgsRasterSymbolLegendNode::drawSymbol( const QgsLegendSettings& settings, ItemContext* ctx, double itemHeight ) const
{
    if ( ctx )
    {
        QColor itemColor = mColor;
        if ( QgsRasterLayer* rasterLayer = dynamic_cast<QgsRasterLayer*>( layerNode()->layer() ) )
        {
            if ( QgsRasterRenderer* rasterRenderer = rasterLayer->renderer() )
                itemColor.setAlpha( rasterRenderer->opacity() * 255.0 );
        }

        ctx->painter->setBrush( itemColor );
        ctx->painter->drawRect( QRectF( ctx->point.x(), ctx->point.y() + ( itemHeight - settings.symbolSize().height() ) / 2,
                                        settings.symbolSize().width(), settings.symbolSize().height() ) );
    }
    return settings.symbolSize();
}
QSizeF QgsRasterSymbolLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight ) const
{
  if ( ctx && ctx->painter )
  {
    QColor itemColor = mColor;
    if ( QgsRasterLayer *rasterLayer = qobject_cast<QgsRasterLayer *>( layerNode()->layer() ) )
    {
      if ( QgsRasterRenderer *rasterRenderer = rasterLayer->renderer() )
        itemColor.setAlpha( rasterRenderer->opacity() * 255.0 );
    }
    ctx->painter->setBrush( itemColor );

    if ( settings.drawRasterStroke() )
    {
      QPen pen;
      pen.setColor( settings.rasterStrokeColor() );
      pen.setWidthF( settings.rasterStrokeWidth() );
      pen.setJoinStyle( Qt::MiterJoin );
      ctx->painter->setPen( pen );
    }
    else
    {
      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() ) );
  }
  return settings.symbolSize();
}
void QgsSymbolLegendNode::exportSymbolToJson( const QgsLegendSettings &settings, const QgsRenderContext &context, QJsonObject &json ) const
{
  const QgsSymbol *s = mItem.symbol();
  if ( !s )
  {
    return;
  }

  QgsRenderContext ctx;
  ctx.setScaleFactor( settings.dpi() / 25.4 );
  ctx.setRendererScale( settings.mapScale() );
  ctx.setMapToPixel( QgsMapToPixel( 1 / ( settings.mmPerMapUnit() * ctx.scaleFactor() ) ) );
  ctx.setForceVectorOutput( true );

  // ensure that a minimal expression context is available
  QgsExpressionContext expContext = context.expressionContext();
  expContext.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( nullptr ) );
  ctx.setExpressionContext( expContext );

  const QPixmap pix = QgsSymbolLayerUtils::symbolPreviewPixmap( mItem.symbol(), minimumIconSize(), 0, &ctx );
  QImage img( pix.toImage().convertToFormat( QImage::Format_ARGB32_Premultiplied ) );

  int opacity = 255;
  if ( QgsVectorLayer *vectorLayer = qobject_cast<QgsVectorLayer *>( layerNode()->layer() ) )
    opacity = ( 255 * vectorLayer->opacity() );

  if ( opacity != 255 )
  {
    QPainter painter;
    painter.begin( &img );
    painter.setCompositionMode( QPainter::CompositionMode_DestinationIn );
    painter.fillRect( pix.rect(), QColor( 0, 0, 0, opacity ) );
    painter.end();
  }

  QByteArray byteArray;
  QBuffer buffer( &byteArray );
  img.save( &buffer, "PNG" );
  const QString base64 = QString::fromLatin1( byteArray.toBase64().data() );
  json[ "icon" ] = base64;
}
QSizeF QgsLayerTreeModelLegendNode::drawSymbolText( const QgsLegendSettings &settings, ItemContext *ctx, QSizeF symbolSize ) const
{
  QSizeF labelSize( 0, 0 );

  QFont symbolLabelFont = settings.style( QgsLegendStyle::SymbolLabel ).font();
  double textHeight = settings.fontHeightCharacterMM( symbolLabelFont, QChar( '0' ) );
  double textDescent = settings.fontDescentMillimeters( symbolLabelFont );

  QgsExpressionContext tempContext;

  const QStringList lines = settings.evaluateItemText( data( Qt::DisplayRole ).toString(), ctx && ctx->context ? ctx->context->expressionContext() : tempContext );

  labelSize.rheight() = lines.count() * textHeight + ( lines.count() - 1 ) * ( settings.lineSpacing() + textDescent );

  double labelX = 0.0, labelY = 0.0;
  if ( ctx && ctx->painter )
  {
    ctx->painter->setPen( settings.fontColor() );

    labelX = ctx->point.x() + std::max( static_cast< double >( symbolSize.width() ), ctx->labelXOffset );
    labelY = ctx->point.y();

    // Vertical alignment of label with symbol
    if ( labelSize.height() < symbolSize.height() )
      labelY += symbolSize.height() / 2 - labelSize.height() / 2;  // label centered with symbol

    labelY += textHeight;
  }

  for ( QStringList::ConstIterator itemPart = lines.constBegin(); itemPart != lines.constEnd(); ++itemPart )
  {
    labelSize.rwidth() = std::max( settings.textWidthMillimeters( symbolLabelFont, *itemPart ), double( labelSize.width() ) );

    if ( ctx && ctx->painter )
    {
      settings.drawText( ctx->painter, labelX, labelY, *itemPart, symbolLabelFont );
      if ( itemPart != ( lines.end() - 1 ) )
        labelY += textDescent + settings.lineSpacing() + textHeight;
    }
  }

  return labelSize;
}
QSizeF QgsLayerTreeModelLegendNode::drawSymbolText( const QgsLegendSettings& settings, ItemContext* ctx, const QSizeF& symbolSize ) const
{
    QSizeF labelSize( 0, 0 );

    QFont symbolLabelFont = settings.style( QgsComposerLegendStyle::SymbolLabel ).font();
    double textHeight = settings.fontHeightCharacterMM( symbolLabelFont, QChar( '0' ) );

    QStringList lines = settings.splitStringForWrapping( data( Qt::DisplayRole ).toString() );

    labelSize.rheight() = lines.count() * textHeight + ( lines.count() - 1 ) * settings.lineSpacing();

    double labelX = 0.0, labelY = 0.0;
    if ( ctx )
    {
        ctx->painter->setPen( settings.fontColor() );

        labelX = ctx->point.x() + qMax(( double ) symbolSize.width(), ctx->labelXOffset );
        labelY = ctx->point.y();

        // Vertical alignment of label with symbol
        if ( labelSize.height() < symbolSize.height() )
            labelY += symbolSize.height() / 2 + textHeight / 2;  // label centered with symbol
        else
            labelY += textHeight; // label starts at top and runs under symbol
    }

    for ( QStringList::Iterator itemPart = lines.begin(); itemPart != lines.end(); ++itemPart )
    {
        labelSize.rwidth() = qMax( settings.textWidthMillimeters( symbolLabelFont, *itemPart ), double( labelSize.width() ) );

        if ( ctx )
        {
            settings.drawText( ctx->painter, labelX, labelY, *itemPart, symbolLabelFont );
            if ( itemPart != lines.end() )
                labelY += settings.lineSpacing() + textHeight;
        }
    }

    return labelSize;
}
void QgsRasterSymbolLegendNode::exportSymbolToJson( const QgsLegendSettings &settings, const QgsRenderContext &, QJsonObject &json ) const
{
  QImage img = QImage( settings.symbolSize().toSize(), QImage::Format_ARGB32 );
  img.fill( Qt::transparent );

  QPainter painter( &img );
  painter.setRenderHint( QPainter::Antialiasing );

  QColor itemColor = mColor;
  if ( QgsRasterLayer *rasterLayer = qobject_cast<QgsRasterLayer *>( layerNode()->layer() ) )
  {
    if ( QgsRasterRenderer *rasterRenderer = rasterLayer->renderer() )
      itemColor.setAlpha( rasterRenderer->opacity() * 255.0 );
  }
  painter.setBrush( itemColor );

  if ( settings.drawRasterStroke() )
  {
    QPen pen;
    pen.setColor( settings.rasterStrokeColor() );
    pen.setWidthF( settings.rasterStrokeWidth() );
    pen.setJoinStyle( Qt::MiterJoin );
    painter.setPen( pen );
  }
  else
  {
    painter.setPen( Qt::NoPen );
  }

  painter.drawRect( QRectF( 0, 0, settings.symbolSize().width(), settings.symbolSize().height() ) );

  QByteArray byteArray;
  QBuffer buffer( &byteArray );
  img.save( &buffer, "PNG" );
  const QString base64 = QString::fromLatin1( byteArray.toBase64().data() );
  json[ "icon" ] = base64;
}
QSizeF QgsSymbolV2LegendNode::drawSymbol( const QgsLegendSettings& settings, ItemContext* ctx, double itemHeight ) const
{
    QgsSymbolV2* s = mItem.symbol();
    if ( !s )
    {
        return QSizeF();
    }

    // setup temporary render context
    QgsRenderContext context;
    context.setScaleFactor( settings.dpi() / 25.4 );
    context.setRendererScale( settings.mapScale() );
    context.setMapToPixel( QgsMapToPixel( 1 / ( settings.mmPerMapUnit() * context.scaleFactor() ) ) );
    context.setForceVectorOutput( true );
    context.setPainter( ctx ? ctx->painter : 0 );

    //Consider symbol size for point markers
    double height = settings.symbolSize().height();
    double width = settings.symbolSize().width();
    double size = 0;
    //Center small marker symbols
    double widthOffset = 0;
    double heightOffset = 0;

    if ( QgsMarkerSymbolV2* markerSymbol = dynamic_cast<QgsMarkerSymbolV2*>( s ) )
    {
        // allow marker symbol to occupy bigger area if necessary
        size = markerSymbol->size() * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context, s->outputUnit(), s->mapUnitScale() ) / context.scaleFactor();
        height = size;
        width = size;
        if ( width < settings.symbolSize().width() )
        {
            widthOffset = ( settings.symbolSize().width() - width ) / 2.0;
        }
        if ( height < settings.symbolSize().height() )
        {
            heightOffset = ( settings.symbolSize().height() - height ) / 2.0;
        }
    }

    if ( ctx )
    {
        double currentXPosition = ctx->point.x();
        double currentYCoord = ctx->point.y() + ( itemHeight - settings.symbolSize().height() ) / 2;
        QPainter* p = ctx->painter;

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

        int opacity = 255;
        if ( QgsVectorLayer* vectorLayer = dynamic_cast<QgsVectorLayer*>( layerNode()->layer() ) )
            opacity = 255 - ( 255 * vectorLayer->layerTransparency() / 100 );

        p->save();
        p->setRenderHint( QPainter::Antialiasing );
        p->translate( currentXPosition + widthOffset, currentYCoord + heightOffset );
        p->scale( 1.0 / dotsPerMM, 1.0 / dotsPerMM );
        if ( opacity != 255 && settings.useAdvancedEffects() )
        {
            //semi transparent layer, so need to draw symbol to an image (to flatten it first)
            //create image which is same size as legend rect, in case symbol bleeds outside its alloted space
            QSize tempImageSize( width * dotsPerMM, height * dotsPerMM );
            QImage tempImage = QImage( tempImageSize, QImage::Format_ARGB32 );
            tempImage.fill( Qt::transparent );
            QPainter imagePainter( &tempImage );
            context.setPainter( &imagePainter );
            s->drawPreviewIcon( &imagePainter, tempImageSize, &context );
            context.setPainter( ctx->painter );
            //reduce opacity of image
            imagePainter.setCompositionMode( QPainter::CompositionMode_DestinationIn );
            imagePainter.fillRect( tempImage.rect(), QColor( 0, 0, 0, opacity ) );
            imagePainter.end();
            //draw rendered symbol image
            p->drawImage( 0, 0, tempImage );
        }
        else
        {
            s->drawPreviewIcon( p, QSize( width * dotsPerMM, height * dotsPerMM ), &context );
        }
        p->restore();
    }

    return QSizeF( qMax( width + 2 * widthOffset, ( double ) settings.symbolSize().width() ),
                   qMax( height + 2 * heightOffset, ( double ) settings.symbolSize().height() ) );
}
QSizeF QgsSymbolLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight ) const
{
  QgsSymbol *s = mItem.symbol();
  if ( !s )
  {
    return QSizeF();
  }

  // setup temporary render context
  QgsRenderContext context;
  context.setScaleFactor( settings.dpi() / 25.4 );
  context.setRendererScale( settings.mapScale() );
  context.setMapToPixel( QgsMapToPixel( 1 / ( settings.mmPerMapUnit() * context.scaleFactor() ) ) );
  context.setForceVectorOutput( true );
  context.setPainter( ctx ? ctx->painter : nullptr );

  if ( ctx && ctx->context )
  {
    context.setExpressionContext( ctx->context->expressionContext() );
  }
  else
  {
    // setup a minimal expression context
    QgsExpressionContext expContext;
    expContext.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( nullptr ) );
    context.setExpressionContext( expContext );
  }

  //Consider symbol size for point markers
  double height = settings.symbolSize().height();
  double width = settings.symbolSize().width();

  //Center small marker symbols
  double widthOffset = 0;
  double heightOffset = 0;

  if ( QgsMarkerSymbol *markerSymbol = dynamic_cast<QgsMarkerSymbol *>( s ) )
  {
    // allow marker symbol to occupy bigger area if necessary
    double size = markerSymbol->size( context ) / context.scaleFactor();
    height = size;
    width = size;
    if ( width < settings.symbolSize().width() )
    {
      widthOffset = ( settings.symbolSize().width() - width ) / 2.0;
    }
    if ( height < settings.symbolSize().height() )
    {
      heightOffset = ( settings.symbolSize().height() - height ) / 2.0;
    }
  }

  if ( ctx && ctx->painter )
  {
    double currentXPosition = ctx->point.x();
    double currentYCoord = ctx->point.y() + ( itemHeight - settings.symbolSize().height() ) / 2;
    QPainter *p = ctx->painter;

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

    int opacity = 255;
    if ( QgsVectorLayer *vectorLayer = qobject_cast<QgsVectorLayer *>( layerNode()->layer() ) )
      opacity = ( 255 * vectorLayer->opacity() );

    p->save();
    p->setRenderHint( QPainter::Antialiasing );
    p->translate( currentXPosition + widthOffset, currentYCoord + heightOffset );
    p->scale( 1.0 / dotsPerMM, 1.0 / dotsPerMM );
    if ( opacity != 255 && settings.useAdvancedEffects() )
    {
      //semi transparent layer, so need to draw symbol to an image (to flatten it first)
      //create image which is same size as legend rect, in case symbol bleeds outside its alloted space
      QSize tempImageSize( width * dotsPerMM, height * dotsPerMM );
      QImage tempImage = QImage( tempImageSize, QImage::Format_ARGB32 );
      tempImage.fill( Qt::transparent );
      QPainter imagePainter( &tempImage );
      context.setPainter( &imagePainter );
      s->drawPreviewIcon( &imagePainter, tempImageSize, &context );
      context.setPainter( ctx->painter );
      //reduce opacity of image
      imagePainter.setCompositionMode( QPainter::CompositionMode_DestinationIn );
      imagePainter.fillRect( tempImage.rect(), QColor( 0, 0, 0, opacity ) );
      imagePainter.end();
      //draw rendered symbol image
      p->drawImage( 0, 0, tempImage );
    }
    else
    {
      s->drawPreviewIcon( p, QSize( width * dotsPerMM, height * dotsPerMM ), &context );
    }

    if ( !mTextOnSymbolLabel.isEmpty() )
    {
      QFontMetricsF fm( mTextOnSymbolTextFormat.scaledFont( context ) );
      qreal yBaselineVCenter = ( height * dotsPerMM + fm.ascent() - fm.descent() ) / 2;
      QgsTextRenderer::drawText( QPointF( width * dotsPerMM / 2, yBaselineVCenter ), 0, QgsTextRenderer::AlignCenter,
                                 QStringList() << mTextOnSymbolLabel, context, mTextOnSymbolTextFormat );
    }

    p->restore();
  }

  return QSizeF( std::max( width + 2 * widthOffset, static_cast< double >( settings.symbolSize().width() ) ),
                 std::max( height + 2 * heightOffset, static_cast< double >( settings.symbolSize().height() ) ) );
}