Skip to content
Permalink
Browse files

[FEATURE][symbology] Add data-defined property to font family/style f…

…or font markers (#35224)
  • Loading branch information
nirvn committed Mar 22, 2020
1 parent 2b58ee3 commit f3e2ef1fe72e5ab18123101db00c0d3746ad6231
@@ -877,8 +877,6 @@ class QgsFontMarkerSymbolLayer : QgsMarkerSymbolLayer
Constructs a font marker symbol layer.
%End

~QgsFontMarkerSymbolLayer();


static QgsSymbolLayer *create( const QgsStringMap &properties = QgsStringMap() ) /Factory/;
%Docstring
@@ -1061,10 +1059,6 @@ Sets the stroke join ``style``.
virtual QRectF bounds( QPointF point, QgsSymbolRenderContext &context );


protected:



};


@@ -143,6 +143,8 @@ class QgsSymbolLayer
PropertyRandomSeed,
PropertyClipPoints,
PropertyDensityArea,
PropertyFontFamily,
PropertyFontStyle,
};

static const QgsPropertiesDefinition &propertyDefinitions();
@@ -2959,11 +2959,6 @@ QgsFontMarkerSymbolLayer::QgsFontMarkerSymbolLayer( const QString &fontFamily, Q
mPenJoinStyle = DEFAULT_FONTMARKER_JOINSTYLE;
}

QgsFontMarkerSymbolLayer::~QgsFontMarkerSymbolLayer()
{
delete mFontMetrics;
}

QgsSymbolLayer *QgsFontMarkerSymbolLayer::create( const QgsStringMap &props )
{
QString fontFamily = DEFAULT_FONTMARKER_FONT;
@@ -3047,8 +3042,7 @@ void QgsFontMarkerSymbolLayer::startRender( QgsSymbolRenderContext &context )
// if a non zero, but small pixel size results, round up to 2 pixels so that a "dot" is at least visible
// (if we set a <=1 pixel size here Qt will reset the font to a default size, leading to much too large symbols)
mFont.setPixelSize( std::max( 2, static_cast< int >( std::round( sizePixels ) ) ) );
delete mFontMetrics;
mFontMetrics = new QFontMetrics( mFont );
mFontMetrics.reset( new QFontMetrics( mFont ) );
#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
mChrWidth = mFontMetrics->width( mString );
#else
@@ -3058,7 +3052,9 @@ void QgsFontMarkerSymbolLayer::startRender( QgsSymbolRenderContext &context )
mOrigSize = mSize; // save in case the size would be data defined

// use caching only when not using a data defined character
mUseCachedPath = !mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyCharacter );
mUseCachedPath = !mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyFontFamily ) &&
!mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyFontStyle ) &&
!mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyCharacter );
if ( mUseCachedPath )
{
QPointF chrOffset = mChrOffset;
@@ -3230,6 +3226,23 @@ void QgsFontMarkerSymbolLayer::renderPoint( QPointF point, QgsSymbolRenderContex
p->setPen( Qt::NoPen );
}

if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyFontFamily ) )
{
context.setOriginalValueVariable( mFontFamily );
QString fontFamily = mDataDefinedProperties.valueAsString( QgsSymbolLayer::PropertyFontFamily, context.renderContext().expressionContext(), mFontFamily, &ok );
mFont.setFamily( ok ? fontFamily : mFontFamily );
}
if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyFontStyle ) )
{
context.setOriginalValueVariable( mFontStyle );
QString fontStyle = mDataDefinedProperties.valueAsString( QgsSymbolLayer::PropertyFontStyle, context.renderContext().expressionContext(), mFontStyle, &ok );
mFont.setStyleName( QgsFontUtils::translateNamedStyle( ok ? fontStyle : mFontStyle ) );
}
if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyFontFamily ) || mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyFontStyle ) )
{
mFontMetrics.reset( new QFontMetrics( mFont ) );
}

QPointF chrOffset = mChrOffset;
double chrWidth;
QString charToRender = characterToRender( context, chrOffset, chrWidth );
@@ -3349,7 +3362,7 @@ QRectF QgsFontMarkerSymbolLayer::bounds( QPointF point, QgsSymbolRenderContext &
( void )characterToRender( context, chrOffset, chrWidth );

if ( !mFontMetrics )
mFontMetrics = new QFontMetrics( mFont );
mFontMetrics.reset( new QFontMetrics( mFont ) );

double scaledSize = calculateSize( context );
if ( !qgsDoubleNear( scaledSize, mOrigSize ) )
@@ -808,8 +808,6 @@ class CORE_EXPORT QgsFontMarkerSymbolLayer : public QgsMarkerSymbolLayer
const QColor &color = DEFAULT_FONTMARKER_COLOR,
double angle = DEFAULT_FONTMARKER_ANGLE );

~QgsFontMarkerSymbolLayer() override;

// static stuff

/**
@@ -972,20 +970,19 @@ class CORE_EXPORT QgsFontMarkerSymbolLayer : public QgsMarkerSymbolLayer

QRectF bounds( QPointF point, QgsSymbolRenderContext &context ) override;

protected:
private:

QString mFontFamily;
QString mFontStyle;
QFontMetrics *mFontMetrics = nullptr;
QFont mFont;
std::unique_ptr< QFontMetrics >mFontMetrics;

QString mString;

double mChrWidth = 0;
QPointF mChrOffset;
QFont mFont;
double mOrigSize;

private:

QColor mStrokeColor;
double mStrokeWidth;
QgsUnitTypes::RenderUnit mStrokeWidthUnit;
@@ -53,6 +53,8 @@ void QgsSymbolLayer::initPropertyDefinitions()
{ QgsSymbolLayer::PropertyStrokeStyle, QgsPropertyDefinition( "outlineStyle", QObject::tr( "Symbol stroke style" ), QgsPropertyDefinition::LineStyle, origin )},
{ QgsSymbolLayer::PropertyOffset, QgsPropertyDefinition( "offset", QObject::tr( "Symbol offset" ), QgsPropertyDefinition::Offset, origin )},
{ QgsSymbolLayer::PropertyCharacter, QgsPropertyDefinition( "char", QObject::tr( "Marker character(s)" ), QgsPropertyDefinition::String, origin )},
{ QgsSymbolLayer::PropertyFontFamily, QgsPropertyDefinition( "fontFamily", QObject::tr( "Font family" ), QgsPropertyDefinition::String, origin )},
{ QgsSymbolLayer::PropertyFontStyle, QgsPropertyDefinition( "fontStyle", QObject::tr( "Font style" ), QgsPropertyDefinition::String, origin )},
{ QgsSymbolLayer::PropertyWidth, QgsPropertyDefinition( "width", QObject::tr( "Symbol width" ), QgsPropertyDefinition::DoublePositive, origin )},
{ QgsSymbolLayer::PropertyHeight, QgsPropertyDefinition( "height", QObject::tr( "Symbol height" ), QgsPropertyDefinition::DoublePositive, origin )},
{ QgsSymbolLayer::PropertyPreserveAspectRatio, QgsPropertyDefinition( "preserveAspectRatio", QObject::tr( "Preserve aspect ratio between width and height" ), QgsPropertyDefinition::Boolean, origin )},
@@ -185,6 +185,8 @@ class CORE_EXPORT QgsSymbolLayer
PropertyRandomSeed, //!< Random number seed
PropertyClipPoints, //!< Whether markers should be clipped to polygon boundaries
PropertyDensityArea, //<! Density area
PropertyFontFamily, //!< Font family
PropertyFontStyle, //!< Font style
};

/**
@@ -3390,6 +3390,8 @@ void QgsFontMarkerSymbolLayerWidget::setSymbolLayer( QgsSymbolLayer *layer )
whileBlocking( mHorizontalAnchorComboBox )->setCurrentIndex( mLayer->horizontalAnchorPoint() );
whileBlocking( mVerticalAnchorComboBox )->setCurrentIndex( mLayer->verticalAnchorPoint() );

registerDataDefinedButton( mFontFamilyDDBtn, QgsSymbolLayer::PropertyFontFamily );
registerDataDefinedButton( mFontStyleDDBtn, QgsSymbolLayer::PropertyFontStyle );
registerDataDefinedButton( mSizeDDBtn, QgsSymbolLayer::PropertySize );
registerDataDefinedButton( mRotationDDBtn, QgsSymbolLayer::PropertyAngle );
registerDataDefinedButton( mColorDDBtn, QgsSymbolLayer::PropertyFillColor );
@@ -120,6 +120,13 @@
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QgsPropertyOverrideButton" name="mFontStyleDDBtn">
<property name="text">
<string>…</string>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
@@ -206,6 +213,13 @@
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QgsPropertyOverrideButton" name="mFontFamilyDDBtn">
<property name="text">
<string>…</string>
</property>
</widget>
</item>
<item row="11" column="0" rowspan="3">
<widget class="QLabel" name="mAnchorPointLabel">
<property name="text">
@@ -58,6 +58,7 @@ class TestQgsFontMarkerSymbol : public QObject
void fontMarkerSymbolStyle();
void fontMarkerSymbolStroke();
void bounds();
void fontMarkerSymbolDataDefinedProperties();

private:
bool mTestHasError = false ;
@@ -156,6 +157,30 @@ void TestQgsFontMarkerSymbol::fontMarkerSymbolStyle()
QgsFontUtils::loadStandardTestFonts( QStringList() << QStringLiteral( "Bold" ) );
}

void TestQgsFontMarkerSymbol::fontMarkerSymbolDataDefinedProperties()
{
mReport += QLatin1String( "<h2>Font marker symbol data defined properties layer test</h2>\n" );

QgsFontUtils::loadStandardTestFonts( QStringList() << QStringLiteral( "Bold" ) << QStringLiteral( "Oblique" ) );
mFontMarkerLayer->setColor( Qt::blue );
QFont font = QgsFontUtils::getStandardTestFont( QStringLiteral( "Bold" ) );
mFontMarkerLayer->setFontFamily( font.family() );
mFontMarkerLayer->setFontStyle( QStringLiteral( "Bold" ) );
mFontMarkerLayer->setDataDefinedProperty( QgsSymbolLayer::PropertyFontStyle, QgsProperty::fromExpression( QStringLiteral( "'Oblique'" ) ) );
mFontMarkerLayer->setCharacter( QChar( 'Z' ) );
mFontMarkerLayer->setDataDefinedProperty( QgsSymbolLayer::PropertyCharacter, QgsProperty::fromExpression( QStringLiteral( "'A'" ) ) );
mFontMarkerLayer->setSize( 12 );
mFontMarkerLayer->setDataDefinedProperty( QgsSymbolLayer::PropertySize, QgsProperty::fromExpression( QStringLiteral( "12" ) ) );
QVERIFY( imageCheck( "fontmarker_datadefinedproperties" ) );

mFontMarkerLayer->setDataDefinedProperties( QgsPropertyCollection() );

// Loading both Bold and Oblique in the initTestCase() function creates inconsistent results on windows and linux, this is a workaround
QFontDatabase fontDb;
fontDb.removeAllApplicationFonts();
QgsFontUtils::loadStandardTestFonts( QStringList() << QStringLiteral( "Bold" ) );
}

void TestQgsFontMarkerSymbol::fontMarkerSymbolStroke()
{
mFontMarkerLayer->setColor( Qt::blue );
Binary file not shown.
Binary file not shown.

0 comments on commit f3e2ef1

Please sign in to comment.
You can’t perform that action at this time.