19#include "moc_qgslayoutitemlabel.cpp"
36#include <QCoreApplication>
40#include <QTextDocument>
46 mHtmlUnitsToLayoutUnits = htmlUnitsToLayoutUnits();
50 const QString defaultFontString = settings.
value( QStringLiteral(
"LayoutDesigner/defaultFont" ), QVariant(),
QgsSettings::Gui ).toString();
51 if ( !defaultFontString.isEmpty() )
53 QFont f = mFormat.
font();
72 refreshExpressionContext();
95 const double penWidth =
frameEnabled() ? ( pen().widthF() / 2.0 ) : 0;
96 const double xPenAdjust = mMarginX < 0 ? -penWidth : penWidth;
97 const double yPenAdjust = mMarginY < 0 ? -penWidth : penWidth;
103 painterRect = QRectF( ( xPenAdjust + mMarginX ) * rectScale,
104 ( yPenAdjust + mMarginY ) * rectScale,
105 ( rect().width() - 2 * xPenAdjust - 2 * mMarginX ) * rectScale,
106 ( rect().height() - 2 * yPenAdjust - 2 * mMarginY ) * rectScale );
111 const double adjustmentFactor = 3.77;
114 painterRect = QRectF( 0, 0,
115 ( rect().width() ) * rectScale,
116 ( rect().height() - yPenAdjust - mMarginY ) * rectScale );
125 QTextDocument document;
126 document.setDocumentMargin( 0 );
128 document.setDefaultStyleSheet( createStylesheet() );
130 document.setDefaultFont( createDefaultFont() );
132 QTextOption textOption = document.defaultTextOption();
133 textOption.setAlignment( mHAlignment );
134 document.setDefaultTextOption( textOption );
136 document.setHtml( QStringLiteral(
"<body>%1</body>" ).arg(
currentText() ) );
137 document.drawContents( painter, painterRect );
157void QgsLayoutItemLabel::contentChanged()
182 mLayout->itemsModel()->updateItemDisplayName(
this );
196 if (
mLayout &&
id().isEmpty() )
199 mLayout->itemsModel()->updateItemDisplayName(
this );
203void QgsLayoutItemLabel::refreshExpressionContext()
212 mDistanceArea->setSourceCrs( layer->
crs(),
mLayout->project()->transformContext() );
219 mDistanceArea->setSourceCrs( referenceMap->
crs(),
mLayout->project()->transformContext() );
221 mDistanceArea->setEllipsoid(
mLayout->project()->ellipsoid() );
227void QgsLayoutItemLabel::updateBoundingRect()
229 QRectF rectangle = rect();
230 const double frameExtension =
frameEnabled() ? pen().widthF() / 2.0 : 0.0;
231 if ( frameExtension > 0 )
232 rectangle.adjust( -frameExtension, -frameExtension, frameExtension, frameExtension );
236 rectangle.adjust( mMarginX, 0, -mMarginX, 0 );
240 rectangle.adjust( 0, mMarginY, 0, -mMarginY );
243 if ( rectangle != mCurrentRectangle )
245 prepareGeometryChange();
246 mCurrentRectangle = rectangle;
253 QString displayText = mText;
254 replaceDateText( displayText );
261void QgsLayoutItemLabel::replaceDateText( QString &text )
const
263 const QString constant = QStringLiteral(
"$CURRENT_DATE" );
264 const int currentDatePos =
text.indexOf( constant );
265 if ( currentDatePos != -1 )
269 const int openingBracketPos =
text.indexOf(
'(', currentDatePos );
270 const int closingBracketPos =
text.indexOf(
')', openingBracketPos + 1 );
271 if ( openingBracketPos != -1 &&
272 closingBracketPos != -1 &&
273 ( closingBracketPos - openingBracketPos ) > 1 &&
274 openingBracketPos == currentDatePos + constant.size() )
276 formatText =
text.mid( openingBracketPos + 1, closingBracketPos - openingBracketPos - 1 );
277 text.replace( currentDatePos, closingBracketPos - currentDatePos + 1, QDate::currentDate().toString( formatText ) );
281 text.replace( QLatin1String(
"$CURRENT_DATE" ), QDate::currentDate().toString() );
289 if ( f.pointSizeF() > 0 )
290 mFormat.
setSize( f.pointSizeF() );
309 updateBoundingRect();
315 updateBoundingRect();
321 updateBoundingRect();
332 itemShiftAdjustSize( newSize.width(), newSize.height(), xShift, yShift );
335 attemptSetSceneRect( QRectF( pos().x() + xShift, pos().y() + yShift, newSize.width(), newSize.height() ) );
342 const QStringList lines =
currentText().split(
'\n' );
346 const double penWidth =
frameEnabled() ? ( pen().widthF() / 2.0 ) : 0;
348 const double width = textWidth + 2 * mMarginX + 2 * penWidth;
349 const double height = fontHeight + 2 * mMarginY + 2 * penWidth;
356 return mFormat.
font();
361 layoutLabelElem.setAttribute( QStringLiteral(
"htmlState" ),
static_cast< int >( mMode ) );
363 layoutLabelElem.setAttribute( QStringLiteral(
"labelText" ), mText );
364 layoutLabelElem.setAttribute( QStringLiteral(
"marginX" ), QString::number( mMarginX ) );
365 layoutLabelElem.setAttribute( QStringLiteral(
"marginY" ), QString::number( mMarginY ) );
366 layoutLabelElem.setAttribute( QStringLiteral(
"halign" ), mHAlignment );
367 layoutLabelElem.setAttribute( QStringLiteral(
"valign" ), mVAlignment );
369 QDomElement textElem = mFormat.
writeXml( doc, rwContext );
370 layoutLabelElem.appendChild( textElem );
380 mText = itemElem.attribute( QStringLiteral(
"labelText" ) );
383 mMode =
static_cast< Mode >( itemElem.attribute( QStringLiteral(
"htmlState" ) ).toInt() );
386 bool marginXOk =
false;
387 bool marginYOk =
false;
388 mMarginX = itemElem.attribute( QStringLiteral(
"marginX" ) ).toDouble( &marginXOk );
389 mMarginY = itemElem.attribute( QStringLiteral(
"marginY" ) ).toDouble( &marginYOk );
390 if ( !marginXOk || !marginYOk )
393 const double margin = itemElem.attribute( QStringLiteral(
"margin" ), QStringLiteral(
"1.0" ) ).toDouble();
399 mHAlignment =
static_cast< Qt::AlignmentFlag
>( itemElem.attribute( QStringLiteral(
"halign" ) ).toInt() );
402 mVAlignment =
static_cast< Qt::AlignmentFlag
>( itemElem.attribute( QStringLiteral(
"valign" ) ).toInt() );
405 QDomNodeList textFormatNodeList = itemElem.elementsByTagName( QStringLiteral(
"text-style" ) );
406 if ( !textFormatNodeList.isEmpty() )
408 QDomElement textFormatElem = textFormatNodeList.at( 0 ).toElement();
409 mFormat.
readXml( textFormatElem, context );
416 f.fromString( itemElem.attribute( QStringLiteral(
"font" ), QString() ) );
419 if ( f.pointSizeF() > 0 )
421 mFormat.
setSize( f.pointSizeF() );
424 else if ( f.pixelSize() > 0 )
426 mFormat.
setSize( f.pixelSize() );
431 const QDomNodeList fontColorList = itemElem.elementsByTagName( QStringLiteral(
"FontColor" ) );
432 if ( !fontColorList.isEmpty() )
434 const QDomElement fontColorElem = fontColorList.at( 0 ).toElement();
435 const int red = fontColorElem.attribute( QStringLiteral(
"red" ), QStringLiteral(
"0" ) ).toInt();
436 const int green = fontColorElem.attribute( QStringLiteral(
"green" ), QStringLiteral(
"0" ) ).toInt();
437 const int blue = fontColorElem.attribute( QStringLiteral(
"blue" ), QStringLiteral(
"0" ) ).toInt();
438 const int alpha = fontColorElem.attribute( QStringLiteral(
"alpha" ), QStringLiteral(
"255" ) ).toInt();
439 mFormat.
setColor( QColor( red, green, blue, alpha ) );
441 else if ( textFormatNodeList.isEmpty() )
443 mFormat.
setColor( QColor( 0, 0, 0 ) );
447 updateBoundingRect();
454 if ( !
id().isEmpty() )
462 return tr(
"<HTML Label>" );
468 const QString
text = mText;
469 if (
text.isEmpty() )
471 return tr(
"<Label>" );
473 if (
text.length() > 25 )
475 return QString( tr(
"%1…" ) ).arg(
text.left( 25 ).simplified() );
479 return text.simplified();
488 return mCurrentRectangle;
494 updateBoundingRect();
500 updateBoundingRect();
507 refreshExpressionContext();
513 if ( evaluated == mText )
519void QgsLayoutItemLabel::itemShiftAdjustSize(
double newWidth,
double newHeight,
double &xShift,
double &yShift )
const
522 const double currentWidth = rect().width();
523 const double currentHeight = rect().height();
527 const double r = rotation();
528 if ( r >= 0 && r < 90 )
530 if ( mHAlignment == Qt::AlignHCenter )
532 xShift = - ( newWidth - currentWidth ) / 2.0;
534 else if ( mHAlignment == Qt::AlignRight )
536 xShift = - ( newWidth - currentWidth );
538 if ( mVAlignment == Qt::AlignVCenter )
540 yShift = -( newHeight - currentHeight ) / 2.0;
542 else if ( mVAlignment == Qt::AlignBottom )
544 yShift = - ( newHeight - currentHeight );
547 if ( r >= 90 && r < 180 )
549 if ( mHAlignment == Qt::AlignHCenter )
551 yShift = -( newHeight - currentHeight ) / 2.0;
553 else if ( mHAlignment == Qt::AlignRight )
555 yShift = -( newHeight - currentHeight );
557 if ( mVAlignment == Qt::AlignTop )
559 xShift = -( newWidth - currentWidth );
561 else if ( mVAlignment == Qt::AlignVCenter )
563 xShift = -( newWidth - currentWidth / 2.0 );
566 else if ( r >= 180 && r < 270 )
568 if ( mHAlignment == Qt::AlignHCenter )
570 xShift = -( newWidth - currentWidth ) / 2.0;
572 else if ( mHAlignment == Qt::AlignLeft )
574 xShift = -( newWidth - currentWidth );
576 if ( mVAlignment == Qt::AlignVCenter )
578 yShift = ( newHeight - currentHeight ) / 2.0;
580 else if ( mVAlignment == Qt::AlignTop )
582 yShift = ( newHeight - currentHeight );
585 else if ( r >= 270 && r < 360 )
587 if ( mHAlignment == Qt::AlignHCenter )
589 yShift = -( newHeight - currentHeight ) / 2.0;
591 else if ( mHAlignment == Qt::AlignLeft )
593 yShift = -( newHeight - currentHeight );
595 if ( mVAlignment == Qt::AlignBottom )
597 xShift = -( newWidth - currentWidth );
599 else if ( mVAlignment == Qt::AlignVCenter )
601 xShift = -( newWidth - currentWidth / 2.0 );
606QFont QgsLayoutItemLabel::createDefaultFont()
const
608 QFont f = mFormat.
font();
612 f.setPointSizeF( mFormat.
size() / 0.352778 );
615 f.setPixelSize( mFormat.
size() );
618 f.setPointSizeF( mFormat.
size() );
621 f.setPointSizeF( mFormat.
size() * 72 );
632double QgsLayoutItemLabel::htmlUnitsToLayoutUnits()
643QString QgsLayoutItemLabel::createStylesheet()
const
647 stylesheet += QStringLiteral(
"body { margin: %1 %2;" ).arg( std::max( mMarginY * mHtmlUnitsToLayoutUnits, 0.0 ) ).arg( std::max( mMarginX * mHtmlUnitsToLayoutUnits, 0.0 ) );
648 stylesheet += mFormat.
asCSS( 0.352778 * mHtmlUnitsToLayoutUnits );
649 stylesheet += QStringLiteral(
"text-align: %1; }" ).arg( mHAlignment == Qt::AlignLeft ? QStringLiteral(
"left" ) : mHAlignment == Qt::AlignRight ? QStringLiteral(
"right" ) : mHAlignment == Qt::AlignHCenter ? QStringLiteral(
"center" ) : QStringLiteral(
"justify" ) );
654QUrl QgsLayoutItemLabel::createStylesheetUrl()
const
657 ba.append( createStylesheet().toUtf8() );
658 QUrl cssFileURL = QUrl( QString(
"data:text/css;charset=utf-8;base64," + ba.toBase64() ) );
@ Millimeters
Millimeters.
@ Percentage
Percentage of another measurement (e.g., canvas size, feature size)
@ Millimeters
Millimeters.
@ Points
Points (e.g., for font sizes)
@ Unknown
Mixed or unknown units.
@ MetersInMapUnits
Meters value as Map units.
@ ApplyScalingWorkaroundForTextRendering
Whether a scaling workaround designed to stablise the rendering of small font sizes (or for painters ...
@ WrapLines
Automatically wrap long lines of text.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
A general purpose distance and area calculator, capable of performing ellipsoid based calculations.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
static QString replaceExpressionText(const QString &action, const QgsExpressionContext *context, const QgsDistanceArea *distanceArea=nullptr)
This function replaces each expression between [% and %] in the string with the result of its evaluat...
static bool setFromXmlChildNode(QFont &font, const QDomElement &element, const QString &childNode)
Sets the properties of a font to match the properties stored in an XML child node.
static void setFontFamily(QFont &font, const QString &family)
Sets the family for a font object.
A layout item subclass for text labels.
Mode mode() const
Returns the label's current mode.
void setMarginX(double margin)
Sets the horizontal margin between the edge of the frame and the label contents, in layout units.
void setFrameEnabled(bool drawFrame) override
Sets whether this item has a frame drawn around it or not.
QRectF boundingRect() const override
QSizeF sizeForText() const
Returns the required item size (in layout units) for the label's text to fill the item.
void setMargin(double margin)
Sets the margin between the edge of the frame and the label contents.
int type() const override
static QgsLayoutItemLabel * create(QgsLayout *layout)
Returns a new label item for the specified layout.
bool readPropertiesFromElement(const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context) override
Sets item state from a DOM element.
Q_DECL_DEPRECATED QFont font() const
Returns the label's current font.
QgsLayoutItemLabel(QgsLayout *layout)
Constructor for QgsLayoutItemLabel, with the specified parent layout.
void setText(const QString &text)
Sets the label's preset text.
void setFrameStrokeWidth(QgsLayoutMeasurement strokeWidth) override
Sets the frame stroke width.
void setMarginY(double margin)
Sets the vertical margin between the edge of the frame and the label contents, in layout units.
void draw(QgsLayoutItemRenderContext &context) override
Draws the item's contents using the specified item render context.
Q_DECL_DEPRECATED void setFont(const QFont &font)
Sets the label's current font.
bool writePropertiesToElement(QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context) const override
Stores item state within an XML DOM element.
void setMode(Mode mode)
Sets the label's current mode, allowing the label to switch between font based and HTML based renderi...
QString displayName() const override
Gets item display name.
QString text() const
Returns the label's preset text.
void convertToStaticText()
Converts the label's text() to a static string, by evaluating any expressions included in the text an...
QgsTextFormat textFormat() const
Returns the text format used for drawing text in the label.
void setTextFormat(const QgsTextFormat &format)
Sets the text format used for drawing text in the label.
QString currentText() const
Returns the text as it appears on the label (with evaluated expressions and other dynamic content).
QIcon icon() const override
Returns the item's icon.
void adjustSizeToText()
Resizes the item so that the label's text fits to the item.
@ ModeHtml
Label displays rendered HTML content.
@ ModeFont
Label displays text rendered using a single font.
Layout graphical items for displaying a map.
QgsCoordinateReferenceSystem crs() const
Returns coordinate reference system used for rendering the map.
Contains settings and helpers relating to a render of a QgsLayoutItem.
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
Base class for graphical items within a QgsLayout.
virtual void drawFrame(QgsRenderContext &context)
Draws the frame around the item.
virtual void setFrameStrokeWidth(QgsLayoutMeasurement width)
Sets the frame stroke width.
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
virtual void setFrameEnabled(bool drawFrame)
Sets whether this item has a frame drawn around it or not.
void sizePositionChanged()
Emitted when the item's size or position changes.
virtual void invalidateCache()
Forces a deferred update of any cached image the item uses.
QString id() const
Returns the item's ID name.
bool frameEnabled() const
Returns true if the item includes a frame.
void refresh() override
Refreshes the item, causing a recalculation of any property overrides and recalculation of its positi...
void attemptSetSceneRect(const QRectF &rect, bool includesFrame=false)
Attempts to update the item's position and size to match the passed rect in layout coordinates.
void setBackgroundEnabled(bool drawBackground)
Sets whether this item has a background drawn under it or not.
This class provides a method of storing measurements for use in QGIS layouts using a variety of diffe...
const QgsLayout * layout() const
Returns the layout the object is attached to.
void changed()
Emitted when the object's properties change.
QPointer< QgsLayout > mLayout
This class provides a method of storing sizes, consisting of a width and height, for use in QGIS layo...
static QgsRenderContext createRenderContextForLayout(QgsLayout *layout, QPainter *painter, double dpi=-1)
Creates a render context suitable for the specified layout and painter destination.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
QgsCoordinateReferenceSystem crs
The class is used as a container of context for various read/write operations on other objects.
Contains information about the context of a rendering operation.
double scaleFactor() const
Returns the scaling factor for the render to convert painter units to physical sizes.
double convertToPainterUnits(double size, Qgis::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
QPainter * painter()
Returns the destination QPainter for the render operation.
void setFlag(Qgis::RenderContextFlag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected)
Scoped object for saving and restoring a QPainter object's state.
This class is a composition of two QSettings instances:
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
Container for all settings relating to text rendering.
void setColor(const QColor &color)
Sets the color that text will be rendered in.
void setSize(double size)
Sets the size for rendered text.
void setFont(const QFont &font)
Sets the font used for rendering text.
void setSizeUnit(Qgis::RenderUnit unit)
Sets the units for the size of rendered text.
void readXml(const QDomElement &elem, const QgsReadWriteContext &context)
Read settings from a DOM element.
Qgis::RenderUnit sizeUnit() const
Returns the units for the size of rendered text.
double size() const
Returns the size for rendered text.
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Write settings into a DOM element.
QString asCSS(double pointToPixelMultiplier=1.0) const
Returns a CSS string representing the specified text format as closely as possible.
QFont font() const
Returns the font used for rendering text.
static Qgis::TextVerticalAlignment convertQtVAlignment(Qt::Alignment alignment)
Converts a Qt vertical alignment flag to a Qgis::TextVerticalAlignment value.
static double textWidth(const QgsRenderContext &context, const QgsTextFormat &format, const QStringList &textLines, QFontMetricsF *fontMetrics=nullptr)
Returns the width of a text based on a given format.
static void drawText(const QRectF &rect, double rotation, Qgis::TextHorizontalAlignment alignment, const QStringList &textLines, QgsRenderContext &context, const QgsTextFormat &format, bool drawAsOutlines=true, Qgis::TextVerticalAlignment vAlignment=Qgis::TextVerticalAlignment::Top, Qgis::TextRendererFlags flags=Qgis::TextRendererFlags(), Qgis::TextLayoutMode mode=Qgis::TextLayoutMode::Rectangle)
Draws text within a rectangle using the specified settings.
static double textHeight(const QgsRenderContext &context, const QgsTextFormat &format, const QStringList &textLines, Qgis::TextLayoutMode mode=Qgis::TextLayoutMode::Point, QFontMetricsF *fontMetrics=nullptr, Qgis::TextRendererFlags flags=Qgis::TextRendererFlags(), double maxLineWidth=0)
Returns the height of a text based on a given format.
static Qgis::TextHorizontalAlignment convertQtHAlignment(Qt::Alignment alignment)
Converts a Qt horizontal alignment flag to a Qgis::TextHorizontalAlignment value.
Represents a vector layer which manages a vector based data sets.