Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[FEATURE][symbology] Unlock string as character for font markers
  • Loading branch information
nirvn committed Apr 30, 2019
1 parent 0f01359 commit 3747cf7
Show file tree
Hide file tree
Showing 9 changed files with 76 additions and 45 deletions.
14 changes: 9 additions & 5 deletions python/core/auto_generated/symbology/qgsmarkersymbollayer.sip.in
Expand Up @@ -867,11 +867,15 @@ class QgsFontMarkerSymbolLayer : QgsMarkerSymbolLayer
#include "qgsmarkersymbollayer.h"
%End
public:

QgsFontMarkerSymbolLayer( const QString &fontFamily = DEFAULT_FONTMARKER_FONT,
QChar chr = DEFAULT_FONTMARKER_CHR,
QString chr = DEFAULT_FONTMARKER_CHR,
double pointSize = DEFAULT_FONTMARKER_SIZE,
const QColor &color = DEFAULT_FONTMARKER_COLOR,
double angle = DEFAULT_FONTMARKER_ANGLE );
%Docstring
Constructs a font marker symbol layer.
%End

~QgsFontMarkerSymbolLayer();

Expand Down Expand Up @@ -923,16 +927,16 @@ Sets the font ``family`` for the font which will be used to render the point.
.. seealso:: :py:func:`fontFamily`
%End

QChar character() const;
QString character() const;
%Docstring
Returns the character used when rendering points.
Returns the character(s) used when rendering points.

.. seealso:: :py:func:`setCharacter`
%End

void setCharacter( QChar ch );
void setCharacter( QString chr );
%Docstring
Sets the character used when rendering points.
Sets the character(s) used when rendering points.

.. seealso:: :py:func:`character`
%End
Expand Down
9 changes: 9 additions & 0 deletions python/gui/auto_generated/symbology/characterwidget.sip.in
Expand Up @@ -101,6 +101,15 @@ Sets the currently selected ``character`` in the widget.
.. seealso:: :py:func:`character`

.. seealso:: :py:func:`characterSelected`
%End

void clearCharacter();
%Docstring
Clears the currently selected character in the widget.

.. seealso:: :py:func:`character`

.. seealso:: :py:func:`setCharacter`
%End

signals:
Expand Down
32 changes: 16 additions & 16 deletions src/core/symbology/qgsmarkersymbollayer.cpp
Expand Up @@ -2923,10 +2923,10 @@ QRectF QgsRasterMarkerSymbolLayer::bounds( QPointF point, QgsSymbolRenderContext

//////////

QgsFontMarkerSymbolLayer::QgsFontMarkerSymbolLayer( const QString &fontFamily, QChar chr, double pointSize, const QColor &color, double angle )
QgsFontMarkerSymbolLayer::QgsFontMarkerSymbolLayer( const QString &fontFamily, QString chr, double pointSize, const QColor &color, double angle )
{
mFontFamily = fontFamily;
mChr = chr;
mString = chr;
mColor = color;
mAngle = angle;
mSize = pointSize;
Expand All @@ -2948,23 +2948,23 @@ QgsFontMarkerSymbolLayer::~QgsFontMarkerSymbolLayer()
QgsSymbolLayer *QgsFontMarkerSymbolLayer::create( const QgsStringMap &props )
{
QString fontFamily = DEFAULT_FONTMARKER_FONT;
QChar chr = DEFAULT_FONTMARKER_CHR;
QString string = DEFAULT_FONTMARKER_CHR;
double pointSize = DEFAULT_FONTMARKER_SIZE;
QColor color = DEFAULT_FONTMARKER_COLOR;
double angle = DEFAULT_FONTMARKER_ANGLE;

if ( props.contains( QStringLiteral( "font" ) ) )
fontFamily = props[QStringLiteral( "font" )];
if ( props.contains( QStringLiteral( "chr" ) ) && props[QStringLiteral( "chr" )].length() > 0 )
chr = props[QStringLiteral( "chr" )].at( 0 );
string = props[QStringLiteral( "chr" )];
if ( props.contains( QStringLiteral( "size" ) ) )
pointSize = props[QStringLiteral( "size" )].toDouble();
if ( props.contains( QStringLiteral( "color" ) ) )
color = QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "color" )] );
if ( props.contains( QStringLiteral( "angle" ) ) )
angle = props[QStringLiteral( "angle" )].toDouble();

QgsFontMarkerSymbolLayer *m = new QgsFontMarkerSymbolLayer( fontFamily, chr, pointSize, color, angle );
QgsFontMarkerSymbolLayer *m = new QgsFontMarkerSymbolLayer( fontFamily, string, pointSize, color, angle );

if ( props.contains( QStringLiteral( "outline_color" ) ) )
m->setStrokeColor( QgsSymbolLayerUtils::decodeColor( props[QStringLiteral( "outline_color" )] ) );
Expand Down Expand Up @@ -3018,7 +3018,7 @@ void QgsFontMarkerSymbolLayer::startRender( QgsSymbolRenderContext &context )
mFont.setPixelSize( context.renderContext().convertToPainterUnits( mSize, mSizeUnit, mSizeMapUnitScale ) );
delete mFontMetrics;
mFontMetrics = new QFontMetrics( mFont );
mChrWidth = mFontMetrics->width( mChr );
mChrWidth = mFontMetrics->width( mString );
mChrOffset = QPointF( mChrWidth / 2.0, -mFontMetrics->ascent() / 2.0 );
mOrigSize = mSize; // save in case the size would be data defined
}
Expand All @@ -3031,18 +3031,18 @@ void QgsFontMarkerSymbolLayer::stopRender( QgsSymbolRenderContext &context )
QString QgsFontMarkerSymbolLayer::characterToRender( QgsSymbolRenderContext &context, QPointF &charOffset, double &charWidth )
{
charOffset = mChrOffset;
QString charToRender = mChr;
QString stringToRender = mString;
if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyCharacter ) )
{
context.setOriginalValueVariable( mChr );
charToRender = mDataDefinedProperties.valueAsString( QgsSymbolLayer::PropertyCharacter, context.renderContext().expressionContext(), mChr );
if ( charToRender != mChr )
context.setOriginalValueVariable( mString );
stringToRender = mDataDefinedProperties.valueAsString( QgsSymbolLayer::PropertyCharacter, context.renderContext().expressionContext(), mString );
if ( stringToRender != mString )
{
charWidth = mFontMetrics->width( charToRender );
charWidth = mFontMetrics->width( stringToRender );
charOffset = QPointF( charWidth / 2.0, -mFontMetrics->ascent() / 2.0 );
}
}
return charToRender;
return stringToRender;
}

void QgsFontMarkerSymbolLayer::calculateOffsetAndRotation( QgsSymbolRenderContext &context,
Expand Down Expand Up @@ -3210,7 +3210,7 @@ QgsStringMap QgsFontMarkerSymbolLayer::properties() const
{
QgsStringMap props;
props[QStringLiteral( "font" )] = mFontFamily;
props[QStringLiteral( "chr" )] = mChr;
props[QStringLiteral( "chr" )] = mString;
props[QStringLiteral( "size" )] = QString::number( mSize );
props[QStringLiteral( "size_unit" )] = QgsUnitTypes::encodeUnit( mSizeUnit );
props[QStringLiteral( "size_map_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( mSizeMapUnitScale );
Expand All @@ -3231,7 +3231,7 @@ QgsStringMap QgsFontMarkerSymbolLayer::properties() const

QgsFontMarkerSymbolLayer *QgsFontMarkerSymbolLayer::clone() const
{
QgsFontMarkerSymbolLayer *m = new QgsFontMarkerSymbolLayer( mFontFamily, mChr, mSize, mColor, mAngle );
QgsFontMarkerSymbolLayer *m = new QgsFontMarkerSymbolLayer( mFontFamily, mString, mSize, mColor, mAngle );
m->setStrokeColor( mStrokeColor );
m->setStrokeWidth( mStrokeWidth );
m->setStrokeWidthUnit( mStrokeWidthUnit );
Expand All @@ -3256,7 +3256,7 @@ void QgsFontMarkerSymbolLayer::writeSldMarker( QDomDocument &doc, QDomElement &e
element.appendChild( graphicElem );

QString fontPath = QStringLiteral( "ttf://%1" ).arg( mFontFamily );
int markIndex = mChr.unicode();
int markIndex = !mString.isEmpty() ? mString.at( 0 ).unicode() : 0;
double size = QgsSymbolLayerUtils::rescaleUom( mSize, mSizeUnit, props );
QgsSymbolLayerUtils::externalMarkerToSld( doc, graphicElem, fontPath, QStringLiteral( "ttf" ), &markIndex, mColor, size );

Expand Down Expand Up @@ -3355,7 +3355,7 @@ QgsSymbolLayer *QgsFontMarkerSymbolLayer::createFromSld( QDomElement &element )
offset.setY( QgsSymbolLayerUtils::sizeInPixelsFromSldUom( uom, offset.y() ) );
size = QgsSymbolLayerUtils::sizeInPixelsFromSldUom( uom, size );

QgsMarkerSymbolLayer *m = new QgsFontMarkerSymbolLayer( fontFamily, chr, size, color );
QgsMarkerSymbolLayer *m = new QgsFontMarkerSymbolLayer( fontFamily, QChar( chr ), size, color );
m->setOutputUnit( QgsUnitTypes::RenderUnit::RenderPixels );
m->setAngle( angle );
m->setOffset( offset );
Expand Down
14 changes: 8 additions & 6 deletions src/core/symbology/qgsmarkersymbollayer.h
Expand Up @@ -800,8 +800,10 @@ class CORE_EXPORT QgsRasterMarkerSymbolLayer : public QgsMarkerSymbolLayer
class CORE_EXPORT QgsFontMarkerSymbolLayer : public QgsMarkerSymbolLayer
{
public:

//! Constructs a font marker symbol layer.
QgsFontMarkerSymbolLayer( const QString &fontFamily = DEFAULT_FONTMARKER_FONT,
QChar chr = DEFAULT_FONTMARKER_CHR,
QString chr = DEFAULT_FONTMARKER_CHR,
double pointSize = DEFAULT_FONTMARKER_SIZE,
const QColor &color = DEFAULT_FONTMARKER_COLOR,
double angle = DEFAULT_FONTMARKER_ANGLE );
Expand Down Expand Up @@ -853,18 +855,18 @@ class CORE_EXPORT QgsFontMarkerSymbolLayer : public QgsMarkerSymbolLayer
void setFontFamily( const QString &family ) { mFontFamily = family; }

/**
* Returns the character used when rendering points.
* Returns the character(s) used when rendering points.
*
* \see setCharacter()
*/
QChar character() const { return mChr; }
QString character() const { return mString; }

/**
* Sets the character used when rendering points.
* Sets the character(s) used when rendering points.
*
* \see character()
*/
void setCharacter( QChar ch ) { mChr = ch; }
void setCharacter( QString chr ) { mString = chr; }

QColor strokeColor() const override { return mStrokeColor; }
void setStrokeColor( const QColor &color ) override { mStrokeColor = color; }
Expand Down Expand Up @@ -958,7 +960,7 @@ class CORE_EXPORT QgsFontMarkerSymbolLayer : public QgsMarkerSymbolLayer

QString mFontFamily;
QFontMetrics *mFontMetrics = nullptr;
QChar mChr;
QString mString;

double mChrWidth = 0;
QPointF mChrOffset;
Expand Down
6 changes: 6 additions & 0 deletions src/gui/symbology/characterwidget.cpp
Expand Up @@ -122,6 +122,12 @@ void CharacterWidget::setCharacter( QChar character )
update();
}

void CharacterWidget::clearCharacter()
{
mLastKey = -1;
update();
}

QSize CharacterWidget::sizeHint() const
{
return QSize( mColumns * mSquareSize, ( 65536 / mColumns ) * mSquareSize );
Expand Down
7 changes: 7 additions & 0 deletions src/gui/symbology/characterwidget.h
Expand Up @@ -142,6 +142,13 @@ class GUI_EXPORT CharacterWidget : public QWidget
*/
void setCharacter( QChar character );

/**
* Clears the currently selected character in the widget.
* \see character()
* \see setCharacter()
*/
void clearCharacter();

signals:

/**
Expand Down
29 changes: 16 additions & 13 deletions src/gui/symbology/qgssymbollayerwidget.cpp
Expand Up @@ -3308,7 +3308,10 @@ void QgsFontMarkerSymbolLayerWidget::setSymbolLayer( QgsSymbolLayer *layer )

widgetChar->blockSignals( true );
widgetChar->setFont( layerFont );
widgetChar->setCharacter( mLayer->character() );
if ( mLayer->character().length() == 1 )
{
widgetChar->setCharacter( mLayer->character().at( 0 ) );
}
widgetChar->blockSignals( false );
whileBlocking( mCharLineEdit )->setText( mLayer->character() );

Expand Down Expand Up @@ -3394,26 +3397,26 @@ void QgsFontMarkerSymbolLayerWidget::setCharacterFromText( const QString &text )
return;

// take the last character of a string for a better experience when users cycle through several characters on their keyboard
QChar chr = text.at( text.length() - 1 );
QString character = text;
if ( text.contains( QRegularExpression( QStringLiteral( "^0x[0-9a-fA-F]{1,4}$" ) ) ) )
{
bool ok = false;
unsigned int value = text.toUInt( &ok, 0 );
if ( ok )
chr = QChar( value );
}
else if ( text.contains( QRegularExpression( QStringLiteral( "^[0-9]{1,}$" ) ) ) )
{
bool ok = false;
unsigned int value = text.toUInt( &ok, 10 );
if ( ok )
chr = QChar( value );
character = QChar( value );
}

if ( chr != mLayer->character() )
if ( character != mLayer->character() )
{
mLayer->setCharacter( chr );
whileBlocking( widgetChar )->setCharacter( mLayer->character() );
mLayer->setCharacter( character );
if ( mLayer->character().length() == 1 )
{
whileBlocking( widgetChar )->setCharacter( mLayer->character().at( 0 ) );
}
else
{
widgetChar->clearCharacter();
}
emit changed();
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/ui/symbollayer/widget_fontmarker.ui
Expand Up @@ -306,14 +306,14 @@
<item row="14" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Character</string>
<string>Character(s)</string>
</property>
</widget>
</item>
<item row="14" column="1" colspan="2">
<widget class="QLineEdit" name="mCharLineEdit">
<property name="toolTip">
<string>Type in a character directly, or enter its decimal/hexadecimal value.</string>
<string>Type in characters directly, or enter a character's hexadecimal value.</string>
</property>
</widget>
</item>
Expand Down
6 changes: 3 additions & 3 deletions tests/src/core/testqgsfontmarker.cpp
Expand Up @@ -129,7 +129,7 @@ void TestQgsFontMarkerSymbol::fontMarkerSymbol()
mFontMarkerLayer->setColor( Qt::blue );
QFont font = QgsFontUtils::getStandardTestFont( QStringLiteral( "Bold" ) );
mFontMarkerLayer->setFontFamily( font.family() );
mFontMarkerLayer->setCharacter( 'A' );
mFontMarkerLayer->setCharacter( QChar( 'A' ) );
mFontMarkerLayer->setSize( 12 );
QVERIFY( imageCheck( "fontmarker" ) );
}
Expand All @@ -139,7 +139,7 @@ void TestQgsFontMarkerSymbol::fontMarkerSymbolStroke()
mFontMarkerLayer->setColor( Qt::blue );
QFont font = QgsFontUtils::getStandardTestFont( QStringLiteral( "Bold" ) );
mFontMarkerLayer->setFontFamily( font.family() );
mFontMarkerLayer->setCharacter( 'A' );
mFontMarkerLayer->setCharacter( QChar( 'A' ) );
mFontMarkerLayer->setSize( 30 );
mFontMarkerLayer->setStrokeWidth( 3.5 );
QVERIFY( imageCheck( "fontmarker_outline" ) );
Expand All @@ -151,7 +151,7 @@ void TestQgsFontMarkerSymbol::bounds()
QFont font = QgsFontUtils::getStandardTestFont( QStringLiteral( "Bold" ) );
mFontMarkerLayer->setFontFamily( font.family() );
//use a narrow character to test that width is correctly calculated
mFontMarkerLayer->setCharacter( 'l' );
mFontMarkerLayer->setCharacter( QChar( 'l' ) );
mFontMarkerLayer->setSize( 12 );
mFontMarkerLayer->setStrokeWidth( 0 );
mFontMarkerLayer->setDataDefinedProperty( QgsSymbolLayer::PropertySize, QgsProperty::fromExpression( QStringLiteral( "min(\"importance\" * 4.47214, 7.07106)" ) ) );
Expand Down

0 comments on commit 3747cf7

Please sign in to comment.