1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
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 <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)
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();
378 int dy = q->height();
381 #if defined(Q_OS_MAC)
382 layoutThread = QThread::currentThread();
385 //setup instance of QTextLayout for all cases other than richtext
387 QRect textRect = setupTextLayout();
388 layedOutTextRect = textRect;
389 size = textRect.size();
392 singleline = false; // richtext can't elide or be optimized for single-line case
394 doc->setDefaultFont(font);
395 QQuickText::HAlignment horizontalAlignment = q->effectiveHAlign();
396 if (rightToLeftText) {
397 if (horizontalAlignment == QQuickText::AlignLeft)
398 horizontalAlignment = QQuickText::AlignRight;
399 else if (horizontalAlignment == QQuickText::AlignRight)
400 horizontalAlignment = QQuickText::AlignLeft;
403 option.setAlignment((Qt::Alignment)int(horizontalAlignment | vAlign));
404 option.setWrapMode(QTextOption::WrapMode(wrapMode));
405 if (!cacheAllTextAsImage && !richTextAsImage && !disableDistanceField)
406 option.setUseDesignMetrics(true);
407 doc->setDefaultTextOption(option);
408 if (requireImplicitWidth && q->widthValid()) {
409 doc->setTextWidth(-1);
410 naturalWidth = doc->idealWidth();
412 if (wrapMode != QQuickText::NoWrap && q->widthValid())
413 doc->setTextWidth(q->width());
415 doc->setTextWidth(doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug)
416 dy -= (int)doc->size().height();
417 QSize dsize = doc->size().toSize();
418 layedOutTextRect = QRect(QPoint(0,0), dsize);
419 size = QSize(int(doc->idealWidth()),dsize.height());
423 if (q->heightValid()) {
424 if (vAlign == QQuickText::AlignBottom)
426 else if (vAlign == QQuickText::AlignVCenter)
429 q->setBaselineOffset(fm.ascent() + yoff);
431 //### need to comfirm cost of always setting these for richText
432 internalWidthUpdate = true;
434 if (!q->widthValid())
435 iWidth = size.width();
436 else if (requireImplicitWidth)
437 iWidth = naturalWidth;
439 q->setImplicitSize(iWidth, size.height());
440 internalWidthUpdate = false;
443 q->setImplicitHeight(size.height());
444 if (paintedSize != size) {
446 emit q->paintedSizeChanged();
451 QQuickTextLine::QQuickTextLine()
452 : QObject(), m_line(0), m_height(0)
456 void QQuickTextLine::setLine(QTextLine *line)
461 int QQuickTextLine::number() const
464 return m_line->lineNumber();
468 qreal QQuickTextLine::width() const
471 return m_line->width();
475 void QQuickTextLine::setWidth(qreal width)
478 m_line->setLineWidth(width);
481 qreal QQuickTextLine::height() const
486 return m_line->height();
490 void QQuickTextLine::setHeight(qreal height)
493 m_line->setPosition(QPointF(m_line->x(), m_line->y() - m_line->height() + height));
497 qreal QQuickTextLine::x() const
504 void QQuickTextLine::setX(qreal x)
507 m_line->setPosition(QPointF(x, m_line->y()));
510 qreal QQuickTextLine::y() const
517 void QQuickTextLine::setY(qreal y)
520 m_line->setPosition(QPointF(m_line->x(), y));
523 void QQuickText::doLayout()
529 bool QQuickTextPrivate::isLineLaidOutConnected()
531 static int idx = this->signalIndex("lineLaidOut(QQuickTextLine*)");
532 return this->isSignalConnected(idx);
535 void QQuickTextPrivate::setupCustomLineGeometry(QTextLine &line, qreal &height, qreal elideWidth = 0)
539 #if defined(Q_OS_MAC)
540 if (QThread::currentThread() != paintingThread) {
541 if (!line.lineNumber())
546 textLine = new QQuickTextLine;
547 textLine->setLine(&line);
548 textLine->setY(height);
549 textLine->setHeight(0);
551 // use the text item's width by default if it has one and wrap is on
552 if (q->widthValid() && q->wrapMode() != QQuickText::NoWrap)
553 textLine->setWidth(q->width() - elideWidth);
555 textLine->setWidth(INT_MAX);
556 if (lineHeight != 1.0)
557 textLine->setHeight((lineHeightMode == QQuickText::FixedHeight) ? lineHeight : line.height() * lineHeight);
559 emit q->lineLaidOut(textLine);
561 height += textLine->height();
563 #if defined(Q_OS_MAC)
564 linesRects << QRectF(textLine->x(), textLine->y(), textLine->width(), textLine->height());
567 if (line.lineNumber() < linesRects.count()) {
568 QRectF r = linesRects.at(line.lineNumber());
569 line.setLineWidth(r.width());
570 line.setPosition(r.topLeft());
577 Lays out the QQuickTextPrivate::layout QTextLayout in the constraints of the QQuickText.
579 Returns the size of the final text. This can be used to position the text vertically (the text is
580 already absolutely positioned horizontally).
582 QRect QQuickTextPrivate::setupTextLayout()
584 // ### text layout handling should be profiled and optimized as needed
585 // what about QStackTextEngine engine(tmp, d->font.font()); QTextLayout textLayout(&engine);
587 layout.setCacheEnabled(true);
590 int visibleCount = 0;
594 lineWidth = q->width();
596 QTextOption textOption = layout.textOption();
597 textOption.setAlignment(Qt::Alignment(q->effectiveHAlign()));
598 textOption.setWrapMode(QTextOption::WrapMode(wrapMode));
599 if (!cacheAllTextAsImage && !richTextAsImage && !disableDistanceField)
600 textOption.setUseDesignMetrics(true);
601 layout.setTextOption(textOption);
603 QFontMetrics fm(layout.font());
604 elidePos = QPointF();
606 if (requireImplicitWidth && q->widthValid()) {
607 // requires an extra layout
609 if (layoutTextElided) {
610 // We have provided elided text to the layout, but we must calculate unelided width.
611 elidedText = layout.text();
612 layout.setText(text);
614 layout.beginLayout();
616 QTextLine line = layout.createLine();
622 for (int i = 0; i < layout.lineCount(); ++i) {
623 QTextLine line = layout.lineAt(i);
624 br = br.united(line.naturalTextRect());
626 naturalWidth = br.width();
627 if (layoutTextElided)
628 layout.setText(elidedText);
631 if ((q->widthValid() && q->width() <= 0. && elideMode != QQuickText::ElideNone)
632 || (q->heightValid() && q->height() <= 0. && wrapMode != QQuickText::NoWrap && elideMode == QQuickText::ElideRight)) {
633 // we are elided and we have a zero width or height
636 emit q->truncatedChanged();
640 emit q->lineCountChanged();
643 qreal height = (lineHeightMode == QQuickText::FixedHeight) ? lineHeight : fm.height() * lineHeight;
644 return QRect(0, 0, 0, height);
650 bool truncate = layoutTextElided;
651 bool customLayout = isLineLaidOutConnected();
652 bool multilineElideEnabled = elideMode == QQuickText::ElideRight && q->widthValid() && wrapMode != QQuickText::NoWrap;
654 layout.beginLayout();
657 int linesLeft = maximumLineCount;
658 int visibleTextLength = 0;
660 QTextLine line = layout.createLine();
666 qreal preLayoutHeight = height;
668 setupCustomLineGeometry(line, height);
669 } else if (lineWidth) {
670 line.setLineWidth(lineWidth);
671 line.setPosition(QPointF(line.position().x(), height));
672 height += (lineHeightMode == QQuickText::FixedHeight) ? lineHeight : line.height() * lineHeight;
676 if (multilineElideEnabled && q->heightValid() && height > q->height()) {
677 // This line does not fit in the remaining area.
679 if (visibleCount > 1) {
681 height = preLayoutHeight;
682 line.setLineWidth(0.0);
683 line.setPosition(QPointF(FLT_MAX,FLT_MAX));
684 line = layout.lineAt(visibleCount-1);
687 visibleTextLength += line.textLength();
690 if (elide || (maximumLineCountValid && --linesLeft == 0)) {
691 if (visibleTextLength < text.length()) {
693 if (multilineElideEnabled) {
694 qreal elideWidth = fm.width(elideChar);
695 // Need to correct for alignment
697 setupCustomLineGeometry(line, height, elideWidth);
699 line.setLineWidth(lineWidth - elideWidth);
700 if (layout.text().mid(line.textStart(), line.textLength()).isRightToLeft()) {
701 line.setPosition(QPointF(line.position().x() + elideWidth, line.position().y()));
702 elidePos.setX(line.naturalTextRect().left() - elideWidth);
704 elidePos.setX(line.naturalTextRect().right());
706 elidePos.setY(line.position().y());
708 elipsisLayout = new QTextLayout(elideChar, layout.font());
709 elipsisLayout->beginLayout();
710 QTextLine el = elipsisLayout->createLine();
711 el.setPosition(elidePos);
712 elipsisLayout->endLayout();
713 br = br.united(el.naturalTextRect());
715 br = br.united(line.naturalTextRect());
719 br = br.united(line.naturalTextRect());
724 if (truncated != truncate) {
725 truncated = truncate;
726 emit q->truncatedChanged();
730 br.setHeight(height);
732 if (!q->widthValid())
733 naturalWidth = br.width();
735 //Update the number of visible lines
736 if (lineCount != visibleCount) {
737 lineCount = visibleCount;
738 emit q->lineCountChanged();
741 return QRect(qRound(br.x()), qRound(br.y()), qCeil(br.width()), qCeil(br.height()));
745 Returns a painted version of the QQuickTextPrivate::layout QTextLayout.
746 If \a drawStyle is true, the style color overrides all colors in the document.
748 QPixmap QQuickTextPrivate::textLayoutImage(bool drawStyle)
750 QSize size = layedOutTextRect.size();
754 if (!size.isEmpty()) {
755 img.fill(Qt::transparent);
756 /*#ifdef Q_OS_MAC // Fails on CocoaX64
757 bool oldSmooth = qt_applefontsmoothing_enabled;
758 qt_applefontsmoothing_enabled = false;
761 /*#ifdef Q_OS_MAC // Fails on CocoaX64
762 qt_applefontsmoothing_enabled = oldSmooth;
764 drawTextLayout(&p, QPointF(-layedOutTextRect.x(),0), drawStyle);
770 Paints the QQuickTextPrivate::layout QTextLayout into \a painter at \a pos. If
771 \a drawStyle is true, the style color overrides all colors in the document.
773 void QQuickTextPrivate::drawTextLayout(QPainter *painter, const QPointF &pos, bool drawStyle)
776 painter->setPen(styleColor);
778 painter->setPen(color);
779 painter->setFont(font);
780 layout.draw(painter, pos);
781 if (!elidePos.isNull())
782 painter->drawText(pos + elidePos, elideChar);
786 Returns a painted version of the QQuickTextPrivate::doc QTextDocument.
787 If \a drawStyle is true, the style color overrides all colors in the document.
789 QPixmap QQuickTextPrivate::textDocumentImage(bool drawStyle)
791 QSize size = doc->size().toSize();
795 img.fill(Qt::transparent);
796 /*#ifdef Q_OS_MAC // Fails on CocoaX64
797 bool oldSmooth = qt_applefontsmoothing_enabled;
798 qt_applefontsmoothing_enabled = false;
801 /*#ifdef Q_OS_MAC // Fails on CocoaX64
802 qt_applefontsmoothing_enabled = oldSmooth;
805 QAbstractTextDocumentLayout::PaintContext context;
807 QTextOption oldOption(doc->defaultTextOption());
809 context.palette.setColor(QPalette::Text, styleColor);
810 QTextOption colorOption(doc->defaultTextOption());
811 colorOption.setFlags(QTextOption::SuppressColors);
812 doc->setDefaultTextOption(colorOption);
814 context.palette.setColor(QPalette::Text, color);
816 doc->documentLayout()->draw(&p, context);
818 doc->setDefaultTextOption(oldOption);
823 void QQuickTextPrivate::markDirty()
826 if (!invalidateImageCache() && q->isComponentComplete())
831 Mark the image cache as dirty.
833 bool QQuickTextPrivate::invalidateImageCache()
837 if (richTextAsImage || cacheAllTextAsImage || (disableDistanceField && style != QQuickText::Normal)) { // If actually using the image cache
841 imageCacheDirty = true;
843 if (q->isComponentComplete())
844 QCoreApplication::postEvent(q, new QEvent(QEvent::User));
852 Tests if the image cache is dirty, and repaints it if it is.
854 void QQuickTextPrivate::checkImageCache()
858 if (!imageCacheDirty)
861 if (text.isEmpty()) {
872 textImage = textDocumentImage(false);
873 if (style != QQuickText::Normal)
874 styledImage = textDocumentImage(true); //### should use styleColor
876 textImage = textLayoutImage(false);
877 if (style != QQuickText::Normal)
878 styledImage = textLayoutImage(true); //### should use styleColor
883 case QQuickText::Outline:
884 imageCache = new QPixmap(drawOutline(textImage, styledImage));
886 case QQuickText::Sunken:
887 imageCache = new QPixmap(drawOutline(textImage, styledImage, -1));
889 case QQuickText::Raised:
890 imageCache = new QPixmap(drawOutline(textImage, styledImage, 1));
893 imageCache = new QPixmap(textImage);
899 imageCacheDirty = false;
900 textureImageCacheDirty = true;
905 Ensures the QQuickTextPrivate::doc variable is set to a valid text document
907 void QQuickTextPrivate::ensureDoc()
911 doc = new QQuickTextDocumentWithImageResources(q);
912 doc->setDocumentMargin(0);
913 doc->setBaseUrl(q->baseUrl());
914 FAST_CONNECT(doc, SIGNAL(imagesLoaded()), q, SLOT(q_imagesLoaded()));
919 Draw \a styleSource as an outline around \a source and return the new image.
921 QPixmap QQuickTextPrivate::drawOutline(const QPixmap &source, const QPixmap &styleSource)
923 QPixmap img = QPixmap(styleSource.width() + 2, styleSource.height() + 2);
924 img.fill(Qt::transparent);
929 pos += QPoint(-1, 0);
930 ppm.drawPixmap(pos, styleSource);
932 ppm.drawPixmap(pos, styleSource);
933 pos += QPoint(-1, -1);
934 ppm.drawPixmap(pos, styleSource);
936 ppm.drawPixmap(pos, styleSource);
938 pos += QPoint(0, -1);
939 ppm.drawPixmap(pos, source);
946 Draw \a styleSource below \a source at \a yOffset and return the new image.
948 QPixmap QQuickTextPrivate::drawOutline(const QPixmap &source, const QPixmap &styleSource, int yOffset)
950 QPixmap img = QPixmap(styleSource.width() + 2, styleSource.height() + 2);
951 img.fill(Qt::transparent);
955 ppm.drawPixmap(QPoint(0, yOffset), styleSource);
956 ppm.drawPixmap(0, 0, source);
964 \qmlclass Text QQuickText
965 \inqmlmodule QtQuick 2
966 \ingroup qml-basic-visual-elements
967 \brief The Text item allows you to add formatted text to a scene.
970 Text items can display both plain and rich text. For example, red text with
971 a specific font and size can be defined like this:
976 font.family: "Helvetica"
982 Rich text is defined using HTML-style markup:
986 text: "<b>Hello</b> <i>World!</i>"
990 \image declarative-text.png
992 If height and width are not explicitly set, Text will attempt to determine how
993 much room is needed and set it accordingly. Unless \l wrapMode is set, it will always
994 prefer width to height (all text will be placed on a single line).
996 The \l elide property can alternatively be used to fit a single line of
997 plain text to a set width.
999 Note that the \l{Supported HTML Subset} is limited. Also, if the text contains
1000 HTML img tags that load remote images, the text is reloaded.
1002 Text provides read-only text. For editable text, see \l TextEdit.
1004 \sa {declarative/text/fonts}{Fonts example}
1006 QQuickText::QQuickText(QQuickItem *parent)
1007 : QQuickImplicitSizeItem(*(new QQuickTextPrivate), parent)
1013 QQuickText::~QQuickText()
1018 \qmlproperty bool QtQuick2::Text::clip
1019 This property holds whether the text is clipped.
1021 Note that if the text does not fit in the bounding rectangle it will be abruptly chopped.
1023 If you want to display potentially long text in a limited space, you probably want to use \c elide instead.
1027 \qmlproperty bool QtQuick2::Text::smooth
1029 This property holds whether the text is smoothly scaled or transformed.
1031 Smooth filtering gives better visual quality, but is slower. If
1032 the item is displayed at its natural size, this property has no visual or
1035 \note Generally scaling artifacts are only visible if the item is stationary on
1036 the screen. A common pattern when animating an item is to disable smooth
1037 filtering at the beginning of the animation and reenable it at the conclusion.
1041 \qmlsignal QtQuick2::Text::onLineLaidOut(line)
1043 This handler is called for every line during the layout process.
1044 This gives the opportunity to position and resize a line as it is being laid out.
1045 It can for example be used to create columns or lay out text around objects.
1047 The properties of a line are:
1049 \o number (read-only)
1056 For example, this will move the first 5 lines of a text element by 100 pixels to the right:
1059 if (line.number < 5) {
1060 line.x = line.x + 100
1061 line.width = line.width - 100
1068 \qmlsignal QtQuick2::Text::onLinkActivated(string link)
1070 This handler is called when the user clicks on a link embedded in the text.
1071 The link must be in rich text or HTML format and the
1072 \a link string provides access to the particular link.
1074 \snippet doc/src/snippets/declarative/text/onLinkActivated.qml 0
1076 The example code will display the text
1077 "The main website is at \l{http://qt.nokia.com}{Nokia Qt DF}."
1079 Clicking on the highlighted link will output
1080 \tt{http://qt.nokia.com link activated} to the console.
1084 \qmlproperty string QtQuick2::Text::font.family
1086 Sets the family name of the font.
1088 The family name is case insensitive and may optionally include a foundry name, e.g. "Helvetica [Cronyx]".
1089 If the family is available from more than one foundry and the foundry isn't specified, an arbitrary foundry is chosen.
1090 If the family isn't available a family will be set using the font matching algorithm.
1094 \qmlproperty bool QtQuick2::Text::font.bold
1096 Sets whether the font weight is bold.
1100 \qmlproperty enumeration QtQuick2::Text::font.weight
1102 Sets the font's weight.
1104 The weight can be one of:
1107 \o Font.Normal - the default
1114 Text { text: "Hello"; font.weight: Font.DemiBold }
1119 \qmlproperty bool QtQuick2::Text::font.italic
1121 Sets whether the font has an italic style.
1125 \qmlproperty bool QtQuick2::Text::font.underline
1127 Sets whether the text is underlined.
1131 \qmlproperty bool QtQuick2::Text::font.strikeout
1133 Sets whether the font has a strikeout style.
1137 \qmlproperty real QtQuick2::Text::font.pointSize
1139 Sets the font size in points. The point size must be greater than zero.
1143 \qmlproperty int QtQuick2::Text::font.pixelSize
1145 Sets the font size in pixels.
1147 Using this function makes the font device dependent.
1148 Use \c pointSize to set the size of the font in a device independent manner.
1152 \qmlproperty real QtQuick2::Text::font.letterSpacing
1154 Sets the letter spacing for the font.
1156 Letter spacing changes the default spacing between individual letters in the font.
1157 A positive value increases the letter spacing by the corresponding pixels; a negative value decreases the spacing.
1161 \qmlproperty real QtQuick2::Text::font.wordSpacing
1163 Sets the word spacing for the font.
1165 Word spacing changes the default spacing between individual words.
1166 A positive value increases the word spacing by a corresponding amount of pixels,
1167 while a negative value decreases the inter-word spacing accordingly.
1171 \qmlproperty enumeration QtQuick2::Text::font.capitalization
1173 Sets the capitalization for the text.
1176 \o Font.MixedCase - This is the normal text rendering option where no capitalization change is applied.
1177 \o Font.AllUppercase - This alters the text to be rendered in all uppercase type.
1178 \o Font.AllLowercase - This alters the text to be rendered in all lowercase type.
1179 \o Font.SmallCaps - This alters the text to be rendered in small-caps type.
1180 \o Font.Capitalize - This alters the text to be rendered with the first character of each word as an uppercase character.
1184 Text { text: "Hello"; font.capitalization: Font.AllLowercase }
1187 QFont QQuickText::font() const
1189 Q_D(const QQuickText);
1190 return d->sourceFont;
1193 void QQuickText::setFont(const QFont &font)
1196 if (d->sourceFont == font)
1199 d->sourceFont = font;
1200 QFont oldFont = d->font;
1203 if (d->font.pointSizeF() != -1) {
1205 qreal size = qRound(d->font.pointSizeF()*2.0);
1206 d->font.setPointSizeF(size/2.0);
1209 if (oldFont != d->font)
1212 emit fontChanged(d->sourceFont);
1216 \qmlproperty string QtQuick2::Text::text
1218 The text to display. Text supports both plain and rich text strings.
1220 The item will try to automatically determine whether the text should
1221 be treated as styled text. This determination is made using Qt::mightBeRichText().
1223 QString QQuickText::text() const
1225 Q_D(const QQuickText);
1229 void QQuickText::setText(const QString &n)
1235 d->richText = d->format == RichText;
1236 d->styledText = d->format == StyledText || (d->format == AutoText && Qt::mightBeRichText(n));
1238 if (isComponentComplete()) {
1242 d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
1243 d->richTextAsImage = enableImageCache();
1245 d->rightToLeftText = d->text.isRightToLeft();
1247 d->determineHorizontalAlignment();
1249 d->textHasChanged = true;
1251 emit textChanged(d->text);
1255 \qmlproperty color QtQuick2::Text::color
1259 An example of green text defined using hexadecimal notation:
1267 An example of steel blue text defined using an SVG color name:
1275 QColor QQuickText::color() const
1277 Q_D(const QQuickText);
1281 void QQuickText::setColor(const QColor &color)
1284 if (d->color == color)
1289 emit colorChanged(d->color);
1292 \qmlproperty enumeration QtQuick2::Text::style
1294 Set an additional text style.
1296 Supported text styles are:
1298 \o Text.Normal - the default
1306 Text { font.pointSize: 24; text: "Normal" }
1307 Text { font.pointSize: 24; text: "Raised"; style: Text.Raised; styleColor: "#AAAAAA" }
1308 Text { font.pointSize: 24; text: "Outline";style: Text.Outline; styleColor: "red" }
1309 Text { font.pointSize: 24; text: "Sunken"; style: Text.Sunken; styleColor: "#AAAAAA" }
1313 \image declarative-textstyle.png
1315 QQuickText::TextStyle QQuickText::style() const
1317 Q_D(const QQuickText);
1321 void QQuickText::setStyle(QQuickText::TextStyle style)
1324 if (d->style == style)
1327 // changing to/from Normal requires the boundingRect() to change
1328 if (isComponentComplete() && (d->style == Normal || style == Normal))
1332 emit styleChanged(d->style);
1336 \qmlproperty color QtQuick2::Text::styleColor
1338 Defines the secondary color used by text styles.
1340 \c styleColor is used as the outline color for outlined text, and as the
1341 shadow color for raised or sunken text. If no style has been set, it is not
1345 Text { font.pointSize: 18; text: "hello"; style: Text.Raised; styleColor: "gray" }
1350 QColor QQuickText::styleColor() const
1352 Q_D(const QQuickText);
1353 return d->styleColor;
1356 void QQuickText::setStyleColor(const QColor &color)
1359 if (d->styleColor == color)
1362 d->styleColor = color;
1364 emit styleColorChanged(d->styleColor);
1368 \qmlproperty enumeration QtQuick2::Text::horizontalAlignment
1369 \qmlproperty enumeration QtQuick2::Text::verticalAlignment
1370 \qmlproperty enumeration QtQuick2::Text::effectiveHorizontalAlignment
1372 Sets the horizontal and vertical alignment of the text within the Text items
1373 width and height. By default, the text is vertically aligned to the top. Horizontal
1374 alignment follows the natural alignment of the text, for example text that is read
1375 from left to right will be aligned to the left.
1377 The valid values for \c horizontalAlignment are \c Text.AlignLeft, \c Text.AlignRight, \c Text.AlignHCenter and
1378 \c Text.AlignJustify. The valid values for \c verticalAlignment are \c Text.AlignTop, \c Text.AlignBottom
1379 and \c Text.AlignVCenter.
1381 Note that for a single line of text, the size of the text is the area of the text. In this common case,
1382 all alignments are equivalent. If you want the text to be, say, centered in its parent, then you will
1383 need to either modify the Item::anchors, or set horizontalAlignment to Text.AlignHCenter and bind the width to
1386 When using the attached property LayoutMirroring::enabled to mirror application
1387 layouts, the horizontal alignment of text will also be mirrored. However, the property
1388 \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment
1389 of Text, use the read-only property \c effectiveHorizontalAlignment.
1391 QQuickText::HAlignment QQuickText::hAlign() const
1393 Q_D(const QQuickText);
1397 void QQuickText::setHAlign(HAlignment align)
1400 bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror;
1401 d->hAlignImplicit = false;
1402 if (d->setHAlign(align, forceAlign) && isComponentComplete())
1406 void QQuickText::resetHAlign()
1409 d->hAlignImplicit = true;
1410 if (isComponentComplete() && d->determineHorizontalAlignment())
1414 QQuickText::HAlignment QQuickText::effectiveHAlign() const
1416 Q_D(const QQuickText);
1417 QQuickText::HAlignment effectiveAlignment = d->hAlign;
1418 if (!d->hAlignImplicit && d->effectiveLayoutMirror) {
1419 switch (d->hAlign) {
1420 case QQuickText::AlignLeft:
1421 effectiveAlignment = QQuickText::AlignRight;
1423 case QQuickText::AlignRight:
1424 effectiveAlignment = QQuickText::AlignLeft;
1430 return effectiveAlignment;
1433 bool QQuickTextPrivate::setHAlign(QQuickText::HAlignment alignment, bool forceAlign)
1436 if (hAlign != alignment || forceAlign) {
1437 QQuickText::HAlignment oldEffectiveHAlign = q->effectiveHAlign();
1440 emit q->horizontalAlignmentChanged(hAlign);
1441 if (oldEffectiveHAlign != q->effectiveHAlign())
1442 emit q->effectiveHorizontalAlignmentChanged();
1448 bool QQuickTextPrivate::determineHorizontalAlignment()
1450 if (hAlignImplicit) {
1451 bool alignToRight = text.isEmpty() ? qApp->inputPanel()->inputDirection() == Qt::RightToLeft : rightToLeftText;
1452 return setHAlign(alignToRight ? QQuickText::AlignRight : QQuickText::AlignLeft);
1457 void QQuickTextPrivate::mirrorChange()
1460 if (q->isComponentComplete()) {
1461 if (!hAlignImplicit && (hAlign == QQuickText::AlignRight || hAlign == QQuickText::AlignLeft)) {
1463 emit q->effectiveHorizontalAlignmentChanged();
1468 QTextDocument *QQuickTextPrivate::textDocument()
1473 QQuickText::VAlignment QQuickText::vAlign() const
1475 Q_D(const QQuickText);
1479 void QQuickText::setVAlign(VAlignment align)
1482 if (d->vAlign == align)
1486 emit verticalAlignmentChanged(align);
1490 \qmlproperty enumeration QtQuick2::Text::wrapMode
1492 Set this property to wrap the text to the Text item's width. The text will only
1493 wrap if an explicit width has been set. wrapMode can be one of:
1496 \o Text.NoWrap (default) - no wrapping will be performed. If the text contains insufficient newlines, then \l paintedWidth will exceed a set width.
1497 \o Text.WordWrap - wrapping is done on word boundaries only. If a word is too long, \l paintedWidth will exceed a set width.
1498 \o Text.WrapAnywhere - wrapping is done at any point on a line, even if it occurs in the middle of a word.
1499 \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.
1502 QQuickText::WrapMode QQuickText::wrapMode() const
1504 Q_D(const QQuickText);
1508 void QQuickText::setWrapMode(WrapMode mode)
1511 if (mode == d->wrapMode)
1517 emit wrapModeChanged();
1521 \qmlproperty int QtQuick2::Text::lineCount
1523 Returns the number of lines visible in the text item.
1525 This property is not supported for rich text.
1527 \sa maximumLineCount
1529 int QQuickText::lineCount() const
1531 Q_D(const QQuickText);
1532 return d->lineCount;
1536 \qmlproperty bool QtQuick2::Text::truncated
1538 Returns true if the text has been truncated due to \l maximumLineCount
1541 This property is not supported for rich text.
1543 \sa maximumLineCount, elide
1545 bool QQuickText::truncated() const
1547 Q_D(const QQuickText);
1548 return d->truncated;
1552 \qmlproperty int QtQuick2::Text::maximumLineCount
1554 Set this property to limit the number of lines that the text item will show.
1555 If elide is set to Text.ElideRight, the text will be elided appropriately.
1556 By default, this is the value of the largest possible integer.
1558 This property is not supported for rich text.
1560 \sa lineCount, elide
1562 int QQuickText::maximumLineCount() const
1564 Q_D(const QQuickText);
1565 return d->maximumLineCount;
1568 void QQuickText::setMaximumLineCount(int lines)
1572 d->maximumLineCountValid = lines==INT_MAX ? false : true;
1573 if (d->maximumLineCount != lines) {
1574 d->maximumLineCount = lines;
1576 emit maximumLineCountChanged();
1580 void QQuickText::resetMaximumLineCount()
1583 setMaximumLineCount(INT_MAX);
1584 d->elidePos = QPointF();
1585 if (d->truncated != false) {
1586 d->truncated = false;
1587 emit truncatedChanged();
1592 \qmlproperty enumeration QtQuick2::Text::textFormat
1594 The way the text property should be displayed.
1596 Supported text formats are:
1599 \o Text.AutoText (default)
1605 If the text format is \c Text.AutoText the text element
1606 will automatically determine whether the text should be treated as
1607 styled text. This determination is made using Qt::mightBeRichText().
1609 Text.StyledText is an optimized format supporting some basic text
1610 styling markup, in the style of html 3.2:
1614 <strong></strong> - bold
1618 <u> - underlined text
1619 <font color="color_name" size="1-7"></font>
1620 <h1> to <h6> - headers
1621 <a href=""> - anchor
1622 <ol type="">, <ul type=""> and <li> - ordered and unordered lists
1623 <pre></pre> - preformatted
1627 \c Text.StyledText parser is strict, requiring tags to be correctly nested.
1636 text: "<b>Hello</b> <i>World!</i>"
1640 textFormat: Text.RichText
1641 text: "<b>Hello</b> <i>World!</i>"
1645 textFormat: Text.PlainText
1646 text: "<b>Hello</b> <i>World!</i>"
1650 \o \image declarative-textformat.png
1653 QQuickText::TextFormat QQuickText::textFormat() const
1655 Q_D(const QQuickText);
1659 void QQuickText::setTextFormat(TextFormat format)
1662 if (format == d->format)
1665 bool wasRich = d->richText;
1666 d->richText = format == RichText;
1667 d->styledText = format == StyledText || (format == AutoText && Qt::mightBeRichText(d->text));
1669 if (isComponentComplete()) {
1670 if (!wasRich && d->richText) {
1672 d->doc->setText(d->text);
1673 d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
1674 d->richTextAsImage = enableImageCache();
1676 d->rightToLeftText = d->text.isRightToLeft();
1678 d->determineHorizontalAlignment();
1682 emit textFormatChanged(d->format);
1686 \qmlproperty enumeration QtQuick2::Text::elide
1688 Set this property to elide parts of the text fit to the Text item's width.
1689 The text will only elide if an explicit width has been set.
1691 This property cannot be used with rich text.
1695 \o Text.ElideNone - the default
1701 If this property is set to Text.ElideRight, it can be used with \l {wrapMode}{wrapped}
1702 text. The text will only elide if \c maximumLineCount, or \c height has been set.
1703 If both \c maximumLineCount and \c height are set, \c maximumLineCount will
1704 apply unless the lines do not fit in the height allowed.
1706 If the text is a multi-length string, and the mode is not \c Text.ElideNone,
1707 the first string that fits will be used, otherwise the last will be elided.
1709 Multi-length strings are ordered from longest to shortest, separated by the
1710 Unicode "String Terminator" character \c U009C (write this in QML with \c{"\u009C"} or \c{"\x9C"}).
1712 QQuickText::TextElideMode QQuickText::elideMode() const
1714 Q_D(const QQuickText);
1715 return d->elideMode;
1718 void QQuickText::setElideMode(QQuickText::TextElideMode mode)
1721 if (mode == d->elideMode)
1724 d->elideMode = mode;
1727 emit elideModeChanged(d->elideMode);
1731 \qmlproperty url QtQuick2::Text::baseUrl
1733 This property specifies a base URL which is used to resolve relative URLs
1736 By default is the url of the Text element.
1739 QUrl QQuickText::baseUrl() const
1741 Q_D(const QQuickText);
1742 if (d->baseUrl.isEmpty()) {
1743 if (QDeclarativeContext *context = qmlContext(this))
1744 const_cast<QQuickTextPrivate *>(d)->baseUrl = context->baseUrl();
1749 void QQuickText::setBaseUrl(const QUrl &url)
1752 if (baseUrl() != url) {
1756 d->doc->setBaseUrl(url);
1757 emit baseUrlChanged();
1761 void QQuickText::resetBaseUrl()
1763 if (QDeclarativeContext *context = qmlContext(this))
1764 setBaseUrl(context->baseUrl());
1770 QRectF QQuickText::boundingRect() const
1772 Q_D(const QQuickText);
1774 QRect rect = d->layedOutTextRect;
1775 if (d->style != Normal)
1776 rect.adjust(-1, 0, 1, 2);
1778 // Could include font max left/right bearings to either side of rectangle.
1781 switch (d->vAlign) {
1785 rect.moveTop(h - rect.height());
1788 rect.moveTop((h - rect.height()) / 2);
1792 return QRectF(rect);
1796 void QQuickText::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
1799 if (d->text.isEmpty()) {
1800 QQuickItem::geometryChanged(newGeometry, oldGeometry);
1804 bool widthChanged = newGeometry.width() != oldGeometry.width();
1805 bool heightChanged = newGeometry.height() != oldGeometry.height();
1806 bool leftAligned = effectiveHAlign() == QQuickText::AlignLeft;
1807 bool wrapped = d->wrapMode != QQuickText::NoWrap;
1808 bool elide = d->elideMode != QQuickText::ElideNone;
1810 if ((!widthChanged && !heightChanged) || d->internalWidthUpdate)
1811 goto geomChangeDone;
1813 if (leftAligned && !wrapped && !elide)
1814 goto geomChangeDone; // left aligned unwrapped text without eliding never needs relayout
1816 if (!widthChanged && !wrapped && d->singleline)
1817 goto geomChangeDone; // only height has changed which doesn't affect single line unwrapped text
1819 if (!widthChanged && wrapped && d->elideMode != QQuickText::ElideRight)
1820 goto geomChangeDone; // only height changed and no multiline eliding.
1822 if (leftAligned && d->elideMode == QQuickText::ElideRight && !d->truncated && d->singleline
1823 && !wrapped && newGeometry.width() > oldGeometry.width())
1824 goto geomChangeDone; // Eliding not affected if we're not currently truncated and we get wider.
1826 if (d->elideMode == QQuickText::ElideRight && wrapped && newGeometry.height() > oldGeometry.height()) {
1828 goto geomChangeDone; // Multiline eliding not affected if we're not currently truncated and we get higher.
1829 if (d->maximumLineCountValid && d->lineCount == d->maximumLineCount)
1830 goto geomChangeDone; // Multiline eliding not affected if we're already at max line count and we get higher.
1833 if (d->updateOnComponentComplete || (elide && widthValid())) {
1834 // We need to re-elide
1837 // We just need to re-layout
1842 QQuickItem::geometryChanged(newGeometry, oldGeometry);
1845 QSGNode *QQuickText::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
1850 if (d->text.isEmpty()) {
1855 QRectF bounds = boundingRect();
1857 // We need to make sure the layout is done in the current thread
1858 #if defined(Q_OS_MAC)
1859 d->paintingThread = QThread::currentThread();
1860 if (d->layoutThread != d->paintingThread)
1864 // XXX todo - some styled text can be done by the QQuickTextNode
1865 if (d->richTextAsImage || d->cacheAllTextAsImage || (d->disableDistanceField && d->style != Normal)) {
1866 bool wasDirty = d->textureImageCacheDirty;
1867 d->textureImageCacheDirty = false;
1869 if (!d->imageCache || d->imageCache->isNull()) {
1874 QSGImageNode *node = 0;
1875 if (!oldNode || d->nodeType != QQuickTextPrivate::NodeIsTexture) {
1877 node = QQuickItemPrivate::get(this)->sceneGraphContext()->createImageNode();
1878 d->texture = new QSGPlainTexture();
1880 d->nodeType = QQuickTextPrivate::NodeIsTexture;
1882 node = static_cast<QSGImageNode *>(oldNode);
1883 Q_ASSERT(d->texture);
1887 qobject_cast<QSGPlainTexture *>(d->texture)->setImage(d->imageCache->toImage());
1888 node->setTexture(0);
1889 node->setTexture(d->texture);
1892 node->setTargetRect(QRectF(bounds.x(), bounds.y(), d->imageCache->width(), d->imageCache->height()));
1893 node->setSourceRect(QRectF(0, 0, 1, 1));
1894 node->setHorizontalWrapMode(QSGTexture::ClampToEdge);
1895 node->setVerticalWrapMode(QSGTexture::ClampToEdge);
1896 node->setFiltering(QSGTexture::Linear); // Nonsmooth text just ugly, so don't do that..
1902 QQuickTextNode *node = 0;
1903 if (!oldNode || d->nodeType != QQuickTextPrivate::NodeIsText) {
1905 node = new QQuickTextNode(QQuickItemPrivate::get(this)->sceneGraphContext());
1906 d->nodeType = QQuickTextPrivate::NodeIsText;
1908 node = static_cast<QQuickTextNode *>(oldNode);
1911 node->deleteContent();
1912 node->setMatrix(QMatrix4x4());
1916 node->addTextDocument(bounds.topLeft(), d->doc, d->color, d->style, d->styleColor);
1918 } else if (d->elideMode == QQuickText::ElideNone || bounds.width() > 0.) {
1919 node->addTextLayout(QPoint(0, bounds.y()), &d->layout, d->color, d->style, d->styleColor);
1920 if (d->elipsisLayout)
1921 node->addTextLayout(QPoint(0, bounds.y()), d->elipsisLayout, d->color, d->style, d->styleColor);
1928 bool QQuickText::event(QEvent *e)
1931 if (e->type() == QEvent::User) {
1932 d->checkImageCache();
1935 return QQuickImplicitSizeItem::event(e);
1940 \qmlproperty real QtQuick2::Text::paintedWidth
1942 Returns the width of the text, including width past the width
1943 which is covered due to insufficient wrapping if WrapMode is set.
1945 qreal QQuickText::paintedWidth() const
1947 Q_D(const QQuickText);
1948 return d->paintedSize.width();
1952 \qmlproperty real QtQuick2::Text::paintedHeight
1954 Returns the height of the text, including height past the height
1955 which is covered due to there being more text than fits in the set height.
1957 qreal QQuickText::paintedHeight() const
1959 Q_D(const QQuickText);
1960 return d->paintedSize.height();
1964 \qmlproperty real QtQuick2::Text::lineHeight
1966 Sets the line height for the text.
1967 The value can be in pixels or a multiplier depending on lineHeightMode.
1969 The default value is a multiplier of 1.0.
1970 The line height must be a positive value.
1972 qreal QQuickText::lineHeight() const
1974 Q_D(const QQuickText);
1975 return d->lineHeight;
1978 void QQuickText::setLineHeight(qreal lineHeight)
1982 if ((d->lineHeight == lineHeight) || (lineHeight < 0.0))
1985 d->lineHeight = lineHeight;
1987 emit lineHeightChanged(lineHeight);
1991 \qmlproperty enumeration QtQuick2::Text::lineHeightMode
1993 This property determines how the line height is specified.
1994 The possible values are:
1997 \o Text.ProportionalHeight (default) - this sets the spacing proportional to the
1998 line (as a multiplier). For example, set to 2 for double spacing.
1999 \o Text.FixedHeight - this sets the line height to a fixed line height (in pixels).
2002 QQuickText::LineHeightMode QQuickText::lineHeightMode() const
2004 Q_D(const QQuickText);
2005 return d->lineHeightMode;
2008 void QQuickText::setLineHeightMode(LineHeightMode mode)
2011 if (mode == d->lineHeightMode)
2014 d->lineHeightMode = mode;
2017 emit lineHeightModeChanged(mode);
2021 Returns the number of resources (images) that are being loaded asynchronously.
2023 int QQuickText::resourcesLoading() const
2025 Q_D(const QQuickText);
2026 return d->doc ? d->doc->resourcesLoading() : 0;
2030 void QQuickText::componentComplete()
2033 if (d->updateOnComponentComplete) {
2036 d->doc->setText(d->text);
2037 d->rightToLeftText = d->doc->toPlainText().isRightToLeft();
2038 d->richTextAsImage = enableImageCache();
2040 d->rightToLeftText = d->text.isRightToLeft();
2042 d->determineHorizontalAlignment();
2044 QQuickItem::componentComplete();
2045 if (d->updateOnComponentComplete)
2048 // Enable accessibility for text items.
2049 d->setAccessibleFlagAndListener();
2053 QString QQuickTextPrivate::anchorAt(const QPointF &mousePos)
2056 for (int i = 0; i < layout.lineCount(); ++i) {
2057 QTextLine line = layout.lineAt(i);
2058 if (line.naturalTextRect().contains(mousePos)) {
2059 int charPos = line.xToCursor(mousePos.x());
2060 foreach (const QTextLayout::FormatRange &formatRange, layout.additionalFormats()) {
2061 if (formatRange.format.isAnchor()
2062 && charPos >= formatRange.start
2063 && charPos <= formatRange.start + formatRange.length) {
2064 return formatRange.format.anchorHref();
2074 bool QQuickTextPrivate::isLinkActivatedConnected()
2076 static int idx = this->signalIndex("linkActivated(QString)");
2077 return this->isSignalConnected(idx);
2081 void QQuickText::mousePressEvent(QMouseEvent *event)
2085 if (d->isLinkActivatedConnected()) {
2087 d->activeLink = d->anchorAt(event->localPos());
2088 else if (d->richText && d->doc)
2089 d->activeLink = d->doc->documentLayout()->anchorAt(event->localPos());
2092 if (d->activeLink.isEmpty())
2093 event->setAccepted(false);
2095 // ### may malfunction if two of the same links are clicked & dragged onto each other)
2097 if (!event->isAccepted())
2098 QQuickItem::mousePressEvent(event);
2103 void QQuickText::mouseReleaseEvent(QMouseEvent *event)
2107 // ### confirm the link, and send a signal out
2110 if (d->isLinkActivatedConnected()) {
2112 link = d->anchorAt(event->localPos());
2113 else if (d->richText && d->doc)
2114 link = d->doc->documentLayout()->anchorAt(event->localPos());
2117 if (!link.isEmpty() && d->activeLink == link)
2118 emit linkActivated(d->activeLink);
2120 event->setAccepted(false);
2122 if (!event->isAccepted())
2123 QQuickItem::mouseReleaseEvent(event);