35 #include <QApplication>
38 #include <QFontMetrics>
41 #include <QDesktopWidget>
72 #include <QMessageBox>
108 if ( !sPropertyDefinitions()->isEmpty() )
111 const QString origin = QStringLiteral(
"labeling" );
123 "e.g. Helvetica or Helvetica [Cronyx]" ), origin )
127 "e.g. Bold Condensed or Light Italic" ), origin )
167 "<b>Ellipse</b>|<b>Circle</b>|<b>SVG</b>]" ), origin )
191 "<b>Buffer</b>|<b>Background</b>]" ), origin )
207 "<b>3</b>=Left|<b>4</b>=Over|<b>5</b>=Right|<br>"
208 "<b>6</b>=Below Left|<b>7</b>=Below|<b>8</b>=Below Right]" ), origin )
225 + QStringLiteral(
"[<b>TL</b>=Top left|<b>TSL</b>=Top, slightly left|<b>T</b>=Top middle|<br>"
226 "<b>TSR</b>=Top, slightly right|<b>TR</b>=Top right|<br>"
227 "<b>L</b>=Left|<b>R</b>=Right|<br>"
228 "<b>BL</b>=Bottom left|<b>BSL</b>=Bottom, slightly left|<b>B</b>=Bottom middle|<br>"
229 "<b>BSR</b>=Bottom, slightly right|<b>BR</b>=Bottom right]" ), origin )
233 + QStringLiteral(
"[<b>OL</b>=On line|<b>AL</b>=Above line|<b>BL</b>=Below line|<br>"
234 "<b>LO</b>=Respect line orientation]" ), origin )
242 "<b>Half</b>|<b>Cap</b>|<b>Top</b>]" ), origin )
265 : predefinedPositionOrder( *DEFAULT_PLACEMENT_ORDER() )
268 initPropertyDefinitions();
275 , mDataDefinedProperties( s.mDataDefinedProperties )
310 mPolygonPlacementFlags = s.mPolygonPlacementFlags;
347 mDataDefinedProperties = s.mDataDefinedProperties;
349 mCallout.reset( s.mCallout ? s.mCallout->clone() :
nullptr );
351 mLineSettings = s.mLineSettings;
352 mObstacleSettings = s.mObstacleSettings;
353 mThinningSettings = s.mThinningSettings;
408 for (
const QString &name : referencedColumns )
410 attributeNames.insert( name );
466 for (
const QString &name : referencedColumns )
468 attributeNames.insert( name );
475 const auto referencedColumns = mCallout->referencedFields( context );
476 for (
const QString &name : referencedColumns )
478 attributeNames.insert( name );
487 QSet<QString> referenced;
515 referenced.unite( mCallout->referencedFields( context ) );
523 if ( mRenderStarted )
525 qWarning(
"Start render called for when a previous render was already underway!!" );
538 mCallout->startRender( context );
541 mRenderStarted =
true;
546 if ( !mRenderStarted )
548 qWarning(
"Stop render called for QgsPalLayerSettings without a startRender call!" );
554 mCallout->stopRender( context );
557 mRenderStarted =
false;
562 if ( mRenderStarted )
564 qWarning(
"stopRender was not called on QgsPalLayerSettings object!" );
575 initPropertyDefinitions();
576 return *sPropertyDefinitions();
591 QString newValue = value;
592 if ( !value.isEmpty() && !value.contains( QLatin1String(
"~~" ) ) )
595 values << QStringLiteral(
"1" );
596 values << QStringLiteral(
"0" );
599 newValue = values.join( QLatin1String(
"~~" ) );
607 QString newPropertyName =
"labeling/dataDefined/" + sPropertyDefinitions()->value( p ).name();
608 QVariant newPropertyField = layer->
customProperty( newPropertyName, QVariant() );
610 if ( !newPropertyField.isValid() )
613 QString ddString = newPropertyField.toString();
615 if ( !ddString.isEmpty() && ddString != QLatin1String(
"0~~0~~~~" ) )
619 QStringList ddv = newStyleString.split( QStringLiteral(
"~~" ) );
621 bool active = ddv.at( 0 ).toInt();
622 if ( ddv.at( 1 ).toInt() )
638 void QgsPalLayerSettings::readOldDataDefinedPropertyMap(
QgsVectorLayer *layer, QDomElement *parentElem )
640 if ( !layer && !parentElem )
645 QgsPropertiesDefinition::const_iterator i = sPropertyDefinitions()->constBegin();
646 for ( ; i != sPropertyDefinitions()->constEnd(); ++i )
651 readOldDataDefinedProperty( layer,
static_cast< Property >( i.key() ) );
653 else if ( parentElem )
656 QDomElement e = parentElem->firstChildElement( i.value().name() );
659 bool active = e.attribute( QStringLiteral(
"active" ) ).compare( QLatin1String(
"true" ), Qt::CaseInsensitive ) == 0;
660 bool isExpression = e.attribute( QStringLiteral(
"useExpr" ) ).compare( QLatin1String(
"true" ), Qt::CaseInsensitive ) == 0;
674 void QgsPalLayerSettings::readFromLayerCustomProperties(
QgsVectorLayer *layer )
676 if ( layer->
customProperty( QStringLiteral(
"labeling" ) ).toString() != QLatin1String(
"pal" ) )
701 QDomDocument doc( QStringLiteral(
"substitutions" ) );
702 doc.setContent( layer->
customProperty( QStringLiteral(
"labeling/substitutions" ) ).toString() );
703 QDomElement replacementElem = doc.firstChildElement( QStringLiteral(
"substitutions" ) );
724 mLineSettings.
setPlacementFlags(
static_cast< QgsLabeling::LinePlacementFlags
>( layer->
customProperty( QStringLiteral(
"labeling/placementFlags" ) ).toUInt() ) );
733 if ( layer->
customProperty( QStringLiteral(
"labeling/distMapUnitScale" ) ).toString().isEmpty() )
736 double oldMin = layer->
customProperty( QStringLiteral(
"labeling/distMapUnitMinScale" ), 0.0 ).toDouble();
738 double oldMax = layer->
customProperty( QStringLiteral(
"labeling/distMapUnitMaxScale" ), 0.0 ).toDouble();
749 if ( layer->
customProperty( QStringLiteral(
"labeling/labelOffsetInMapUnits" ), QVariant(
true ) ).toBool() )
754 if ( layer->
customProperty( QStringLiteral(
"labeling/labelOffsetMapUnitScale" ) ).toString().isEmpty() )
757 double oldMin = layer->
customProperty( QStringLiteral(
"labeling/labelOffsetMapUnitMinScale" ), 0.0 ).toDouble();
759 double oldMax = layer->
customProperty( QStringLiteral(
"labeling/labelOffsetMapUnitMaxScale" ), 0.0 ).toDouble();
767 QVariant tempAngle = layer->
customProperty( QStringLiteral(
"labeling/angleOffset" ), QVariant() );
768 if ( tempAngle.isValid() )
770 double oldAngle = layer->
customProperty( QStringLiteral(
"labeling/angleOffset" ), QVariant( 0.0 ) ).toDouble();
783 switch ( layer->
customProperty( QStringLiteral(
"labeling/repeatDistanceUnit" ), QVariant( 1 ) ).toUInt() )
798 if ( layer->
customProperty( QStringLiteral(
"labeling/repeatDistanceMapUnitScale" ) ).toString().isEmpty() )
801 double oldMin = layer->
customProperty( QStringLiteral(
"labeling/repeatDistanceMapUnitMinScale" ), 0.0 ).toDouble();
803 double oldMax = layer->
customProperty( QStringLiteral(
"labeling/repeatDistanceMapUnitMaxScale" ), 0.0 ).toDouble();
812 double scalemn = layer->
customProperty( QStringLiteral(
"labeling/scaleMin" ), QVariant( 0 ) ).toDouble();
813 double scalemx = layer->
customProperty( QStringLiteral(
"labeling/scaleMax" ), QVariant( 0 ) ).toDouble();
816 QVariant scalevis = layer->
customProperty( QStringLiteral(
"labeling/scaleVisibility" ), QVariant() );
817 if ( scalevis.isValid() )
823 else if ( scalemn > 0 || scalemx > 0 )
848 mObstacleSettings.
setFactor( layer->
customProperty( QStringLiteral(
"labeling/obstacleFactor" ), QVariant( 1.0 ) ).toDouble() );
850 zIndex = layer->
customProperty( QStringLiteral(
"labeling/zIndex" ), QVariant( 0.0 ) ).toDouble();
852 mDataDefinedProperties.
clear();
853 if ( layer->
customProperty( QStringLiteral(
"labeling/ddProperties" ) ).isValid() )
855 QDomDocument doc( QStringLiteral(
"dd" ) );
856 doc.setContent( layer->
customProperty( QStringLiteral(
"labeling/ddProperties" ) ).toString() );
857 QDomElement elem = doc.firstChildElement( QStringLiteral(
"properties" ) );
858 mDataDefinedProperties.
readXml( elem, *sPropertyDefinitions() );
863 readOldDataDefinedPropertyMap( layer,
nullptr );
907 QDomElement textStyleElem = elem.firstChildElement( QStringLiteral(
"text-style" ) );
908 fieldName = textStyleElem.attribute( QStringLiteral(
"fieldName" ) );
909 isExpression = textStyleElem.attribute( QStringLiteral(
"isExpression" ) ).toInt();
911 mFormat.
readXml( elem, context );
913 previewBkgrdColor = QColor( textStyleElem.attribute( QStringLiteral(
"previewBkgrdColor" ), QStringLiteral(
"#ffffff" ) ) );
916 useSubstitutions = textStyleElem.attribute( QStringLiteral(
"useSubstitutions" ) ).toInt();
919 QDomElement textFormatElem = elem.firstChildElement( QStringLiteral(
"text-format" ) );
920 wrapChar = textFormatElem.attribute( QStringLiteral(
"wrapChar" ) );
921 autoWrapLength = textFormatElem.attribute( QStringLiteral(
"autoWrapLength" ), QStringLiteral(
"0" ) ).toInt();
922 useMaxLineLengthForAutoWrap = textFormatElem.attribute( QStringLiteral(
"useMaxLineLengthForAutoWrap" ), QStringLiteral(
"1" ) ).toInt();
924 mLineSettings.
setAddDirectionSymbol( textFormatElem.attribute( QStringLiteral(
"addDirectionSymbol" ) ).toInt() );
925 mLineSettings.
setLeftDirectionSymbol( textFormatElem.attribute( QStringLiteral(
"leftDirectionSymbol" ), QStringLiteral(
"<" ) ) );
926 mLineSettings.
setRightDirectionSymbol( textFormatElem.attribute( QStringLiteral(
"rightDirectionSymbol" ), QStringLiteral(
">" ) ) );
927 mLineSettings.
setReverseDirectionSymbol( textFormatElem.attribute( QStringLiteral(
"reverseDirectionSymbol" ) ).toInt() );
929 formatNumbers = textFormatElem.attribute( QStringLiteral(
"formatNumbers" ) ).toInt();
930 decimals = textFormatElem.attribute( QStringLiteral(
"decimals" ) ).toInt();
931 plusSign = textFormatElem.attribute( QStringLiteral(
"plussign" ) ).toInt();
934 QDomElement placementElem = elem.firstChildElement( QStringLiteral(
"placement" ) );
935 placement =
static_cast< Placement >( placementElem.attribute( QStringLiteral(
"placement" ) ).toInt() );
936 mLineSettings.
setPlacementFlags(
static_cast< QgsLabeling::LinePlacementFlags
>( placementElem.attribute( QStringLiteral(
"placementFlags" ) ).toUInt() ) );
937 mPolygonPlacementFlags =
static_cast< QgsLabeling::PolygonPlacementFlags
>( placementElem.attribute( QStringLiteral(
"polygonPlacementFlags" ), QString::number(
static_cast< int >( QgsLabeling::PolygonPlacementFlag::AllowPlacementInsideOfPolygon ) ) ).toInt() );
939 centroidWhole = placementElem.attribute( QStringLiteral(
"centroidWhole" ), QStringLiteral(
"0" ) ).toInt();
940 centroidInside = placementElem.attribute( QStringLiteral(
"centroidInside" ), QStringLiteral(
"0" ) ).toInt();
944 fitInPolygonOnly = placementElem.attribute( QStringLiteral(
"fitInPolygonOnly" ), QStringLiteral(
"0" ) ).toInt();
945 dist = placementElem.attribute( QStringLiteral(
"dist" ) ).toDouble();
946 if ( !placementElem.hasAttribute( QStringLiteral(
"distUnits" ) ) )
948 if ( placementElem.attribute( QStringLiteral(
"distInMapUnits" ) ).toInt() )
957 if ( !placementElem.hasAttribute( QStringLiteral(
"distMapUnitScale" ) ) )
960 double oldMin = placementElem.attribute( QStringLiteral(
"distMapUnitMinScale" ), QStringLiteral(
"0" ) ).toDouble();
962 double oldMax = placementElem.attribute( QStringLiteral(
"distMapUnitMaxScale" ), QStringLiteral(
"0" ) ).toDouble();
971 xOffset = placementElem.attribute( QStringLiteral(
"xOffset" ), QStringLiteral(
"0" ) ).toDouble();
972 yOffset = placementElem.attribute( QStringLiteral(
"yOffset" ), QStringLiteral(
"0" ) ).toDouble();
973 if ( !placementElem.hasAttribute( QStringLiteral(
"offsetUnits" ) ) )
981 if ( !placementElem.hasAttribute( QStringLiteral(
"labelOffsetMapUnitScale" ) ) )
984 double oldMin = placementElem.attribute( QStringLiteral(
"labelOffsetMapUnitMinScale" ), QStringLiteral(
"0" ) ).toDouble();
986 double oldMax = placementElem.attribute( QStringLiteral(
"labelOffsetMapUnitMaxScale" ), QStringLiteral(
"0" ) ).toDouble();
994 if ( placementElem.hasAttribute( QStringLiteral(
"angleOffset" ) ) )
996 double oldAngle = placementElem.attribute( QStringLiteral(
"angleOffset" ), QStringLiteral(
"0" ) ).toDouble();
1001 angleOffset = placementElem.attribute( QStringLiteral(
"rotationAngle" ), QStringLiteral(
"0" ) ).toDouble();
1004 preserveRotation = placementElem.attribute( QStringLiteral(
"preserveRotation" ), QStringLiteral(
"1" ) ).toInt();
1005 maxCurvedCharAngleIn = placementElem.attribute( QStringLiteral(
"maxCurvedCharAngleIn" ), QStringLiteral(
"25" ) ).toDouble();
1006 maxCurvedCharAngleOut = placementElem.attribute( QStringLiteral(
"maxCurvedCharAngleOut" ), QStringLiteral(
"-25" ) ).toDouble();
1007 priority = placementElem.attribute( QStringLiteral(
"priority" ) ).toInt();
1008 repeatDistance = placementElem.attribute( QStringLiteral(
"repeatDistance" ), QStringLiteral(
"0" ) ).toDouble();
1009 if ( !placementElem.hasAttribute( QStringLiteral(
"repeatDistanceUnits" ) ) )
1012 switch ( placementElem.attribute( QStringLiteral(
"repeatDistanceUnit" ), QString::number( 1 ) ).toUInt() )
1032 if ( !placementElem.hasAttribute( QStringLiteral(
"repeatDistanceMapUnitScale" ) ) )
1035 double oldMin = placementElem.attribute( QStringLiteral(
"repeatDistanceMapUnitMinScale" ), QStringLiteral(
"0" ) ).toDouble();
1037 double oldMax = placementElem.attribute( QStringLiteral(
"repeatDistanceMapUnitMaxScale" ), QStringLiteral(
"0" ) ).toDouble();
1045 mLineSettings.
setOverrunDistance( placementElem.attribute( QStringLiteral(
"overrunDistance" ), QStringLiteral(
"0" ) ).toDouble() );
1048 mLineSettings.
setLineAnchorPercent( placementElem.attribute( QStringLiteral(
"lineAnchorPercent" ), QStringLiteral(
"0.5" ) ).toDouble() );
1051 geometryGenerator = placementElem.attribute( QStringLiteral(
"geometryGenerator" ) );
1058 QDomElement renderingElem = elem.firstChildElement( QStringLiteral(
"rendering" ) );
1060 drawLabels = renderingElem.attribute( QStringLiteral(
"drawLabels" ), QStringLiteral(
"1" ) ).toInt();
1062 maximumScale = renderingElem.attribute( QStringLiteral(
"scaleMin" ), QStringLiteral(
"0" ) ).toDouble();
1063 minimumScale = renderingElem.attribute( QStringLiteral(
"scaleMax" ), QStringLiteral(
"0" ) ).toDouble();
1064 scaleVisibility = renderingElem.attribute( QStringLiteral(
"scaleVisibility" ) ).toInt();
1066 fontLimitPixelSize = renderingElem.attribute( QStringLiteral(
"fontLimitPixelSize" ), QStringLiteral(
"0" ) ).toInt();
1067 fontMinPixelSize = renderingElem.attribute( QStringLiteral(
"fontMinPixelSize" ), QStringLiteral(
"0" ) ).toInt();
1068 fontMaxPixelSize = renderingElem.attribute( QStringLiteral(
"fontMaxPixelSize" ), QStringLiteral(
"10000" ) ).toInt();
1069 displayAll = renderingElem.attribute( QStringLiteral(
"displayAll" ), QStringLiteral(
"0" ) ).toInt();
1072 labelPerPart = renderingElem.attribute( QStringLiteral(
"labelPerPart" ) ).toInt();
1073 mLineSettings.
setMergeLines( renderingElem.attribute( QStringLiteral(
"mergeLines" ) ).toInt() );
1074 mThinningSettings.
setMinimumFeatureSize( renderingElem.attribute( QStringLiteral(
"minFeatureSize" ) ).toDouble() );
1075 mThinningSettings.
setLimitNumberLabelsEnabled( renderingElem.attribute( QStringLiteral(
"limitNumLabels" ), QStringLiteral(
"0" ) ).toInt() );
1076 mThinningSettings.
setMaximumNumberLabels( renderingElem.attribute( QStringLiteral(
"maxNumLabels" ), QStringLiteral(
"2000" ) ).toInt() );
1077 mObstacleSettings.
setIsObstacle( renderingElem.attribute( QStringLiteral(
"obstacle" ), QStringLiteral(
"1" ) ).toInt() );
1078 mObstacleSettings.
setFactor( renderingElem.attribute( QStringLiteral(
"obstacleFactor" ), QStringLiteral(
"1" ) ).toDouble() );
1080 zIndex = renderingElem.attribute( QStringLiteral(
"zIndex" ), QStringLiteral(
"0.0" ) ).toDouble();
1082 QDomElement ddElem = elem.firstChildElement( QStringLiteral(
"dd_properties" ) );
1083 if ( !ddElem.isNull() )
1085 mDataDefinedProperties.
readXml( ddElem, *sPropertyDefinitions() );
1090 mDataDefinedProperties.
clear();
1091 QDomElement ddElem = elem.firstChildElement( QStringLiteral(
"data-defined" ) );
1092 readOldDataDefinedPropertyMap(
nullptr, &ddElem );
1133 const QString calloutType = elem.attribute( QStringLiteral(
"calloutType" ) );
1134 if ( calloutType.isEmpty() )
1146 QDomElement textStyleElem = mFormat.
writeXml( doc, context );
1149 textStyleElem.setAttribute( QStringLiteral(
"fieldName" ),
fieldName );
1150 textStyleElem.setAttribute( QStringLiteral(
"isExpression" ),
isExpression );
1151 QDomElement replacementElem = doc.createElement( QStringLiteral(
"substitutions" ) );
1153 textStyleElem.appendChild( replacementElem );
1154 textStyleElem.setAttribute( QStringLiteral(
"useSubstitutions" ),
useSubstitutions );
1157 QDomElement textFormatElem = doc.createElement( QStringLiteral(
"text-format" ) );
1158 textFormatElem.setAttribute( QStringLiteral(
"wrapChar" ),
wrapChar );
1159 textFormatElem.setAttribute( QStringLiteral(
"autoWrapLength" ),
autoWrapLength );
1161 textFormatElem.setAttribute( QStringLiteral(
"multilineAlign" ),
static_cast< unsigned int >(
multilineAlign ) );
1162 textFormatElem.setAttribute( QStringLiteral(
"addDirectionSymbol" ), mLineSettings.
addDirectionSymbol() );
1163 textFormatElem.setAttribute( QStringLiteral(
"leftDirectionSymbol" ), mLineSettings.
leftDirectionSymbol() );
1164 textFormatElem.setAttribute( QStringLiteral(
"rightDirectionSymbol" ), mLineSettings.
rightDirectionSymbol() );
1165 textFormatElem.setAttribute( QStringLiteral(
"reverseDirectionSymbol" ), mLineSettings.
reverseDirectionSymbol() );
1166 textFormatElem.setAttribute( QStringLiteral(
"placeDirectionSymbol" ),
static_cast< unsigned int >( mLineSettings.
directionSymbolPlacement() ) );
1167 textFormatElem.setAttribute( QStringLiteral(
"formatNumbers" ),
formatNumbers );
1168 textFormatElem.setAttribute( QStringLiteral(
"decimals" ),
decimals );
1169 textFormatElem.setAttribute( QStringLiteral(
"plussign" ),
plusSign );
1172 QDomElement placementElem = doc.createElement( QStringLiteral(
"placement" ) );
1173 placementElem.setAttribute( QStringLiteral(
"placement" ),
placement );
1174 placementElem.setAttribute( QStringLiteral(
"polygonPlacementFlags" ),
static_cast< int >( mPolygonPlacementFlags ) );
1175 placementElem.setAttribute( QStringLiteral(
"placementFlags" ),
static_cast< unsigned int >( mLineSettings.
placementFlags() ) );
1176 placementElem.setAttribute( QStringLiteral(
"centroidWhole" ),
centroidWhole );
1177 placementElem.setAttribute( QStringLiteral(
"centroidInside" ),
centroidInside );
1179 placementElem.setAttribute( QStringLiteral(
"fitInPolygonOnly" ),
fitInPolygonOnly );
1180 placementElem.setAttribute( QStringLiteral(
"dist" ),
dist );
1183 placementElem.setAttribute( QStringLiteral(
"offsetType" ),
static_cast< unsigned int >(
offsetType ) );
1184 placementElem.setAttribute( QStringLiteral(
"quadOffset" ),
static_cast< unsigned int >(
quadOffset ) );
1185 placementElem.setAttribute( QStringLiteral(
"xOffset" ),
xOffset );
1186 placementElem.setAttribute( QStringLiteral(
"yOffset" ),
yOffset );
1189 placementElem.setAttribute( QStringLiteral(
"rotationAngle" ),
angleOffset );
1190 placementElem.setAttribute( QStringLiteral(
"preserveRotation" ),
preserveRotation );
1193 placementElem.setAttribute( QStringLiteral(
"priority" ),
priority );
1194 placementElem.setAttribute( QStringLiteral(
"repeatDistance" ),
repeatDistance );
1197 placementElem.setAttribute( QStringLiteral(
"overrunDistance" ), mLineSettings.
overrunDistance() );
1200 placementElem.setAttribute( QStringLiteral(
"lineAnchorPercent" ), mLineSettings.
lineAnchorPercent() );
1201 placementElem.setAttribute( QStringLiteral(
"lineAnchorType" ),
static_cast< int >( mLineSettings.
anchorType() ) );
1203 placementElem.setAttribute( QStringLiteral(
"geometryGenerator" ),
geometryGenerator );
1205 const QMetaEnum metaEnum( QMetaEnum::fromType<QgsWkbTypes::GeometryType>() );
1206 placementElem.setAttribute( QStringLiteral(
"geometryGeneratorType" ), metaEnum.valueToKey(
geometryGeneratorType ) );
1208 placementElem.setAttribute( QStringLiteral(
"layerType" ), metaEnum.valueToKey(
layerType ) );
1211 QDomElement renderingElem = doc.createElement( QStringLiteral(
"rendering" ) );
1212 renderingElem.setAttribute( QStringLiteral(
"drawLabels" ),
drawLabels );
1213 renderingElem.setAttribute( QStringLiteral(
"scaleVisibility" ),
scaleVisibility );
1214 renderingElem.setAttribute( QStringLiteral(
"scaleMin" ),
maximumScale );
1215 renderingElem.setAttribute( QStringLiteral(
"scaleMax" ),
minimumScale );
1216 renderingElem.setAttribute( QStringLiteral(
"fontLimitPixelSize" ),
fontLimitPixelSize );
1217 renderingElem.setAttribute( QStringLiteral(
"fontMinPixelSize" ),
fontMinPixelSize );
1218 renderingElem.setAttribute( QStringLiteral(
"fontMaxPixelSize" ),
fontMaxPixelSize );
1219 renderingElem.setAttribute( QStringLiteral(
"displayAll" ),
displayAll );
1220 renderingElem.setAttribute( QStringLiteral(
"upsidedownLabels" ),
static_cast< unsigned int >(
upsidedownLabels ) );
1222 renderingElem.setAttribute( QStringLiteral(
"labelPerPart" ),
labelPerPart );
1223 renderingElem.setAttribute( QStringLiteral(
"mergeLines" ), mLineSettings.
mergeLines() );
1224 renderingElem.setAttribute( QStringLiteral(
"minFeatureSize" ), mThinningSettings.
minimumFeatureSize() );
1226 renderingElem.setAttribute( QStringLiteral(
"maxNumLabels" ), mThinningSettings.
maximumNumberLabels() );
1227 renderingElem.setAttribute( QStringLiteral(
"obstacle" ), mObstacleSettings.
isObstacle() );
1228 renderingElem.setAttribute( QStringLiteral(
"obstacleFactor" ), mObstacleSettings.
factor() );
1229 renderingElem.setAttribute( QStringLiteral(
"obstacleType" ),
static_cast< unsigned int >( mObstacleSettings.
type() ) );
1230 renderingElem.setAttribute( QStringLiteral(
"zIndex" ),
zIndex );
1232 QDomElement ddElem = doc.createElement( QStringLiteral(
"dd_properties" ) );
1233 mDataDefinedProperties.
writeXml( ddElem, *sPropertyDefinitions() );
1235 QDomElement elem = doc.createElement( QStringLiteral(
"settings" ) );
1236 elem.appendChild( textStyleElem );
1237 elem.appendChild( textFormatElem );
1238 elem.appendChild( placementElem );
1239 elem.appendChild( renderingElem );
1240 elem.appendChild( ddElem );
1244 elem.setAttribute( QStringLiteral(
"calloutType" ), mCallout->type() );
1245 mCallout->saveProperties( doc, elem, context );
1260 QPixmap pixmap( size );
1261 pixmap.fill( Qt::transparent );
1263 painter.begin( &pixmap );
1265 painter.setRenderHint( QPainter::Antialiasing );
1267 QRect rect( 0, 0, size.width(), size.height() );
1270 painter.setPen( Qt::NoPen );
1272 if ( ( background1.lightnessF() < 0.7 ) )
1274 background1 = background1.darker( 125 );
1278 background1 = background1.lighter( 125 );
1281 QLinearGradient linearGrad( QPointF( 0, 0 ), QPointF( 0, rect.height() ) );
1282 linearGrad.setColorAt( 0, background1 );
1283 linearGrad.setColorAt( 1, background2 );
1284 painter.setBrush( QBrush( linearGrad ) );
1285 if ( size.width() > 30 )
1287 painter.drawRoundedRect( rect, 6, 6 );
1292 painter.drawRect( rect );
1294 painter.setBrush( Qt::NoBrush );
1295 painter.setPen( Qt::NoPen );
1304 context.
setScaleFactor( QgsApplication::desktop()->logicalDpiX() / 25.4 );
1315 double ytrans = 0.0;
1321 const QStringList text = QStringList() << ( previewText.isEmpty() ? QObject::tr(
"Aa" ) : previewText );
1323 QRectF textRect = rect;
1324 textRect.setLeft( xtrans + padding );
1325 textRect.setWidth( rect.width() - xtrans - 2 * padding );
1327 if ( textRect.width() > 2000 )
1328 textRect.setWidth( 2000 - 2 * padding );
1330 const double bottom = textRect.height() / 2 + textHeight / 2;
1331 textRect.setTop( bottom - textHeight );
1332 textRect.setBottom( bottom );
1334 #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
1347 QRectF labelRect( textRect.left() + ( textRect.width() - textWidth ) / 2.0, textRect.top(), textWidth, textRect.height() );
1354 if ( size.width() > 30 )
1359 rect.width() - iconWidth * 3, rect.height() - iconWidth * 3,
1360 iconWidth * 2, iconWidth * 2 ), Qt::AlignRight | Qt::AlignBottom );
1364 painter.setBrush( Qt::NoBrush );
1366 if ( size.width() > 30 )
1368 painter.drawRoundedRect( rect, 6, 6 );
1373 painter.drawRect( rect );
1382 return QgsPalLabeling::checkMinimumSizeMM(
ct, geom, minSize );
1392 QString textCopy( text );
1395 std::unique_ptr< QgsRenderContext > scopedRc;
1400 scopedRc->expressionContext().setFeature( *f );
1516 if ( wrapchr.isEmpty() )
1518 wrapchr = QStringLiteral(
"\n" );
1523 && ( !leftDirSymb.isEmpty() || !rightDirSymb.isEmpty() ) )
1525 QString dirSym = leftDirSymb;
1527 #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
1528 if ( fm->width( rightDirSymb ) > fm->width( dirSym ) )
1530 if ( fm->horizontalAdvance( rightDirSymb ) > fm->horizontalAdvance( dirSym ) )
1532 dirSym = rightDirSymb;
1534 switch ( placeDirSymb )
1537 textCopy.append( dirSym );
1542 textCopy.prepend( dirSym + QStringLiteral(
"\n" ) );
1547 double w = 0.0, h = 0.0, rw = 0.0, rh = 0.0;
1548 double labelHeight = fm->ascent() + fm->descent();
1550 QStringList multiLineSplit;
1562 int lines = multiLineSplit.size();
1564 switch ( orientation )
1568 h += fm->height() +
static_cast< double >( ( lines - 1 ) * labelHeight * multilineH );
1570 for (
const auto &line : multiLineSplit )
1572 #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
1573 w = std::max( w, fm->width( line ) );
1575 w = std::max( w, fm->horizontalAdvance( line ) );
1583 double letterSpacing = mFormat.
scaledFont( *context ).letterSpacing();
1584 double labelWidth = fm->maxWidth();
1585 w = labelWidth + ( lines - 1 ) * labelWidth * multilineH;
1587 int maxLineLength = 0;
1588 for (
const auto &line : multiLineSplit )
1590 maxLineLength = std::max( maxLineLength, line.length() );
1592 h = fm->ascent() * maxLineLength + ( maxLineLength - 1 ) * letterSpacing;
1598 double widthHorizontal = 0.0;
1599 for (
const auto &line : multiLineSplit )
1601 #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
1602 widthHorizontal = std::max( w, fm->width( line ) );
1604 widthHorizontal = std::max( w, fm->horizontalAdvance( line ) );
1608 double widthVertical = 0.0;
1609 double letterSpacing = mFormat.
scaledFont( *context ).letterSpacing();
1610 double labelWidth = fm->maxWidth();
1611 widthVertical = labelWidth + ( lines - 1 ) * labelWidth * multilineH;
1613 double heightHorizontal = 0.0;
1614 heightHorizontal += fm->height() +
static_cast< double >( ( lines - 1 ) * labelHeight * multilineH );
1616 double heightVertical = 0.0;
1617 int maxLineLength = 0;
1618 for (
const auto &line : multiLineSplit )
1620 maxLineLength = std::max( maxLineLength, line.length() );
1622 heightVertical = fm->ascent() * maxLineLength + ( maxLineLength - 1 ) * letterSpacing;
1624 w = widthHorizontal;
1625 rw = heightVertical;
1626 h = heightHorizontal;
1634 labelX = std::fabs( ptSize.
x() -
ptZero.
x() );
1635 labelY = std::fabs( ptSize.
y() -
ptZero.
y() );
1640 if ( rotatedLabelX && rotatedLabelY )
1642 *rotatedLabelX = rw * uPP;
1643 *rotatedLabelY = rh * uPP;
1651 Q_ASSERT( labelFeature );
1657 bool isObstacle = mObstacleSettings.
isObstacle();
1665 registerObstacleFeature( f, context, labelFeature, obstacleGeometry );
1677 if ( obstacleGeometry.
isNull() )
1690 dataDefinedValues.clear();
1707 if ( useScaleVisibility )
1720 maxScale = 1 / std::fabs( maxScale );
1739 minScale = 1 / std::fabs( minScale );
1748 QFont labelFont = mFormat.
font();
1754 if ( exprVal.isValid() )
1756 QString units = exprVal.toString();
1757 if ( !units.isEmpty() )
1767 double fontSize = mFormat.
size();
1773 if ( fontSize <= 0.0 )
1780 if ( fontPixelSize < 1 )
1784 labelFont.setPixelSize( fontPixelSize );
1796 if ( fontMinPixel > labelFont.pixelSize() || labelFont.pixelSize() > fontMaxPixel )
1808 labelFont.setCapitalization( QFont::MixedCase );
1810 parseTextStyle( labelFont, fontunits, context );
1813 parseTextFormatting( context );
1814 parseTextBuffer( context );
1815 parseTextMask( context );
1816 parseShapeBackground( context );
1817 parseDropShadow( context );
1838 labelText = result.isNull() ? QString() : result.toString();
1843 labelText = v.isNull() ? QString() : v.toString();
1863 if ( exprVal.isValid() )
1865 QString fcase = exprVal.toString().trimmed();
1866 QgsDebugMsgLevel( QStringLiteral(
"exprVal FontCase:%1" ).arg( fcase ), 4 );
1868 if ( !fcase.isEmpty() )
1870 if ( fcase.compare( QLatin1String(
"NoChange" ), Qt::CaseInsensitive ) == 0 )
1874 else if ( fcase.compare( QLatin1String(
"Upper" ), Qt::CaseInsensitive ) == 0 )
1878 else if ( fcase.compare( QLatin1String(
"Lower" ), Qt::CaseInsensitive ) == 0 )
1882 else if ( fcase.compare( QLatin1String(
"Capitalize" ), Qt::CaseInsensitive ) == 0 )
1886 else if ( fcase.compare( QLatin1String(
"Title" ), Qt::CaseInsensitive ) == 0 )
1901 if ( evalFormatNumbers )
1905 if ( decimalPlaces <= 0 )
1911 QVariant textV( labelText );
1913 double d = textV.toDouble( &ok );
1916 QString numberFormat;
1917 if ( d > 0 && signPlus )
1919 numberFormat.append(
'+' );
1921 numberFormat.append(
"%1" );
1922 labelText = numberFormat.arg( d, 0,
'f', decimalPlaces );
1927 std::unique_ptr<QFontMetricsF> labelFontMetrics(
new QFontMetricsF( labelFont ) );
1928 double labelX, labelY, rotatedLabelX, rotatedLabelY;
1931 if (
format().allowHtmlFormatting() )
1935 calculateLabelSize( labelFontMetrics.get(), labelText, labelX, labelY,
mCurFeat, &context, &rotatedLabelX, &rotatedLabelY,
format().allowHtmlFormatting() ? &doc :
nullptr );
1939 double maxcharanglein = 20.0;
1940 double maxcharangleout = -20.0;
1955 maxcharanglein = qBound( 20.0,
static_cast< double >( maxcharanglePt.x() ), 60.0 );
1956 maxcharangleout = qBound( 20.0,
static_cast< double >( maxcharanglePt.y() ), 95.0 );
1960 maxcharangleout = -( std::fabs( maxcharangleout ) );
1968 if ( exprVal.isValid() )
1970 QString str = exprVal.toString().trimmed();
1971 QgsDebugMsgLevel( QStringLiteral(
"exprVal CentroidWhole:%1" ).arg( str ), 4 );
1973 if ( !str.isEmpty() )
1975 if ( str.compare( QLatin1String(
"Visible" ), Qt::CaseInsensitive ) == 0 )
1977 wholeCentroid =
false;
1979 else if ( str.compare( QLatin1String(
"Whole" ), Qt::CaseInsensitive ) == 0 )
1981 wholeCentroid =
true;
1995 std::unique_ptr<QgsGeometry> scopedClonedGeom;
2001 geom = simplifier.
simplify( geom );
2018 bool doClip =
false;
2019 if ( !centroidPoly || !wholeCentroid )
2025 QgsLabeling::PolygonPlacementFlags polygonPlacement = mPolygonPlacementFlags;
2029 if ( dataDefinedOutside.isValid() )
2031 if ( dataDefinedOutside.type() == QVariant::String )
2033 const QString value = dataDefinedOutside.toString().trimmed();
2034 if ( value.compare( QLatin1String(
"force" ), Qt::CaseInsensitive ) == 0 )
2037 polygonPlacement &= ~static_cast< int >( QgsLabeling::PolygonPlacementFlag::AllowPlacementInsideOfPolygon );
2038 polygonPlacement |= QgsLabeling::PolygonPlacementFlag::AllowPlacementOutsideOfPolygon;
2040 else if ( value.compare( QLatin1String(
"yes" ), Qt::CaseInsensitive ) == 0 )
2043 polygonPlacement |= QgsLabeling::PolygonPlacementFlag::AllowPlacementOutsideOfPolygon;
2045 else if ( value.compare( QLatin1String(
"no" ), Qt::CaseInsensitive ) == 0 )
2048 polygonPlacement &= ~static_cast< int >( QgsLabeling::PolygonPlacementFlag::AllowPlacementOutsideOfPolygon );
2053 if ( dataDefinedOutside.toBool() )
2056 polygonPlacement |= QgsLabeling::PolygonPlacementFlag::AllowPlacementOutsideOfPolygon;
2061 polygonPlacement &= ~static_cast< int >( QgsLabeling::PolygonPlacementFlag::AllowPlacementOutsideOfPolygon );
2076 permissibleZone = geom;
2115 if ( !geos_geom_clone )
2144 bool dataDefinedPosition =
false;
2145 bool layerDefinedRotation =
false;
2146 bool dataDefinedRotation =
false;
2147 double xPos = 0.0, yPos = 0.0,
angle = 0.0;
2148 bool ddXPos =
false, ddYPos =
false;
2149 double quadOffsetX = 0.0, quadOffsetY = 0.0;
2150 double offsetX = 0.0, offsetY = 0.0;
2162 bool ddFixedQuad =
false;
2168 if ( exprVal.isValid() )
2171 int quadInt = exprVal.toInt( &ok );
2172 if ( ok && 0 <= quadInt && quadInt <= 8 )
2240 if ( exprVal.isValid() )
2242 QString units = exprVal.toString().trimmed();
2243 if ( !units.isEmpty() )
2249 offUnit = decodedUnits;
2265 layerDefinedRotation =
true;
2275 if ( exprVal.isValid() )
2278 double rotD = exprVal.toDouble( &ok );
2281 dataDefinedRotation =
true;
2285 angle = ( 360 - rotD ) * M_PI / 180.0;
2293 if ( exprVal.isValid() )
2295 if ( !exprVal.isNull() )
2296 xPos = exprVal.toDouble( &ddXPos );
2301 if ( exprVal.isValid() )
2304 if ( !exprVal.isNull() )
2305 yPos = exprVal.toDouble( &ddYPos );
2307 if ( ddXPos && ddYPos )
2309 dataDefinedPosition =
true;
2311 if ( layerDefinedRotation && !dataDefinedRotation )
2320 if ( exprVal.isValid() )
2322 QString haliString = exprVal.toString();
2323 if ( haliString.compare( QLatin1String(
"Center" ), Qt::CaseInsensitive ) == 0 )
2325 xdiff -= labelX / 2.0;
2327 else if ( haliString.compare( QLatin1String(
"Right" ), Qt::CaseInsensitive ) == 0 )
2338 if ( exprVal.isValid() )
2340 QString valiString = exprVal.toString();
2341 if ( valiString.compare( QLatin1String(
"Bottom" ), Qt::CaseInsensitive ) != 0 )
2343 if ( valiString.compare( QLatin1String(
"Top" ), Qt::CaseInsensitive ) == 0 )
2349 double descentRatio = labelFontMetrics->descent() / labelFontMetrics->height();
2350 if ( valiString.compare( QLatin1String(
"Base" ), Qt::CaseInsensitive ) == 0 )
2352 ydiff -= labelY * descentRatio;
2356 double capHeightRatio = ( labelFontMetrics->boundingRect(
'H' ).height() + 1 + labelFontMetrics->descent() ) / labelFontMetrics->height();
2357 ydiff -= labelY * capHeightRatio;
2358 if ( valiString.compare( QLatin1String(
"Half" ), Qt::CaseInsensitive ) == 0 )
2360 ydiff += labelY * ( capHeightRatio - descentRatio ) / 2.0;
2368 if ( dataDefinedRotation )
2371 double xd = xdiff * std::cos(
angle ) - ydiff * std::sin(
angle );
2372 double yd = xdiff * std::sin(
angle ) + ydiff * std::cos(
angle );
2407 bool alwaysShow =
false;
2427 if ( exprVal.isValid() )
2429 QString units = exprVal.toString().trimmed();
2430 if ( !units.isEmpty() )
2436 repeatUnits = decodedUnits;
2463 if ( !dataDefinedPosition )
2484 ( *labelFeature )->setFixedPosition(
QgsPointXY( xPos, yPos ) );
2486 ( *labelFeature )->setHasFixedAngle( dataDefinedRotation || ( !dataDefinedPosition && !
qgsDoubleNear(
angle, 0.0 ) ) );
2487 ( *labelFeature )->setFixedAngle(
angle );
2488 ( *labelFeature )->setQuadOffset( QPointF( quadOffsetX, quadOffsetY ) );
2489 ( *labelFeature )->setPositionOffset(
QgsPointXY( offsetX, offsetY ) );
2490 ( *labelFeature )->setOffsetType(
offsetType );
2491 ( *labelFeature )->setAlwaysShow( alwaysShow );
2492 ( *labelFeature )->setRepeatDistance( repeatDist );
2493 ( *labelFeature )->setLabelText( labelText );
2494 ( *labelFeature )->setPermissibleZone( permissibleZone );
2495 ( *labelFeature )->setOverrunDistance( overrunDistanceEval );
2496 ( *labelFeature )->setOverrunSmoothDistance( overrunSmoothDist );
2499 ( *labelFeature )->setLabelAllParts( labelAll );
2503 ( *labelFeature )->setSymbolSize( QSizeF( obstacleGeometry.
boundingBox().
width(),
2509 double topMargin = std::max( 0.25 * labelFontMetrics->ascent(), 0.0 );
2510 double bottomMargin = 1.0 + labelFontMetrics->descent();
2511 QgsMargins vm( 0.0, topMargin, 0.0, bottomMargin );
2513 ( *labelFeature )->setVisualMargin( vm );
2516 QgsDebugMsgLevel( QStringLiteral(
"PAL font stored definedFont: %1, Style: %2" ).arg( labelFont.toString(), labelFont.styleName() ), 4 );
2522 labelFontMetrics.get(),
xform, maxcharanglein, maxcharangleout,
format().allowHtmlFormatting() ? &doc :
nullptr );
2528 double distance =
dist;
2540 if ( exprVal.isValid() )
2542 QString units = exprVal.toString().trimmed();
2543 QgsDebugMsgLevel( QStringLiteral(
"exprVal DistanceUnits:%1" ).arg( units ), 4 );
2544 if ( !units.isEmpty() )
2550 distUnit = decodedUnits;
2563 distance = ( distance < 0 ? -1 : 1 ) * std::max( std::fabs( distance ), 1.0 );
2571 distance = std::max( distance, 2.0 );
2577 ( *labelFeature )->setDistLabel( d );
2582 ( *labelFeature )->setHasFixedQuadrant(
true );
2587 ( *labelFeature )->setPolygonPlacementFlags( polygonPlacement );
2596 ( *labelFeature )->setZIndex( z );
2603 if ( exprVal.isValid() )
2606 double priorityD = exprVal.toDouble( &ok );
2609 priorityD = qBound( 0.0, priorityD, 10.0 );
2610 priorityD = 1 - priorityD / 10.0;
2611 ( *labelFeature )->setPriority( priorityD );
2623 if ( positionOrder.isEmpty() )
2624 positionOrder = *DEFAULT_PLACEMENT_ORDER();
2630 if ( !dataDefinedOrder.isEmpty() )
2635 ( *labelFeature )->setPredefinedPositionOrder( positionOrder );
2646 if ( !obstacleGeometry.
isNull() )
2648 geom = obstacleGeometry;
2662 std::unique_ptr<QgsGeometry> scopedClonedGeom;
2668 geom = simplifier.
simplify( geom );
2672 std::unique_ptr<QgsGeometry> scopedPreparedGeom;
2680 if ( !geos_geom_clone )
2684 *obstacleFeature =
new QgsLabelFeature( f.
id(), std::move( geos_geom_clone ), QSizeF( 0, 0 ) );
2685 ( *obstacleFeature )->setFeature( f );
2690 ( *obstacleFeature )->setObstacleSettings( os );
2695 bool QgsPalLayerSettings::dataDefinedValEval( DataDefinedValueType valType,
2699 if ( !mDataDefinedProperties.
isActive( p ) )
2703 exprVal = mDataDefinedProperties.
value( p, context );
2704 if ( exprVal.isValid() )
2710 bool bol = exprVal.toBool();
2711 dataDefinedValues.insert( p, QVariant( bol ) );
2717 int size = exprVal.toInt( &ok );
2721 dataDefinedValues.insert( p, QVariant( size ) );
2729 int size = exprVal.toInt( &ok );
2731 if ( ok && size > 0 )
2733 dataDefinedValues.insert( p, QVariant( size ) );
2741 double size = exprVal.toDouble( &ok );
2745 dataDefinedValues.insert( p, QVariant( size ) );
2753 double size = exprVal.toDouble( &ok );
2755 if ( ok && size > 0.0 )
2757 dataDefinedValues.insert( p, QVariant( size ) );
2765 double rot = exprVal.toDouble( &ok );
2768 if ( rot < -180.0 && rot >= -360 )
2772 if ( rot > 180.0 && rot <= 360 )
2776 if ( rot >= -180 && rot <= 180 )
2778 dataDefinedValues.insert( p, QVariant( rot ) );
2787 int size = exprVal.toInt( &ok );
2788 if ( ok && size >= 0 && size <= 100 )
2790 dataDefinedValues.insert( p, QVariant( size ) );
2797 QString str = exprVal.toString();
2799 dataDefinedValues.insert( p, QVariant( str ) );
2804 QString unitstr = exprVal.toString().trimmed();
2806 if ( !unitstr.isEmpty() )
2815 QString colorstr = exprVal.toString().trimmed();
2818 if ( color.isValid() )
2820 dataDefinedValues.insert( p, QVariant( color ) );
2827 QString joinstr = exprVal.toString().trimmed();
2829 if ( !joinstr.isEmpty() )
2838 QString blendstr = exprVal.toString().trimmed();
2840 if ( !blendstr.isEmpty() )
2853 dataDefinedValues.insert( p, res );
2864 dataDefinedValues.insert( p, res );
2874 void QgsPalLayerSettings::parseTextStyle( QFont &labelFont,
2887 QString ddFontFamily;
2892 if ( exprVal.isValid() )
2894 QString family = exprVal.toString().trimmed();
2895 QgsDebugMsgLevel( QStringLiteral(
"exprVal Font family:%1" ).arg( family ), 4 );
2897 if ( labelFont.family() != family )
2903 ddFontFamily = family;
2910 QString ddFontStyle;
2914 if ( exprVal.isValid() )
2916 QString fontstyle = exprVal.toString().trimmed();
2917 QgsDebugMsgLevel( QStringLiteral(
"exprVal Font style:%1" ).arg( fontstyle ), 4 );
2918 ddFontStyle = fontstyle;
2923 bool ddBold =
false;
2931 bool ddItalic =
false;
2941 QFont appFont = QApplication::font();
2942 bool newFontBuilt =
false;
2943 if ( ddBold || ddItalic )
2946 newFont = QFont( !ddFontFamily.isEmpty() ? ddFontFamily : labelFont.family() );
2947 newFontBuilt =
true;
2948 newFont.setBold( ddBold );
2949 newFont.setItalic( ddItalic );
2951 else if ( !ddFontStyle.isEmpty()
2952 && ddFontStyle.compare( QLatin1String(
"Ignore" ), Qt::CaseInsensitive ) != 0 )
2954 if ( !ddFontFamily.isEmpty() )
2957 QFont styledfont = mFontDB.font( ddFontFamily, ddFontStyle, appFont.pointSize() );
2958 if ( appFont != styledfont )
2960 newFont = styledfont;
2961 newFontBuilt =
true;
2968 else if ( !ddFontFamily.isEmpty() )
2970 if ( ddFontStyle.compare( QLatin1String(
"Ignore" ), Qt::CaseInsensitive ) != 0 )
2973 QFont styledfont = mFontDB.font( ddFontFamily, mFormat.
namedStyle(), appFont.pointSize() );
2974 if ( appFont != styledfont )
2976 newFont = styledfont;
2977 newFontBuilt =
true;
2982 newFont = QFont( ddFontFamily );
2983 newFontBuilt =
true;
2991 newFont.setPixelSize( labelFont.pixelSize() );
2992 newFont.setUnderline( labelFont.underline() );
2993 newFont.setStrikeOut( labelFont.strikeOut() );
2994 newFont.setWordSpacing( labelFont.wordSpacing() );
2995 newFont.setLetterSpacing( QFont::AbsoluteSpacing, labelFont.letterSpacing() );
2997 labelFont = newFont;
3001 double wordspace = labelFont.wordSpacing();
3010 double letterspace = labelFont.letterSpacing();
3023 labelFont.setStrikeOut( strikeout );
3031 labelFont.setUnderline( underline );
3057 drawBuffer = exprVal.toBool();
3071 double bufrSize = buffer.
size();
3074 bufrSize = exprVal.toDouble();
3078 double bufferOpacity = buffer.
opacity() * 100;
3081 bufferOpacity = exprVal.toDouble();
3084 drawBuffer = ( drawBuffer && bufrSize > 0.0 && bufferOpacity > 0 );
3114 bool maskEnabled = mask.
enabled();
3117 maskEnabled = exprVal.toBool();
3126 double bufrSize = mask.
size();
3129 bufrSize = exprVal.toDouble();
3133 double opacity = mask.
opacity() * 100;
3136 opacity = exprVal.toDouble();
3139 maskEnabled = ( maskEnabled && bufrSize > 0.0 && opacity > 0 );
3164 wrapchr = exprVal.toString();
3170 evalAutoWrapLength = exprVal.toInt();
3181 if ( exprVal.isValid() )
3183 QString str = exprVal.toString().trimmed();
3184 QgsDebugMsgLevel( QStringLiteral(
"exprVal MultiLineAlignment:%1" ).arg( str ), 4 );
3186 if ( !str.isEmpty() )
3191 if ( str.compare( QLatin1String(
"Center" ), Qt::CaseInsensitive ) == 0 )
3195 else if ( str.compare( QLatin1String(
"Right" ), Qt::CaseInsensitive ) == 0 )
3199 else if ( str.compare( QLatin1String(
"Follow" ), Qt::CaseInsensitive ) == 0 )
3203 else if ( str.compare( QLatin1String(
"Justify" ), Qt::CaseInsensitive ) == 0 )
3218 if ( exprVal.isValid() )
3220 QString str = exprVal.toString().trimmed();
3221 if ( !str.isEmpty() )
3230 drawDirSymb = exprVal.toBool();
3243 if ( exprVal.isValid() )
3245 QString str = exprVal.toString().trimmed();
3246 QgsDebugMsgLevel( QStringLiteral(
"exprVal DirSymbPlacement:%1" ).arg( str ), 4 );
3248 if ( !str.isEmpty() )
3253 if ( str.compare( QLatin1String(
"Above" ), Qt::CaseInsensitive ) == 0 )
3257 else if ( str.compare( QLatin1String(
"Below" ), Qt::CaseInsensitive ) == 0 )
3272 void QgsPalLayerSettings::parseShapeBackground(
QgsRenderContext &context )
3279 bool drawShape = background.
enabled();
3282 drawShape = exprVal.toBool();
3291 double shapeOpacity = background.
opacity() * 100;
3294 shapeOpacity = 100.0 * exprVal.toDouble();
3297 drawShape = ( drawShape && shapeOpacity > 0 );
3311 if ( exprVal.isValid() )
3313 QString skind = exprVal.toString().trimmed();
3314 QgsDebugMsgLevel( QStringLiteral(
"exprVal ShapeKind:%1" ).arg( skind ), 4 );
3316 if ( !skind.isEmpty() )
3325 QString svgPath = background.
svgFile();
3330 if ( exprVal.isValid() )
3332 QString svgfile = exprVal.toString().trimmed();
3333 QgsDebugMsgLevel( QStringLiteral(
"exprVal ShapeSVGFile:%1" ).arg( svgfile ), 4 );
3346 if ( exprVal.isValid() )
3348 QString stype = exprVal.toString().trimmed();
3349 QgsDebugMsgLevel( QStringLiteral(
"exprVal ShapeSizeType:%1" ).arg( stype ), 4 );
3351 if ( !stype.isEmpty() )
3360 double ddShpSizeX = background.
size().width();
3363 ddShpSizeX = exprVal.toDouble();
3367 double ddShpSizeY = background.
size().height();
3370 ddShpSizeY = exprVal.toDouble();
3376 && ( svgPath.isEmpty()
3377 || ( !svgPath.isEmpty()
3379 && ddShpSizeX == 0.0 ) ) )
3387 && ddShpSizeX == 0.0 ) ) )
3394 && ( ddShpSizeX == 0.0 || ddShpSizeY == 0.0 ) )
3417 if ( exprVal.isValid() )
3419 QString rotstr = exprVal.toString().trimmed();
3420 QgsDebugMsgLevel( QStringLiteral(
"exprVal ShapeRotationType:%1" ).arg( rotstr ), 4 );
3422 if ( !rotstr.isEmpty() )
3473 bool drawShadow = shadow.
enabled();
3476 drawShadow = exprVal.toBool();
3485 double shadowOpacity = shadow.
opacity() * 100;
3488 shadowOpacity = exprVal.toDouble();
3495 shadowOffDist = exprVal.toDouble();
3502 shadowRad = exprVal.toDouble();
3505 drawShadow = ( drawShadow && shadowOpacity > 0 && !( shadowOffDist == 0.0 && shadowRad == 0.0 ) );
3520 if ( exprVal.isValid() )
3522 QString str = exprVal.toString().trimmed();
3523 QgsDebugMsgLevel( QStringLiteral(
"exprVal ShadowUnder:%1" ).arg( str ), 4 );
3525 if ( !str.isEmpty() )
3560 switch ( layer->
type() )
3564 const QgsVectorLayer *vl = qobject_cast< const QgsVectorLayer * >( layer );
3575 return !labeling->styles().empty();
3622 QStringList
QgsPalLabeling::splitToLines(
const QString &text,
const QString &wrapCharacter,
const int autoWrapLength,
const bool useMaxLineLengthWhenAutoWrapping )
3624 QStringList multiLineSplit;
3625 if ( !wrapCharacter.isEmpty() && wrapCharacter != QLatin1String(
"\n" ) )
3628 const QStringList lines = text.split( wrapCharacter );
3629 for (
const QString &line : lines )
3631 multiLineSplit.append( line.split(
'\n' ) );
3636 multiLineSplit = text.split(
'\n' );
3640 if ( autoWrapLength != 0 )
3642 QStringList autoWrappedLines;
3643 autoWrappedLines.reserve( multiLineSplit.count() );
3644 for (
const QString &line : qgis::as_const( multiLineSplit ) )
3646 autoWrappedLines.append(
QgsStringUtils::wordWrap( line, autoWrapLength, useMaxLineLengthWhenAutoWrapping ).split(
'\n' ) );
3648 multiLineSplit = autoWrappedLines;
3650 return multiLineSplit;
3655 QStringList graphemes;
3656 QTextBoundaryFinder boundaryFinder( QTextBoundaryFinder::Grapheme, text );
3657 int currentBoundary = -1;
3658 int previousBoundary = 0;
3659 while ( ( currentBoundary = boundaryFinder.toNextBoundary() ) > 0 )
3661 graphemes << text.mid( previousBoundary, currentBoundary - previousBoundary );
3662 previousBoundary = currentBoundary;
3692 QgsDebugMsgLevel( QStringLiteral(
"Ignoring feature due to transformation exception" ), 4 );
3698 return std::isfinite( point.
x() ) && std::isfinite( point.
y() );
3701 cp->removeInvalidRings();
3711 QgsDebugMsg( QStringLiteral(
"Error rotating geometry" ).arg( geom.
asWkt() ) );
3725 QVector< QgsGeometry> parts;
3726 parts.reserve( qgsgeometry_cast< const QgsGeometryCollection * >( geom.
constGet() )->numGeometries() );
3732 partGeom = partGeom.
buffer( 0, 0 );
3734 parts.append( partGeom );
3741 if ( bufferGeom.
isNull() )
3743 QgsDebugMsg( QStringLiteral(
"Could not repair geometry: %1" ).arg( bufferGeom.
lastError() ) );
3750 if ( !clipGeometry.
isNull() &&
3786 double length = geom.
length();
3787 if ( length >= 0.0 )
3789 return ( length >= ( minSize * mapUnitsPerMM ) );
3794 double area = geom.
area();
3797 return ( std::sqrt( area ) >= ( minSize * mapUnitsPerMM ) );
3805 const QMap< QgsPalLayerSettings::Property, QVariant > &ddValues )
3808 bool changed =
false;
3814 format.
setColor( ddColor.value<QColor>() );
3839 const QMap< QgsPalLayerSettings::Property, QVariant > &ddValues )
3901 const QMap< QgsPalLayerSettings::Property, QVariant > &ddValues )
3904 bool changed =
false;
3952 buffer.
setColor( ddColor.value<QColor>() );
3979 const QMap< QgsPalLayerSettings::Property, QVariant > &ddValues )
3981 if ( ddValues.isEmpty() )
3985 bool changed =
false;
4045 const QMap< QgsPalLayerSettings::Property, QVariant > &ddValues )
4048 bool changed =
false;
4088 QSizeF size = background.
size();
4095 QSizeF size = background.
size();
4196 const QMap< QgsPalLayerSettings::Property, QVariant > &ddValues )
4199 bool changed =
false;
4258 shadow.
setColor( ddColor.value<QColor>() );
4296 #if 0 // TODO: generalize some of this
4299 double cx = lp->
getX() + w / 2.0;
4300 double cy = lp->
getY() + h / 2.0;
4303 double sw = w * scale;
4304 double sh = h * scale;
4305 QRectF rect( -sw / 2, -sh / 2, sw, sh );
4307 painter->translate( xform->
transform( QPointF( cx, cy ) ).toQPointF() );
4311 if ( lp->
getFeaturePart()->getLayer()->getArrangement() != P_POINT &&
4312 lp->
getFeaturePart()->getLayer()->getArrangement() != P_POINT_OVER &&
4315 painter->rotate( rotation );
4318 painter->translate( rect.bottomLeft() );
4319 painter->rotate( -lp->
getAlpha() * 180 / M_PI );
4320 painter->translate( -rect.bottomLeft() );
4323 QRectF rect( 0, 0, outPt2.
x() - outPt.
x(), outPt2.
y() - outPt.
y() );
4324 painter->translate( QPointF( outPt.
x(), outPt.
y() ) );
4325 painter->rotate( -lp->
getAlpha() * 180 / M_PI );
4330 painter->setPen( QColor( 255, 0, 0, 64 ) );
4334 painter->setPen( QColor( 0, 0, 0, 64 ) );
4336 painter->drawRect( rect );
4340 rect.moveTo( outPt.
x(), outPt.
y() );
4358 QList<QgsLabelPosition> positions;
4360 QList<QgsLabelPosition *> positionPointers;
4361 if ( mLabelSearchTree )
4363 mLabelSearchTree->label( p, positionPointers );
4364 QList<QgsLabelPosition *>::const_iterator pointerIt = positionPointers.constBegin();
4365 for ( ; pointerIt != positionPointers.constEnd(); ++pointerIt )
4376 QList<QgsLabelPosition> positions;
4378 QList<QgsLabelPosition *> positionPointers;
4379 if ( mLabelSearchTree )
4381 mLabelSearchTree->labelsInRect( r, positionPointers );
4382 QList<QgsLabelPosition *>::const_iterator pointerIt = positionPointers.constBegin();
4383 for ( ; pointerIt != positionPointers.constEnd(); ++pointerIt )
4394 mLabelSearchTree->setMapSettings( settings );