31  : mLegendModel( legendModel )
 
   32  , mSettings( settings )
 
 
   38  std::unique_ptr< QgsRenderContext > tmpContext;
 
   45    tmpContext->setRendererScale( mSettings.
mapScale() );
 
   48    renderContext = tmpContext.get();
 
   53  return paintAndDetermineSize( *renderContext );
 
 
   62  context.setRendererScale( mSettings.
mapScale() );
 
   66  paintAndDetermineSize( context );
 
 
   78  json[QStringLiteral( 
"title" )] = mSettings.
title();
 
 
   86  const QList<QgsLayerTreeNode *> childNodes = nodeGroup->
children();
 
   92      const QModelIndex idx = mLegendModel->
node2index( nodeGroup );
 
   93      const QString text = mLegendModel->
data( idx, Qt::DisplayRole ).toString();
 
   96      group[ QStringLiteral( 
"type" ) ] = QStringLiteral( 
"group" );
 
   97      group[ QStringLiteral( 
"title" ) ] = text;
 
   98      nodes.append( group );
 
  107        const QModelIndex idx = mLegendModel->
node2index( nodeLayer );
 
  108        text = mLegendModel->
data( idx, Qt::DisplayRole ).toString();
 
  111      QList<QgsLayerTreeModelLegendNode *> legendNodes = mLegendModel->
layerLegendNodes( nodeLayer );
 
  116      if ( legendNodes.count() == 1 )
 
  118        QJsonObject group = legendNodes.at( 0 )->exportToJson( mSettings, context );
 
  119        group[ QStringLiteral( 
"type" ) ] = QStringLiteral( 
"layer" );
 
  124            if ( vLayer->renderer() )
 
  127              if ( ! ruleKey.isEmpty() )
 
  130                const QString ruleExp { vLayer->renderer()->legendKeyToExpression( ruleKey, vLayer, ok ) };
 
  133                  group[ QStringLiteral( 
"rule" ) ] = ruleExp;
 
  139        nodes.append( group );
 
  141      else if ( legendNodes.count() > 1 )
 
  144        group[ QStringLiteral( 
"type" ) ] = QStringLiteral( 
"layer" );
 
  145        group[ QStringLiteral( 
"title" ) ] = text;
 
  148        for ( 
int j = 0; j < legendNodes.count(); j++ )
 
  156              if ( vLayer->renderer() )
 
  159                if ( ! ruleKey.isEmpty() )
 
  162                  const QString ruleExp { vLayer->renderer()->legendKeyToExpression( ruleKey, vLayer, ok ) };
 
  165                    symbol[ QStringLiteral( 
"rule" ) ] = ruleExp;
 
  171          symbols.append( symbol );
 
  173        group[ QStringLiteral( 
"symbols" ) ] = symbols;
 
  175        nodes.append( group );
 
  180  json[QStringLiteral( 
"nodes" )] = nodes;
 
  195  QList<LegendComponentGroup> componentGroups = createComponentGroupList( rootGroup, context );
 
  197  const int columnCount = setColumns( componentGroups );
 
  199  QMap< int, double > maxColumnWidths;
 
  200  qreal maxEqualColumnWidth = 0;
 
  208  for ( 
const LegendComponentGroup &group : std::as_const( componentGroups ) )
 
  210    const QSizeF actualSize = drawGroup( group, context, ColumnContext() );
 
  211    maxEqualColumnWidth = std::max( actualSize.width(), maxEqualColumnWidth );
 
  212    maxColumnWidths[ group.column ] = std::max( actualSize.width(), maxColumnWidths.value( group.column, 0 ) );
 
  215  if ( columnCount == 1 )
 
  218    maxEqualColumnWidth = std::max( maxEqualColumnWidth, mLegendSize.width() - 2 * mSettings.
boxSpace() );
 
  219    maxColumnWidths[ 0 ] = maxEqualColumnWidth;
 
  223  QSizeF titleSize = drawTitle( context, 0 );
 
  225  titleSize.rwidth() += mSettings.
boxSpace() * 2.0;
 
  230  bool firstInColumn = 
true;
 
  231  double columnMaxHeight = 0;
 
  232  qreal columnWidth = 0;
 
  234  ColumnContext columnContext;
 
  235  columnContext.left = mSettings.
boxSpace();
 
  236  columnContext.right = std::max( mLegendSize.width() - mSettings.
boxSpace(), mSettings.
boxSpace() );
 
  237  double currentY = columnTop;
 
  239  for ( 
const LegendComponentGroup &group : std::as_const( componentGroups ) )
 
  241    if ( group.column > column )
 
  244      columnContext.left = group.column > 0 ? ( columnContext.right + mSettings.
columnSpace() ) : mSettings.boxSpace();
 
  245      columnWidth = mSettings.
equalColumnWidth() ? maxEqualColumnWidth : maxColumnWidths.value( group.column );
 
  246      columnContext.right = columnContext.left + columnWidth;
 
  247      currentY = columnTop;
 
  249      firstInColumn = 
true;
 
  251    if ( !firstInColumn )
 
  253      currentY += spaceAboveGroup( group );
 
  256    drawGroup( group, context, columnContext, currentY );
 
  258    currentY += group.size.height();
 
  259    columnMaxHeight = std::max( currentY - columnTop, columnMaxHeight );
 
  261    firstInColumn = 
false;
 
  263  const double totalWidth = columnContext.right + mSettings.
boxSpace();
 
  265  size.rheight() = columnTop + columnMaxHeight + mSettings.
boxSpace();
 
  266  size.rwidth() = totalWidth;
 
  267  if ( !mSettings.
title().isEmpty() )
 
  269    size.rwidth() = std::max( titleSize.width(), size.width() );
 
  273  if ( mLegendSize.isValid() )
 
  275    qreal w = std::max( size.width(), mLegendSize.width() );
 
  276    qreal h = std::max( size.height(), mLegendSize.height() );
 
  277    size = QSizeF( w, h );
 
  281  if ( !mSettings.
title().isEmpty() )
 
  289void QgsLegendRenderer::widthAndOffsetForTitleText( 
const Qt::AlignmentFlag halignment, 
const double legendWidth, 
double &textBoxWidth, 
double &textBoxLeft )
 const 
  291  switch ( halignment )
 
  295      textBoxWidth = legendWidth - 2 * mSettings.
boxSpace();
 
  298    case Qt::AlignHCenter:
 
  301      const double centerX = legendWidth / 2;
 
  302      textBoxWidth = ( std::min( 
static_cast< double >( centerX ), legendWidth - centerX ) - mSettings.
boxSpace() ) * 2.0;
 
  303      textBoxLeft = centerX - textBoxWidth / 2.;
 
  309QList<QgsLegendRenderer::LegendComponentGroup> QgsLegendRenderer::createComponentGroupList( 
QgsLayerTreeGroup *parentGroup, 
QgsRenderContext &context, 
double indent )
 
  311  QList<LegendComponentGroup> componentGroups;
 
  314    return componentGroups;
 
  316  const QList<QgsLayerTreeNode *> childNodes = parentGroup->
children();
 
  322      QString style = node->customProperty( QStringLiteral( 
"legend/title-style" ) ).toString();
 
  324      double newIndent = indent;
 
  325      if ( style == QLatin1String( 
"subgroup" ) )
 
  335      QList<LegendComponentGroup> subgroups = createComponentGroupList( nodeGroup, context, newIndent );
 
  337      bool hasSubItems = !subgroups.empty();
 
  341        LegendComponent component;
 
  342        component.item = node;
 
  343        component.indent = newIndent;
 
  344        component.size = drawGroupTitle( nodeGroup, context );
 
  346        if ( !subgroups.isEmpty() )
 
  349          subgroups[0].size.rheight() += spaceAboveGroup( subgroups[0] );
 
  351          subgroups[0].components.prepend( component );
 
  352          subgroups[0].size.rheight() += component.size.height();
 
  353          subgroups[0].size.rwidth() = std::max( component.size.width(), subgroups[0].size.width() );
 
  354          if ( nodeGroup->
customProperty( QStringLiteral( 
"legend/column-break" ) ).toInt() )
 
  355            subgroups[0].placeColumnBreakBeforeGroup = 
true;
 
  360          LegendComponentGroup group;
 
  361          group.placeColumnBreakBeforeGroup = nodeGroup->
customProperty( QStringLiteral( 
"legend/column-break" ) ).toInt();
 
  362          group.components.append( component );
 
  363          group.size.rwidth() += component.size.width();
 
  364          group.size.rheight() += component.size.height();
 
  365          group.size.rwidth() = std::max( component.size.width(), group.size.width() );
 
  366          subgroups.append( group );
 
  372        componentGroups.append( subgroups );
 
  380      bool allowColumnSplit = 
false;
 
  387          allowColumnSplit = 
true;
 
  390          allowColumnSplit = 
false;
 
  394      LegendComponentGroup group;
 
  395      group.placeColumnBreakBeforeGroup = nodeLayer->
customProperty( QStringLiteral( 
"legend/column-break" ) ).toInt();
 
  399        LegendComponent component;
 
  400        component.item = node;
 
  401        component.size = drawLayerTitle( nodeLayer, context );
 
  402        component.indent = indent;
 
  403        group.components.append( component );
 
  404        group.size.rwidth() = component.size.width();
 
  405        group.size.rheight() = component.size.height();
 
  408      QList<QgsLayerTreeModelLegendNode *> legendNodes = mLegendModel->
layerLegendNodes( nodeLayer );
 
  416      QList<LegendComponentGroup> layerGroups;
 
  417      layerGroups.reserve( legendNodes.count() );
 
  419      bool groupIsLayerGroup = 
true;
 
  420      double symbolIndent = indent;
 
  421      switch ( layerStyle )
 
  425          symbolIndent += mSettings.
style( layerStyle ).
indent( );
 
  430      for ( 
int j = 0; j < legendNodes.count(); j++ )
 
  434        LegendComponent symbolComponent = drawSymbolItem( legendNode, context, ColumnContext(), 0 );
 
  438        if ( !allowColumnSplit || j == 0 )
 
  442            if ( groupIsLayerGroup )
 
  443              layerGroups.prepend( group );
 
  445              layerGroups.append( group );
 
  447            group = LegendComponentGroup();
 
  448            group.placeColumnBreakBeforeGroup = 
true;
 
  449            groupIsLayerGroup = 
false;
 
  454          group.size.rwidth() = std::max( symbolComponent.size.width(), group.size.width() );
 
  456          if ( !group.components.isEmpty() )
 
  461          group.size.rheight() += symbolComponent.size.height();
 
  462          symbolComponent.indent = symbolIndent;
 
  463          group.components.append( symbolComponent );
 
  467          if ( group.size.height() > 0 )
 
  469            if ( groupIsLayerGroup )
 
  470              layerGroups.prepend( group );
 
  472              layerGroups.append( group );
 
  473            group = LegendComponentGroup();
 
  474            groupIsLayerGroup = 
false;
 
  476          LegendComponentGroup symbolGroup;
 
  477          symbolGroup.placeColumnBreakBeforeGroup = forceBreak;
 
  478          symbolComponent.indent = symbolIndent;
 
  479          symbolGroup.components.append( symbolComponent );
 
  480          symbolGroup.size.rwidth() = symbolComponent.size.width();
 
  481          symbolGroup.size.rheight() = symbolComponent.size.height();
 
  482          layerGroups.append( symbolGroup );
 
  485      if ( group.size.height() > 0 )
 
  487        if ( groupIsLayerGroup )
 
  488          layerGroups.prepend( group );
 
  490          layerGroups.append( group );
 
  492      componentGroups.append( layerGroups );
 
  496  return componentGroups;
 
  500int QgsLegendRenderer::setColumns( QList<LegendComponentGroup> &componentGroups )
 
  503  double totalHeight = 0;
 
  504  qreal maxGroupHeight = 0;
 
  505  int forcedColumnBreaks = 0;
 
  506  double totalSpaceAboveGroups = 0;
 
  508  for ( 
const LegendComponentGroup &group : std::as_const( componentGroups ) )
 
  510    const double topMargin = spaceAboveGroup( group );
 
  511    totalHeight += topMargin;
 
  512    totalSpaceAboveGroups += topMargin;
 
  514    const double groupHeight = group.size.height();
 
  515    totalHeight += groupHeight;
 
  516    maxGroupHeight = std::max( groupHeight, maxGroupHeight );
 
  518    if ( group.placeColumnBreakBeforeGroup )
 
  519      forcedColumnBreaks++;
 
  521  const double totalGroupHeight = ( totalHeight - totalSpaceAboveGroups );
 
  522  double averageGroupHeight = totalGroupHeight / componentGroups.size();
 
  524  if ( mSettings.
columnCount() == 0 && forcedColumnBreaks == 0 )
 
  529  const int targetNumberColumns = std::max( forcedColumnBreaks + 1, mSettings.
columnCount() );
 
  530  const int numberAutoPlacedBreaks = targetNumberColumns - forcedColumnBreaks - 1;
 
  537  double maxColumnHeight = 0;
 
  538  int currentColumn = 0;
 
  539  int currentColumnGroupCount = 0; 
 
  540  double currentColumnHeight = 0;
 
  541  int autoPlacedBreaks = 0;
 
  544  double averageSpaceAboveGroups = 0;
 
  545  if ( componentGroups.size() > targetNumberColumns )
 
  546    averageSpaceAboveGroups = totalSpaceAboveGroups / ( componentGroups.size() );
 
  548  double totalRemainingGroupHeight = totalGroupHeight;
 
  549  double totalRemainingSpaceAboveGroups = totalSpaceAboveGroups;
 
  550  for ( 
int i = 0; i < componentGroups.size(); i++ )
 
  552    const LegendComponentGroup &group = componentGroups.at( i );
 
  553    const double currentGroupHeight = group.size.height();
 
  554    const double spaceAboveCurrentGroup = spaceAboveGroup( group );
 
  556    totalRemainingGroupHeight -= currentGroupHeight;
 
  557    totalRemainingSpaceAboveGroups -= spaceAboveCurrentGroup;
 
  559    double currentColumnHeightIfGroupIsIncluded = currentColumnHeight;
 
  560    if ( currentColumnGroupCount > 0 )
 
  561      currentColumnHeightIfGroupIsIncluded += spaceAboveCurrentGroup;
 
  562    currentColumnHeightIfGroupIsIncluded += currentGroupHeight;
 
  564    const int numberRemainingGroupsIncludingThisOne = componentGroups.size() - i;
 
  565    const int numberRemainingColumnsIncludingThisOne = numberAutoPlacedBreaks + 1 - autoPlacedBreaks;
 
  566    const int numberRemainingColumnBreaks = numberRemainingColumnsIncludingThisOne - 1;
 
  568    const double averageRemainingSpaceAboveGroups = numberRemainingGroupsIncludingThisOne > 1 ? ( totalRemainingSpaceAboveGroups / ( numberRemainingGroupsIncludingThisOne - 1 ) ) : 0;
 
  569    const double estimatedRemainingSpaceAboveGroupsWhichWontBeUsedBecauseGroupsAreFirstInColumn = numberRemainingColumnBreaks * averageRemainingSpaceAboveGroups;
 
  570    const double estimatedRemainingTotalHeightAfterThisGroup = totalRemainingGroupHeight
 
  571        + totalRemainingSpaceAboveGroups
 
  572        - estimatedRemainingSpaceAboveGroupsWhichWontBeUsedBecauseGroupsAreFirstInColumn;
 
  574    const double estimatedTotalHeightOfRemainingColumnsIncludingThisOne = currentColumnHeightIfGroupIsIncluded
 
  575        + estimatedRemainingTotalHeightAfterThisGroup;
 
  578    double averageRemainingColumnHeightIncludingThisOne = estimatedTotalHeightOfRemainingColumnsIncludingThisOne / numberRemainingColumnsIncludingThisOne;
 
  582    const int averageGroupsPerRemainingColumnsIncludingThisOne = std::ceil( averageRemainingColumnHeightIncludingThisOne / ( averageGroupHeight + averageSpaceAboveGroups ) );
 
  584    averageRemainingColumnHeightIncludingThisOne = averageGroupsPerRemainingColumnsIncludingThisOne * ( averageGroupHeight + averageSpaceAboveGroups ) - averageSpaceAboveGroups;
 
  586    bool canCreateNewColumn = ( currentColumnGroupCount > 0 )  
 
  587                              && ( currentColumn < targetNumberColumns - 1 ) 
 
  588                              && ( autoPlacedBreaks < numberAutoPlacedBreaks );
 
  590    bool shouldCreateNewColumn = currentColumnHeightIfGroupIsIncluded > averageRemainingColumnHeightIncludingThisOne  
 
  591                                 && currentColumnGroupCount > 0 
 
  592                                 && currentColumnHeightIfGroupIsIncluded > maxGroupHeight  
 
  593                                 && currentColumnHeightIfGroupIsIncluded > maxColumnHeight; 
 
  595    shouldCreateNewColumn |= group.placeColumnBreakBeforeGroup;
 
  596    canCreateNewColumn |= group.placeColumnBreakBeforeGroup;
 
  600    shouldCreateNewColumn |= ( componentGroups.size() - i < targetNumberColumns - currentColumn );
 
  602    if ( canCreateNewColumn && shouldCreateNewColumn )
 
  606      if ( !group.placeColumnBreakBeforeGroup )
 
  608      currentColumnGroupCount = 0;
 
  609      currentColumnHeight = group.size.height();
 
  613      currentColumnHeight = currentColumnHeightIfGroupIsIncluded;
 
  615    componentGroups[i].column = currentColumn;
 
  616    currentColumnGroupCount++;
 
  617    maxColumnHeight = std::max( currentColumnHeight, maxColumnHeight );
 
  620  auto refineColumns = [&componentGroups, 
this]() -> 
bool 
  622    QHash< int, double > columnHeights;
 
  623    QHash< int, int > columnGroupCounts;
 
  624    double currentColumnHeight = 0;
 
  625    int currentColumn = -1;
 
  628    double maxCurrentColumnHeight = 0;
 
  629    for ( 
int i = 0; i < componentGroups.size(); i++ )
 
  631      const LegendComponentGroup &group = componentGroups.at( i );
 
  632      if ( group.column != currentColumn )
 
  634        if ( currentColumn >= 0 )
 
  636          columnHeights.insert( currentColumn, currentColumnHeight );
 
  637          columnGroupCounts.insert( currentColumn, groupCount );
 
  640        currentColumn = group.column;
 
  641        currentColumnHeight = 0;
 
  643        columnCount = std::max( columnCount, currentColumn + 1 );
 
  646      const double spaceAbove = spaceAboveGroup( group );
 
  647      currentColumnHeight += spaceAbove + group.size.height();
 
  650    columnHeights.insert( currentColumn, currentColumnHeight );
 
  651    columnGroupCounts.insert( currentColumn, groupCount );
 
  653    double totalColumnHeights = 0;
 
  654    for ( 
int i = 0; i < columnCount; ++ i )
 
  656      totalColumnHeights += columnHeights[i];
 
  657      maxCurrentColumnHeight = std::max( maxCurrentColumnHeight, columnHeights[i] );
 
  660    const double averageColumnHeight = totalColumnHeights / columnCount;
 
  662    bool changed = 
false;
 
  663    int nextCandidateColumnForShift = 1;
 
  664    for ( 
int i = 0; i < componentGroups.size(); i++ )
 
  666      LegendComponentGroup &group = componentGroups[ i ];
 
  667      if ( group.column < nextCandidateColumnForShift )
 
  671      const bool canShift = !group.placeColumnBreakBeforeGroup
 
  672                            && columnGroupCounts[ group.column ] >= 2;
 
  675           && columnHeights[ group.column - 1 ] < averageColumnHeight
 
  676           && ( columnHeights[ group.column - 1 ] + group.size.height() ) * 0.9 < maxCurrentColumnHeight
 
  680        columnHeights[ group.column ] += group.size.height() + spaceAboveGroup( group );
 
  681        columnGroupCounts[ group.column ]++;
 
  682        columnHeights[ group.column + 1 ] -= group.size.height();
 
  683        columnGroupCounts[ group.column + 1]--;
 
  688        nextCandidateColumnForShift = group.column + 1;
 
  694  bool wasRefined = 
true;
 
  696  while ( wasRefined && iterations < 2 )
 
  698    wasRefined = refineColumns();
 
  703  QMap<QString, qreal> maxSymbolWidth;
 
  704  for ( 
int i = 0; i < componentGroups.size(); i++ )
 
  706    LegendComponentGroup &group = componentGroups[i];
 
  707    for ( 
int j = 0; j < group.components.size(); j++ )
 
  711        QString key = QStringLiteral( 
"%1-%2" ).arg( 
reinterpret_cast< qulonglong 
>( 
legendNode->
layerNode() ) ).arg( group.column );
 
  712        maxSymbolWidth[key] = std::max( group.components.at( j ).symbolSize.width(), maxSymbolWidth[key] );
 
  716  for ( 
int i = 0; i < componentGroups.size(); i++ )
 
  718    LegendComponentGroup &group = componentGroups[i];
 
  719    for ( 
int j = 0; j < group.components.size(); j++ )
 
  723        QString key = QStringLiteral( 
"%1-%2" ).arg( 
reinterpret_cast< qulonglong 
>( 
legendNode->
layerNode() ) ).arg( group.column );
 
  726        group.components[j].labelXOffset = maxSymbolWidth[key] + space;
 
  727        group.components[j].maxSiblingSymbolWidth = maxSymbolWidth[key];
 
  728        group.components[j].size.rwidth() = maxSymbolWidth[key] + space + group.components.at( j ).labelSize.width();
 
  732  return targetNumberColumns;
 
  735QSizeF QgsLegendRenderer::drawTitle( 
QgsRenderContext &context, 
double top, Qt::AlignmentFlag halignment, 
double legendWidth )
 const 
  738  if ( mSettings.
title().isEmpty() )
 
  748  widthAndOffsetForTitleText( halignment, legendWidth, textBoxWidth, textBoxLeft );
 
  753  double overallTextHeight = 0;
 
  754  double overallTextWidth = 0;
 
  762  size.rheight() = overallTextHeight / dotsPerMM;
 
  763  size.rwidth() = overallTextWidth / dotsPerMM;
 
  769    const QRectF r( textBoxLeft * dotsPerMM, top * dotsPerMM, textBoxWidth * dotsPerMM, overallTextHeight );
 
  781double QgsLegendRenderer::spaceAboveGroup( 
const LegendComponentGroup &group )
 
  783  if ( group.components.isEmpty() ) 
return 0;
 
  785  LegendComponent component = group.components.first();
 
  787  if ( 
QgsLayerTreeGroup *nodeGroup = qobject_cast<QgsLayerTreeGroup *>( component.item ) )
 
  791  else if ( 
QgsLayerTreeLayer *nodeLayer = qobject_cast<QgsLayerTreeLayer *>( component.item ) )
 
  795  else if ( qobject_cast<QgsLayerTreeModelLegendNode *>( component.item ) )
 
  804QSizeF QgsLegendRenderer::drawGroup( 
const LegendComponentGroup &group, 
QgsRenderContext &context, ColumnContext columnContext, 
double top )
 
  807  QSizeF size = QSizeF( group.size );
 
  808  double currentY = top;
 
  809  for ( 
const LegendComponent &component : std::as_const( group.components ) )
 
  811    if ( 
QgsLayerTreeGroup *groupItem = qobject_cast<QgsLayerTreeGroup *>( component.item ) )
 
  821        ColumnContext columnContextForItem = columnContext;
 
  822        double indentWidth =  component.indent;
 
  835          columnContextForItem.left += indentWidth;
 
  839          columnContextForItem.right -= indentWidth;
 
  841        groupSize = drawGroupTitle( groupItem, context, columnContextForItem, currentY );
 
  842        size.rwidth() = std::max( groupSize.width(), size.width() );
 
  845    else if ( 
QgsLayerTreeLayer *layerItem = qobject_cast<QgsLayerTreeLayer *>( component.item ) )
 
  856        ColumnContext columnContextForItem = columnContext;
 
  857        double indentWidth =  component.indent;
 
  858        columnContextForItem.left += indentWidth;
 
  859        subGroupSize = drawLayerTitle( layerItem, context, columnContextForItem, currentY );
 
  860        size.rwidth() = std::max( subGroupSize.width(), size.width() );
 
  870      ColumnContext columnContextForItem = columnContext;
 
  871      double indentWidth = 0;
 
  872      indentWidth = component.indent;
 
  875        columnContextForItem.left += indentWidth;
 
  879        columnContextForItem.right -= indentWidth;
 
  882      LegendComponent symbolComponent = drawSymbolItem( legendNode, context, columnContextForItem, currentY, component.maxSiblingSymbolWidth );
 
  884      size.rwidth() = std::max( symbolComponent.size.width() + indentWidth, size.width() );
 
  886    currentY += component.size.height();
 
  907  ctx.
point = QPointF( columnContext.left, top );
 
  933    symbolScope = symbolNode->createSymbolScope();
 
  948  LegendComponent component;
 
  949  component.item = symbolItem;
 
  956  double width = std::max( 
static_cast< double >( im.
symbolSize.width() ), maxSiblingSymbolWidth )
 
  963  component.size = QSizeF( width, height );
 
  970  QModelIndex idx = mLegendModel->
node2index( nodeLayer );
 
  971  QString titleString = mLegendModel->
data( idx, Qt::DisplayRole ).toString();
 
  973  if ( titleString.isEmpty() )
 
  979  if ( nodeLayer->
layer() )
 
  989  double overallTextHeight = 0;
 
  990  double overallTextWidth = 0;
 
  998  size.rheight() = overallTextHeight / dotsPerMM;
 
  999  size.rwidth() = overallTextWidth / dotsPerMM + sideMargin *
 
 1009                    ( ( columnContext.right - columnContext.left ) - ( halign == 
Qgis::TextHorizontalAlignment::
Right ? sideMargin : 0 ) ) * dotsPerMM, overallTextHeight );
 
 1023  QSizeF size( 0, 0 );
 
 1024  QModelIndex idx = mLegendModel->
node2index( nodeGroup );
 
 1030  double overallTextHeight = 0;
 
 1031  double overallTextWidth = 0;
 
 1042  size.rheight() = overallTextHeight / dotsPerMM;
 
 1043  size.rwidth() = overallTextWidth / dotsPerMM + sideMargin *
 
 1054                    dotsPerMM * ( ( columnContext.right - columnContext.left ) - ( halign == 
Qgis::TextHorizontalAlignment::
Right ? sideMargin : 0 ) ), overallTextHeight );
 
 1064  QString style = node->
customProperty( QStringLiteral( 
"legend/title-style" ) ).toString();
 
 1065  if ( style == QLatin1String( 
"hidden" ) )
 
 1067  else if ( style == QLatin1String( 
"group" ) )
 
 1069  else if ( style == QLatin1String( 
"subgroup" ) )
 
 
 1096      str = QStringLiteral( 
"hidden" );
 
 1099      str = QStringLiteral( 
"group" );
 
 1102      str = QStringLiteral( 
"subgroup" );
 
 1108  if ( !
str.isEmpty() )
 
 
 1116  paintAndDetermineSize( context );
 
 
The Qgis class provides global constants for use throughout the application.
 
@ RectangleAscentBased
Similar to Rectangle mode, but uses ascents only when calculating font and line heights....
 
@ Rectangle
Text within rectangle layout mode.
 
@ ShowRuleDetails
If set, the rule expression of a rule based renderer legend item will be added to the JSON.
 
@ ApplyScalingWorkaroundForTextRendering
Whether a scaling workaround designed to stablise the rendering of small font sizes (or for painters ...
 
TextHorizontalAlignment
Text horizontal alignment.
 
Single scope for storing variables and functions for use within a QgsExpressionContext.
 
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
 
QgsExpressionContextScope * popScope()
Removes the last scope from the expression context and return it.
 
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
 
Layer tree group node serves as a container for layers and further groups.
 
Layer tree node points to a map layer.
 
@ AllowSplittingLegendNodesOverMultipleColumns
Allow splitting node's legend nodes across multiple columns.
 
@ PreventSplittingLegendNodesOverMultipleColumns
Prevent splitting node's legend nodes across multiple columns.
 
@ UseDefaultLegendSetting
Inherit default legend column splitting setting.
 
LegendNodesSplitBehavior legendSplitBehavior() const
Returns the column split behavior for the node.
 
QgsMapLayer * layer() const
Returns the map layer associated with this node.
 
The QgsLegendRendererItem class is abstract interface for legend items returned from QgsMapLayerLegen...
 
virtual QVariant data(int role) const =0
Returns data associated with the item. Must be implemented in derived class.
 
QJsonObject exportToJson(const QgsLegendSettings &settings, const QgsRenderContext &context)
Entry point called from QgsLegendRenderer to do the rendering in a JSON object.
 
virtual bool columnBreak() const
Returns whether a forced column break should occur before the node.
 
@ RuleKey
Rule key of the node (QString)
 
virtual QSizeF userPatchSize() const
Returns the user (overridden) size for the legend node.
 
virtual ItemMetrics draw(const QgsLegendSettings &settings, ItemContext *ctx)
Entry point called from QgsLegendRenderer to do the rendering.
 
QgsLayerTreeLayer * layerNode() const
Returns pointer to the parent layer node.
 
The QgsLayerTreeModel class is model implementation for Qt item views framework.
 
QModelIndex node2index(QgsLayerTreeNode *node) const
Returns index for a given node. If the node does not belong to the layer tree, the result is undefine...
 
QList< QgsLayerTreeModelLegendNode * > layerLegendNodes(QgsLayerTreeLayer *nodeLayer, bool skipNodeEmbeddedInParent=false)
Returns filtered list of active legend nodes attached to a particular layer node (by default it retur...
 
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
 
QgsLayerTree * rootGroup() const
Returns pointer to the root node of the layer tree. Always a non nullptr value.
 
QgsLayerTreeModelLegendNode * legendNodeEmbeddedInParent(QgsLayerTreeLayer *nodeLayer) const
Returns legend node that may be embedded in parent (i.e.
 
const QgsMapSettings * legendFilterMapSettings() const
Returns the current map settings used for the current legend filter (or nullptr if none is enabled)
 
This class is a base class for nodes in a layer tree.
 
void setCustomProperty(const QString &key, const QVariant &value)
Sets a custom property for the node. Properties are stored in a map and saved in project file.
 
QList< QgsLayerTreeNode * > children()
Gets list of children of the node. Children are owned by the parent.
 
void removeCustomProperty(const QString &key)
Remove a custom property from layer. Properties are stored in a map and saved in project file.
 
QVariant customProperty(const QString &key, const QVariant &defaultValue=QVariant()) const
Read a custom property from layer. Properties are stored in a map and saved in project file.
 
static QgsLayerTreeLayer * toLayer(QgsLayerTreeNode *node)
Cast node to a layer.
 
static bool isLayer(const QgsLayerTreeNode *node)
Check whether the node is a valid layer node.
 
static bool isGroup(QgsLayerTreeNode *node)
Check whether the node is a valid group node.
 
static QgsLayerTreeGroup * toGroup(QgsLayerTreeNode *node)
Cast node to a group.
 
QSizeF minimumSize(QgsRenderContext *renderContext=nullptr)
Runs the layout algorithm and returns the minimum size required for the legend.
 
static void setNodeLegendStyle(QgsLayerTreeNode *node, QgsLegendStyle::Style style)
Sets the style of a node.
 
QJsonObject exportLegendToJson(const QgsRenderContext &context)
Renders the legend in a json object.
 
QgsLegendRenderer(QgsLayerTreeModel *legendModel, const QgsLegendSettings &settings)
Constructor for QgsLegendRenderer.
 
static QgsLegendStyle::Style nodeLegendStyle(QgsLayerTreeNode *node, QgsLayerTreeModel *model)
Returns the style for the given node, within the specified model.
 
Q_DECL_DEPRECATED void drawLegend(QPainter *painter)
Draws the legend with given painter.
 
The QgsLegendSettings class stores the appearance and layout settings for legend drawing with QgsLege...
 
int columnCount() const
Returns the desired minimum number of columns to show in the legend.
 
QgsLegendStyle style(QgsLegendStyle::Style s) const
Returns the style for a legend component.
 
Qt::AlignmentFlag titleAlignment() const
Returns the alignment of the legend title.
 
QString title() const
Returns the title for the legend, which will be rendered above all legend items.
 
double columnSpace() const
Returns the margin space between adjacent columns (in millimeters).
 
double boxSpace() const
Returns the legend box space (in millimeters), which is the empty margin around the inside of the leg...
 
Q_DECL_DEPRECATED double mmPerMapUnit() const
 
bool splitLayer() const
Returns true if layer components can be split over multiple columns.
 
QStringList evaluateItemText(const QString &text, const QgsExpressionContext &context) const
Splits a string using the wrap char taking into account handling empty wrap char which means no wrapp...
 
Qgis::LegendJsonRenderFlags jsonRenderFlags() const
Returns the JSON export flags.
 
QStringList splitStringForWrapping(const QString &stringToSplt) const
Splits a string using the wrap char taking into account handling empty wrap char which means no wrapp...
 
Qt::AlignmentFlag symbolAlignment() const
Returns the alignment for placement of legend symbols.
 
bool equalColumnWidth() const
Returns true if all columns should have equal widths.
 
Q_DECL_DEPRECATED double mapScale() const
Returns the legend map scale.
 
double margin(Side side)
Returns the margin (in mm) for the specified side of the component.
 
Qt::Alignment alignment() const
Returns the alignment for the legend component.
 
QgsTextFormat & textFormat()
Returns the text format used for rendering this legend component.
 
Style
Component of legends which can be styled.
 
@ Group
Legend group title.
 
@ Symbol
Symbol icon (excluding label)
 
@ Undefined
Should not happen, only if corrupted project file.
 
@ Subgroup
Legend subgroup title.
 
@ Hidden
Special style, item is hidden including margins around.
 
@ SymbolLabel
Symbol label (excluding icon)
 
double indent() const
Returns the indent (in mm) of a group or subgroup.
 
Perform transforms between map coordinates and device coordinates.
 
Contains information about the context of a rendering operation.
 
double scaleFactor() const
Returns the scaling factor for the render to convert painter units to physical sizes.
 
QPainter * painter()
Returns the destination QPainter for the render operation.
 
QgsExpressionContext & expressionContext()
Gets the expression context.
 
static QgsRenderContext fromQPainter(QPainter *painter)
Creates a default render context given a pixel based QPainter destination.
 
Scoped object for temporary replacement of a QgsRenderContext destination painter.
 
Scoped object for temporary scaling of a QgsRenderContext for millimeter based rendering.
 
Scoped object for temporary scaling of a QgsRenderContext for pixel based rendering.
 
Implementation of legend node interface for displaying preview of vector symbols and their labels and...
 
Container for all settings relating to text rendering.
 
static double textWidth(const QgsRenderContext &context, const QgsTextFormat &format, const QStringList &textLines, QFontMetricsF *fontMetrics=nullptr)
Returns the width of a text based on a given format.
 
static void drawText(const QRectF &rect, double rotation, Qgis::TextHorizontalAlignment alignment, const QStringList &textLines, QgsRenderContext &context, const QgsTextFormat &format, bool drawAsOutlines=true, Qgis::TextVerticalAlignment vAlignment=Qgis::TextVerticalAlignment::Top, Qgis::TextRendererFlags flags=Qgis::TextRendererFlags(), Qgis::TextLayoutMode mode=Qgis::TextLayoutMode::Rectangle)
Draws text within a rectangle using the specified settings.
 
static double textHeight(const QgsRenderContext &context, const QgsTextFormat &format, const QStringList &textLines, Qgis::TextLayoutMode mode=Qgis::TextLayoutMode::Point, QFontMetricsF *fontMetrics=nullptr, Qgis::TextRendererFlags flags=Qgis::TextRendererFlags(), double maxLineWidth=0)
Returns the height of a text based on a given format.
 
Represents a vector layer which manages a vector based data sets.
 
QgsLayerTreeModelLegendNode * legendNode(const QString &rule, QgsLayerTreeModel &model)
 
#define Q_NOWARN_DEPRECATED_POP
 
#define Q_NOWARN_DEPRECATED_PUSH
 
QPainter * painter
Painter.
 
double top
Top y-position of legend item.
 
Q_DECL_DEPRECATED double labelXOffset
Offset from the left side where label should start.
 
QgsLegendPatchShape patchShape
The patch shape to render for the node.
 
double maxSiblingSymbolWidth
Largest symbol width, considering all other sibling legend components associated with the current com...
 
QSizeF patchSize
Symbol patch size to render for the node.
 
double columnLeft
Left side of current legend column.
 
double columnRight
Right side of current legend column.
 
Q_DECL_DEPRECATED QPointF point
Top-left corner of the legend item.
 
Q_NOWARN_DEPRECATED_POP QgsRenderContext * context
Render context, if available.