1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquicktext_p.h"
43 #include "qquicktext_p_p.h"
45 #include <private/qsgdistancefieldglyphcache_p.h>
46 #include <private/qsgcontext_p.h>
47 #include <private/qsgadaptationlayer_p.h>
48 #include "qquicktextnode_p.h"
49 #include "qquickimage_p_p.h"
50 #include <private/qsgtexture_p.h>
52 #include <QtDeclarative/qdeclarativeinfo.h>
53 #include <QtGui/qevent.h>
54 #include <QtGui/qabstracttextdocumentlayout.h>
55 #include <QtGui/qpainter.h>
56 #include <QtGui/qtextdocument.h>
57 #include <QtGui/qtextobject.h>
58 #include <QtGui/qtextcursor.h>
59 #include <QtGui/qguiapplication.h>
61 #include <private/qdeclarativestyledtext_p.h>
62 #include <private/qdeclarativepixmapcache_p.h>
69 extern Q_GUI_EXPORT bool qt_applefontsmoothing_enabled;
71 class QQuickTextDocumentWithImageResources : public QTextDocument {
75 QQuickTextDocumentWithImageResources(QQuickText *parent);
76 virtual ~QQuickTextDocumentWithImageResources();
78 void setText(const QString &);
79 int resourcesLoading() const { return outstanding; }
82 QVariant loadResource(int type, const QUrl &name);
85 void requestFinished();
88 QHash<QUrl, QDeclarativePixmap *> m_resources;
91 static QSet<QUrl> errors;
94 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
95 DEFINE_BOOL_CONFIG_OPTION(enableImageCache, QML_ENABLE_TEXT_IMAGE_CACHE);
97 QString QQuickTextPrivate::elideChar = QString(0x2026);
99 QQuickTextPrivate::QQuickTextPrivate()
100 : color((QRgb)0), style(QQuickText::Normal), hAlign(QQuickText::AlignLeft),
101 vAlign(QQuickText::AlignTop), elideMode(QQuickText::ElideNone),
102 format(QQuickText::AutoText), wrapMode(QQuickText::NoWrap), lineHeight(1),
103 lineHeightMode(QQuickText::ProportionalHeight), lineCount(1), maximumLineCount(INT_MAX),
104 maximumLineCountValid(false),
106 imageCacheDirty(false), updateOnComponentComplete(true),
107 richText(false), styledText(false), singleline(false), cacheAllTextAsImage(true), internalWidthUpdate(false),
108 requireImplicitWidth(false), truncated(false), hAlignImplicit(true), rightToLeftText(false),
109 layoutTextElided(false), richTextAsImage(false), textureImageCacheDirty(false), textHasChanged(true),
110 naturalWidth(0), doc(0), textLine(0), nodeType(NodeIsNull)
112 #if defined(Q_OS_MAC)
113 , layoutThread(0), paintingThread(0)
117 cacheAllTextAsImage = enableImageCache();
120 void QQuickTextPrivate::init()
123 q->setAcceptedMouseButtons(Qt::LeftButton);
124 q->setFlag(QQuickItem::ItemHasContents);
127 QQuickTextDocumentWithImageResources::QQuickTextDocumentWithImageResources(QQuickText *parent)
128 : QTextDocument(parent), outstanding(0)
130 setUndoRedoEnabled(false);
133 QQuickTextDocumentWithImageResources::~QQuickTextDocumentWithImageResources()
135 if (!m_resources.isEmpty())
136 qDeleteAll(m_resources);
139 QVariant QQuickTextDocumentWithImageResources::loadResource(int type, const QUrl &name)
141 QDeclarativeContext *context = qmlContext(parent());
142 QUrl url = context->resolvedUrl(name);
144 if (type == QTextDocument::ImageResource) {
145 QHash<QUrl, QDeclarativePixmap *>::Iterator iter = m_resources.find(url);
147 if (iter == m_resources.end()) {
148 QDeclarativePixmap *p = new QDeclarativePixmap(context->engine(), url);
149 iter = m_resources.insert(name, p);
151 if (p->isLoading()) {
152 p->connectFinished(this, SLOT(requestFinished()));
157 QDeclarativePixmap *p = *iter;
160 } else if (p->isError()) {
161 if (!errors.contains(url)) {
163 qmlInfo(parent()) << p->error();
168 return QTextDocument::loadResource(type,url); // The *resolved* URL
171 void QQuickTextDocumentWithImageResources::requestFinished()
174 if (outstanding == 0) {
175 QQuickText *textItem = static_cast<QQuickText*>(parent());
176 QString text = textItem->text();
177 #ifndef QT_NO_TEXTHTMLPARSER
182 QQuickTextPrivate *d = QQuickTextPrivate::get(textItem);
187 void QQuickTextDocumentWithImageResources::setText(const QString &text)
189 if (!m_resources.isEmpty()) {
190 qDeleteAll(m_resources);
195 #ifndef QT_NO_TEXTHTMLPARSER
202 QSet<QUrl> QQuickTextDocumentWithImageResources::errors;
204 QQuickTextPrivate::~QQuickTextPrivate()
206 delete textLine; textLine = 0;
209 qreal QQuickTextPrivate::getImplicitWidth() const
211 if (!requireImplicitWidth) {
212 // We don't calculate implicitWidth unless it is required.
213 // We need to force a size update now to ensure implicitWidth is calculated
214 QQuickTextPrivate *me = const_cast<QQuickTextPrivate*>(this);
215 me->requireImplicitWidth = true;
218 return implicitWidth;
221 void QQuickTextPrivate::updateLayout()
224 if (!q->isComponentComplete()) {
225 updateOnComponentComplete = true;
229 layoutTextElided = false;
230 // Setup instance of QTextLayout for all cases other than richtext
232 layout.clearLayout();
233 layout.setFont(font);
236 tmp.replace(QLatin1Char('\n'), QChar::LineSeparator);
237 singleline = !tmp.contains(QChar::LineSeparator);
238 if (singleline && !maximumLineCountValid && elideMode != QQuickText::ElideNone && q->widthValid()) {
239 QFontMetrics fm(font);
240 tmp = fm.elidedText(tmp,(Qt::TextElideMode)elideMode,q->width());
242 layoutTextElided = true;
245 emit q->truncatedChanged();
252 if (textHasChanged) {
253 QDeclarativeStyledText::parse(text, layout);
254 textHasChanged = false;
259 QTextBlockFormat::LineHeightTypes type;
260 type = lineHeightMode == QQuickText::FixedHeight ? QTextBlockFormat::FixedHeight : QTextBlockFormat::ProportionalHeight;
261 QTextBlockFormat blockFormat;
262 blockFormat.setLineHeight((lineHeightMode == QQuickText::FixedHeight ? lineHeight : lineHeight * 100), type);
263 for (QTextBlock it = doc->begin(); it != doc->end(); it = it.next()) {
264 QTextCursor cursor(it);
265 cursor.mergeBlockFormat(blockFormat);
272 void QQuickTextPrivate::updateSize()
276 if (!q->isComponentComplete()) {
277 updateOnComponentComplete = true;
281 if (!requireImplicitWidth) {
282 emit q->implicitWidthChanged();
283 // if the implicitWidth is used, then updateSize() has already been called (recursively)
284 if (requireImplicitWidth)
288 invalidateImageCache();
290 QFontMetrics fm(font);
291 if (text.isEmpty()) {
292 q->setImplicitWidth(0);
293 q->setImplicitHeight(fm.height());
294 paintedSize = QSize(0, fm.height());
295 emit q->paintedSizeChanged();
300 int dy = q->height();
303 #if defined(Q_OS_MAC)
304 layoutThread = QThread::currentThread();
307 //setup instance of QTextLayout for all cases other than richtext
309 QRect textRect = setupTextLayout();
310 layedOutTextRect = textRect;
311 size = textRect.size();
314 singleline = false; // richtext can't elide or be optimized for single-line case
316 doc->setDefaultFont(font);
317 QQuickText::HAlignment horizontalAlignment = q->effectiveHAlign();
318 if (rightToLeftText) {
319 if (horizontalAlignment == QQuickText::AlignLeft)
320 horizontalAlignment = QQuickText::AlignRight;
321 else if (horizontalAlignment == QQuickText::AlignRight)
322 horizontalAlignment = QQuickText::AlignLeft;
325 option.setAlignment((Qt::Alignment)int(horizontalAlignment | vAlign));
326 option.setWrapMode(QTextOption::WrapMode(wrapMode));
327 if (!cacheAllTextAsImage && !richTextAsImage && !qmlDisableDistanceField())
328 option.setUseDesignMetrics(true);
329 doc->setDefaultTextOption(option);
330 if (requireImplicitWidth && q->widthValid()) {
331 doc->setTextWidth(-1);
332 naturalWidth = doc->idealWidth();
334 if (wrapMode != QQuickText::NoWrap && q->widthValid())
335 doc->setTextWidth(q->width());
337 doc->setTextWidth(doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug)
338 dy -= (int)doc->size().height();
339 QSize dsize = doc->size().toSize();
340 layedOutTextRect = QRect(QPoint(0,0), dsize);
341 size = QSize(int(doc->idealWidth()),dsize.height());
345 if (q->heightValid()) {
346 if (vAlign == QQuickText::AlignBottom)
348 else if (vAlign == QQuickText::AlignVCenter)
351 q->setBaselineOffset(fm.ascent() + yoff);
353 //### need to comfirm cost of always setting these for richText
354 internalWidthUpdate = true;
355 if (!q->widthValid())
356 q->setImplicitWidth(size.width());
357 else if (requireImplicitWidth)
358 q->setImplicitWidth(naturalWidth);
359 internalWidthUpdate = false;
361 q->setImplicitHeight(size.height());
362 if (paintedSize != size) {
364 emit q->paintedSizeChanged();
369 QQuickTextLine::QQuickTextLine()
370 : QObject(), m_line(0), m_height(0)
374 void QQuickTextLine::setLine(QTextLine *line)
379 int QQuickTextLine::number() const
382 return m_line->lineNumber();
386 qreal QQuickTextLine::width() const
389 return m_line->width();
393 void QQuickTextLine::setWidth(qreal width)
396 m_line->setLineWidth(width);
399 qreal QQuickTextLine::height() const
404 return m_line->height();
408 void QQuickTextLine::setHeight(qreal height)
411 m_line->setPosition(QPointF(m_line->x(), m_line->y() - m_line->height() + height));
415 qreal QQuickTextLine::x() const
422 void QQuickTextLine::setX(qreal x)
425 m_line->setPosition(QPointF(x, m_line->y()));
428 qreal QQuickTextLine::y() const
435 void QQuickTextLine::setY(qreal y)
438 m_line->setPosition(QPointF(m_line->x(), y));
441 void QQuickText::doLayout()
448 \qmlsignal QtQuick2::Text::onLineLaidOut(line)
450 This handler is called for every line during the layout process.
451 This gives the opportunity to position and resize a line as it is being laid out.
452 It can for example be used to create columns or lay out text around objects.
454 The properties of a line are:
456 \o number (read-only)
463 For example, this will move the first 5 lines of a text element by 100 pixels to the right:
466 if (line.number < 5) {
467 line.x = line.x + 100
468 line.width = line.width - 100
474 bool QQuickTextPrivate::isLineLaidOutConnected()
476 static int idx = this->signalIndex("lineLaidOut(QQuickTextLine*)");
477 return this->isSignalConnected(idx);
480 void QQuickTextPrivate::setupCustomLineGeometry(QTextLine &line, qreal &height, qreal elideWidth = 0)
484 #if defined(Q_OS_MAC)
485 if (QThread::currentThread() != paintingThread) {
487 if (!line.lineNumber())
491 textLine = new QQuickTextLine;
492 textLine->setLine(&line);
493 textLine->setY(height);
494 textLine->setHeight(0);
496 // use the text item's width by default if it has one and wrap is on
497 if (q->widthValid() && q->wrapMode() != QQuickText::NoWrap)
498 textLine->setWidth(q->width() - elideWidth);
500 textLine->setWidth(INT_MAX);
501 if (lineHeight != 1.0)
502 textLine->setHeight((lineHeightMode == QQuickText::FixedHeight) ? lineHeight : line.height() * lineHeight);
504 emit q->lineLaidOut(textLine);
506 linesRects << QRectF(textLine->x(), textLine->y(), textLine->width(), textLine->height());
507 height += textLine->height();
509 #if defined(Q_OS_MAC)
511 if (line.lineNumber() < linesRects.count()) {
512 QRectF r = linesRects.at(line.lineNumber());
513 line.setLineWidth(r.width());
514 line.setPosition(r.topLeft());
521 Lays out the QQuickTextPrivate::layout QTextLayout in the constraints of the QQuickText.
523 Returns the size of the final text. This can be used to position the text vertically (the text is
524 already absolutely positioned horizontally).
526 QRect QQuickTextPrivate::setupTextLayout()
528 // ### text layout handling should be profiled and optimized as needed
529 // what about QStackTextEngine engine(tmp, d->font.font()); QTextLayout textLayout(&engine);
531 layout.setCacheEnabled(true);
534 int visibleCount = 0;
538 lineWidth = q->width();
540 QTextOption textOption = layout.textOption();
541 textOption.setAlignment(Qt::Alignment(q->effectiveHAlign()));
542 textOption.setWrapMode(QTextOption::WrapMode(wrapMode));
543 if (!cacheAllTextAsImage && !richTextAsImage && !qmlDisableDistanceField())
544 textOption.setUseDesignMetrics(true);
545 layout.setTextOption(textOption);
547 bool elideText = false;
548 bool truncate = false;
550 QFontMetrics fm(layout.font());
551 elidePos = QPointF();
553 if (requireImplicitWidth && q->widthValid()) {
554 // requires an extra layout
556 if (layoutTextElided) {
557 // We have provided elided text to the layout, but we must calculate unelided width.
558 elidedText = layout.text();
559 layout.setText(text);
561 layout.beginLayout();
563 QTextLine line = layout.createLine();
569 for (int i = 0; i < layout.lineCount(); ++i) {
570 QTextLine line = layout.lineAt(i);
571 br = br.united(line.naturalTextRect());
573 naturalWidth = br.width();
574 if (layoutTextElided)
575 layout.setText(elidedText);
579 bool customLayout = isLineLaidOutConnected();
581 if (maximumLineCountValid) {
582 layout.beginLayout();
585 int linesLeft = maximumLineCount;
586 int visibleTextLength = 0;
587 while (linesLeft > 0) {
588 QTextLine line = layout.createLine();
595 setupCustomLineGeometry(line, height);
597 line.setLineWidth(lineWidth);
598 visibleTextLength += line.textLength();
600 if (--linesLeft == 0) {
601 if (visibleTextLength < text.length()) {
603 if (elideMode == QQuickText::ElideRight && q->widthValid()) {
604 qreal elideWidth = fm.width(elideChar);
605 // Need to correct for alignment
607 setupCustomLineGeometry(line, height, elideWidth);
609 line.setLineWidth(lineWidth - elideWidth);
610 if (layout.text().mid(line.textStart(), line.textLength()).isRightToLeft()) {
611 line.setPosition(QPointF(line.position().x() + elideWidth, line.position().y()));
612 elidePos.setX(line.naturalTextRect().left() - elideWidth);
614 elidePos.setX(line.naturalTextRect().right());
624 if (truncated != truncate) {
625 truncated = truncate;
626 emit q->truncatedChanged();
629 layout.beginLayout();
631 QTextLine line = layout.createLine();
636 setupCustomLineGeometry(line, height);
639 line.setLineWidth(lineWidth);
647 for (int i = 0; i < layout.lineCount(); ++i) {
648 QTextLine line = layout.lineAt(i);
651 line.setPosition(QPointF(line.position().x(), height));
652 if (elideText && i == layout.lineCount()-1) {
653 elidePos.setY(height + fm.ascent());
654 br = br.united(QRectF(elidePos, QSizeF(fm.width(elideChar), fm.ascent())));
656 br = br.united(line.naturalTextRect());
657 height += (lineHeightMode == QQuickText::FixedHeight) ? lineHeight : line.height() * lineHeight;
660 br.setHeight(height);
662 if (!q->widthValid())
663 naturalWidth = br.width();
665 //Update the number of visible lines
666 if (lineCount != visibleCount) {
667 lineCount = visibleCount;
668 emit q->lineCountChanged();
671 return QRect(qRound(br.x()), qRound(br.y()), qCeil(br.width()), qCeil(br.height()));
675 Returns a painted version of the QQuickTextPrivate::layout QTextLayout.
676 If \a drawStyle is true, the style color overrides all colors in the document.
678 QPixmap QQuickTextPrivate::textLayoutImage(bool drawStyle)
680 QSize size = layedOutTextRect.size();
684 if (!size.isEmpty()) {
685 img.fill(Qt::transparent);
687 bool oldSmooth = qt_applefontsmoothing_enabled;
688 qt_applefontsmoothing_enabled = false;
692 qt_applefontsmoothing_enabled = oldSmooth;
694 drawTextLayout(&p, QPointF(-layedOutTextRect.x(),0), drawStyle);
700 Paints the QQuickTextPrivate::layout QTextLayout into \a painter at \a pos. If
701 \a drawStyle is true, the style color overrides all colors in the document.
703 void QQuickTextPrivate::drawTextLayout(QPainter *painter, const QPointF &pos, bool drawStyle)
706 painter->setPen(styleColor);
708 painter->setPen(color);
709 painter->setFont(font);
710 layout.draw(painter, pos);
711 if (!elidePos.isNull())
712 painter->drawText(pos + elidePos, elideChar);
716 Returns a painted version of the QQuickTextPrivate::doc QTextDocument.
717 If \a drawStyle is true, the style color overrides all colors in the document.
719 QPixmap QQuickTextPrivate::textDocumentImage(bool drawStyle)
721 QSize size = doc->size().toSize();
725 img.fill(Qt::transparent);
727 bool oldSmooth = qt_applefontsmoothing_enabled;
728 qt_applefontsmoothing_enabled = false;
732 qt_applefontsmoothing_enabled = oldSmooth;
735 QAbstractTextDocumentLayout::PaintContext context;
737 QTextOption oldOption(doc->defaultTextOption());
739 context.palette.setColor(QPalette::Text, styleColor);
740 QTextOption colorOption(doc->defaultTextOption());
741 colorOption.setFlags(QTextOption::SuppressColors);
742 doc->setDefaultTextOption(colorOption);
744 context.palette.setColor(QPalette::Text, color);
746 doc->documentLayout()->draw(&p, context);
748 doc->setDefaultTextOption(oldOption);
753 Mark the image cache as dirty.
755 void QQuickTextPrivate::invalidateImageCache()
759 if (richTextAsImage || cacheAllTextAsImage || (qmlDisableDistanceField() && style != QQuickText::Normal)) { // If actually using the image cache
763 imageCacheDirty = true;
765 if (q->isComponentComplete())
766 QCoreApplication::postEvent(q, new QEvent(QEvent::User));
767 } else if (q->isComponentComplete())
772 Tests if the image cache is dirty, and repaints it if it is.
774 void QQuickTextPrivate::checkImageCache()
778 if (!imageCacheDirty)
781 if (text.isEmpty()) {
783 imageCache = QPixmap();
791 textImage = textDocumentImage(false);
792 if (style != QQuickText::Normal)
793 styledImage = textDocumentImage(true); //### should use styleColor
795 textImage = textLayoutImage(false);
796 if (style != QQuickText::Normal)
797 styledImage = textLayoutImage(true); //### should use styleColor
801 case QQuickText::Outline:
802 imageCache = drawOutline(textImage, styledImage);
804 case QQuickText::Sunken:
805 imageCache = drawOutline(textImage, styledImage, -1);
807 case QQuickText::Raised:
808 imageCache = drawOutline(textImage, styledImage, 1);
811 imageCache = textImage;
817 imageCacheDirty = false;
818 textureImageCacheDirty = true;
823 Ensures the QQuickTextPrivate::doc variable is set to a valid text document
825 void QQuickTextPrivate::ensureDoc()
829 doc = new QQuickTextDocumentWithImageResources(q);
830 doc->setDocumentMargin(0);
835 Draw \a styleSource as an outline around \a source and return the new image.
837 QPixmap QQuickTextPrivate::drawOutline(const QPixmap &source, const QPixmap &styleSource)
839 QPixmap img = QPixmap(styleSource.width() + 2, styleSource.height() + 2);
840 img.fill(Qt::transparent);
845 pos += QPoint(-1, 0);
846 ppm.drawPixmap(pos, styleSource);
848 ppm.drawPixmap(pos, styleSource);
849 pos += QPoint(-1, -1);
850 ppm.drawPixmap(pos, styleSource);
852 ppm.drawPixmap(pos, styleSource);
854 pos += QPoint(0, -1);
855 ppm.drawPixmap(pos, source);
862 Draw \a styleSource below \a source at \a yOffset and return the new image.
864 QPixmap QQuickTextPrivate::drawOutline(const QPixmap &source, const QPixmap &styleSource, int yOffset)
866 QPixmap img = QPixmap(styleSource.width() + 2, styleSource.height() + 2);
867 img.fill(Qt::transparent);
871 ppm.drawPixmap(QPoint(0, yOffset), styleSource);
872 ppm.drawPixmap(0, 0, source);
880 \qmlclass Text QQuickText
881 \inqmlmodule QtQuick 2
882 \ingroup qml-basic-visual-elements
883 \brief The Text item allows you to add formatted text to a scene.
886 Text items can display both plain and rich text. For example, red text with
887 a specific font and size can be defined like this:
892 font.family: "Helvetica"
898 Rich text is defined using HTML-style markup:
902 text: "<b>Hello</b> <i>World!</i>"
906 \image declarative-text.png
908 If height and width are not explicitly set, Text will attempt to determine how
909 much room is needed and set it accordingly. Unless \l wrapMode is set, it will always
910 prefer width to height (all text will be placed on a single line).
912 The \l elide property can alternatively be used to fit a single line of
913 plain text to a set width.
915 Note that the \l{Supported HTML Subset} is limited. Also, if the text contains
916 HTML img tags that load remote images, the text is reloaded.
918 Text provides read-only text. For editable text, see \l TextEdit.
920 \sa {declarative/text/fonts}{Fonts example}
922 QQuickText::QQuickText(QQuickItem *parent)
923 : QQuickImplicitSizeItem(*(new QQuickTextPrivate), parent)
929 QQuickText::~QQuickText()
934 \qmlproperty bool QtQuick2::Text::clip
935 This property holds whether the text is clipped.
937 Note that if the text does not fit in the bounding rectangle it will be abruptly chopped.
939 If you want to display potentially long text in a limited space, you probably want to use \c elide instead.
943 \qmlproperty bool QtQuick2::Text::smooth
945 This property holds whether the text is smoothly scaled or transformed.
947 Smooth filtering gives better visual quality, but is slower. If
948 the item is displayed at its natural size, this property has no visual or
951 \note Generally scaling artifacts are only visible if the item is stationary on
952 the screen. A common pattern when animating an item is to disable smooth
953 filtering at the beginning of the animation and reenable it at the conclusion.
957 \qmlsignal QtQuick2::Text::onLinkActivated(string link)
959 This handler is called when the user clicks on a link embedded in the text.
960 The link must be in rich text or HTML format and the
961 \a link string provides access to the particular link.
963 \snippet doc/src/snippets/declarative/text/onLinkActivated.qml 0
965 The example code will display the text
966 "The main website is at \l{http://qt.nokia.com}{Nokia Qt DF}."
968 Clicking on the highlighted link will output
969 \tt{http://qt.nokia.com link activated} to the console.
973 \qmlproperty string QtQuick2::Text::font.family
975 Sets the family name of the font.
977 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
978 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
979 If the family isn't available a family will be set using the font matching algorithm.
983 \qmlproperty bool QtQuick2::Text::font.bold
985 Sets whether the font weight is bold.
989 \qmlproperty enumeration QtQuick2::Text::font.weight
991 Sets the font's weight.
993 The weight can be one of:
996 \o Font.Normal - the default
1003 Text { text: "Hello"; font.weight: Font.DemiBold }
1008 \qmlproperty bool QtQuick2::Text::font.italic
1010 Sets whether the font has an italic style.
1014 \qmlproperty bool QtQuick2::Text::font.underline
1016 Sets whether the text is underlined.
1020 \qmlproperty bool QtQuick2::Text::font.strikeout
1022 Sets whether the font has a strikeout style.
1026 \qmlproperty real QtQuick2::Text::font.pointSize
1028 Sets the font size in points. The point size must be greater than zero.
1032 \qmlproperty int QtQuick2::Text::font.pixelSize
1034 Sets the font size in pixels.
1036 Using this function makes the font device dependent.
1037 Use \c pointSize to set the size of the font in a device independent manner.
1041 \qmlproperty real QtQuick2::Text::font.letterSpacing
1043 Sets the letter spacing for the font.
1045 Letter spacing changes the default spacing between individual letters in the font.
1046 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
1050 \qmlproperty real QtQuick2::Text::font.wordSpacing
1052 Sets the word spacing for the font.
1054 Word spacing changes the default spacing between individual words.
1055 A positive value increases the word spacing by a corresponding amount of pixels,
1056 while a negative value decreases the inter-word spacing accordingly.
1060 \qmlproperty enumeration QtQuick2::Text::font.capitalization
1062 Sets the capitalization for the text.
1065 \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
1066 \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
1067 \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
1068 \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
1069 \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
1073 Text { text: "Hello"; font.capitalization: Font.AllLowercase }
1076 QFont QQuickText::font() const
1078 Q_D(const QQuickText);
1079 return d->sourceFont;
1082 void QQuickText::setFont(const QFont &font)
1085 if (d->sourceFont == font)
1088 d->sourceFont = font;
1089 QFont oldFont = d->font;
1092 if (d->font.pointSizeF() != -1) {
1094 qreal size = qRound(d->font.pointSizeF()*2.0);
1095 d->font.setPointSizeF(size/2.0);
1098 if (oldFont != d->font)
1101 emit fontChanged(d->sourceFont);
1105 \qmlproperty string QtQuick2::Text::text
1107 The text to display. Text supports both plain and rich text strings.
1109 The item will try to automatically determine whether the text should
1110 be treated as styled text. This determination is made using Qt::mightBeRichText().
1112 QString QQuickText::text() const
1114 Q_D(const QQuickText);
1118 void QQuickText::setText(const QString &n)
1124 d->richText = d->format == RichText;
1125 d->styledText = d->format == StyledText || (d->format == AutoText && Qt::mightBeRichText(n));
1127 if (isComponentComplete()) {
1131 d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
1132 d->richTextAsImage = enableImageCache();
1134 d->rightToLeftText = d->text.isRightToLeft();
1136 d->determineHorizontalAlignment();
1138 d->textHasChanged = true;
1140 emit textChanged(d->text);
1144 \qmlproperty color QtQuick2::Text::color
1148 An example of green text defined using hexadecimal notation:
1156 An example of steel blue text defined using an SVG color name:
1164 QColor QQuickText::color() const
1166 Q_D(const QQuickText);
1170 void QQuickText::setColor(const QColor &color)
1173 if (d->color == color)
1177 d->invalidateImageCache();
1178 emit colorChanged(d->color);
1181 \qmlproperty enumeration QtQuick2::Text::style
1183 Set an additional text style.
1185 Supported text styles are:
1187 \o Text.Normal - the default
1195 Text { font.pointSize: 24; text: "Normal" }
1196 Text { font.pointSize: 24; text: "Raised"; style: Text.Raised; styleColor: "#AAAAAA" }
1197 Text { font.pointSize: 24; text: "Outline";style: Text.Outline; styleColor: "red" }
1198 Text { font.pointSize: 24; text: "Sunken"; style: Text.Sunken; styleColor: "#AAAAAA" }
1202 \image declarative-textstyle.png
1204 QQuickText::TextStyle QQuickText::style() const
1206 Q_D(const QQuickText);
1210 void QQuickText::setStyle(QQuickText::TextStyle style)
1213 if (d->style == style)
1216 // changing to/from Normal requires the boundingRect() to change
1217 if (isComponentComplete() && (d->style == Normal || style == Normal))
1220 d->invalidateImageCache();
1221 emit styleChanged(d->style);
1225 \qmlproperty color QtQuick2::Text::styleColor
1227 Defines the secondary color used by text styles.
1229 \c styleColor is used as the outline color for outlined text, and as the
1230 shadow color for raised or sunken text. If no style has been set, it is not
1234 Text { font.pointSize: 18; text: "hello"; style: Text.Raised; styleColor: "gray" }
1239 QColor QQuickText::styleColor() const
1241 Q_D(const QQuickText);
1242 return d->styleColor;
1245 void QQuickText::setStyleColor(const QColor &color)
1248 if (d->styleColor == color)
1251 d->styleColor = color;
1252 d->invalidateImageCache();
1253 emit styleColorChanged(d->styleColor);
1257 \qmlproperty enumeration QtQuick2::Text::horizontalAlignment
1258 \qmlproperty enumeration QtQuick2::Text::verticalAlignment
1259 \qmlproperty enumeration QtQuick2::Text::effectiveHorizontalAlignment
1261 Sets the horizontal and vertical alignment of the text within the Text items
1262 width and height. By default, the text is vertically aligned to the top. Horizontal
1263 alignment follows the natural alignment of the text, for example text that is read
1264 from left to right will be aligned to the left.
1266 The valid values for \c horizontalAlignment are \c Text.AlignLeft, \c Text.AlignRight, \c Text.AlignHCenter and
1267 \c Text.AlignJustify. The valid values for \c verticalAlignment are \c Text.AlignTop, \c Text.AlignBottom
1268 and \c Text.AlignVCenter.
1270 Note that for a single line of text, the size of the text is the area of the text. In this common case,
1271 all alignments are equivalent. If you want the text to be, say, centered in its parent, then you will
1272 need to either modify the Item::anchors, or set horizontalAlignment to Text.AlignHCenter and bind the width to
1275 When using the attached property LayoutMirroring::enabled to mirror application
1276 layouts, the horizontal alignment of text will also be mirrored. However, the property
1277 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
1278 of Text, use the read-only property \c effectiveHorizontalAlignment.
1280 QQuickText::HAlignment QQuickText::hAlign() const
1282 Q_D(const QQuickText);
1286 void QQuickText::setHAlign(HAlignment align)
1289 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
1290 d->hAlignImplicit = false;
1291 if (d->setHAlign(align, forceAlign) && isComponentComplete())
1295 void QQuickText::resetHAlign()
1298 d->hAlignImplicit = true;
1299 if (d->determineHorizontalAlignment() && isComponentComplete())
1303 QQuickText::HAlignment QQuickText::effectiveHAlign() const
1305 Q_D(const QQuickText);
1306 QQuickText::HAlignment effectiveAlignment = d->hAlign;
1307 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
1308 switch (d->hAlign) {
1309 case QQuickText::AlignLeft:
1310 effectiveAlignment = QQuickText::AlignRight;
1312 case QQuickText::AlignRight:
1313 effectiveAlignment = QQuickText::AlignLeft;
1319 return effectiveAlignment;
1322 bool QQuickTextPrivate::setHAlign(QQuickText::HAlignment alignment, bool forceAlign)
1325 if (hAlign != alignment || forceAlign) {
1326 QQuickText::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
1329 emit q->horizontalAlignmentChanged(hAlign);
1330 if (oldEffectiveHAlign != q->effectiveHAlign())
1331 emit q->effectiveHorizontalAlignmentChanged();
1337 bool QQuickTextPrivate::determineHorizontalAlignment()
1340 if (hAlignImplicit && q->isComponentComplete()) {
1341 bool alignToRight = text.isEmpty() ? QGuiApplication::keyboardInputDirection() == Qt::RightToLeft : rightToLeftText;
1342 return setHAlign(alignToRight ? QQuickText::AlignRight : QQuickText::AlignLeft);
1347 void QQuickTextPrivate::mirrorChange()
1350 if (q->isComponentComplete()) {
1351 if (!hAlignImplicit && (hAlign == QQuickText::AlignRight || hAlign == QQuickText::AlignLeft)) {
1353 emit q->effectiveHorizontalAlignmentChanged();
1358 QTextDocument *QQuickTextPrivate::textDocument()
1363 QQuickText::VAlignment QQuickText::vAlign() const
1365 Q_D(const QQuickText);
1369 void QQuickText::setVAlign(VAlignment align)
1372 if (d->vAlign == align)
1376 emit verticalAlignmentChanged(align);
1380 \qmlproperty enumeration QtQuick2::Text::wrapMode
1382 Set this property to wrap the text to the Text item's width. The text will only
1383 wrap if an explicit width has been set. wrapMode can be one of:
1386 \o Text.NoWrap (default) - no wrapping will be performed. If the text contains insufficient newlines, then \l paintedWidth will exceed a set width.
1387 \o Text.WordWrap - wrapping is done on word boundaries only. If a word is too long, \l paintedWidth will exceed a set width.
1388 \o Text.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
1389 \o Text.Wrap - if possible, wrapping occurs at a word boundary; otherwise it will occur at the appropriate point on the line, even in the middle of a word.
1392 QQuickText::WrapMode QQuickText::wrapMode() const
1394 Q_D(const QQuickText);
1398 void QQuickText::setWrapMode(WrapMode mode)
1401 if (mode == d->wrapMode)
1407 emit wrapModeChanged();
1411 \qmlproperty int QtQuick2::Text::lineCount
1413 Returns the number of lines visible in the text item.
1415 This property is not supported for rich text.
1417 \sa maximumLineCount
1419 int QQuickText::lineCount() const
1421 Q_D(const QQuickText);
1422 return d->lineCount;
1426 \qmlproperty bool QtQuick2::Text::truncated
1428 Returns true if the text has been truncated due to \l maximumLineCount
1431 This property is not supported for rich text.
1433 \sa maximumLineCount, elide
1435 bool QQuickText::truncated() const
1437 Q_D(const QQuickText);
1438 return d->truncated;
1442 \qmlproperty int QtQuick2::Text::maximumLineCount
1444 Set this property to limit the number of lines that the text item will show.
1445 If elide is set to Text.ElideRight, the text will be elided appropriately.
1446 By default, this is the value of the largest possible integer.
1448 This property is not supported for rich text.
1450 \sa lineCount, elide
1452 int QQuickText::maximumLineCount() const
1454 Q_D(const QQuickText);
1455 return d->maximumLineCount;
1458 void QQuickText::setMaximumLineCount(int lines)
1462 d->maximumLineCountValid = lines==INT_MAX ? false : true;
1463 if (d->maximumLineCount != lines) {
1464 d->maximumLineCount = lines;
1466 emit maximumLineCountChanged();
1470 void QQuickText::resetMaximumLineCount()
1473 setMaximumLineCount(INT_MAX);
1474 d->elidePos = QPointF();
1475 if (d->truncated != false) {
1476 d->truncated = false;
1477 emit truncatedChanged();
1482 \qmlproperty enumeration QtQuick2::Text::textFormat
1484 The way the text property should be displayed.
1486 Supported text formats are:
1489 \o Text.AutoText (default)
1495 If the text format is \c Text.AutoText the text element
1496 will automatically determine whether the text should be treated as
1497 styled text. This determination is made using Qt::mightBeRichText().
1499 Text.StyledText is an optimized format supporting some basic text
1500 styling markup, in the style of html 3.2:
1507 <u> - underlined text
1508 <font color="color_name" size="1-7"></font>
1509 <h1> to <h6> - headers
1510 <a href=""> - anchor
1511 <ol type="">, <ul type=""> and <li> - ordered and unordered lists
1515 \c Text.StyledText parser is strict, requiring tags to be correctly nested.
1524 text: "<b>Hello</b> <i>World!</i>"
1528 textFormat: Text.RichText
1529 text: "<b>Hello</b> <i>World!</i>"
1533 textFormat: Text.PlainText
1534 text: "<b>Hello</b> <i>World!</i>"
1538 \o \image declarative-textformat.png
1541 QQuickText::TextFormat QQuickText::textFormat() const
1543 Q_D(const QQuickText);
1547 void QQuickText::setTextFormat(TextFormat format)
1550 if (format == d->format)
1553 bool wasRich = d->richText;
1554 d->richText = format == RichText;
1555 d->styledText = format == StyledText || (format == AutoText && Qt::mightBeRichText(d->text));
1557 if (!wasRich && d->richText && isComponentComplete()) {
1559 d->doc->setText(d->text);
1560 d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
1561 d->richTextAsImage = enableImageCache();
1563 d->rightToLeftText = d->text.isRightToLeft();
1565 d->determineHorizontalAlignment();
1568 emit textFormatChanged(d->format);
1572 \qmlproperty enumeration QtQuick2::Text::elide
1574 Set this property to elide parts of the text fit to the Text item's width.
1575 The text will only elide if an explicit width has been set.
1577 This property cannot be used with rich text.
1581 \o Text.ElideNone - the default
1587 If this property is set to Text.ElideRight, it can be used with multiline
1588 text. The text will only elide if maximumLineCount has been set.
1590 If the text is a multi-length string, and the mode is not \c Text.ElideNone,
1591 the first string that fits will be used, otherwise the last will be elided.
1593 Multi-length strings are ordered from longest to shortest, separated by the
1594 Unicode "String Terminator" character \c U009C (write this in QML with \c{"\u009C"} or \c{"\x9C"}).
1596 QQuickText::TextElideMode QQuickText::elideMode() const
1598 Q_D(const QQuickText);
1599 return d->elideMode;
1602 void QQuickText::setElideMode(QQuickText::TextElideMode mode)
1605 if (mode == d->elideMode)
1608 d->elideMode = mode;
1611 emit elideModeChanged(d->elideMode);
1615 QRectF QQuickText::boundingRect() const
1617 Q_D(const QQuickText);
1619 QRect rect = d->layedOutTextRect;
1620 if (d->style != Normal)
1621 rect.adjust(-1, 0, 1, 2);
1623 // Could include font max left/right bearings to either side of rectangle.
1626 switch (d->vAlign) {
1630 rect.moveTop(h - rect.height());
1633 rect.moveTop((h - rect.height()) / 2);
1637 return QRectF(rect);
1641 void QQuickText::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
1644 if ((!d->internalWidthUpdate && newGeometry.width() != oldGeometry.width())
1645 && (d->wrapMode != QQuickText::NoWrap
1646 || d->elideMode != QQuickText::ElideNone
1647 || d->hAlign != QQuickText::AlignLeft)) {
1648 if ((d->singleline || d->maximumLineCountValid) && d->elideMode != QQuickText::ElideNone && widthValid()) {
1649 // We need to re-elide
1652 // We just need to re-layout
1657 QQuickItem::geometryChanged(newGeometry, oldGeometry);
1660 QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1665 if (d->text.isEmpty()) {
1670 QRectF bounds = boundingRect();
1672 // We need to make sure the layout is done in the current thread
1673 #if defined(Q_OS_MAC)
1674 d->paintingThread = QThread::currentThread();
1675 if (d->layoutThread != d->paintingThread)
1679 // XXX todo - some styled text can be done by the QQuickTextNode
1680 if (d->richTextAsImage || d->cacheAllTextAsImage || (qmlDisableDistanceField() && d->style != Normal)) {
1681 bool wasDirty = d->textureImageCacheDirty;
1682 d->textureImageCacheDirty = false;
1684 if (d->imageCache.isNull()) {
1689 QSGImageNode *node = 0;
1690 if (!oldNode || d->nodeType != QQuickTextPrivate::NodeIsTexture) {
1692 node = QQuickItemPrivate::get(this)->sceneGraphContext()->createImageNode();
1693 d->texture = new QSGPlainTexture();
1695 d->nodeType = QQuickTextPrivate::NodeIsTexture;
1697 node = static_cast<QSGImageNode *>(oldNode);
1698 Q_ASSERT(d->texture);
1702 qobject_cast<QSGPlainTexture *>(d->texture)->setImage(d->imageCache.toImage());
1703 node->setTexture(0);
1704 node->setTexture(d->texture);
1707 node->setTargetRect(QRectF(bounds.x(), bounds.y(), d->imageCache.width(), d->imageCache.height()));
1708 node->setSourceRect(QRectF(0, 0, 1, 1));
1709 node->setHorizontalWrapMode(QSGTexture::ClampToEdge);
1710 node->setVerticalWrapMode(QSGTexture::ClampToEdge);
1711 node->setFiltering(QSGTexture::Linear); // Nonsmooth text just ugly, so don't do that..
1717 QQuickTextNode *node = 0;
1718 if (!oldNode || d->nodeType != QQuickTextPrivate::NodeIsText) {
1720 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext());
1721 d->nodeType = QQuickTextPrivate::NodeIsText;
1723 node = static_cast<QQuickTextNode *>(oldNode);
1726 node->deleteContent();
1727 node->setMatrix(QMatrix4x4());
1731 node->addTextDocument(bounds.topLeft(), d->doc, QColor(), d->style, d->styleColor);
1734 node->addTextLayout(QPoint(0, bounds.y()), &d->layout, d->color, d->style, d->styleColor);
1741 bool QQuickText::event(QEvent *e)
1744 if (e->type() == QEvent::User) {
1745 d->checkImageCache();
1748 return QQuickImplicitSizeItem::event(e);
1753 \qmlproperty real QtQuick2::Text::paintedWidth
1755 Returns the width of the text, including width past the width
1756 which is covered due to insufficient wrapping if WrapMode is set.
1758 qreal QQuickText::paintedWidth() const
1760 Q_D(const QQuickText);
1761 return d->paintedSize.width();
1765 \qmlproperty real QtQuick2::Text::paintedHeight
1767 Returns the height of the text, including height past the height
1768 which is covered due to there being more text than fits in the set height.
1770 qreal QQuickText::paintedHeight() const
1772 Q_D(const QQuickText);
1773 return d->paintedSize.height();
1777 \qmlproperty real QtQuick2::Text::lineHeight
1779 Sets the line height for the text.
1780 The value can be in pixels or a multiplier depending on lineHeightMode.
1782 The default value is a multiplier of 1.0.
1783 The line height must be a positive value.
1785 qreal QQuickText::lineHeight() const
1787 Q_D(const QQuickText);
1788 return d->lineHeight;
1791 void QQuickText::setLineHeight(qreal lineHeight)
1795 if ((d->lineHeight == lineHeight) || (lineHeight < 0.0))
1798 d->lineHeight = lineHeight;
1800 emit lineHeightChanged(lineHeight);
1804 \qmlproperty enumeration QtQuick2::Text::lineHeightMode
1806 This property determines how the line height is specified.
1807 The possible values are:
1810 \o Text.ProportionalHeight (default) - this sets the spacing proportional to the
1811 line (as a multiplier). For example, set to 2 for double spacing.
1812 \o Text.FixedHeight - this sets the line height to a fixed line height (in pixels).
1815 QQuickText::LineHeightMode QQuickText::lineHeightMode() const
1817 Q_D(const QQuickText);
1818 return d->lineHeightMode;
1821 void QQuickText::setLineHeightMode(LineHeightMode mode)
1824 if (mode == d->lineHeightMode)
1827 d->lineHeightMode = mode;
1830 emit lineHeightModeChanged(mode);
1834 Returns the number of resources (images) that are being loaded asynchronously.
1836 int QQuickText::resourcesLoading() const
1838 Q_D(const QQuickText);
1839 return d->doc ? d->doc->resourcesLoading() : 0;
1843 void QQuickText::componentComplete()
1846 QQuickItem::componentComplete();
1847 if (d->updateOnComponentComplete) {
1848 d->updateOnComponentComplete = false;
1851 d->doc->setText(d->text);
1852 d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
1853 d->richTextAsImage = enableImageCache();
1855 d->rightToLeftText = d->text.isRightToLeft();
1857 d->determineHorizontalAlignment();
1863 QString QQuickTextPrivate::anchorAt(const QPointF &mousePos)
1866 for (int i = 0; i < layout.lineCount(); ++i) {
1867 QTextLine line = layout.lineAt(i);
1868 if (line.naturalTextRect().contains(mousePos)) {
1869 int charPos = line.xToCursor(mousePos.x());
1870 foreach (const QTextLayout::FormatRange &formatRange, layout.additionalFormats()) {
1871 if (formatRange.format.isAnchor()
1872 && charPos >= formatRange.start
1873 && charPos <= formatRange.start + formatRange.length) {
1874 return formatRange.format.anchorHref();
1884 bool QQuickTextPrivate::isLinkActivatedConnected()
1886 static int idx = this->signalIndex("linkActivated(QString)");
1887 return this->isSignalConnected(idx);
1891 void QQuickText::mousePressEvent(QMouseEvent *event)
1895 if (d->isLinkActivatedConnected()) {
1897 d->activeLink = d->anchorAt(event->localPos());
1898 else if (d->richText && d->doc)
1899 d->activeLink = d->doc->documentLayout()->anchorAt(event->localPos());
1902 if (d->activeLink.isEmpty())
1903 event->setAccepted(false);
1905 // ### may malfunction if two of the same links are clicked & dragged onto each other)
1907 if (!event->isAccepted())
1908 QQuickItem::mousePressEvent(event);
1913 void QQuickText::mouseReleaseEvent(QMouseEvent *event)
1917 // ### confirm the link, and send a signal out
1920 if (d->isLinkActivatedConnected()) {
1922 link = d->anchorAt(event->localPos());
1923 else if (d->richText && d->doc)
1924 link = d->doc->documentLayout()->anchorAt(event->localPos());
1927 if (!link.isEmpty() && d->activeLink == link)
1928 emit linkActivated(d->activeLink);
1930 event->setAccepted(false);
1932 if (!event->isAccepted())
1933 QQuickItem::mouseReleaseEvent(event);
1938 #include "qquicktext.moc"