mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-28 00:17:30 -05:00
[api] Allow data defined properties to be set in QgsTextFormat, so
that these are automatically respected whenever the format is rendered using QgsTextRenderer This is done transparently to the caller - so by porting away from the raw QPainter text apis to use QgsTextRenderer instead, then they immediately gain the ability to use data defined properties in their text formats.
This commit is contained in:
parent
859d9a7233
commit
19a2b0e5d5
@ -10,7 +10,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
class QgsTextBufferSettings
|
||||
{
|
||||
%Docstring
|
||||
@ -240,6 +239,13 @@ Sets the current paint ``effect`` for the buffer.
|
||||
:param effect: paint effect. Ownership is transferred to the buffer settings.
|
||||
|
||||
.. seealso:: :py:func:`paintEffect`
|
||||
%End
|
||||
|
||||
void updateDataDefinedProperties( QgsRenderContext &context, const QgsPropertyCollection &properties );
|
||||
%Docstring
|
||||
Updates the format by evaluating current values of data defined properties.
|
||||
|
||||
.. versionadded:: 3.10
|
||||
%End
|
||||
|
||||
};
|
||||
@ -827,6 +833,13 @@ Read settings from a DOM element.
|
||||
Write settings into a DOM element.
|
||||
|
||||
.. seealso:: :py:func:`readXml`
|
||||
%End
|
||||
|
||||
void updateDataDefinedProperties( QgsRenderContext &context, const QgsPropertyCollection &properties );
|
||||
%Docstring
|
||||
Updates the format by evaluating current values of data defined properties.
|
||||
|
||||
.. versionadded:: 3.10
|
||||
%End
|
||||
|
||||
};
|
||||
@ -1167,6 +1180,13 @@ Read settings from a DOM element.
|
||||
Write settings into a DOM element.
|
||||
|
||||
.. seealso:: :py:func:`readXml`
|
||||
%End
|
||||
|
||||
void updateDataDefinedProperties( QgsRenderContext &context, const QgsPropertyCollection &properties );
|
||||
%Docstring
|
||||
Updates the format by evaluating current values of data defined properties.
|
||||
|
||||
.. versionadded:: 3.10
|
||||
%End
|
||||
|
||||
};
|
||||
@ -1549,6 +1569,34 @@ was not found on the system this will return the name of the replacement
|
||||
font.
|
||||
|
||||
.. seealso:: :py:func:`fontFound`
|
||||
%End
|
||||
|
||||
QgsPropertyCollection &dataDefinedProperties();
|
||||
%Docstring
|
||||
Returns a reference to the format's property collection, used for data defined overrides.
|
||||
|
||||
.. seealso:: :py:func:`setDataDefinedProperties`
|
||||
|
||||
.. versionadded:: 3.10
|
||||
%End
|
||||
|
||||
|
||||
void setDataDefinedProperties( const QgsPropertyCollection &collection );
|
||||
%Docstring
|
||||
Sets the format's property collection, used for data defined overrides.
|
||||
|
||||
:param collection: property collection. Existing properties will be replaced.
|
||||
|
||||
.. seealso:: :py:func:`dataDefinedProperties`
|
||||
|
||||
.. versionadded:: 3.10
|
||||
%End
|
||||
|
||||
void updateDataDefinedProperties( QgsRenderContext &context );
|
||||
%Docstring
|
||||
Updates the format by evaluating current values of data defined properties.
|
||||
|
||||
.. versionadded:: 3.10
|
||||
%End
|
||||
|
||||
static QPixmap textFormatPreviewPixmap( const QgsTextFormat &format, QSize size, const QString &previewText = QString(), int padding = 0 );
|
||||
@ -1727,6 +1775,42 @@ Returns the height of a text based on a given format.
|
||||
|
||||
};
|
||||
|
||||
class QgsTextRendererUtils
|
||||
{
|
||||
%Docstring
|
||||
Utility functions for text rendering.
|
||||
|
||||
.. versionadded:: 3.10
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgstextrenderer.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
static QgsTextBackgroundSettings::ShapeType decodeShapeType( const QString &string );
|
||||
%Docstring
|
||||
Decodes a string representation of a background shape type to a type.
|
||||
%End
|
||||
|
||||
static QgsTextBackgroundSettings::SizeType decodeBackgroundSizeType( const QString &string );
|
||||
%Docstring
|
||||
Decodes a string representation of a background size type to a type.
|
||||
%End
|
||||
|
||||
static QgsTextBackgroundSettings::RotationType decodeBackgroundRotationType( const QString &string );
|
||||
%Docstring
|
||||
Decodes a string representation of a background rotation type to a type.
|
||||
%End
|
||||
|
||||
static QgsTextShadowSettings::ShadowPlacement decodeShadowPlacementType( const QString &string );
|
||||
%Docstring
|
||||
Decodes a string representation of a shadow placement type to a type.
|
||||
%End
|
||||
|
||||
};
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
|
@ -591,13 +591,6 @@ QgsExpression *QgsPalLayerSettings::getLabelExpression()
|
||||
return expression;
|
||||
}
|
||||
|
||||
static Qt::PenJoinStyle _decodePenJoinStyle( const QString &str )
|
||||
{
|
||||
if ( str.compare( QLatin1String( "Miter" ), Qt::CaseInsensitive ) == 0 ) return Qt::MiterJoin;
|
||||
if ( str.compare( QLatin1String( "Round" ), Qt::CaseInsensitive ) == 0 ) return Qt::RoundJoin;
|
||||
return Qt::BevelJoin; // "Bevel"
|
||||
}
|
||||
|
||||
QString updateDataDefinedString( const QString &value )
|
||||
{
|
||||
// TODO: update or remove this when project settings for labeling are migrated to better XML layout
|
||||
@ -2530,7 +2523,7 @@ bool QgsPalLayerSettings::dataDefinedValEval( DataDefinedValueType valType,
|
||||
|
||||
if ( !joinstr.isEmpty() )
|
||||
{
|
||||
dataDefinedValues.insert( p, QVariant( static_cast< int >( _decodePenJoinStyle( joinstr ) ) ) );
|
||||
dataDefinedValues.insert( p, QVariant( static_cast< int >( QgsSymbolLayerUtils::decodePenJoinStyle( joinstr ) ) ) );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -2920,31 +2913,8 @@ void QgsPalLayerSettings::parseShapeBackground( QgsRenderContext &context )
|
||||
|
||||
if ( !skind.isEmpty() )
|
||||
{
|
||||
// "Rectangle"
|
||||
QgsTextBackgroundSettings::ShapeType shpkind = QgsTextBackgroundSettings::ShapeRectangle;
|
||||
|
||||
if ( skind.compare( QLatin1String( "Square" ), Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
shpkind = QgsTextBackgroundSettings::ShapeSquare;
|
||||
}
|
||||
else if ( skind.compare( QLatin1String( "Ellipse" ), Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
shpkind = QgsTextBackgroundSettings::ShapeEllipse;
|
||||
}
|
||||
else if ( skind.compare( QLatin1String( "Circle" ), Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
shpkind = QgsTextBackgroundSettings::ShapeCircle;
|
||||
}
|
||||
else if ( skind.compare( QLatin1String( "SVG" ), Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
shpkind = QgsTextBackgroundSettings::ShapeSVG;
|
||||
}
|
||||
else if ( skind.compare( QLatin1String( "marker" ), Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
shpkind = QgsTextBackgroundSettings::ShapeMarkerSymbol;
|
||||
}
|
||||
shapeKind = shpkind;
|
||||
dataDefinedValues.insert( QgsPalLayerSettings::ShapeKind, QVariant( static_cast< int >( shpkind ) ) );
|
||||
shapeKind = QgsTextRendererUtils::decodeShapeType( skind );
|
||||
dataDefinedValues.insert( QgsPalLayerSettings::ShapeKind, QVariant( static_cast< int >( shapeKind ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
@ -2972,15 +2942,8 @@ void QgsPalLayerSettings::parseShapeBackground( QgsRenderContext &context )
|
||||
|
||||
if ( !stype.isEmpty() )
|
||||
{
|
||||
// "Buffer"
|
||||
QgsTextBackgroundSettings::SizeType sizType = QgsTextBackgroundSettings::SizeBuffer;
|
||||
|
||||
if ( stype.compare( QLatin1String( "Fixed" ), Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
sizType = QgsTextBackgroundSettings::SizeFixed;
|
||||
}
|
||||
shpSizeType = sizType;
|
||||
dataDefinedValues.insert( QgsPalLayerSettings::ShapeSizeType, QVariant( static_cast< int >( sizType ) ) );
|
||||
shpSizeType = QgsTextRendererUtils::decodeBackgroundSizeType( stype );
|
||||
dataDefinedValues.insert( QgsPalLayerSettings::ShapeSizeType, QVariant( static_cast< int >( shpSizeType ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
@ -3048,16 +3011,7 @@ void QgsPalLayerSettings::parseShapeBackground( QgsRenderContext &context )
|
||||
if ( !rotstr.isEmpty() )
|
||||
{
|
||||
// "Sync"
|
||||
QgsTextBackgroundSettings::RotationType rottype = QgsTextBackgroundSettings::RotationSync;
|
||||
|
||||
if ( rotstr.compare( QLatin1String( "Offset" ), Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
rottype = QgsTextBackgroundSettings::RotationOffset;
|
||||
}
|
||||
else if ( rotstr.compare( QLatin1String( "Fixed" ), Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
rottype = QgsTextBackgroundSettings::RotationFixed;
|
||||
}
|
||||
QgsTextBackgroundSettings::RotationType rottype = QgsTextRendererUtils::decodeBackgroundRotationType( rotstr );
|
||||
dataDefinedValues.insert( QgsPalLayerSettings::ShapeRotationType, QVariant( static_cast< int >( rottype ) ) );
|
||||
}
|
||||
}
|
||||
@ -3156,21 +3110,7 @@ void QgsPalLayerSettings::parseDropShadow( QgsRenderContext &context )
|
||||
|
||||
if ( !str.isEmpty() )
|
||||
{
|
||||
// "Lowest"
|
||||
QgsTextShadowSettings::ShadowPlacement shdwtype = QgsTextShadowSettings::ShadowLowest;
|
||||
|
||||
if ( str.compare( QLatin1String( "Text" ), Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
shdwtype = QgsTextShadowSettings::ShadowText;
|
||||
}
|
||||
else if ( str.compare( QLatin1String( "Buffer" ), Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
shdwtype = QgsTextShadowSettings::ShadowBuffer;
|
||||
}
|
||||
else if ( str.compare( QLatin1String( "Background" ), Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
shdwtype = QgsTextShadowSettings::ShadowShape;
|
||||
}
|
||||
QgsTextShadowSettings::ShadowPlacement shdwtype = QgsTextRendererUtils::decodeShadowPlacementType( str );
|
||||
dataDefinedValues.insert( QgsPalLayerSettings::ShadowUnder, QVariant( static_cast< int >( shdwtype ) ) );
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "qgspainting.h"
|
||||
#include "qgsmarkersymbollayer.h"
|
||||
#include "qgspainteffectregistry.h"
|
||||
#include "qgspallabeling.h"
|
||||
#include <QFontDatabase>
|
||||
#include <QDesktopWidget>
|
||||
|
||||
@ -185,6 +186,64 @@ void QgsTextBufferSettings::setPaintEffect( QgsPaintEffect *effect )
|
||||
d->paintEffect.reset( effect );
|
||||
}
|
||||
|
||||
void QgsTextBufferSettings::updateDataDefinedProperties( QgsRenderContext &context, const QgsPropertyCollection &properties )
|
||||
{
|
||||
if ( properties.isActive( QgsPalLayerSettings::BufferDraw ) )
|
||||
{
|
||||
context.expressionContext().setOriginalValueVariable( d->enabled );
|
||||
d->enabled = properties.valueAsBool( QgsPalLayerSettings::BufferDraw, context.expressionContext(), d->enabled );
|
||||
}
|
||||
|
||||
if ( properties.isActive( QgsPalLayerSettings::BufferSize ) )
|
||||
{
|
||||
context.expressionContext().setOriginalValueVariable( d->size );
|
||||
d->size = properties.valueAsDouble( QgsPalLayerSettings::BufferSize, context.expressionContext(), d->size );
|
||||
}
|
||||
|
||||
QVariant exprVal = properties.value( QgsPalLayerSettings::BufferUnit, context.expressionContext() );
|
||||
if ( exprVal.isValid() )
|
||||
{
|
||||
QString units = exprVal.toString();
|
||||
if ( !units.isEmpty() )
|
||||
{
|
||||
bool ok;
|
||||
QgsUnitTypes::RenderUnit res = QgsUnitTypes::decodeRenderUnit( units, &ok );
|
||||
if ( ok )
|
||||
d->sizeUnit = res;
|
||||
}
|
||||
}
|
||||
|
||||
if ( properties.isActive( QgsPalLayerSettings::BufferOpacity ) )
|
||||
{
|
||||
context.expressionContext().setOriginalValueVariable( d->opacity * 100 );
|
||||
d->opacity = properties.value( QgsPalLayerSettings::BufferOpacity, context.expressionContext(), d->opacity * 100 ).toDouble() / 100.0;
|
||||
}
|
||||
|
||||
if ( properties.isActive( QgsPalLayerSettings::BufferColor ) )
|
||||
{
|
||||
context.expressionContext().setOriginalValueVariable( QgsSymbolLayerUtils::encodeColor( d->color ) );
|
||||
d->color = properties.valueAsColor( QgsPalLayerSettings::BufferColor, context.expressionContext(), d->color );
|
||||
}
|
||||
|
||||
if ( properties.isActive( QgsPalLayerSettings::BufferBlendMode ) )
|
||||
{
|
||||
exprVal = properties.value( QgsPalLayerSettings::BufferBlendMode, context.expressionContext() );
|
||||
QString blendstr = exprVal.toString().trimmed();
|
||||
if ( !blendstr.isEmpty() )
|
||||
d->blendMode = QgsSymbolLayerUtils::decodeBlendMode( blendstr );
|
||||
}
|
||||
|
||||
if ( properties.isActive( QgsPalLayerSettings::BufferJoinStyle ) )
|
||||
{
|
||||
exprVal = properties.value( QgsPalLayerSettings::BufferJoinStyle, context.expressionContext() );
|
||||
QString joinstr = exprVal.toString().trimmed();
|
||||
if ( !joinstr.isEmpty() )
|
||||
{
|
||||
d->joinStyle = QgsSymbolLayerUtils::decodePenJoinStyle( joinstr );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsTextBufferSettings::readFromLayer( QgsVectorLayer *layer )
|
||||
{
|
||||
// text buffer
|
||||
@ -915,6 +974,181 @@ QDomElement QgsTextBackgroundSettings::writeXml( QDomDocument &doc, const QgsRea
|
||||
return backgroundElem;
|
||||
}
|
||||
|
||||
void QgsTextBackgroundSettings::updateDataDefinedProperties( QgsRenderContext &context, const QgsPropertyCollection &properties )
|
||||
{
|
||||
if ( properties.isActive( QgsPalLayerSettings::ShapeDraw ) )
|
||||
{
|
||||
context.expressionContext().setOriginalValueVariable( d->enabled );
|
||||
d->enabled = properties.valueAsBool( QgsPalLayerSettings::ShapeDraw, context.expressionContext(), d->enabled );
|
||||
}
|
||||
|
||||
if ( properties.isActive( QgsPalLayerSettings::ShapeSizeX ) )
|
||||
{
|
||||
context.expressionContext().setOriginalValueVariable( d->size.width() );
|
||||
d->size.setWidth( properties.valueAsDouble( QgsPalLayerSettings::ShapeSizeX, context.expressionContext(), d->size.width() ) );
|
||||
}
|
||||
if ( properties.isActive( QgsPalLayerSettings::ShapeSizeY ) )
|
||||
{
|
||||
context.expressionContext().setOriginalValueVariable( d->size.height() );
|
||||
d->size.setHeight( properties.valueAsDouble( QgsPalLayerSettings::ShapeSizeY, context.expressionContext(), d->size.height() ) );
|
||||
}
|
||||
|
||||
QVariant exprVal = properties.value( QgsPalLayerSettings::ShapeSizeUnits, context.expressionContext() );
|
||||
if ( exprVal.isValid() )
|
||||
{
|
||||
QString units = exprVal.toString();
|
||||
if ( !units.isEmpty() )
|
||||
{
|
||||
bool ok;
|
||||
QgsUnitTypes::RenderUnit res = QgsUnitTypes::decodeRenderUnit( units, &ok );
|
||||
if ( ok )
|
||||
d->sizeUnits = res;
|
||||
}
|
||||
}
|
||||
|
||||
exprVal = properties.value( QgsPalLayerSettings::ShapeKind, context.expressionContext() );
|
||||
if ( exprVal.isValid() )
|
||||
{
|
||||
const QString skind = exprVal.toString().trimmed();
|
||||
if ( !skind.isEmpty() )
|
||||
{
|
||||
d->type = QgsTextRendererUtils::decodeShapeType( skind );
|
||||
}
|
||||
}
|
||||
|
||||
exprVal = properties.value( QgsPalLayerSettings::ShapeSizeType, context.expressionContext() );
|
||||
if ( exprVal.isValid() )
|
||||
{
|
||||
QString stype = exprVal.toString().trimmed();
|
||||
if ( !stype.isEmpty() )
|
||||
{
|
||||
d->sizeType = QgsTextRendererUtils::decodeBackgroundSizeType( stype );
|
||||
}
|
||||
}
|
||||
|
||||
// data defined shape SVG path?
|
||||
context.expressionContext().setOriginalValueVariable( d->svgFile );
|
||||
exprVal = properties.value( QgsPalLayerSettings::ShapeSVGFile, context.expressionContext() );
|
||||
if ( exprVal.isValid() )
|
||||
{
|
||||
QString svgfile = exprVal.toString().trimmed();
|
||||
d->svgFile = QgsSymbolLayerUtils::svgSymbolNameToPath( svgfile, context.pathResolver() );
|
||||
}
|
||||
|
||||
if ( properties.isActive( QgsPalLayerSettings::ShapeRotation ) )
|
||||
{
|
||||
context.expressionContext().setOriginalValueVariable( d->rotation );
|
||||
d->rotation = properties.valueAsDouble( QgsPalLayerSettings::ShapeRotation, context.expressionContext(), d->rotation );
|
||||
}
|
||||
exprVal = properties.value( QgsPalLayerSettings::ShapeRotationType, context.expressionContext() );
|
||||
if ( exprVal.isValid() )
|
||||
{
|
||||
QString rotstr = exprVal.toString().trimmed();
|
||||
if ( !rotstr.isEmpty() )
|
||||
{
|
||||
d->rotationType = QgsTextRendererUtils::decodeBackgroundRotationType( rotstr );
|
||||
}
|
||||
}
|
||||
|
||||
exprVal = properties.value( QgsPalLayerSettings::ShapeOffset, context.expressionContext() );
|
||||
if ( exprVal.isValid() )
|
||||
{
|
||||
QString offset = exprVal.toString();
|
||||
if ( !offset.isEmpty() )
|
||||
{
|
||||
d->offset = QgsSymbolLayerUtils::decodePoint( offset );
|
||||
}
|
||||
}
|
||||
exprVal = properties.value( QgsPalLayerSettings::ShapeOffsetUnits, context.expressionContext() );
|
||||
if ( exprVal.isValid() )
|
||||
{
|
||||
QString units = exprVal.toString();
|
||||
if ( !units.isEmpty() )
|
||||
{
|
||||
bool ok;
|
||||
QgsUnitTypes::RenderUnit res = QgsUnitTypes::decodeRenderUnit( units, &ok );
|
||||
if ( ok )
|
||||
d->offsetUnits = res;
|
||||
}
|
||||
}
|
||||
|
||||
exprVal = properties.value( QgsPalLayerSettings::ShapeRadii, context.expressionContext() );
|
||||
if ( exprVal.isValid() )
|
||||
{
|
||||
QString ptstr = exprVal.toString();
|
||||
if ( !ptstr.isEmpty() )
|
||||
{
|
||||
d->radii = QgsSymbolLayerUtils::decodeSize( ptstr );
|
||||
}
|
||||
}
|
||||
|
||||
exprVal = properties.value( QgsPalLayerSettings::ShapeRadiiUnits, context.expressionContext() );
|
||||
if ( exprVal.isValid() )
|
||||
{
|
||||
QString units = exprVal.toString();
|
||||
if ( !units.isEmpty() )
|
||||
{
|
||||
bool ok;
|
||||
QgsUnitTypes::RenderUnit res = QgsUnitTypes::decodeRenderUnit( units, &ok );
|
||||
if ( ok )
|
||||
d->radiiUnits = res;
|
||||
}
|
||||
}
|
||||
|
||||
if ( properties.isActive( QgsPalLayerSettings::ShapeOpacity ) )
|
||||
{
|
||||
context.expressionContext().setOriginalValueVariable( d->opacity * 100 );
|
||||
d->opacity = properties.value( QgsPalLayerSettings::ShapeOpacity, context.expressionContext(), d->opacity * 100 ).toDouble() / 100.0;
|
||||
}
|
||||
|
||||
if ( properties.isActive( QgsPalLayerSettings::ShapeFillColor ) )
|
||||
{
|
||||
context.expressionContext().setOriginalValueVariable( QgsSymbolLayerUtils::encodeColor( d->fillColor ) );
|
||||
d->fillColor = properties.valueAsColor( QgsPalLayerSettings::ShapeFillColor, context.expressionContext(), d->fillColor );
|
||||
}
|
||||
if ( properties.isActive( QgsPalLayerSettings::ShapeStrokeColor ) )
|
||||
{
|
||||
context.expressionContext().setOriginalValueVariable( QgsSymbolLayerUtils::encodeColor( d->strokeColor ) );
|
||||
d->strokeColor = properties.valueAsColor( QgsPalLayerSettings::ShapeStrokeColor, context.expressionContext(), d->strokeColor );
|
||||
}
|
||||
|
||||
if ( properties.isActive( QgsPalLayerSettings::ShapeStrokeWidth ) )
|
||||
{
|
||||
context.expressionContext().setOriginalValueVariable( d->strokeWidth );
|
||||
d->strokeWidth = properties.valueAsDouble( QgsPalLayerSettings::ShapeStrokeWidth, context.expressionContext(), d->strokeWidth );
|
||||
}
|
||||
exprVal = properties.value( QgsPalLayerSettings::ShapeStrokeWidthUnits, context.expressionContext() );
|
||||
if ( exprVal.isValid() )
|
||||
{
|
||||
QString units = exprVal.toString();
|
||||
if ( !units.isEmpty() )
|
||||
{
|
||||
bool ok;
|
||||
QgsUnitTypes::RenderUnit res = QgsUnitTypes::decodeRenderUnit( units, &ok );
|
||||
if ( ok )
|
||||
d->strokeWidthUnits = res;
|
||||
}
|
||||
}
|
||||
|
||||
if ( properties.isActive( QgsPalLayerSettings::ShapeBlendMode ) )
|
||||
{
|
||||
exprVal = properties.value( QgsPalLayerSettings::ShapeBlendMode, context.expressionContext() );
|
||||
QString blendstr = exprVal.toString().trimmed();
|
||||
if ( !blendstr.isEmpty() )
|
||||
d->blendMode = QgsSymbolLayerUtils::decodeBlendMode( blendstr );
|
||||
}
|
||||
|
||||
if ( properties.isActive( QgsPalLayerSettings::ShapeJoinStyle ) )
|
||||
{
|
||||
exprVal = properties.value( QgsPalLayerSettings::ShapeJoinStyle, context.expressionContext() );
|
||||
QString joinstr = exprVal.toString().trimmed();
|
||||
if ( !joinstr.isEmpty() )
|
||||
{
|
||||
d->joinStyle = QgsSymbolLayerUtils::decodePenJoinStyle( joinstr );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// QgsTextShadowSettings
|
||||
@ -1247,6 +1481,95 @@ QDomElement QgsTextShadowSettings::writeXml( QDomDocument &doc ) const
|
||||
return shadowElem;
|
||||
}
|
||||
|
||||
void QgsTextShadowSettings::updateDataDefinedProperties( QgsRenderContext &context, const QgsPropertyCollection &properties )
|
||||
{
|
||||
if ( properties.isActive( QgsPalLayerSettings::ShadowDraw ) )
|
||||
{
|
||||
context.expressionContext().setOriginalValueVariable( d->enabled );
|
||||
d->enabled = properties.valueAsBool( QgsPalLayerSettings::ShadowDraw, context.expressionContext(), d->enabled );
|
||||
}
|
||||
|
||||
// data defined shadow under type?
|
||||
QVariant exprVal = properties.value( QgsPalLayerSettings::ShadowUnder, context.expressionContext() );
|
||||
if ( exprVal.isValid() )
|
||||
{
|
||||
QString str = exprVal.toString().trimmed();
|
||||
if ( !str.isEmpty() )
|
||||
{
|
||||
d->shadowUnder = QgsTextRendererUtils::decodeShadowPlacementType( str );
|
||||
}
|
||||
}
|
||||
|
||||
if ( properties.isActive( QgsPalLayerSettings::ShadowOffsetAngle ) )
|
||||
{
|
||||
context.expressionContext().setOriginalValueVariable( d->offsetAngle );
|
||||
d->offsetAngle = properties.valueAsInt( QgsPalLayerSettings::ShadowOffsetAngle, context.expressionContext(), d->offsetAngle );
|
||||
}
|
||||
if ( properties.isActive( QgsPalLayerSettings::ShadowOffsetDist ) )
|
||||
{
|
||||
context.expressionContext().setOriginalValueVariable( d->offsetDist );
|
||||
d->offsetDist = properties.valueAsDouble( QgsPalLayerSettings::ShadowOffsetDist, context.expressionContext(), d->offsetDist );
|
||||
}
|
||||
|
||||
exprVal = properties.value( QgsPalLayerSettings::ShadowOffsetUnits, context.expressionContext() );
|
||||
if ( exprVal.isValid() )
|
||||
{
|
||||
QString units = exprVal.toString();
|
||||
if ( !units.isEmpty() )
|
||||
{
|
||||
bool ok;
|
||||
QgsUnitTypes::RenderUnit res = QgsUnitTypes::decodeRenderUnit( units, &ok );
|
||||
if ( ok )
|
||||
d->offsetUnits = res;
|
||||
}
|
||||
}
|
||||
|
||||
if ( properties.isActive( QgsPalLayerSettings::ShadowRadius ) )
|
||||
{
|
||||
context.expressionContext().setOriginalValueVariable( d->radius );
|
||||
d->radius = properties.valueAsDouble( QgsPalLayerSettings::ShadowRadius, context.expressionContext(), d->radius );
|
||||
}
|
||||
|
||||
exprVal = properties.value( QgsPalLayerSettings::ShadowRadiusUnits, context.expressionContext() );
|
||||
if ( exprVal.isValid() )
|
||||
{
|
||||
QString units = exprVal.toString();
|
||||
if ( !units.isEmpty() )
|
||||
{
|
||||
bool ok;
|
||||
QgsUnitTypes::RenderUnit res = QgsUnitTypes::decodeRenderUnit( units, &ok );
|
||||
if ( ok )
|
||||
d->radiusUnits = res;
|
||||
}
|
||||
}
|
||||
|
||||
if ( properties.isActive( QgsPalLayerSettings::ShadowOpacity ) )
|
||||
{
|
||||
context.expressionContext().setOriginalValueVariable( d->opacity * 100 );
|
||||
d->opacity = properties.value( QgsPalLayerSettings::ShadowOpacity, context.expressionContext(), d->opacity * 100 ).toDouble() / 100.0;
|
||||
}
|
||||
|
||||
if ( properties.isActive( QgsPalLayerSettings::ShadowScale ) )
|
||||
{
|
||||
context.expressionContext().setOriginalValueVariable( d->scale );
|
||||
d->scale = properties.valueAsInt( QgsPalLayerSettings::ShadowScale, context.expressionContext(), d->scale );
|
||||
}
|
||||
|
||||
if ( properties.isActive( QgsPalLayerSettings::ShadowColor ) )
|
||||
{
|
||||
context.expressionContext().setOriginalValueVariable( QgsSymbolLayerUtils::encodeColor( d->color ) );
|
||||
d->color = properties.valueAsColor( QgsPalLayerSettings::ShadowColor, context.expressionContext(), d->color );
|
||||
}
|
||||
|
||||
if ( properties.isActive( QgsPalLayerSettings::ShadowBlendMode ) )
|
||||
{
|
||||
exprVal = properties.value( QgsPalLayerSettings::ShadowBlendMode, context.expressionContext() );
|
||||
QString blendstr = exprVal.toString().trimmed();
|
||||
if ( !blendstr.isEmpty() )
|
||||
d->blendMode = QgsSymbolLayerUtils::decodeBlendMode( blendstr );
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// QgsTextFormat
|
||||
//
|
||||
@ -1596,6 +1919,29 @@ void QgsTextFormat::readXml( const QDomElement &elem, const QgsReadWriteContext
|
||||
{
|
||||
mBackgroundSettings.readXml( textStyleElem, context );
|
||||
}
|
||||
|
||||
if ( textStyleElem.firstChildElement( QStringLiteral( "dd_properties" ) ).isNull() )
|
||||
{
|
||||
mBackgroundSettings.readXml( elem, context );
|
||||
}
|
||||
else
|
||||
{
|
||||
mBackgroundSettings.readXml( textStyleElem, context );
|
||||
}
|
||||
|
||||
QDomElement ddElem = textStyleElem.firstChildElement( QStringLiteral( "dd_properties" ) );
|
||||
if ( ddElem.isNull() )
|
||||
{
|
||||
ddElem = elem.firstChildElement( QStringLiteral( "dd_properties" ) );
|
||||
}
|
||||
if ( !ddElem.isNull() )
|
||||
{
|
||||
d->mDataDefinedProperties.readXml( ddElem, QgsPalLayerSettings::propertyDefinitions() );
|
||||
}
|
||||
else
|
||||
{
|
||||
d->mDataDefinedProperties.clear();
|
||||
}
|
||||
}
|
||||
|
||||
QDomElement QgsTextFormat::writeXml( QDomDocument &doc, const QgsReadWriteContext &context ) const
|
||||
@ -1620,9 +1966,14 @@ QDomElement QgsTextFormat::writeXml( QDomDocument &doc, const QgsReadWriteContex
|
||||
textStyleElem.setAttribute( QStringLiteral( "blendMode" ), QgsPainting::getBlendModeEnum( d->blendMode ) );
|
||||
textStyleElem.setAttribute( QStringLiteral( "multilineHeight" ), d->multilineHeight );
|
||||
|
||||
QDomElement ddElem = doc.createElement( QStringLiteral( "dd_properties" ) );
|
||||
d->mDataDefinedProperties.writeXml( ddElem, QgsPalLayerSettings::propertyDefinitions() );
|
||||
|
||||
textStyleElem.appendChild( mBufferSettings.writeXml( doc ) );
|
||||
textStyleElem.appendChild( mBackgroundSettings.writeXml( doc, context ) );
|
||||
textStyleElem.appendChild( mShadowSettings.writeXml( doc ) );
|
||||
textStyleElem.appendChild( ddElem );
|
||||
|
||||
return textStyleElem;
|
||||
}
|
||||
|
||||
@ -1735,6 +2086,195 @@ bool QgsTextFormat::containsAdvancedEffects() const
|
||||
return false;
|
||||
}
|
||||
|
||||
QgsPropertyCollection &QgsTextFormat::dataDefinedProperties()
|
||||
{
|
||||
return d->mDataDefinedProperties;
|
||||
}
|
||||
|
||||
const QgsPropertyCollection &QgsTextFormat::dataDefinedProperties() const
|
||||
{
|
||||
return d->mDataDefinedProperties;
|
||||
}
|
||||
|
||||
void QgsTextFormat::setDataDefinedProperties( const QgsPropertyCollection &collection )
|
||||
{
|
||||
d->mDataDefinedProperties = collection;
|
||||
}
|
||||
|
||||
void QgsTextFormat::updateDataDefinedProperties( QgsRenderContext &context )
|
||||
{
|
||||
if ( !d->mDataDefinedProperties.hasActiveProperties() )
|
||||
return;
|
||||
|
||||
QString ddFontFamily;
|
||||
context.expressionContext().setOriginalValueVariable( d->textFont.family() );
|
||||
QVariant exprVal = d->mDataDefinedProperties.value( QgsPalLayerSettings::Family, context.expressionContext() );
|
||||
if ( exprVal.isValid() )
|
||||
{
|
||||
QString family = exprVal.toString().trimmed();
|
||||
if ( d->textFont.family() != family )
|
||||
{
|
||||
// testing for ddFontFamily in QFontDatabase.families() may be slow to do for every feature
|
||||
// (i.e. don't use QgsFontUtils::fontFamilyMatchOnSystem( family ) here)
|
||||
if ( QgsFontUtils::fontFamilyOnSystem( family ) )
|
||||
{
|
||||
ddFontFamily = family;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// data defined named font style?
|
||||
QString ddFontStyle;
|
||||
context.expressionContext().setOriginalValueVariable( d->textNamedStyle );
|
||||
exprVal = d->mDataDefinedProperties.value( QgsPalLayerSettings::FontStyle, context.expressionContext() );
|
||||
if ( exprVal.isValid() )
|
||||
{
|
||||
QString fontstyle = exprVal.toString().trimmed();
|
||||
ddFontStyle = fontstyle;
|
||||
}
|
||||
|
||||
bool ddBold = false;
|
||||
if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::Bold ) )
|
||||
{
|
||||
context.expressionContext().setOriginalValueVariable( d->textFont.bold() );
|
||||
ddBold = d->mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::Bold, context.expressionContext(), false ) ;
|
||||
}
|
||||
|
||||
bool ddItalic = false;
|
||||
if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::Italic ) )
|
||||
{
|
||||
context.expressionContext().setOriginalValueVariable( d->textFont.italic() );
|
||||
ddItalic = d->mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::Italic, context.expressionContext(), false );
|
||||
}
|
||||
|
||||
// TODO: update when pref for how to resolve missing family (use matching algorithm or just default font) is implemented
|
||||
// (currently defaults to what has been read in from layer settings)
|
||||
QFont newFont;
|
||||
QFontDatabase fontDb;
|
||||
QFont appFont = QApplication::font();
|
||||
bool newFontBuilt = false;
|
||||
if ( ddBold || ddItalic )
|
||||
{
|
||||
// new font needs built, since existing style needs removed
|
||||
newFont = QFont( !ddFontFamily.isEmpty() ? ddFontFamily : d->textFont.family() );
|
||||
newFontBuilt = true;
|
||||
newFont.setBold( ddBold );
|
||||
newFont.setItalic( ddItalic );
|
||||
}
|
||||
else if ( !ddFontStyle.isEmpty()
|
||||
&& ddFontStyle.compare( QLatin1String( "Ignore" ), Qt::CaseInsensitive ) != 0 )
|
||||
{
|
||||
if ( !ddFontFamily.isEmpty() )
|
||||
{
|
||||
// both family and style are different, build font from database
|
||||
QFont styledfont = fontDb.font( ddFontFamily, ddFontStyle, appFont.pointSize() );
|
||||
if ( appFont != styledfont )
|
||||
{
|
||||
newFont = styledfont;
|
||||
newFontBuilt = true;
|
||||
}
|
||||
}
|
||||
|
||||
// update the font face style
|
||||
QgsFontUtils::updateFontViaStyle( newFontBuilt ? newFont : d->textFont, ddFontStyle );
|
||||
}
|
||||
else if ( !ddFontFamily.isEmpty() )
|
||||
{
|
||||
if ( ddFontStyle.compare( QLatin1String( "Ignore" ), Qt::CaseInsensitive ) != 0 )
|
||||
{
|
||||
// just family is different, build font from database
|
||||
QFont styledfont = fontDb.font( ddFontFamily, d->textNamedStyle, appFont.pointSize() );
|
||||
if ( appFont != styledfont )
|
||||
{
|
||||
newFont = styledfont;
|
||||
newFontBuilt = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
newFont = QFont( ddFontFamily );
|
||||
newFontBuilt = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( newFontBuilt )
|
||||
{
|
||||
// copy over existing font settings
|
||||
newFont.setUnderline( d->textFont.underline() );
|
||||
newFont.setStrikeOut( d->textFont.strikeOut() );
|
||||
newFont.setWordSpacing( d->textFont.wordSpacing() );
|
||||
newFont.setLetterSpacing( QFont::AbsoluteSpacing, d->textFont.letterSpacing() );
|
||||
d->textFont = newFont;
|
||||
}
|
||||
|
||||
if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::Underline ) )
|
||||
{
|
||||
context.expressionContext().setOriginalValueVariable( d->textFont.underline() );
|
||||
d->textFont.setUnderline( d->mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::Underline, context.expressionContext(), d->textFont.underline() ) );
|
||||
}
|
||||
|
||||
if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::Strikeout ) )
|
||||
{
|
||||
context.expressionContext().setOriginalValueVariable( d->textFont.strikeOut() );
|
||||
d->textFont.setStrikeOut( d->mDataDefinedProperties.valueAsBool( QgsPalLayerSettings::Strikeout, context.expressionContext(), d->textFont.strikeOut() ) );
|
||||
}
|
||||
|
||||
if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::Color ) )
|
||||
{
|
||||
context.expressionContext().setOriginalValueVariable( QgsSymbolLayerUtils::encodeColor( d->textColor ) );
|
||||
d->textColor = d->mDataDefinedProperties.valueAsColor( QgsPalLayerSettings::Color, context.expressionContext(), d->textColor );
|
||||
}
|
||||
|
||||
if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::Size ) )
|
||||
{
|
||||
context.expressionContext().setOriginalValueVariable( size() );
|
||||
d->fontSize = d->mDataDefinedProperties.valueAsDouble( QgsPalLayerSettings::Size, context.expressionContext(), d->fontSize );
|
||||
}
|
||||
|
||||
exprVal = d->mDataDefinedProperties.value( QgsPalLayerSettings::FontSizeUnit, context.expressionContext() );
|
||||
if ( exprVal.isValid() )
|
||||
{
|
||||
QString units = exprVal.toString();
|
||||
if ( !units.isEmpty() )
|
||||
{
|
||||
bool ok;
|
||||
QgsUnitTypes::RenderUnit res = QgsUnitTypes::decodeRenderUnit( units, &ok );
|
||||
if ( ok )
|
||||
d->fontSizeUnits = res;
|
||||
}
|
||||
}
|
||||
|
||||
if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::FontOpacity ) )
|
||||
{
|
||||
context.expressionContext().setOriginalValueVariable( d->opacity * 100 );
|
||||
d->opacity = d->mDataDefinedProperties.value( QgsPalLayerSettings::FontOpacity, context.expressionContext(), d->opacity * 100 ).toDouble() / 100.0;
|
||||
}
|
||||
|
||||
if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::FontLetterSpacing ) )
|
||||
{
|
||||
context.expressionContext().setOriginalValueVariable( d->textFont.letterSpacing() );
|
||||
d->textFont.setLetterSpacing( QFont::AbsoluteSpacing, d->mDataDefinedProperties.value( QgsPalLayerSettings::FontLetterSpacing, context.expressionContext(), d->textFont.letterSpacing() ).toDouble() );
|
||||
}
|
||||
|
||||
if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::FontWordSpacing ) )
|
||||
{
|
||||
context.expressionContext().setOriginalValueVariable( d->textFont.wordSpacing() );
|
||||
d->textFont.setWordSpacing( d->mDataDefinedProperties.value( QgsPalLayerSettings::FontWordSpacing, context.expressionContext(), d->textFont.wordSpacing() ).toDouble() );
|
||||
}
|
||||
|
||||
if ( d->mDataDefinedProperties.isActive( QgsPalLayerSettings::FontBlendMode ) )
|
||||
{
|
||||
exprVal = d->mDataDefinedProperties.value( QgsPalLayerSettings::FontBlendMode, context.expressionContext() );
|
||||
QString blendstr = exprVal.toString().trimmed();
|
||||
if ( !blendstr.isEmpty() )
|
||||
d->blendMode = QgsSymbolLayerUtils::decodeBlendMode( blendstr );
|
||||
}
|
||||
|
||||
mShadowSettings.updateDataDefinedProperties( context, d->mDataDefinedProperties );
|
||||
mBackgroundSettings.updateDataDefinedProperties( context, d->mDataDefinedProperties );
|
||||
mBufferSettings.updateDataDefinedProperties( context, d->mDataDefinedProperties );
|
||||
}
|
||||
|
||||
QPixmap QgsTextFormat::textFormatPreviewPixmap( const QgsTextFormat &format, QSize size, const QString &previewText, int padding )
|
||||
{
|
||||
QgsTextFormat tempFormat = format;
|
||||
@ -1837,7 +2377,10 @@ int QgsTextRenderer::sizeToPixel( double size, const QgsRenderContext &c, QgsUni
|
||||
|
||||
void QgsTextRenderer::drawText( const QRectF &rect, double rotation, QgsTextRenderer::HAlignment alignment, const QStringList &textLines, QgsRenderContext &context, const QgsTextFormat &format, bool )
|
||||
{
|
||||
QgsTextFormat tmpFormat = updateShadowPosition( format );
|
||||
QgsTextFormat tmpFormat = format;
|
||||
if ( format.dataDefinedProperties().hasActiveProperties() ) // note, we use format instead of tmpFormat here, it's const and potentially avoids a detach
|
||||
tmpFormat.updateDataDefinedProperties( context );
|
||||
tmpFormat = updateShadowPosition( tmpFormat );
|
||||
|
||||
if ( tmpFormat.background().enabled() )
|
||||
{
|
||||
@ -1854,7 +2397,10 @@ void QgsTextRenderer::drawText( const QRectF &rect, double rotation, QgsTextRend
|
||||
|
||||
void QgsTextRenderer::drawText( QPointF point, double rotation, QgsTextRenderer::HAlignment alignment, const QStringList &textLines, QgsRenderContext &context, const QgsTextFormat &format, bool )
|
||||
{
|
||||
QgsTextFormat tmpFormat = updateShadowPosition( format );
|
||||
QgsTextFormat tmpFormat = format;
|
||||
if ( format.dataDefinedProperties().hasActiveProperties() ) // note, we use format instead of tmpFormat here, it's const and potentially avoids a detach
|
||||
tmpFormat.updateDataDefinedProperties( context );
|
||||
tmpFormat = updateShadowPosition( tmpFormat );
|
||||
|
||||
if ( tmpFormat.background().enabled() )
|
||||
{
|
||||
@ -2843,3 +3389,86 @@ void QgsTextRenderer::drawTextInternal( TextPart drawType,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// QgsTextRendererUtils
|
||||
//
|
||||
|
||||
QgsTextBackgroundSettings::ShapeType QgsTextRendererUtils::decodeShapeType( const QString &string )
|
||||
{
|
||||
QgsTextBackgroundSettings::ShapeType shpkind = QgsTextBackgroundSettings::ShapeRectangle;
|
||||
const QString skind = string.trimmed();
|
||||
|
||||
if ( skind.compare( QLatin1String( "Square" ), Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
shpkind = QgsTextBackgroundSettings::ShapeSquare;
|
||||
}
|
||||
else if ( skind.compare( QLatin1String( "Ellipse" ), Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
shpkind = QgsTextBackgroundSettings::ShapeEllipse;
|
||||
}
|
||||
else if ( skind.compare( QLatin1String( "Circle" ), Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
shpkind = QgsTextBackgroundSettings::ShapeCircle;
|
||||
}
|
||||
else if ( skind.compare( QLatin1String( "SVG" ), Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
shpkind = QgsTextBackgroundSettings::ShapeSVG;
|
||||
}
|
||||
else if ( skind.compare( QLatin1String( "marker" ), Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
shpkind = QgsTextBackgroundSettings::ShapeMarkerSymbol;
|
||||
}
|
||||
return shpkind;
|
||||
}
|
||||
|
||||
QgsTextBackgroundSettings::SizeType QgsTextRendererUtils::decodeBackgroundSizeType( const QString &string )
|
||||
{
|
||||
const QString stype = string.trimmed();
|
||||
// "Buffer"
|
||||
QgsTextBackgroundSettings::SizeType sizType = QgsTextBackgroundSettings::SizeBuffer;
|
||||
|
||||
if ( stype.compare( QLatin1String( "Fixed" ), Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
sizType = QgsTextBackgroundSettings::SizeFixed;
|
||||
}
|
||||
return sizType;
|
||||
}
|
||||
|
||||
QgsTextBackgroundSettings::RotationType QgsTextRendererUtils::decodeBackgroundRotationType( const QString &string )
|
||||
{
|
||||
const QString rotstr = string.trimmed();
|
||||
// "Sync"
|
||||
QgsTextBackgroundSettings::RotationType rottype = QgsTextBackgroundSettings::RotationSync;
|
||||
|
||||
if ( rotstr.compare( QLatin1String( "Offset" ), Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
rottype = QgsTextBackgroundSettings::RotationOffset;
|
||||
}
|
||||
else if ( rotstr.compare( QLatin1String( "Fixed" ), Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
rottype = QgsTextBackgroundSettings::RotationFixed;
|
||||
}
|
||||
return rottype;
|
||||
}
|
||||
|
||||
QgsTextShadowSettings::ShadowPlacement QgsTextRendererUtils::decodeShadowPlacementType( const QString &string )
|
||||
{
|
||||
const QString str = string.trimmed();
|
||||
// "Lowest"
|
||||
QgsTextShadowSettings::ShadowPlacement shdwtype = QgsTextShadowSettings::ShadowLowest;
|
||||
|
||||
if ( str.compare( QLatin1String( "Text" ), Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
shdwtype = QgsTextShadowSettings::ShadowText;
|
||||
}
|
||||
else if ( str.compare( QLatin1String( "Buffer" ), Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
shdwtype = QgsTextShadowSettings::ShadowBuffer;
|
||||
}
|
||||
else if ( str.compare( QLatin1String( "Background" ), Qt::CaseInsensitive ) == 0 )
|
||||
{
|
||||
shdwtype = QgsTextShadowSettings::ShadowShape;
|
||||
}
|
||||
return shdwtype;
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ class QgsTextSettingsPrivate;
|
||||
class QgsVectorLayer;
|
||||
class QgsPaintEffect;
|
||||
class QgsMarkerSymbol;
|
||||
class QgsPropertyCollection;
|
||||
|
||||
/**
|
||||
* \class QgsTextBufferSettings
|
||||
@ -43,7 +44,6 @@ class QgsMarkerSymbol;
|
||||
* \note QgsTextBufferSettings objects are implicitly shared.
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
|
||||
class CORE_EXPORT QgsTextBufferSettings
|
||||
{
|
||||
public:
|
||||
@ -226,6 +226,12 @@ class CORE_EXPORT QgsTextBufferSettings
|
||||
*/
|
||||
void setPaintEffect( QgsPaintEffect *effect SIP_TRANSFER );
|
||||
|
||||
/**
|
||||
* Updates the format by evaluating current values of data defined properties.
|
||||
* \since QGIS 3.10
|
||||
*/
|
||||
void updateDataDefinedProperties( QgsRenderContext &context, const QgsPropertyCollection &properties );
|
||||
|
||||
private:
|
||||
|
||||
QSharedDataPointer<QgsTextBufferSettingsPrivate> d;
|
||||
@ -700,6 +706,12 @@ class CORE_EXPORT QgsTextBackgroundSettings
|
||||
*/
|
||||
QDomElement writeXml( QDomDocument &doc, const QgsReadWriteContext &context ) const;
|
||||
|
||||
/**
|
||||
* Updates the format by evaluating current values of data defined properties.
|
||||
* \since QGIS 3.10
|
||||
*/
|
||||
void updateDataDefinedProperties( QgsRenderContext &context, const QgsPropertyCollection &properties );
|
||||
|
||||
private:
|
||||
|
||||
QSharedDataPointer<QgsTextBackgroundSettingsPrivate> d;
|
||||
@ -980,6 +992,12 @@ class CORE_EXPORT QgsTextShadowSettings
|
||||
*/
|
||||
QDomElement writeXml( QDomDocument &doc ) const;
|
||||
|
||||
/**
|
||||
* Updates the format by evaluating current values of data defined properties.
|
||||
* \since QGIS 3.10
|
||||
*/
|
||||
void updateDataDefinedProperties( QgsRenderContext &context, const QgsPropertyCollection &properties );
|
||||
|
||||
private:
|
||||
|
||||
QSharedDataPointer<QgsTextShadowSettingsPrivate> d;
|
||||
@ -1306,6 +1324,35 @@ class CORE_EXPORT QgsTextFormat
|
||||
*/
|
||||
QString resolvedFontFamily() const { return mTextFontFamily; }
|
||||
|
||||
/**
|
||||
* Returns a reference to the format's property collection, used for data defined overrides.
|
||||
* \see setDataDefinedProperties()
|
||||
* \since QGIS 3.10
|
||||
*/
|
||||
QgsPropertyCollection &dataDefinedProperties();
|
||||
|
||||
/**
|
||||
* Returns a reference to the format's property collection, used for data defined overrides.
|
||||
* \see setDataDefinedProperties()
|
||||
* \note not available in Python bindings
|
||||
* \since QGIS 3.10
|
||||
*/
|
||||
const QgsPropertyCollection &dataDefinedProperties() const SIP_SKIP;
|
||||
|
||||
/**
|
||||
* Sets the format's property collection, used for data defined overrides.
|
||||
* \param collection property collection. Existing properties will be replaced.
|
||||
* \see dataDefinedProperties()
|
||||
* \since QGIS 3.10
|
||||
*/
|
||||
void setDataDefinedProperties( const QgsPropertyCollection &collection );
|
||||
|
||||
/**
|
||||
* Updates the format by evaluating current values of data defined properties.
|
||||
* \since QGIS 3.10
|
||||
*/
|
||||
void updateDataDefinedProperties( QgsRenderContext &context );
|
||||
|
||||
/**
|
||||
* Returns a pixmap preview for a text \a format.
|
||||
* \param format text format
|
||||
@ -1550,4 +1597,37 @@ class CORE_EXPORT QgsTextRenderer
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* \class QgsTextRendererUtils
|
||||
* \ingroup core
|
||||
* Utility functions for text rendering.
|
||||
* \since QGIS 3.10
|
||||
*/
|
||||
class CORE_EXPORT QgsTextRendererUtils
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Decodes a string representation of a background shape type to a type.
|
||||
*/
|
||||
static QgsTextBackgroundSettings::ShapeType decodeShapeType( const QString &string );
|
||||
|
||||
/**
|
||||
* Decodes a string representation of a background size type to a type.
|
||||
*/
|
||||
static QgsTextBackgroundSettings::SizeType decodeBackgroundSizeType( const QString &string );
|
||||
|
||||
/**
|
||||
* Decodes a string representation of a background rotation type to a type.
|
||||
*/
|
||||
static QgsTextBackgroundSettings::RotationType decodeBackgroundRotationType( const QString &string );
|
||||
|
||||
/**
|
||||
* Decodes a string representation of a shadow placement type to a type.
|
||||
*/
|
||||
static QgsTextShadowSettings::ShadowPlacement decodeShadowPlacementType( const QString &string );
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // QGSTEXTRENDERER_H
|
||||
|
@ -218,6 +218,7 @@ class QgsTextSettingsPrivate : public QSharedData
|
||||
, blendMode( other.blendMode )
|
||||
, multilineHeight( other.multilineHeight )
|
||||
, previewBackgroundColor( other.previewBackgroundColor )
|
||||
, mDataDefinedProperties( other.mDataDefinedProperties )
|
||||
{
|
||||
}
|
||||
|
||||
@ -232,6 +233,10 @@ class QgsTextSettingsPrivate : public QSharedData
|
||||
double multilineHeight = 1.0 ; //0.0 to 10.0, leading between lines as multiplyer of line height
|
||||
QColor previewBackgroundColor = Qt::white;
|
||||
|
||||
//! Property collection for data defined settings
|
||||
QgsPropertyCollection mDataDefinedProperties;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -186,9 +186,13 @@ QString QgsSymbolLayerUtils::encodePenJoinStyle( Qt::PenJoinStyle style )
|
||||
|
||||
Qt::PenJoinStyle QgsSymbolLayerUtils::decodePenJoinStyle( const QString &str )
|
||||
{
|
||||
if ( str == QLatin1String( "bevel" ) ) return Qt::BevelJoin;
|
||||
if ( str == QLatin1String( "miter" ) ) return Qt::MiterJoin;
|
||||
if ( str == QLatin1String( "round" ) ) return Qt::RoundJoin;
|
||||
const QString cleaned = str.toLower().trimmed();
|
||||
if ( cleaned == QLatin1String( "bevel" ) )
|
||||
return Qt::BevelJoin;
|
||||
if ( cleaned == QLatin1String( "miter" ) )
|
||||
return Qt::MiterJoin;
|
||||
if ( cleaned == QLatin1String( "round" ) )
|
||||
return Qt::RoundJoin;
|
||||
return Qt::BevelJoin;
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,10 @@ from qgis.core import (QgsTextBufferSettings,
|
||||
QgsRectangle,
|
||||
QgsRenderChecker,
|
||||
QgsBlurEffect,
|
||||
QgsMarkerSymbol)
|
||||
QgsMarkerSymbol,
|
||||
QgsPalLayerSettings,
|
||||
QgsProperty,
|
||||
QgsFontUtils)
|
||||
from qgis.PyQt.QtGui import (QColor, QPainter, QFont, QImage, QBrush, QPen, QFontMetricsF)
|
||||
from qgis.PyQt.QtCore import (Qt, QSizeF, QPointF, QRectF, QDir, QSize)
|
||||
from qgis.PyQt.QtXml import QDomDocument
|
||||
@ -48,6 +51,7 @@ class PyQgsTextRenderer(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.report = "<h1>Python QgsTextRenderer Tests</h1>\n"
|
||||
QgsFontUtils.loadStandardTestFonts(['Bold', 'Oblique'])
|
||||
|
||||
def tearDown(self):
|
||||
report_file_path = "%s/qgistest.html" % QDir.tempPath()
|
||||
@ -289,6 +293,7 @@ class PyQgsTextRenderer(unittest.TestCase):
|
||||
s.setBlendMode(QPainter.CompositionMode_DestinationAtop)
|
||||
s.setLineHeight(5)
|
||||
s.setPreviewBackgroundColor(QColor(100, 150, 200))
|
||||
s.dataDefinedProperties().setProperty(QgsPalLayerSettings.Bold, QgsProperty.fromExpression('1>2'))
|
||||
return s
|
||||
|
||||
def checkTextFormat(self, s):
|
||||
@ -309,6 +314,7 @@ class PyQgsTextRenderer(unittest.TestCase):
|
||||
self.assertEqual(s.blendMode(), QPainter.CompositionMode_DestinationAtop)
|
||||
self.assertEqual(s.lineHeight(), 5)
|
||||
self.assertEqual(s.previewBackgroundColor().name(), '#6496c8')
|
||||
self.assertEqual(s.dataDefinedProperties().property(QgsPalLayerSettings.Bold).expressionString(), '1>2')
|
||||
|
||||
def testFormatGettersSetters(self):
|
||||
s = self.createFormatSettings()
|
||||
@ -372,6 +378,318 @@ class PyQgsTextRenderer(unittest.TestCase):
|
||||
t.shadow().setBlendMode(QPainter.CompositionMode_SourceOver)
|
||||
self.assertFalse(t.containsAdvancedEffects())
|
||||
|
||||
def testDataDefinedBufferSettings(self):
|
||||
f = QgsTextFormat()
|
||||
context = QgsRenderContext()
|
||||
|
||||
# buffer enabled
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.BufferDraw, QgsProperty.fromExpression('1'))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertTrue(f.buffer().enabled())
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.BufferDraw, QgsProperty.fromExpression('0'))
|
||||
context = QgsRenderContext()
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertFalse(f.buffer().enabled())
|
||||
|
||||
# buffer size
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.BufferSize, QgsProperty.fromExpression('7.8'))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.buffer().size(), 7.8)
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.BufferUnit, QgsProperty.fromExpression("'pixel'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.buffer().sizeUnit(), QgsUnitTypes.RenderPixels)
|
||||
|
||||
# buffer opacity
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.BufferOpacity, QgsProperty.fromExpression('37'))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.buffer().opacity(), 0.37)
|
||||
|
||||
# blend mode
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.BufferBlendMode, QgsProperty.fromExpression("'burn'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.buffer().blendMode(), QPainter.CompositionMode_ColorBurn)
|
||||
|
||||
# join style
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.BufferJoinStyle, QgsProperty.fromExpression("'miter'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.buffer().joinStyle(), Qt.MiterJoin)
|
||||
|
||||
# color
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.BufferColor, QgsProperty.fromExpression("'#ff0088'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.buffer().color().name(), '#ff0088')
|
||||
|
||||
def testDataDefinedBackgroundSettings(self):
|
||||
f = QgsTextFormat()
|
||||
context = QgsRenderContext()
|
||||
|
||||
# background enabled
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShapeDraw, QgsProperty.fromExpression('1'))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertTrue(f.background().enabled())
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShapeDraw, QgsProperty.fromExpression('0'))
|
||||
context = QgsRenderContext()
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertFalse(f.background().enabled())
|
||||
|
||||
# background size
|
||||
f.background().setSize(QSizeF(13, 14))
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShapeSizeX, QgsProperty.fromExpression('7.8'))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.background().size().width(), 7.8)
|
||||
self.assertEqual(f.background().size().height(), 14)
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShapeSizeY, QgsProperty.fromExpression('17.8'))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.background().size().width(), 7.8)
|
||||
self.assertEqual(f.background().size().height(), 17.8)
|
||||
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShapeSizeUnits, QgsProperty.fromExpression("'pixel'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.background().sizeUnit(), QgsUnitTypes.RenderPixels)
|
||||
|
||||
# shape kind
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShapeKind, QgsProperty.fromExpression("'square'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.background().type(), QgsTextBackgroundSettings.ShapeSquare)
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShapeKind, QgsProperty.fromExpression("'ellipse'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.background().type(), QgsTextBackgroundSettings.ShapeEllipse)
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShapeKind, QgsProperty.fromExpression("'circle'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.background().type(), QgsTextBackgroundSettings.ShapeCircle)
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShapeKind, QgsProperty.fromExpression("'svg'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.background().type(), QgsTextBackgroundSettings.ShapeSVG)
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShapeKind, QgsProperty.fromExpression("'marker'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.background().type(), QgsTextBackgroundSettings.ShapeMarkerSymbol)
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShapeKind, QgsProperty.fromExpression("'rect'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.background().type(), QgsTextBackgroundSettings.ShapeRectangle)
|
||||
|
||||
# size type
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShapeSizeType, QgsProperty.fromExpression("'fixed'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.background().sizeType(), QgsTextBackgroundSettings.SizeFixed)
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShapeSizeType, QgsProperty.fromExpression("'buffer'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.background().sizeType(), QgsTextBackgroundSettings.SizeBuffer)
|
||||
|
||||
# svg path
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShapeSVGFile, QgsProperty.fromExpression("'my.svg'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.background().svgFile(), 'my.svg')
|
||||
|
||||
# shape rotation
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShapeRotation, QgsProperty.fromExpression('67'))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.background().rotation(), 67)
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShapeRotationType, QgsProperty.fromExpression("'offset'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.background().rotationType(), QgsTextBackgroundSettings.RotationOffset)
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShapeRotationType, QgsProperty.fromExpression("'fixed'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.background().rotationType(), QgsTextBackgroundSettings.RotationFixed)
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShapeRotationType, QgsProperty.fromExpression("'sync'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.background().rotationType(), QgsTextBackgroundSettings.RotationSync)
|
||||
|
||||
# shape offset
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShapeOffset, QgsProperty.fromExpression("'7,9'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.background().offset(), QPointF(7, 9))
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShapeOffsetUnits, QgsProperty.fromExpression("'pixel'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.background().offsetUnit(), QgsUnitTypes.RenderPixels)
|
||||
|
||||
# shape radii
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShapeRadii, QgsProperty.fromExpression("'18,19'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.background().radii(), QSizeF(18, 19))
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShapeRadiiUnits, QgsProperty.fromExpression("'pixel'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.background().radiiUnit(), QgsUnitTypes.RenderPixels)
|
||||
|
||||
# shape opacity
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShapeOpacity, QgsProperty.fromExpression('37'))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.background().opacity(), 0.37)
|
||||
|
||||
# color
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShapeFillColor, QgsProperty.fromExpression("'#ff0088'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.background().fillColor().name(), '#ff0088')
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShapeStrokeColor, QgsProperty.fromExpression("'#8800ff'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.background().strokeColor().name(), '#8800ff')
|
||||
|
||||
# stroke width
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShapeStrokeWidth, QgsProperty.fromExpression('88'))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.background().strokeWidth(), 88)
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShapeStrokeWidthUnits, QgsProperty.fromExpression("'pixel'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.background().strokeWidthUnit(), QgsUnitTypes.RenderPixels)
|
||||
|
||||
# blend mode
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShapeBlendMode, QgsProperty.fromExpression("'burn'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.background().blendMode(), QPainter.CompositionMode_ColorBurn)
|
||||
|
||||
# join style
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShapeJoinStyle, QgsProperty.fromExpression("'miter'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.background().joinStyle(), Qt.MiterJoin)
|
||||
|
||||
def testDataDefinedShadowSettings(self):
|
||||
f = QgsTextFormat()
|
||||
context = QgsRenderContext()
|
||||
|
||||
# shadow enabled
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShadowDraw, QgsProperty.fromExpression('1'))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertTrue(f.shadow().enabled())
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShadowDraw, QgsProperty.fromExpression('0'))
|
||||
context = QgsRenderContext()
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertFalse(f.shadow().enabled())
|
||||
|
||||
# placement type
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShadowUnder, QgsProperty.fromExpression("'text'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.shadow().shadowPlacement(), QgsTextShadowSettings.ShadowText)
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShadowUnder, QgsProperty.fromExpression("'buffer'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.shadow().shadowPlacement(), QgsTextShadowSettings.ShadowBuffer)
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShadowUnder, QgsProperty.fromExpression("'background'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.shadow().shadowPlacement(), QgsTextShadowSettings.ShadowShape)
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShadowUnder, QgsProperty.fromExpression("'svg'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.shadow().shadowPlacement(), QgsTextShadowSettings.ShadowLowest)
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShadowUnder, QgsProperty.fromExpression("'lowest'"))
|
||||
|
||||
# offset angle
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShadowOffsetAngle, QgsProperty.fromExpression('67'))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.shadow().offsetAngle(), 67)
|
||||
|
||||
# offset distance
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShadowOffsetDist, QgsProperty.fromExpression('38'))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.shadow().offsetDistance(), 38)
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShadowOffsetUnits, QgsProperty.fromExpression("'pixel'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.shadow().offsetUnit(), QgsUnitTypes.RenderPixels)
|
||||
|
||||
# radius
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShadowRadius, QgsProperty.fromExpression('58'))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.shadow().blurRadius(), 58)
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShadowRadiusUnits, QgsProperty.fromExpression("'pixel'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.shadow().blurRadiusUnit(), QgsUnitTypes.RenderPixels)
|
||||
|
||||
# opacity
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShadowOpacity, QgsProperty.fromExpression('37'))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.shadow().opacity(), 0.37)
|
||||
|
||||
# color
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShadowColor, QgsProperty.fromExpression("'#ff0088'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.shadow().color().name(), '#ff0088')
|
||||
|
||||
# blend mode
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.ShadowBlendMode, QgsProperty.fromExpression("'burn'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.shadow().blendMode(), QPainter.CompositionMode_ColorBurn)
|
||||
|
||||
def testDataDefinedFormatSettings(self):
|
||||
f = QgsTextFormat()
|
||||
font = f.font()
|
||||
font.setUnderline(True)
|
||||
font.setStrikeOut(True)
|
||||
font.setWordSpacing(5.7)
|
||||
font.setLetterSpacing(QFont.AbsoluteSpacing, 3.3)
|
||||
f.setFont(font)
|
||||
context = QgsRenderContext()
|
||||
|
||||
# family
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Family, QgsProperty.fromExpression("'{}'".format(QgsFontUtils.getStandardTestFont().family())))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.font().family(), QgsFontUtils.getStandardTestFont().family())
|
||||
|
||||
# style
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.FontStyle, QgsProperty.fromExpression("'Bold'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.font().styleName(), 'Bold')
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.FontStyle, QgsProperty.fromExpression("'Roman'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.font().styleName(), 'Roman')
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Bold, QgsProperty.fromExpression("1"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertTrue(f.font().bold())
|
||||
self.assertFalse(f.font().italic())
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Bold, QgsProperty.fromExpression("0"))
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Italic, QgsProperty.fromExpression("1"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertFalse(f.font().bold())
|
||||
self.assertTrue(f.font().italic())
|
||||
self.assertTrue(f.font().underline())
|
||||
self.assertTrue(f.font().strikeOut())
|
||||
self.assertAlmostEqual(f.font().wordSpacing(), 5.7, 1)
|
||||
self.assertAlmostEqual(f.font().letterSpacing(), 3.3, 1)
|
||||
|
||||
# underline
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Underline, QgsProperty.fromExpression("0"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertFalse(f.font().underline())
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Underline, QgsProperty.fromExpression("1"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertTrue(f.font().underline())
|
||||
|
||||
# strikeout
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Strikeout, QgsProperty.fromExpression("0"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertFalse(f.font().strikeOut())
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Strikeout, QgsProperty.fromExpression("1"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertTrue(f.font().strikeOut())
|
||||
|
||||
# color
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Color, QgsProperty.fromExpression("'#ff0088'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.color().name(), '#ff0088')
|
||||
|
||||
# size
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.Size, QgsProperty.fromExpression('38'))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.size(), 38)
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.FontSizeUnit, QgsProperty.fromExpression("'pixel'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.sizeUnit(), QgsUnitTypes.RenderPixels)
|
||||
|
||||
# opacity
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.FontOpacity, QgsProperty.fromExpression('37'))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.opacity(), 0.37)
|
||||
|
||||
# letter spacing
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.FontLetterSpacing, QgsProperty.fromExpression('58'))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.font().letterSpacing(), 58)
|
||||
|
||||
# word spacing
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.FontWordSpacing, QgsProperty.fromExpression('8'))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.font().wordSpacing(), 8)
|
||||
|
||||
# blend mode
|
||||
f.dataDefinedProperties().setProperty(QgsPalLayerSettings.FontBlendMode, QgsProperty.fromExpression("'burn'"))
|
||||
f.updateDataDefinedProperties(context)
|
||||
self.assertEqual(f.blendMode(), QPainter.CompositionMode_ColorBurn)
|
||||
|
||||
def testFontFoundFromLayer(self):
|
||||
layer = createEmptyLayer()
|
||||
layer.setCustomProperty('labeling/fontFamily', 'asdasd')
|
||||
@ -1733,6 +2051,35 @@ class PyQgsTextRenderer(unittest.TestCase):
|
||||
assert self.checkRenderPoint(format, 'text_point_center_aligned', text=['test'],
|
||||
alignment=QgsTextRenderer.AlignCenter, point=QPointF(200, 200))
|
||||
|
||||
def testDrawTextDataDefinedColorPoint(self):
|
||||
format = QgsTextFormat()
|
||||
format.setFont(getTestFont('bold'))
|
||||
format.setSize(60)
|
||||
format.setSizeUnit(QgsUnitTypes.RenderPoints)
|
||||
format.setColor(QColor(0, 255, 0))
|
||||
format.dataDefinedProperties().setProperty(QgsPalLayerSettings.Color, QgsProperty.fromExpression("'#bb00cc'"))
|
||||
assert self.checkRenderPoint(format, 'text_dd_color_point', None, text=['test'], point=QPointF(50, 200))
|
||||
|
||||
def testDrawTextDataDefinedColorRect(self):
|
||||
format = QgsTextFormat()
|
||||
format.setFont(getTestFont('bold'))
|
||||
format.setSize(60)
|
||||
format.setSizeUnit(QgsUnitTypes.RenderPoints)
|
||||
format.setColor(QColor(0, 255, 0))
|
||||
format.dataDefinedProperties().setProperty(QgsPalLayerSettings.Color, QgsProperty.fromExpression("'#bb00cc'"))
|
||||
assert self.checkRender(format, 'text_dd_color_rect', None, text=['test'], alignment=QgsTextRenderer.AlignCenter, rect=QRectF(100, 100, 100, 100))
|
||||
|
||||
def testDrawTextDataDefinedBufferColorPoint(self):
|
||||
format = QgsTextFormat()
|
||||
format.setFont(getTestFont('bold'))
|
||||
format.setSize(60)
|
||||
format.setSizeUnit(QgsUnitTypes.RenderPoints)
|
||||
format.setColor(QColor(0, 255, 0))
|
||||
format.dataDefinedProperties().setProperty(QgsPalLayerSettings.BufferColor, QgsProperty.fromExpression("'#bb00cc'"))
|
||||
format.buffer().setEnabled(True)
|
||||
format.buffer().setSize(5)
|
||||
assert self.checkRenderPoint(format, 'text_dd_buffer_color', None, text=['test'], point=QPointF(50, 200))
|
||||
|
||||
def testTextRenderFormat(self):
|
||||
format = QgsTextFormat()
|
||||
format.setFont(getTestFont('bold'))
|
||||
|
BIN
tests/testdata/control_images/text_renderer/text_dd_buffer_color/text_dd_buffer_color.png
vendored
Normal file
BIN
tests/testdata/control_images/text_renderer/text_dd_buffer_color/text_dd_buffer_color.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.9 KiB |
BIN
tests/testdata/control_images/text_renderer/text_dd_color_point/text_dd_color_point.png
vendored
Normal file
BIN
tests/testdata/control_images/text_renderer/text_dd_color_point/text_dd_color_point.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.8 KiB |
BIN
tests/testdata/control_images/text_renderer/text_dd_color_rect/text_dd_color_rect.png
vendored
Normal file
BIN
tests/testdata/control_images/text_renderer/text_dd_color_rect/text_dd_color_rect.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.8 KiB |
Loading…
x
Reference in New Issue
Block a user