1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** 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 <QtQuick/private/qsgcontext_p.h>
46 #include <private/qsgadaptationlayer_p.h>
47 #include "qquicktextnode_p.h"
48 #include "qquickimage_p_p.h"
49 #include <QtQuick/private/qsgtexture_p.h>
51 #include <QtDeclarative/qdeclarativeinfo.h>
52 #include <QtGui/qevent.h>
53 #include <QtGui/qabstracttextdocumentlayout.h>
54 #include <QtGui/qpainter.h>
55 #include <QtGui/qtextdocument.h>
56 #include <QtGui/qtextobject.h>
57 #include <QtGui/qtextcursor.h>
58 #include <QtGui/qguiapplication.h>
59 #include <QtGui/qinputpanel.h>
61 #include <private/qdeclarativestyledtext_p.h>
62 #include <QtQuick/private/qdeclarativepixmapcache_p.h>
69 extern Q_GUI_EXPORT bool qt_applefontsmoothing_enabled;
71 DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
72 DEFINE_BOOL_CONFIG_OPTION(enableImageCache, QML_ENABLE_TEXT_IMAGE_CACHE);
74 QString QQuickTextPrivate::elideChar = QString(0x2026);
76 QQuickTextPrivate::QQuickTextPrivate()
77 : color((QRgb)0), style(QQuickText::Normal), hAlign(QQuickText::AlignLeft),
78 vAlign(QQuickText::AlignTop), elideMode(QQuickText::ElideNone),
79 format(QQuickText::AutoText), wrapMode(QQuickText::NoWrap), lineHeight(1),
80 lineHeightMode(QQuickText::ProportionalHeight), lineCount(1), maximumLineCount(INT_MAX),
81 maximumLineCountValid(false),
82 imageCache(0), texture(0),
83 imageCacheDirty(false), updateOnComponentComplete(true),
84 richText(false), styledText(false), singleline(false), cacheAllTextAsImage(true),
85 disableDistanceField(false), internalWidthUpdate(false),
86 requireImplicitWidth(false), truncated(false), hAlignImplicit(true), rightToLeftText(false),
87 layoutTextElided(false), richTextAsImage(false), textureImageCacheDirty(false), textHasChanged(true),
88 naturalWidth(0), doc(0), elipsisLayout(0), textLine(0), nodeType(NodeIsNull), updateType(UpdatePaintNode)
91 , layoutThread(0), paintingThread(0)
95 cacheAllTextAsImage = enableImageCache();
96 disableDistanceField = qmlDisableDistanceField();
99 void QQuickTextPrivate::init()
102 q->setAcceptedMouseButtons(Qt::LeftButton);
103 q->setFlag(QQuickItem::ItemHasContents);
106 QQuickTextDocumentWithImageResources::QQuickTextDocumentWithImageResources(QQuickItem *parent)
107 : QTextDocument(parent), outstanding(0)
109 setUndoRedoEnabled(false);
110 documentLayout()->registerHandler(QTextFormat::ImageObject, this);
113 QQuickTextDocumentWithImageResources::~QQuickTextDocumentWithImageResources()
115 if (!m_resources.isEmpty())
116 qDeleteAll(m_resources);
119 QVariant QQuickTextDocumentWithImageResources::loadResource(int type, const QUrl &name)
121 QDeclarativeContext *context = qmlContext(parent());
122 QUrl url = m_baseUrl.resolved(name);
124 if (type == QTextDocument::ImageResource) {
125 QDeclarativePixmap *p = loadPixmap(context, url);
129 return QTextDocument::loadResource(type,url); // The *resolved* URL
132 void QQuickTextDocumentWithImageResources::requestFinished()
135 if (outstanding == 0) {
136 markContentsDirty(0, characterCount());
141 void QQuickTextDocumentWithImageResources::clear()
145 QTextDocument::clear();
149 QSizeF QQuickTextDocumentWithImageResources::intrinsicSize(
150 QTextDocument *, int, const QTextFormat &format)
152 if (format.isImageFormat()) {
153 QTextImageFormat imageFormat = format.toImageFormat();
155 const bool hasWidth = imageFormat.hasProperty(QTextFormat::ImageWidth);
156 const int width = qRound(imageFormat.width());
157 const bool hasHeight = imageFormat.hasProperty(QTextFormat::ImageHeight);
158 const int height = qRound(imageFormat.height());
160 QSizeF size(width, height);
161 if (!hasWidth || !hasHeight) {
162 QDeclarativeContext *context = qmlContext(parent());
163 QUrl url = m_baseUrl.resolved(QUrl(imageFormat.name()));
165 QDeclarativePixmap *p = loadPixmap(context, url);
173 QSize implicitSize = p->implicitSize();
177 size.setWidth(implicitSize.width());
179 size.setWidth(qRound(height * (implicitSize.width() / (qreal) implicitSize.height())));
183 size.setHeight(implicitSize.height());
185 size.setHeight(qRound(width * (implicitSize.height() / (qreal) implicitSize.width())));
193 void QQuickTextDocumentWithImageResources::drawObject(
194 QPainter *, const QRectF &, QTextDocument *, int, const QTextFormat &)
198 QImage QQuickTextDocumentWithImageResources::image(const QTextImageFormat &format)
200 QDeclarativeContext *context = qmlContext(parent());
201 QUrl url = m_baseUrl.resolved(QUrl(format.name()));
203 QDeclarativePixmap *p = loadPixmap(context, url);
207 void QQuickTextDocumentWithImageResources::setBaseUrl(const QUrl &url, bool clear)
212 markContentsDirty(0, characterCount());
216 QDeclarativePixmap *QQuickTextDocumentWithImageResources::loadPixmap(
217 QDeclarativeContext *context, const QUrl &url)
220 QHash<QUrl, QDeclarativePixmap *>::Iterator iter = m_resources.find(url);
222 if (iter == m_resources.end()) {
223 QDeclarativePixmap *p = new QDeclarativePixmap(context->engine(), url);
224 iter = m_resources.insert(url, p);
226 if (p->isLoading()) {
227 p->connectFinished(this, SLOT(requestFinished()));
232 QDeclarativePixmap *p = *iter;
234 if (!errors.contains(url)) {
236 qmlInfo(parent()) << p->error();
242 void QQuickTextDocumentWithImageResources::clearResources()
244 foreach (QDeclarativePixmap *pixmap, m_resources)
246 qDeleteAll(m_resources);
251 void QQuickTextDocumentWithImageResources::setText(const QString &text)
255 #ifndef QT_NO_TEXTHTMLPARSER
262 QSet<QUrl> QQuickTextDocumentWithImageResources::errors;
264 QQuickTextPrivate::~QQuickTextPrivate()
266 delete elipsisLayout;
267 delete textLine; textLine = 0;
271 qreal QQuickTextPrivate::getImplicitWidth() const
273 if (!requireImplicitWidth) {
274 // We don't calculate implicitWidth unless it is required.
275 // We need to force a size update now to ensure implicitWidth is calculated
276 QQuickTextPrivate *me = const_cast<QQuickTextPrivate*>(this);
277 me->requireImplicitWidth = true;
280 return implicitWidth;
283 void QQuickText::q_imagesLoaded()
289 void QQuickTextPrivate::updateLayout()
292 if (!q->isComponentComplete()) {
293 updateOnComponentComplete = true;
296 updateOnComponentComplete = false;
297 layoutTextElided = false;
298 // Setup instance of QTextLayout for all cases other than richtext
301 delete elipsisLayout;
304 layout.setFont(font);
305 if (text.isEmpty()) {
306 if (!layout.text().isEmpty())
307 layout.setText(text);
308 } else if (!styledText) {
310 tmp.replace(QLatin1Char('\n'), QChar::LineSeparator);
311 singleline = !tmp.contains(QChar::LineSeparator);
312 if (singleline && !maximumLineCountValid && elideMode != QQuickText::ElideNone && q->widthValid() && wrapMode == QQuickText::NoWrap) {
313 if (q->width() <= 0) {
316 QFontMetrics fm(font);
317 tmp = fm.elidedText(tmp,(Qt::TextElideMode)elideMode,q->width());
320 layoutTextElided = true;
323 emit q->truncatedChanged();
330 if (textHasChanged) {
331 QDeclarativeStyledText::parse(text, layout);
332 textHasChanged = false;
337 QTextBlockFormat::LineHeightTypes type;
338 type = lineHeightMode == QQuickText::FixedHeight ? QTextBlockFormat::FixedHeight : QTextBlockFormat::ProportionalHeight;
339 QTextBlockFormat blockFormat;
340 blockFormat.setLineHeight((lineHeightMode == QQuickText::FixedHeight ? lineHeight : lineHeight * 100), type);
341 for (QTextBlock it = doc->begin(); it != doc->end(); it = it.next()) {
342 QTextCursor cursor(it);
343 cursor.mergeBlockFormat(blockFormat);
350 void QQuickTextPrivate::updateSize()
354 if (!q->isComponentComplete()) {
355 updateOnComponentComplete = true;
359 if (!requireImplicitWidth) {
360 emit q->implicitWidthChanged();
361 // if the implicitWidth is used, then updateSize() has already been called (recursively)
362 if (requireImplicitWidth)
366 invalidateImageCache();
368 QFontMetrics fm(font);
369 if (text.isEmpty()) {
370 qreal fontHeight = fm.height();
371 q->setImplicitSize(0, fontHeight);
372 paintedSize = QSize(0, fontHeight);
373 emit q->paintedSizeChanged();
374 updateType = UpdatePaintNode;
379 int dy = q->height();
382 #if defined(Q_OS_MAC)
383 layoutThread = QThread::currentThread();
386 //setup instance of QTextLayout for all cases other than richtext
388 QRect textRect = setupTextLayout();
389 layedOutTextRect = textRect;
390 size = textRect.size();
393 singleline = false; // richtext can't elide or be optimized for single-line case
395 doc->setDefaultFont(font);
396 QQuickText::HAlignment horizontalAlignment = q->effectiveHAlign();
397 if (rightToLeftText) {
398 if (horizontalAlignment == QQuickText::AlignLeft)
399 horizontalAlignment = QQuickText::AlignRight;
400 else if (horizontalAlignment == QQuickText::AlignRight)
401 horizontalAlignment = QQuickText::AlignLeft;
404 option.setAlignment((Qt::Alignment)int(horizontalAlignment | vAlign));
405 option.setWrapMode(QTextOption::WrapMode(wrapMode));
406 if (!cacheAllTextAsImage && !richTextAsImage && !disableDistanceField)
407 option.setUseDesignMetrics(true);
408 doc->setDefaultTextOption(option);
409 if (requireImplicitWidth && q->widthValid()) {
410 doc->setTextWidth(-1);
411 naturalWidth = doc->idealWidth();
413 if (wrapMode != QQuickText::NoWrap && q->widthValid())
414 doc->setTextWidth(q->width());
416 doc->setTextWidth(doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug)
417 dy -= (int)doc->size().height();
418 QSize dsize = doc->size().toSize();
419 layedOutTextRect = QRect(QPoint(0,0), dsize);
420 size = QSize(int(doc->idealWidth()),dsize.height());
424 if (q->heightValid()) {
425 if (vAlign == QQuickText::AlignBottom)
427 else if (vAlign == QQuickText::AlignVCenter)
430 q->setBaselineOffset(fm.ascent() + yoff);
432 //### need to comfirm cost of always setting these for richText
433 internalWidthUpdate = true;
435 if (!q->widthValid())
436 iWidth = size.width();
437 else if (requireImplicitWidth)
438 iWidth = naturalWidth;
440 q->setImplicitSize(iWidth, size.height());
441 internalWidthUpdate = false;
444 q->setImplicitHeight(size.height());
445 if (paintedSize != size) {
447 emit q->paintedSizeChanged();
449 updateType = UpdatePaintNode;
453 QQuickTextLine::QQuickTextLine()
454 : QObject(), m_line(0), m_height(0)
458 void QQuickTextLine::setLine(QTextLine *line)
463 int QQuickTextLine::number() const
466 return m_line->lineNumber();
470 qreal QQuickTextLine::width() const
473 return m_line->width();
477 void QQuickTextLine::setWidth(qreal width)
480 m_line->setLineWidth(width);
483 qreal QQuickTextLine::height() const
488 return m_line->height();
492 void QQuickTextLine::setHeight(qreal height)
495 m_line->setPosition(QPointF(m_line->x(), m_line->y() - m_line->height() + height));
499 qreal QQuickTextLine::x() const
506 void QQuickTextLine::setX(qreal x)
509 m_line->setPosition(QPointF(x, m_line->y()));
512 qreal QQuickTextLine::y() const
519 void QQuickTextLine::setY(qreal y)
522 m_line->setPosition(QPointF(m_line->x(), y));
525 void QQuickText::doLayout()
531 bool QQuickTextPrivate::isLineLaidOutConnected()
533 static int idx = this->signalIndex("lineLaidOut(QQuickTextLine*)");
534 return this->isSignalConnected(idx);
537 void QQuickTextPrivate::setupCustomLineGeometry(QTextLine &line, qreal &height, qreal elideWidth = 0)
541 #if defined(Q_OS_MAC)
542 if (QThread::currentThread() != paintingThread) {
543 if (!line.lineNumber())
548 textLine = new QQuickTextLine;
549 textLine->setLine(&line);
550 textLine->setY(height);
551 textLine->setHeight(0);
553 // use the text item's width by default if it has one and wrap is on
554 if (q->widthValid() && q->wrapMode() != QQuickText::NoWrap)
555 textLine->setWidth(q->width() - elideWidth);
557 textLine->setWidth(INT_MAX);
558 if (lineHeight != 1.0)
559 textLine->setHeight((lineHeightMode == QQuickText::FixedHeight) ? lineHeight : line.height() * lineHeight);
561 emit q->lineLaidOut(textLine);
563 height += textLine->height();
565 #if defined(Q_OS_MAC)
566 linesRects << QRectF(textLine->x(), textLine->y(), textLine->width(), textLine->height());
569 if (line.lineNumber() < linesRects.count()) {
570 QRectF r = linesRects.at(line.lineNumber());
571 line.setLineWidth(r.width());
572 line.setPosition(r.topLeft());
579 Lays out the QQuickTextPrivate::layout QTextLayout in the constraints of the QQuickText.
581 Returns the size of the final text. This can be used to position the text vertically (the text is
582 already absolutely positioned horizontally).
584 QRect QQuickTextPrivate::setupTextLayout()
586 // ### text layout handling should be profiled and optimized as needed
587 // what about QStackTextEngine engine(tmp, d->font.font()); QTextLayout textLayout(&engine);
589 layout.setCacheEnabled(true);
592 int visibleCount = 0;
596 lineWidth = q->width();
598 QTextOption textOption = layout.textOption();
599 textOption.setAlignment(Qt::Alignment(q->effectiveHAlign()));
600 textOption.setWrapMode(QTextOption::WrapMode(wrapMode));
601 if (!cacheAllTextAsImage && !richTextAsImage && !disableDistanceField)
602 textOption.setUseDesignMetrics(true);
603 layout.setTextOption(textOption);
605 QFontMetrics fm(layout.font());
606 elidePos = QPointF();
608 if (requireImplicitWidth && q->widthValid()) {
609 // requires an extra layout
611 if (layoutTextElided) {
612 // We have provided elided text to the layout, but we must calculate unelided width.
613 elidedText = layout.text();
614 layout.setText(text);
616 layout.beginLayout();
618 QTextLine line = layout.createLine();
624 for (int i = 0; i < layout.lineCount(); ++i) {
625 QTextLine line = layout.lineAt(i);
626 br = br.united(line.naturalTextRect());
628 naturalWidth = br.width();
629 if (layoutTextElided)
630 layout.setText(elidedText);
633 if ((q->widthValid() && q->width() <= 0. && elideMode != QQuickText::ElideNone)
634 || (q->heightValid() && q->height() <= 0. && wrapMode != QQuickText::NoWrap && elideMode == QQuickText::ElideRight)) {
635 // we are elided and we have a zero width or height
638 emit q->truncatedChanged();
642 emit q->lineCountChanged();
645 qreal height = (lineHeightMode == QQuickText::FixedHeight) ? lineHeight : fm.height() * lineHeight;
646 return QRect(0, 0, 0, height);
652 bool truncate = layoutTextElided;
653 bool customLayout = isLineLaidOutConnected();
654 bool multilineElideEnabled = elideMode == QQuickText::ElideRight && q->widthValid() && wrapMode != QQuickText::NoWrap;
656 layout.beginLayout();
659 int linesLeft = maximumLineCount;
660 int visibleTextLength = 0;
662 QTextLine line = layout.createLine();
668 qreal preLayoutHeight = height;
670 setupCustomLineGeometry(line, height);
671 } else if (lineWidth) {
672 line.setLineWidth(lineWidth);
673 line.setPosition(QPointF(line.position().x(), height));
674 height += (lineHeightMode == QQuickText::FixedHeight) ? lineHeight : line.height() * lineHeight;
678 if (multilineElideEnabled && q->heightValid() && height > q->height()) {
679 // This line does not fit in the remaining area.
681 if (visibleCount > 1) {
683 height = preLayoutHeight;
684 line.setLineWidth(0.0);
685 line.setPosition(QPointF(FLT_MAX,FLT_MAX));
686 line = layout.lineAt(visibleCount-1);
689 visibleTextLength += line.textLength();
692 if (elide || (maximumLineCountValid && --linesLeft == 0)) {
693 if (visibleTextLength < text.length()) {
695 if (multilineElideEnabled) {
696 qreal elideWidth = fm.width(elideChar);
697 // Need to correct for alignment
699 setupCustomLineGeometry(line, height, elideWidth);
701 line.setLineWidth(lineWidth - elideWidth);
702 if (layout.text().mid(line.textStart(), line.textLength()).isRightToLeft()) {
703 line.setPosition(QPointF(line.position().x() + elideWidth, line.position().y()));
704 elidePos.setX(line.naturalTextRect().left() - elideWidth);
706 elidePos.setX(line.naturalTextRect().right());
708 elidePos.setY(line.position().y());
710 elipsisLayout = new QTextLayout(elideChar, layout.font());
711 elipsisLayout->beginLayout();
712 QTextLine el = elipsisLayout->createLine();
713 el.setPosition(elidePos);
714 elipsisLayout->endLayout();
715 br = br.united(el.naturalTextRect());
717 br = br.united(line.naturalTextRect());
721 br = br.united(line.naturalTextRect());
726 if (truncated != truncate) {
727 truncated = truncate;
728 emit q->truncatedChanged();
732 br.setHeight(height);
734 if (!q->widthValid())
735 naturalWidth = br.width();
737 //Update the number of visible lines
738 if (lineCount != visibleCount) {
739 lineCount = visibleCount;
740 emit q->lineCountChanged();
743 return QRect(qRound(br.x()), qRound(br.y()), qCeil(br.width()), qCeil(br.height()));
747 Returns a painted version of the QQuickTextPrivate::layout QTextLayout.
748 If \a drawStyle is true, the style color overrides all colors in the document.
750 QPixmap QQuickTextPrivate::textLayoutImage(bool drawStyle)
752 QSize size = layedOutTextRect.size();
756 if (!size.isEmpty()) {
757 img.fill(Qt::transparent);
758 /*#ifdef Q_OS_MAC // Fails on CocoaX64
759 bool oldSmooth = qt_applefontsmoothing_enabled;
760 qt_applefontsmoothing_enabled = false;
763 /*#ifdef Q_OS_MAC // Fails on CocoaX64
764 qt_applefontsmoothing_enabled = oldSmooth;
766 drawTextLayout(&p, QPointF(-layedOutTextRect.x(),0), drawStyle);
772 Paints the QQuickTextPrivate::layout QTextLayout into \a painter at \a pos. If
773 \a drawStyle is true, the style color overrides all colors in the document.
775 void QQuickTextPrivate::drawTextLayout(QPainter *painter, const QPointF &pos, bool drawStyle)
778 painter->setPen(styleColor);
780 painter->setPen(color);
781 painter->setFont(font);
782 layout.draw(painter, pos);
783 if (!elidePos.isNull())
784 painter->drawText(pos + elidePos, elideChar);
788 Returns a painted version of the QQuickTextPrivate::doc QTextDocument.
789 If \a drawStyle is true, the style color overrides all colors in the document.
791 QPixmap QQuickTextPrivate::textDocumentImage(bool drawStyle)
793 QSize size = doc->size().toSize();
797 img.fill(Qt::transparent);
798 /*#ifdef Q_OS_MAC // Fails on CocoaX64
799 bool oldSmooth = qt_applefontsmoothing_enabled;
800 qt_applefontsmoothing_enabled = false;
803 /*#ifdef Q_OS_MAC // Fails on CocoaX64
804 qt_applefontsmoothing_enabled = oldSmooth;
807 QAbstractTextDocumentLayout::PaintContext context;
809 QTextOption oldOption(doc->defaultTextOption());
811 context.palette.setColor(QPalette::Text, styleColor);
812 QTextOption colorOption(doc->defaultTextOption());
813 colorOption.setFlags(QTextOption::SuppressColors);
814 doc->setDefaultTextOption(colorOption);
816 context.palette.setColor(QPalette::Text, color);
818 doc->documentLayout()->draw(&p, context);
820 doc->setDefaultTextOption(oldOption);
825 void QQuickTextPrivate::markDirty()
828 if (!invalidateImageCache() && q->isComponentComplete())
833 Mark the image cache as dirty.
835 bool QQuickTextPrivate::invalidateImageCache()
839 if (richTextAsImage || cacheAllTextAsImage || (disableDistanceField && style != QQuickText::Normal)) { // If actually using the image cache
843 imageCacheDirty = true;
845 if (q->isComponentComplete())
846 QCoreApplication::postEvent(q, new QEvent(QEvent::User));
854 Tests if the image cache is dirty, and repaints it if it is.
856 void QQuickTextPrivate::checkImageCache()
860 if (!imageCacheDirty)
863 if (text.isEmpty()) {
874 textImage = textDocumentImage(false);
875 if (style != QQuickText::Normal)
876 styledImage = textDocumentImage(true); //### should use styleColor
878 textImage = textLayoutImage(false);
879 if (style != QQuickText::Normal)
880 styledImage = textLayoutImage(true); //### should use styleColor
885 case QQuickText::Outline:
886 imageCache = new QPixmap(drawOutline(textImage, styledImage));
888 case QQuickText::Sunken:
889 imageCache = new QPixmap(drawOutline(textImage, styledImage, -1));
891 case QQuickText::Raised:
892 imageCache = new QPixmap(drawOutline(textImage, styledImage, 1));
895 imageCache = new QPixmap(textImage);
901 imageCacheDirty = false;
902 textureImageCacheDirty = true;
903 updateType = UpdatePaintNode;
908 Ensures the QQuickTextPrivate::doc variable is set to a valid text document
910 void QQuickTextPrivate::ensureDoc()
914 doc = new QQuickTextDocumentWithImageResources(q);
915 doc->setDocumentMargin(0);
916 doc->setBaseUrl(q->baseUrl());
917 FAST_CONNECT(doc, SIGNAL(imagesLoaded()), q, SLOT(q_imagesLoaded()));
922 Draw \a styleSource as an outline around \a source and return the new image.
924 QPixmap QQuickTextPrivate::drawOutline(const QPixmap &source, const QPixmap &styleSource)
926 QPixmap img = QPixmap(styleSource.width() + 2, styleSource.height() + 2);
927 img.fill(Qt::transparent);
932 pos += QPoint(-1, 0);
933 ppm.drawPixmap(pos, styleSource);
935 ppm.drawPixmap(pos, styleSource);
936 pos += QPoint(-1, -1);
937 ppm.drawPixmap(pos, styleSource);
939 ppm.drawPixmap(pos, styleSource);
941 pos += QPoint(0, -1);
942 ppm.drawPixmap(pos, source);
949 Draw \a styleSource below \a source at \a yOffset and return the new image.
951 QPixmap QQuickTextPrivate::drawOutline(const QPixmap &source, const QPixmap &styleSource, int yOffset)
953 QPixmap img = QPixmap(styleSource.width() + 2, styleSource.height() + 2);
954 img.fill(Qt::transparent);
958 ppm.drawPixmap(QPoint(0, yOffset), styleSource);
959 ppm.drawPixmap(0, 0, source);
967 \qmlclass Text QQuickText
968 \inqmlmodule QtQuick 2
969 \ingroup qml-basic-visual-elements
970 \brief The Text item allows you to add formatted text to a scene.
973 Text items can display both plain and rich text. For example, red text with
974 a specific font and size can be defined like this:
979 font.family: "Helvetica"
985 Rich text is defined using HTML-style markup:
989 text: "<b>Hello</b> <i>World!</i>"
993 \image declarative-text.png
995 If height and width are not explicitly set, Text will attempt to determine how
996 much room is needed and set it accordingly. Unless \l wrapMode is set, it will always
997 prefer width to height (all text will be placed on a single line).
999 The \l elide property can alternatively be used to fit a single line of
1000 plain text to a set width.
1002 Note that the \l{Supported HTML Subset} is limited. Also, if the text contains
1003 HTML img tags that load remote images, the text is reloaded.
1005 Text provides read-only text. For editable text, see \l TextEdit.
1007 \sa {declarative/text/fonts}{Fonts example}
1009 QQuickText::QQuickText(QQuickItem *parent)
1010 : QQuickImplicitSizeItem(*(new QQuickTextPrivate), parent)
1016 QQuickText::~QQuickText()
1021 \qmlproperty bool QtQuick2::Text::clip
1022 This property holds whether the text is clipped.
1024 Note that if the text does not fit in the bounding rectangle it will be abruptly chopped.
1026 If you want to display potentially long text in a limited space, you probably want to use \c elide instead.
1030 \qmlproperty bool QtQuick2::Text::smooth
1032 This property holds whether the text is smoothly scaled or transformed.
1034 Smooth filtering gives better visual quality, but is slower. If
1035 the item is displayed at its natural size, this property has no visual or
1038 \note Generally scaling artifacts are only visible if the item is stationary on
1039 the screen. A common pattern when animating an item is to disable smooth
1040 filtering at the beginning of the animation and reenable it at the conclusion.
1044 \qmlsignal QtQuick2::Text::onLineLaidOut(line)
1046 This handler is called for every line during the layout process.
1047 This gives the opportunity to position and resize a line as it is being laid out.
1048 It can for example be used to create columns or lay out text around objects.
1050 The properties of a line are:
1052 \o number (read-only)
1059 For example, this will move the first 5 lines of a text element by 100 pixels to the right:
1062 if (line.number < 5) {
1063 line.x = line.x + 100
1064 line.width = line.width - 100
1071 \qmlsignal QtQuick2::Text::onLinkActivated(string link)
1073 This handler is called when the user clicks on a link embedded in the text.
1074 The link must be in rich text or HTML format and the
1075 \a link string provides access to the particular link.
1077 \snippet doc/src/snippets/declarative/text/onLinkActivated.qml 0
1079 The example code will display the text
1080 "The main website is at \l{http://qt.nokia.com}{Nokia Qt DF}."
1082 Clicking on the highlighted link will output
1083 \tt{http://qt.nokia.com link activated} to the console.
1087 \qmlproperty string QtQuick2::Text::font.family
1089 Sets the family name of the font.
1091 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
1092 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
1093 If the family isn't available a family will be set using the font matching algorithm.
1097 \qmlproperty bool QtQuick2::Text::font.bold
1099 Sets whether the font weight is bold.
1103 \qmlproperty enumeration QtQuick2::Text::font.weight
1105 Sets the font's weight.
1107 The weight can be one of:
1110 \o Font.Normal - the default
1117 Text { text: "Hello"; font.weight: Font.DemiBold }
1122 \qmlproperty bool QtQuick2::Text::font.italic
1124 Sets whether the font has an italic style.
1128 \qmlproperty bool QtQuick2::Text::font.underline
1130 Sets whether the text is underlined.
1134 \qmlproperty bool QtQuick2::Text::font.strikeout
1136 Sets whether the font has a strikeout style.
1140 \qmlproperty real QtQuick2::Text::font.pointSize
1142 Sets the font size in points. The point size must be greater than zero.
1146 \qmlproperty int QtQuick2::Text::font.pixelSize
1148 Sets the font size in pixels.
1150 Using this function makes the font device dependent.
1151 Use \c pointSize to set the size of the font in a device independent manner.
1155 \qmlproperty real QtQuick2::Text::font.letterSpacing
1157 Sets the letter spacing for the font.
1159 Letter spacing changes the default spacing between individual letters in the font.
1160 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
1164 \qmlproperty real QtQuick2::Text::font.wordSpacing
1166 Sets the word spacing for the font.
1168 Word spacing changes the default spacing between individual words.
1169 A positive value increases the word spacing by a corresponding amount of pixels,
1170 while a negative value decreases the inter-word spacing accordingly.
1174 \qmlproperty enumeration QtQuick2::Text::font.capitalization
1176 Sets the capitalization for the text.
1179 \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
1180 \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
1181 \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
1182 \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
1183 \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
1187 Text { text: "Hello"; font.capitalization: Font.AllLowercase }
1190 QFont QQuickText::font() const
1192 Q_D(const QQuickText);
1193 return d->sourceFont;
1196 void QQuickText::setFont(const QFont &font)
1199 if (d->sourceFont == font)
1202 d->sourceFont = font;
1203 QFont oldFont = d->font;
1206 if (d->font.pointSizeF() != -1) {
1208 qreal size = qRound(d->font.pointSizeF()*2.0);
1209 d->font.setPointSizeF(size/2.0);
1212 if (oldFont != d->font)
1215 emit fontChanged(d->sourceFont);
1219 \qmlproperty string QtQuick2::Text::text
1221 The text to display. Text supports both plain and rich text strings.
1223 The item will try to automatically determine whether the text should
1224 be treated as styled text. This determination is made using Qt::mightBeRichText().
1226 QString QQuickText::text() const
1228 Q_D(const QQuickText);
1232 void QQuickText::setText(const QString &n)
1238 d->richText = d->format == RichText;
1239 d->styledText = d->format == StyledText || (d->format == AutoText && Qt::mightBeRichText(n));
1241 if (isComponentComplete()) {
1245 d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
1246 d->richTextAsImage = enableImageCache();
1248 d->rightToLeftText = d->text.isRightToLeft();
1250 d->determineHorizontalAlignment();
1252 d->textHasChanged = true;
1254 emit textChanged(d->text);
1258 \qmlproperty color QtQuick2::Text::color
1262 An example of green text defined using hexadecimal notation:
1270 An example of steel blue text defined using an SVG color name:
1278 QColor QQuickText::color() const
1280 Q_D(const QQuickText);
1284 void QQuickText::setColor(const QColor &color)
1287 if (d->color == color)
1292 emit colorChanged(d->color);
1295 \qmlproperty enumeration QtQuick2::Text::style
1297 Set an additional text style.
1299 Supported text styles are:
1301 \o Text.Normal - the default
1309 Text { font.pointSize: 24; text: "Normal" }
1310 Text { font.pointSize: 24; text: "Raised"; style: Text.Raised; styleColor: "#AAAAAA" }
1311 Text { font.pointSize: 24; text: "Outline";style: Text.Outline; styleColor: "red" }
1312 Text { font.pointSize: 24; text: "Sunken"; style: Text.Sunken; styleColor: "#AAAAAA" }
1316 \image declarative-textstyle.png
1318 QQuickText::TextStyle QQuickText::style() const
1320 Q_D(const QQuickText);
1324 void QQuickText::setStyle(QQuickText::TextStyle style)
1327 if (d->style == style)
1330 // changing to/from Normal requires the boundingRect() to change
1331 if (isComponentComplete() && (d->style == Normal || style == Normal)) {
1332 d->updateType = QQuickTextPrivate::UpdatePaintNode;
1337 emit styleChanged(d->style);
1341 \qmlproperty color QtQuick2::Text::styleColor
1343 Defines the secondary color used by text styles.
1345 \c styleColor is used as the outline color for outlined text, and as the
1346 shadow color for raised or sunken text. If no style has been set, it is not
1350 Text { font.pointSize: 18; text: "hello"; style: Text.Raised; styleColor: "gray" }
1355 QColor QQuickText::styleColor() const
1357 Q_D(const QQuickText);
1358 return d->styleColor;
1361 void QQuickText::setStyleColor(const QColor &color)
1364 if (d->styleColor == color)
1367 d->styleColor = color;
1369 emit styleColorChanged(d->styleColor);
1373 \qmlproperty enumeration QtQuick2::Text::horizontalAlignment
1374 \qmlproperty enumeration QtQuick2::Text::verticalAlignment
1375 \qmlproperty enumeration QtQuick2::Text::effectiveHorizontalAlignment
1377 Sets the horizontal and vertical alignment of the text within the Text items
1378 width and height. By default, the text is vertically aligned to the top. Horizontal
1379 alignment follows the natural alignment of the text, for example text that is read
1380 from left to right will be aligned to the left.
1382 The valid values for \c horizontalAlignment are \c Text.AlignLeft, \c Text.AlignRight, \c Text.AlignHCenter and
1383 \c Text.AlignJustify. The valid values for \c verticalAlignment are \c Text.AlignTop, \c Text.AlignBottom
1384 and \c Text.AlignVCenter.
1386 Note that for a single line of text, the size of the text is the area of the text. In this common case,
1387 all alignments are equivalent. If you want the text to be, say, centered in its parent, then you will
1388 need to either modify the Item::anchors, or set horizontalAlignment to Text.AlignHCenter and bind the width to
1391 When using the attached property LayoutMirroring::enabled to mirror application
1392 layouts, the horizontal alignment of text will also be mirrored. However, the property
1393 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
1394 of Text, use the read-only property \c effectiveHorizontalAlignment.
1396 QQuickText::HAlignment QQuickText::hAlign() const
1398 Q_D(const QQuickText);
1402 void QQuickText::setHAlign(HAlignment align)
1405 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
1406 d->hAlignImplicit = false;
1407 if (d->setHAlign(align, forceAlign) && isComponentComplete())
1411 void QQuickText::resetHAlign()
1414 d->hAlignImplicit = true;
1415 if (isComponentComplete() && d->determineHorizontalAlignment())
1419 QQuickText::HAlignment QQuickText::effectiveHAlign() const
1421 Q_D(const QQuickText);
1422 QQuickText::HAlignment effectiveAlignment = d->hAlign;
1423 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
1424 switch (d->hAlign) {
1425 case QQuickText::AlignLeft:
1426 effectiveAlignment = QQuickText::AlignRight;
1428 case QQuickText::AlignRight:
1429 effectiveAlignment = QQuickText::AlignLeft;
1435 return effectiveAlignment;
1438 bool QQuickTextPrivate::setHAlign(QQuickText::HAlignment alignment, bool forceAlign)
1441 if (hAlign != alignment || forceAlign) {
1442 QQuickText::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
1445 emit q->horizontalAlignmentChanged(hAlign);
1446 if (oldEffectiveHAlign != q->effectiveHAlign())
1447 emit q->effectiveHorizontalAlignmentChanged();
1453 bool QQuickTextPrivate::determineHorizontalAlignment()
1455 if (hAlignImplicit) {
1456 bool alignToRight = text.isEmpty() ? qApp->inputPanel()->inputDirection() == Qt::RightToLeft : rightToLeftText;
1457 return setHAlign(alignToRight ? QQuickText::AlignRight : QQuickText::AlignLeft);
1462 void QQuickTextPrivate::mirrorChange()
1465 if (q->isComponentComplete()) {
1466 if (!hAlignImplicit && (hAlign == QQuickText::AlignRight || hAlign == QQuickText::AlignLeft)) {
1468 emit q->effectiveHorizontalAlignmentChanged();
1473 QTextDocument *QQuickTextPrivate::textDocument()
1478 QQuickText::VAlignment QQuickText::vAlign() const
1480 Q_D(const QQuickText);
1484 void QQuickText::setVAlign(VAlignment align)
1487 if (d->vAlign == align)
1491 emit verticalAlignmentChanged(align);
1495 \qmlproperty enumeration QtQuick2::Text::wrapMode
1497 Set this property to wrap the text to the Text item's width. The text will only
1498 wrap if an explicit width has been set. wrapMode can be one of:
1501 \o Text.NoWrap (default) - no wrapping will be performed. If the text contains insufficient newlines, then \l paintedWidth will exceed a set width.
1502 \o Text.WordWrap - wrapping is done on word boundaries only. If a word is too long, \l paintedWidth will exceed a set width.
1503 \o Text.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
1504 \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.
1507 QQuickText::WrapMode QQuickText::wrapMode() const
1509 Q_D(const QQuickText);
1513 void QQuickText::setWrapMode(WrapMode mode)
1516 if (mode == d->wrapMode)
1522 emit wrapModeChanged();
1526 \qmlproperty int QtQuick2::Text::lineCount
1528 Returns the number of lines visible in the text item.
1530 This property is not supported for rich text.
1532 \sa maximumLineCount
1534 int QQuickText::lineCount() const
1536 Q_D(const QQuickText);
1537 return d->lineCount;
1541 \qmlproperty bool QtQuick2::Text::truncated
1543 Returns true if the text has been truncated due to \l maximumLineCount
1546 This property is not supported for rich text.
1548 \sa maximumLineCount, elide
1550 bool QQuickText::truncated() const
1552 Q_D(const QQuickText);
1553 return d->truncated;
1557 \qmlproperty int QtQuick2::Text::maximumLineCount
1559 Set this property to limit the number of lines that the text item will show.
1560 If elide is set to Text.ElideRight, the text will be elided appropriately.
1561 By default, this is the value of the largest possible integer.
1563 This property is not supported for rich text.
1565 \sa lineCount, elide
1567 int QQuickText::maximumLineCount() const
1569 Q_D(const QQuickText);
1570 return d->maximumLineCount;
1573 void QQuickText::setMaximumLineCount(int lines)
1577 d->maximumLineCountValid = lines==INT_MAX ? false : true;
1578 if (d->maximumLineCount != lines) {
1579 d->maximumLineCount = lines;
1581 emit maximumLineCountChanged();
1585 void QQuickText::resetMaximumLineCount()
1588 setMaximumLineCount(INT_MAX);
1589 d->elidePos = QPointF();
1590 if (d->truncated != false) {
1591 d->truncated = false;
1592 emit truncatedChanged();
1597 \qmlproperty enumeration QtQuick2::Text::textFormat
1599 The way the text property should be displayed.
1601 Supported text formats are:
1604 \o Text.AutoText (default)
1610 If the text format is \c Text.AutoText the text element
1611 will automatically determine whether the text should be treated as
1612 styled text. This determination is made using Qt::mightBeRichText().
1614 Text.StyledText is an optimized format supporting some basic text
1615 styling markup, in the style of html 3.2:
1619 <strong></strong> - bold
1623 <u> - underlined text
1624 <font color="color_name" size="1-7"></font>
1625 <h1> to <h6> - headers
1626 <a href=""> - anchor
1627 <ol type="">, <ul type=""> and <li> - ordered and unordered lists
1628 <pre></pre> - preformatted
1632 \c Text.StyledText parser is strict, requiring tags to be correctly nested.
1641 text: "<b>Hello</b> <i>World!</i>"
1645 textFormat: Text.RichText
1646 text: "<b>Hello</b> <i>World!</i>"
1650 textFormat: Text.PlainText
1651 text: "<b>Hello</b> <i>World!</i>"
1655 \o \image declarative-textformat.png
1658 QQuickText::TextFormat QQuickText::textFormat() const
1660 Q_D(const QQuickText);
1664 void QQuickText::setTextFormat(TextFormat format)
1667 if (format == d->format)
1670 bool wasRich = d->richText;
1671 d->richText = format == RichText;
1672 d->styledText = format == StyledText || (format == AutoText && Qt::mightBeRichText(d->text));
1674 if (isComponentComplete()) {
1675 if (!wasRich && d->richText) {
1677 d->doc->setText(d->text);
1678 d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
1679 d->richTextAsImage = enableImageCache();
1681 d->rightToLeftText = d->text.isRightToLeft();
1683 d->determineHorizontalAlignment();
1687 emit textFormatChanged(d->format);
1691 \qmlproperty enumeration QtQuick2::Text::elide
1693 Set this property to elide parts of the text fit to the Text item's width.
1694 The text will only elide if an explicit width has been set.
1696 This property cannot be used with rich text.
1700 \o Text.ElideNone - the default
1706 If this property is set to Text.ElideRight, it can be used with \l {wrapMode}{wrapped}
1707 text. The text will only elide if \c maximumLineCount, or \c height has been set.
1708 If both \c maximumLineCount and \c height are set, \c maximumLineCount will
1709 apply unless the lines do not fit in the height allowed.
1711 If the text is a multi-length string, and the mode is not \c Text.ElideNone,
1712 the first string that fits will be used, otherwise the last will be elided.
1714 Multi-length strings are ordered from longest to shortest, separated by the
1715 Unicode "String Terminator" character \c U009C (write this in QML with \c{"\u009C"} or \c{"\x9C"}).
1717 QQuickText::TextElideMode QQuickText::elideMode() const
1719 Q_D(const QQuickText);
1720 return d->elideMode;
1723 void QQuickText::setElideMode(QQuickText::TextElideMode mode)
1726 if (mode == d->elideMode)
1729 d->elideMode = mode;
1732 emit elideModeChanged(d->elideMode);
1736 \qmlproperty url QtQuick2::Text::baseUrl
1738 This property specifies a base URL which is used to resolve relative URLs
1741 By default is the url of the Text element.
1744 QUrl QQuickText::baseUrl() const
1746 Q_D(const QQuickText);
1747 if (d->baseUrl.isEmpty()) {
1748 if (QDeclarativeContext *context = qmlContext(this))
1749 const_cast<QQuickTextPrivate *>(d)->baseUrl = context->baseUrl();
1754 void QQuickText::setBaseUrl(const QUrl &url)
1757 if (baseUrl() != url) {
1761 d->doc->setBaseUrl(url);
1762 emit baseUrlChanged();
1766 void QQuickText::resetBaseUrl()
1768 if (QDeclarativeContext *context = qmlContext(this))
1769 setBaseUrl(context->baseUrl());
1775 QRectF QQuickText::boundingRect() const
1777 Q_D(const QQuickText);
1779 QRect rect = d->layedOutTextRect;
1780 if (d->style != Normal)
1781 rect.adjust(-1, 0, 1, 2);
1783 // Could include font max left/right bearings to either side of rectangle.
1786 switch (d->vAlign) {
1790 rect.moveTop(h - rect.height());
1793 rect.moveTop((h - rect.height()) / 2);
1797 return QRectF(rect);
1801 void QQuickText::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
1804 if (d->text.isEmpty()) {
1805 QQuickItem::geometryChanged(newGeometry, oldGeometry);
1809 bool widthChanged = newGeometry.width() != oldGeometry.width();
1810 bool heightChanged = newGeometry.height() != oldGeometry.height();
1811 bool leftAligned = effectiveHAlign() == QQuickText::AlignLeft;
1812 bool wrapped = d->wrapMode != QQuickText::NoWrap;
1813 bool elide = d->elideMode != QQuickText::ElideNone;
1815 if ((!widthChanged && !heightChanged) || d->internalWidthUpdate)
1816 goto geomChangeDone;
1818 if (leftAligned && !wrapped && !elide)
1819 goto geomChangeDone; // left aligned unwrapped text without eliding never needs relayout
1821 if (!widthChanged && !wrapped && d->singleline)
1822 goto geomChangeDone; // only height has changed which doesn't affect single line unwrapped text
1824 if (!widthChanged && wrapped && d->elideMode != QQuickText::ElideRight)
1825 goto geomChangeDone; // only height changed and no multiline eliding.
1827 if (leftAligned && d->elideMode == QQuickText::ElideRight && !d->truncated && d->singleline
1828 && !wrapped && newGeometry.width() > oldGeometry.width())
1829 goto geomChangeDone; // Eliding not affected if we're not currently truncated and we get wider.
1831 if (d->elideMode == QQuickText::ElideRight && wrapped && newGeometry.height() > oldGeometry.height()) {
1833 goto geomChangeDone; // Multiline eliding not affected if we're not currently truncated and we get higher.
1834 if (d->maximumLineCountValid && d->lineCount == d->maximumLineCount)
1835 goto geomChangeDone; // Multiline eliding not affected if we're already at max line count and we get higher.
1838 if (d->updateOnComponentComplete || (elide && widthValid())) {
1839 // We need to re-elide
1842 // We just need to re-layout
1847 QQuickItem::geometryChanged(newGeometry, oldGeometry);
1850 void QQuickText::triggerPreprocess()
1853 if (d->updateType == QQuickTextPrivate::UpdateNone)
1854 d->updateType = QQuickTextPrivate::UpdatePreprocess;
1858 QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1863 if (d->text.isEmpty()) {
1868 if (d->updateType != QQuickTextPrivate::UpdatePaintNode && oldNode != 0) {
1869 // Update done in preprocess() in the nodes
1870 d->updateType = QQuickTextPrivate::UpdateNone;
1874 d->updateType = QQuickTextPrivate::UpdateNone;
1876 QRectF bounds = boundingRect();
1878 // We need to make sure the layout is done in the current thread
1879 #if defined(Q_OS_MAC)
1880 d->paintingThread = QThread::currentThread();
1881 if (d->layoutThread != d->paintingThread)
1885 // XXX todo - some styled text can be done by the QQuickTextNode
1886 if (d->richTextAsImage || d->cacheAllTextAsImage || (d->disableDistanceField && d->style != Normal)) {
1887 bool wasDirty = d->textureImageCacheDirty;
1888 d->textureImageCacheDirty = false;
1890 if (!d->imageCache || d->imageCache->isNull()) {
1895 QSGImageNode *node = 0;
1896 if (!oldNode || d->nodeType != QQuickTextPrivate::NodeIsTexture) {
1898 node = QQuickItemPrivate::get(this)->sceneGraphContext()->createImageNode();
1899 d->texture = new QSGPlainTexture();
1901 d->nodeType = QQuickTextPrivate::NodeIsTexture;
1903 node = static_cast<QSGImageNode *>(oldNode);
1904 Q_ASSERT(d->texture);
1908 qobject_cast<QSGPlainTexture *>(d->texture)->setImage(d->imageCache->toImage());
1909 node->setTexture(0);
1910 node->setTexture(d->texture);
1913 node->setTargetRect(QRectF(bounds.x(), bounds.y(), d->imageCache->width(), d->imageCache->height()));
1914 node->setSourceRect(QRectF(0, 0, 1, 1));
1915 node->setHorizontalWrapMode(QSGTexture::ClampToEdge);
1916 node->setVerticalWrapMode(QSGTexture::ClampToEdge);
1917 node->setFiltering(QSGTexture::Linear); // Nonsmooth text just ugly, so don't do that..
1923 QQuickTextNode *node = 0;
1924 if (!oldNode || d->nodeType != QQuickTextPrivate::NodeIsText) {
1926 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext(), this);
1927 d->nodeType = QQuickTextPrivate::NodeIsText;
1929 node = static_cast<QQuickTextNode *>(oldNode);
1932 node->deleteContent();
1933 node->setMatrix(QMatrix4x4());
1937 node->addTextDocument(bounds.topLeft(), d->doc, d->color, d->style, d->styleColor);
1939 } else if (d->elideMode == QQuickText::ElideNone || bounds.width() > 0.) {
1940 node->addTextLayout(QPoint(0, bounds.y()), &d->layout, d->color, d->style, d->styleColor);
1941 if (d->elipsisLayout)
1942 node->addTextLayout(QPoint(0, bounds.y()), d->elipsisLayout, d->color, d->style, d->styleColor);
1949 bool QQuickText::event(QEvent *e)
1952 if (e->type() == QEvent::User) {
1953 d->checkImageCache();
1956 return QQuickImplicitSizeItem::event(e);
1961 \qmlproperty real QtQuick2::Text::paintedWidth
1963 Returns the width of the text, including width past the width
1964 which is covered due to insufficient wrapping if WrapMode is set.
1966 qreal QQuickText::paintedWidth() const
1968 Q_D(const QQuickText);
1969 return d->paintedSize.width();
1973 \qmlproperty real QtQuick2::Text::paintedHeight
1975 Returns the height of the text, including height past the height
1976 which is covered due to there being more text than fits in the set height.
1978 qreal QQuickText::paintedHeight() const
1980 Q_D(const QQuickText);
1981 return d->paintedSize.height();
1985 \qmlproperty real QtQuick2::Text::lineHeight
1987 Sets the line height for the text.
1988 The value can be in pixels or a multiplier depending on lineHeightMode.
1990 The default value is a multiplier of 1.0.
1991 The line height must be a positive value.
1993 qreal QQuickText::lineHeight() const
1995 Q_D(const QQuickText);
1996 return d->lineHeight;
1999 void QQuickText::setLineHeight(qreal lineHeight)
2003 if ((d->lineHeight == lineHeight) || (lineHeight < 0.0))
2006 d->lineHeight = lineHeight;
2008 emit lineHeightChanged(lineHeight);
2012 \qmlproperty enumeration QtQuick2::Text::lineHeightMode
2014 This property determines how the line height is specified.
2015 The possible values are:
2018 \o Text.ProportionalHeight (default) - this sets the spacing proportional to the
2019 line (as a multiplier). For example, set to 2 for double spacing.
2020 \o Text.FixedHeight - this sets the line height to a fixed line height (in pixels).
2023 QQuickText::LineHeightMode QQuickText::lineHeightMode() const
2025 Q_D(const QQuickText);
2026 return d->lineHeightMode;
2029 void QQuickText::setLineHeightMode(LineHeightMode mode)
2032 if (mode == d->lineHeightMode)
2035 d->lineHeightMode = mode;
2038 emit lineHeightModeChanged(mode);
2042 Returns the number of resources (images) that are being loaded asynchronously.
2044 int QQuickText::resourcesLoading() const
2046 Q_D(const QQuickText);
2047 return d->doc ? d->doc->resourcesLoading() : 0;
2051 void QQuickText::componentComplete()
2054 if (d->updateOnComponentComplete) {
2057 d->doc->setText(d->text);
2058 d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
2059 d->richTextAsImage = enableImageCache();
2061 d->rightToLeftText = d->text.isRightToLeft();
2063 d->determineHorizontalAlignment();
2065 QQuickItem::componentComplete();
2066 if (d->updateOnComponentComplete)
2069 // Enable accessibility for text items.
2070 d->setAccessibleFlagAndListener();
2074 QString QQuickTextPrivate::anchorAt(const QPointF &mousePos)
2077 for (int i = 0; i < layout.lineCount(); ++i) {
2078 QTextLine line = layout.lineAt(i);
2079 if (line.naturalTextRect().contains(mousePos)) {
2080 int charPos = line.xToCursor(mousePos.x());
2081 foreach (const QTextLayout::FormatRange &formatRange, layout.additionalFormats()) {
2082 if (formatRange.format.isAnchor()
2083 && charPos >= formatRange.start
2084 && charPos <= formatRange.start + formatRange.length) {
2085 return formatRange.format.anchorHref();
2095 bool QQuickTextPrivate::isLinkActivatedConnected()
2097 static int idx = this->signalIndex("linkActivated(QString)");
2098 return this->isSignalConnected(idx);
2102 void QQuickText::mousePressEvent(QMouseEvent *event)
2106 if (d->isLinkActivatedConnected()) {
2108 d->activeLink = d->anchorAt(event->localPos());
2109 else if (d->richText && d->doc)
2110 d->activeLink = d->doc->documentLayout()->anchorAt(event->localPos());
2113 if (d->activeLink.isEmpty())
2114 event->setAccepted(false);
2116 // ### may malfunction if two of the same links are clicked & dragged onto each other)
2118 if (!event->isAccepted())
2119 QQuickItem::mousePressEvent(event);
2124 void QQuickText::mouseReleaseEvent(QMouseEvent *event)
2128 // ### confirm the link, and send a signal out
2131 if (d->isLinkActivatedConnected()) {
2133 link = d->anchorAt(event->localPos());
2134 else if (d->richText && d->doc)
2135 link = d->doc->documentLayout()->anchorAt(event->localPos());
2138 if (!link.isEmpty() && d->activeLink == link)
2139 emit linkActivated(d->activeLink);
2141 event->setAccepted(false);
2143 if (!event->isAccepted())
2144 QQuickItem::mouseReleaseEvent(event);