30   std::unique_ptr< QgsSimpleLineSymbolLayer > lineSymbolLayer = std::make_unique< QgsSimpleLineSymbolLayer >( QColor( 0, 0, 0 ), 0.2 );
 
   31   mLineSymbol = std::make_unique< QgsLineSymbol >( 
QgsSymbolLayerList() << lineSymbolLayer.release() );
 
   37   : mType( other.mType )
 
   38   , mTitleLabel( other.mTitleLabel )
 
   39   , mSizeClasses( other.mSizeClasses )
 
   40   , mSymbol( other.mSymbol.get() ? other.mSymbol->clone() : nullptr )
 
   41   , mLineSymbol( other.mLineSymbol.get() ? other.mLineSymbol->clone() : nullptr )
 
   42   , mSizeScaleTransformer( other.mSizeScaleTransformer.get() ? new 
QgsSizeScaleTransformer( *other.mSizeScaleTransformer ) : nullptr )
 
   43   , mVAlign( other.mVAlign )
 
   44   , mFont( other.mFont )
 
   45   , mTextColor( other.mTextColor )
 
   46   , mTextAlignment( other.mTextAlignment )
 
   55     mTitleLabel = other.mTitleLabel;
 
   56     mSizeClasses = other.mSizeClasses;
 
   57     mSymbol.reset( other.mSymbol.get() ? other.mSymbol->clone() : 
nullptr );
 
   58     mLineSymbol.reset( other.mLineSymbol.get() ? other.mLineSymbol->clone() : 
nullptr );
 
   59     mSizeScaleTransformer.reset( other.mSizeScaleTransformer.get() ? 
new QgsSizeScaleTransformer( *other.mSizeScaleTransformer ) : 
nullptr );
 
   60     mVAlign = other.mVAlign;
 
   62     mTextColor = other.mTextColor;
 
   63     mTextAlignment = other.mTextAlignment;
 
   80   mLineSymbol.reset( 
symbol );
 
   85   return mLineSymbol.get();
 
   90   mSizeScaleTransformer.reset( transformer );
 
   95   return mSizeScaleTransformer.get();
 
  105   mSizeScaleTransformer.reset( sizeTransformer ? sizeTransformer->
clone() : nullptr );
 
  107   if ( mTitleLabel.isEmpty() )
 
  111   if ( sizeTransformer && mSizeClasses.isEmpty() )
 
  113     mSizeClasses.clear();
 
  115     for ( 
double v : prettyBreaks )
 
  117       mSizeClasses << 
SizeClass( v, QString::number( v ) );
 
  125   if ( !mTitleLabel.isEmpty() )
 
  143       lst.reserve( mSizeClasses.size() );
 
  144       for ( 
const SizeClass &cl : mSizeClasses )
 
  148         double size = cl.
size;
 
  149         if ( mSizeScaleTransformer )
 
  151           size = mSizeScaleTransformer->size( size );
 
  171       *outputSize = QSizeF();
 
  178   double hLengthLineMM = 2;       
 
  179   double hSpaceLineTextMM = 1;    
 
  181   std::unique_ptr<QgsMarkerSymbol> s( mSymbol->clone() );
 
  183   QList<SizeClass> 
classes = mSizeClasses;
 
  186   if ( mSizeScaleTransformer )
 
  189       cls.size = mSizeScaleTransformer->size( cls.size );
 
  197   int dpm = std::round( context.
scaleFactor() * 1000 );  
 
  200   QImage tmpImg( QSize( 1, 1 ), QImage::Format_ARGB32_Premultiplied );
 
  201   tmpImg.setDotsPerMeterX( dpm );
 
  202   tmpImg.setDotsPerMeterY( dpm );
 
  203   QFontMetricsF fm( mFont, &tmpImg );
 
  204   double textHeight = fm.height();
 
  205   double leading = fm.leading();
 
  206   double minTextDistY = textHeight + leading;
 
  213   double maxTextWidth = 0;
 
  216     maxTextWidth = std::max( maxTextWidth, fm.boundingRect( 
c.label ).width() );
 
  222   double largestSize = 
classes.at( 0 ).size;
 
  223   double outputLargestSize = context.
convertToPainterUnits( largestSize, s->sizeUnit(), s->sizeMapUnitScale() );
 
  226   QList<double> symbolTopY;
 
  233         symbolTopY << outputLargestSize / 2 - outputSymbolSize / 2;
 
  236         symbolTopY <<  outputLargestSize - outputSymbolSize;
 
  243   double middleIndex = 0; 
 
  244   QList<double> textCenterY;
 
  245   double lastY = middleIndex < symbolTopY.size() ? symbolTopY[middleIndex] : 0;
 
  246   textCenterY << lastY;
 
  247   for ( 
int i = middleIndex + 1; i < 
classes.count(); ++i )
 
  249     double symbolY = symbolTopY[i];
 
  250     if ( symbolY - lastY < minTextDistY )
 
  251       symbolY = lastY + minTextDistY;
 
  252     textCenterY << symbolY;
 
  256   double textTopY = textCenterY.first() - textHeight / 2;
 
  257   double textBottomY = textCenterY.last() + textHeight / 2;
 
  258   double totalTextHeight = textBottomY - textTopY;
 
  260   double fullWidth = outputLargestSize + hLengthLine + hSpaceLineText + maxTextWidth;
 
  261   double fullHeight = std::max( outputLargestSize - textTopY, totalTextHeight );
 
  264     *outputSize = QSizeF( fullWidth, fullHeight );
 
  266     *labelXOffset = outputLargestSize + hLengthLine + hSpaceLineText;
 
  275   QPainter *p = context.
painter();
 
  277   p->translate( 0, -textTopY );
 
  282     s->setSize( 
c.size );
 
  285     double tx = ( outputLargestSize - outputSymbolSize ) / 2;
 
  291         p->translate( tx, ( outputLargestSize - outputSymbolSize ) / 2 );
 
  294         p->translate( tx, outputLargestSize - outputSymbolSize );
 
  297     s->drawPreviewIcon( 
nullptr, QSize( outputSymbolSize, outputSymbolSize ), &context );
 
  305     mLineSymbol->startRender( context );
 
  314       mLineSymbol->renderPolyline( QPolygonF() << QPointF( outputLargestSize / 2, symbolTopY[i] )
 
  315                                    << QPointF( outputLargestSize + hLengthLine, textCenterY[i] ), 
nullptr, context );
 
  319     QRect rect( outputLargestSize + hLengthLine + hSpaceLineText, textCenterY[i] - textHeight / 2,
 
  320                 maxTextWidth, textHeight );
 
  323                                QStringList() << 
c.label, context, format );
 
  328     mLineSymbol->stopRender( context );
 
  342   int dpm = std::round( context.
scaleFactor() * 1000 );  
 
  344   QImage img( contentSize.width() + padding * 2, contentSize.height() + padding * 2, QImage::Format_ARGB32_Premultiplied );
 
  345   img.setDotsPerMeterX( dpm );
 
  346   img.setDotsPerMeterY( dpm );
 
  347   img.fill( backgroundColor );
 
  349   QPainter painter( &img );
 
  350   painter.setRenderHint( QPainter::Antialiasing, 
true );
 
  352   painter.translate( padding, padding ); 
 
  355   QPainter *oldPainter = context.
painter();
 
  371   ddsLegend->
setTitle( elem.attribute( QStringLiteral( 
"title" ) ) );
 
  373   QDomElement elemSymbol = elem.firstChildElement( QStringLiteral( 
"symbol" ) );
 
  374   if ( !elemSymbol.isNull() )
 
  376     ddsLegend->
setSymbol( QgsSymbolLayerUtils::loadSymbol<QgsMarkerSymbol>( elemSymbol, context ) );
 
  379   const QDomElement lineSymbolElem = elem.firstChildElement( QStringLiteral( 
"lineSymbol" ) );
 
  380   if ( !lineSymbolElem.isNull() )
 
  382     ddsLegend->
setLineSymbol( QgsSymbolLayerUtils::loadSymbol<QgsLineSymbol>( lineSymbolElem.firstChildElement(), context ) );
 
  386   QDomElement elemTransformer = elem.firstChildElement( QStringLiteral( 
"transformer" ) );
 
  387   if ( !elemTransformer.isNull() )
 
  394   QDomElement elemTextStyle = elem.firstChildElement( QStringLiteral( 
"text-style" ) );
 
  395   if ( !elemTextStyle.isNull() )
 
  397     QDomElement elemFont = elemTextStyle.firstChildElement( QStringLiteral( 
"font" ) );
 
  398     if ( !elemFont.isNull() )
 
  400       ddsLegend->
setFont( QFont( elemFont.attribute( QStringLiteral( 
"family" ) ), elemFont.attribute( QStringLiteral( 
"size" ) ).toInt(),
 
  401                                  elemFont.attribute( QStringLiteral( 
"weight" ) ).toInt(), elemFont.attribute( QStringLiteral( 
"italic" ) ).toInt() ) );
 
  404     ddsLegend->
setTextAlignment( 
static_cast<Qt::AlignmentFlag
>( elemTextStyle.attribute( QStringLiteral( 
"align" ) ).toInt() ) );
 
  407   QDomElement elemClasses = elem.firstChildElement( QStringLiteral( 
"classes" ) );
 
  408   if ( !elemClasses.isNull() )
 
  411     QDomElement elemClass = elemClasses.firstChildElement( QStringLiteral( 
"class" ) );
 
  412     while ( !elemClass.isNull() )
 
  414       classes << 
SizeClass( elemClass.attribute( QStringLiteral( 
"size" ) ).toDouble(), elemClass.attribute( QStringLiteral( 
"label" ) ) );
 
  415       elemClass = elemClass.nextSiblingElement();
 
  425   QDomDocument doc = elem.ownerDocument();
 
  427   elem.setAttribute( QStringLiteral( 
"type" ), mType == 
LegendCollapsed ? 
"collapsed" : 
"separated" );
 
  428   elem.setAttribute( QStringLiteral( 
"valign" ), mVAlign == 
AlignCenter ? 
"center" : 
"bottom" );
 
  429   elem.setAttribute( QStringLiteral( 
"title" ), mTitleLabel );
 
  434     elem.appendChild( elemSymbol );
 
  439     QDomElement lineSymbolElem = doc.createElement( QStringLiteral( 
"lineSymbol" ) );
 
  441     elem.appendChild( lineSymbolElem );
 
  444   if ( mSizeScaleTransformer )
 
  447     elemTransformer.setTagName( QStringLiteral( 
"transformer" ) );
 
  448     elem.appendChild( elemTransformer );
 
  451   QDomElement elemFont = doc.createElement( QStringLiteral( 
"font" ) );
 
  452   elemFont.setAttribute( QStringLiteral( 
"family" ), mFont.family() );
 
  453   elemFont.setAttribute( QStringLiteral( 
"size" ), mFont.pointSize() );
 
  454   elemFont.setAttribute( QStringLiteral( 
"weight" ), mFont.weight() );
 
  455   elemFont.setAttribute( QStringLiteral( 
"italic" ), mFont.italic() );
 
  457   QDomElement elemTextStyle = doc.createElement( QStringLiteral( 
"text-style" ) );
 
  459   elemTextStyle.setAttribute( QStringLiteral( 
"align" ), 
static_cast<int>( mTextAlignment ) );
 
  460   elemTextStyle.appendChild( elemFont );
 
  461   elem.appendChild( elemTextStyle );
 
  463   if ( !mSizeClasses.isEmpty() )
 
  465     QDomElement elemClasses = doc.createElement( QStringLiteral( 
"classes" ) );
 
  466     for ( 
const SizeClass &sc : std::as_const( mSizeClasses ) )
 
  468       QDomElement elemClass = doc.createElement( QStringLiteral( 
"class" ) );
 
  469       elemClass.setAttribute( QStringLiteral( 
"size" ), sc.size );
 
  470       elemClass.setAttribute( QStringLiteral( 
"label" ), sc.label );
 
  471       elemClasses.appendChild( elemClass );
 
  473     elem.appendChild( elemClasses );